Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache Images for faster parsing subsequent images (or frames in animation) #396 #398

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion source/core/support/imageutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1388,11 +1388,17 @@ ImageData *Copy_Image(ImageData *Old)
void Destroy_Image(ImageData *image)
{
if ((image == nullptr) || (--(image->References) > 0))
return;
return;

image->data = nullptr; // Prevent the image from being deleted. Images are now cached.
delete image;
}

void Remove_Cached_Image(Image* image) {
delete image;
}


ImageData::~ImageData()
{
#ifdef POV_VIDCAP_IMPL
Expand Down
1 change: 1 addition & 0 deletions source/core/support/imageutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ int map_pos(const Vector3d& EPoint, const ImageData* pImage, DBL *xcoor, DBL *yc
ImageData *Copy_Image(ImageData *old);
ImageData *Create_Image(void);
void Destroy_Image(ImageData *image);
void Remove_Cached_Image(Image* image);

/// @}
///
Expand Down
135 changes: 135 additions & 0 deletions source/parser/ImageCache.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//******************************************************************************
///
/// @file parser/ImageCache.cpp
///
/// This module implements a cache for images used in a scene so they only heve
/// to be loaded once during animation rendering or between manual renders
///
/// @copyright
/// @parblock
///
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
/// Copyright 1991-2019 Persistence of Vision Raytracer Pty. Ltd.
///
/// POV-Ray is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License as
/// published by the Free Software Foundation, either version 3 of the
/// License, or (at your option) any later version.
///
/// POV-Ray is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/// GNU Affero General Public License for more details.
///
/// You should have received a copy of the GNU Affero General Public License
/// along with this program. If not, see <http://www.gnu.org/licenses/>.
///
/// ----------------------------------------------------------------------------
///
/// POV-Ray is based on the popular DKB raytracer version 2.12.
/// DKBTrace was originally written by David K. Buck.
/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
///
/// @endparblock
///
//******************************************************************************


// C++ variants of C standard header files
#include <map>

#include <sys/types.h>
#include <sys/stat.h>

#ifndef WIN32
#include <unistd.h> // Unix lib for getting last modified file date and time
#endif
#ifdef WIN32
#define stat _stat // Windows lib for getting last modified file date and time
#endif


// POV-Ray header files (base module)
#include "base/base_fwd.h"
#include "base/messenger_fwd.h"
#include "base/povassert.h"
#include "base/stringtypes.h"
#include "base/textstream_fwd.h"
#include "base/textstreambuffer.h"
#include "base/image/image_fwd.h"
#include "base/stringutilities.h"
#include "core/support/imageutil.h"

// this must be the last file included
#include "base/povdebug.h"


namespace pov_image_cache
{
using namespace pov_base;
using namespace std;
using namespace pov;

struct ImageCacheEntry final
{
Image* image;
long lastModified;
};

static std::map<std::string, ImageCacheEntry> Cache; // <- The actual cache

// Gets the last modified time from the filesystem
long GetLastModifiedTime(const std::string filename)
{
const char* cstrFilename = filename.c_str();

struct stat result;
if (stat(cstrFilename, &result) == 0)
{
return (long)result.st_mtime;
}
return 0;
}

// Try to get the image from the cache
Image* GetCachedImage(const UCS2* filename)
{
std::string lookupFilename = pov_base::UCS2toSysString(filename);

std::map<std::string, ImageCacheEntry>::iterator idx = Cache.find(lookupFilename);
if (idx != Cache.end())
{
long lastModified = GetLastModifiedTime(lookupFilename);
if (lastModified == Cache[lookupFilename].lastModified)
return idx->second.image; //Cache[lookupFilename].image;

// Remove old image from cache and release memory so the newer version can be loaded
pov::Remove_Cached_Image(idx->second.image);
Cache.erase(idx);
}

return nullptr;
}

// Store a new image into cache
void StoreImageInCache(const UCS2* filename, Image* image)
{
std::string lookupFilename = pov_base::UCS2toSysString(filename);
long lastModified = GetLastModifiedTime(lookupFilename);
Cache[lookupFilename] = ImageCacheEntry{ image = image, lastModified = lastModified };
}

// May be called frome some menu item, personally, I'd just close PovRay and start a new process (different scenes often share resources in my case)
// Do not allow calling it while parsing or rendering!
void ClearCache()
{
std::map<std::string, ImageCacheEntry>::iterator it = Cache.begin();

// Iterate over the map using Iterator till end.
while (it != Cache.end())
{
pov::Remove_Cached_Image(it->second.image);
Cache.erase(it);
}
}
}
79 changes: 79 additions & 0 deletions source/parser/ImageCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//******************************************************************************
///
/// @file parser/ImageCache.h
///
/// Declarations related to the Image Cache.
///
/// @copyright
/// @parblock
///
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
/// Copyright 1991-2019 Persistence of Vision Raytracer Pty. Ltd.
///
/// POV-Ray is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License as
/// published by the Free Software Foundation, either version 3 of the
/// License, or (at your option) any later version.
///
/// POV-Ray is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/// GNU Affero General Public License for more details.
///
/// You should have received a copy of the GNU Affero General Public License
/// along with this program. If not, see <http://www.gnu.org/licenses/>.
///
/// ----------------------------------------------------------------------------
///
/// POV-Ray is based on the popular DKB raytracer version 2.12.
/// DKBTrace was originally written by David K. Buck.
/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
///
/// @endparblock
///
//******************************************************************************

#ifndef POVRAY_PARSER_IMAGE_CACHE_H
#define POVRAY_PARSER_IMAGE_CACHE_H

#include <sys/types.h>
#include <sys/stat.h>

#ifndef WIN32
#include <unistd.h> // Unix lib for getting last modified file date and time
#endif
#ifdef WIN32
#define stat _stat // Windows lib for getting last modified file date and time
#endif


// POV-Ray header files (base module)
#include "base/base_fwd.h"
#include "base/messenger_fwd.h"
#include "base/povassert.h"
#include "base/stringtypes.h"
#include "base/textstream_fwd.h"
#include "base/textstreambuffer.h"
#include "base/image/image_fwd.h"

namespace pov
{
class Blob_Element;
struct ContainedByShape;
struct GenericSpline;
class ImageData;
class Mesh;
struct PavementPattern;
struct TilingPattern;
struct TrueTypeFont;
}

namespace pov_image_cache
{
using namespace pov_base;

Image* GetCachedImage(const UCS2* filename);
void StoreImageInCache(const UCS2* filename, Image* image);
};

#endif // POVRAY_PARSER_IMAGE_CACHE_H
15 changes: 12 additions & 3 deletions source/parser/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
#include "vm/fnpovfpu.h"

// POV-Ray header files (parser module)
// (none at the moment)
#include "parser/ImageCache.h"

// this must be the last file included
#include "base/povdebug.h"
Expand All @@ -122,6 +122,7 @@ namespace pov_parser
{

using namespace pov;
using namespace pov_image_cache;

using std::min;
using std::max;
Expand Down Expand Up @@ -9971,8 +9972,12 @@ OStream *Parser::CreateFile(const UCS2String& filename, unsigned int stype, bool

//******************************************************************************

Image *Parser::Read_Image(int filetype, const UCS2 *filename, const ImageReadOptions& options)
Image *Parser::Read_Image(int filetype, const UCS2* filename, const ImageReadOptions& options)
{
Image* img = pov_image_cache::GetCachedImage(filename);
if (img != nullptr)
return img;

unsigned int stype;
Image::ImageFileType type;
UCS2String ign;
Expand Down Expand Up @@ -10040,7 +10045,11 @@ Image *Parser::Read_Image(int filetype, const UCS2 *filename, const ImageReadOpt
if (file == nullptr)
throw POV_EXCEPTION(kCannotOpenFileErr, "Cannot find image file.");

return Image::Read(type, file.get(), options);
img = Image::Read(type, file.get(), options);

pov_image_cache::StoreImageInCache(filename, img);

return img;
}

//******************************************************************************
Expand Down
2 changes: 2 additions & 0 deletions windows/vs2015/povparser.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\source\parser\fncode.cpp" />
<ClCompile Include="..\..\source\parser\ImageCache.cpp" />
<ClCompile Include="..\..\source\parser\parser.cpp" />
<ClCompile Include="..\..\source\parser\parsertypes.cpp" />
<ClCompile Include="..\..\source\parser\parser_expressions.cpp" />
Expand All @@ -424,6 +425,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\source\parser\fncode.h" />
<ClInclude Include="..\..\source\parser\ImageCache.h" />
<ClInclude Include="..\..\source\parser\parser.h" />
<ClInclude Include="..\..\source\parser\parsertypes.h" />
<ClInclude Include="..\..\source\parser\parser_fwd.h" />
Expand Down
6 changes: 6 additions & 0 deletions windows/vs2015/povparser.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
<ClInclude Include="..\..\source\parser\parser_fwd.h">
<Filter>Parser Headers</Filter>
</ClInclude>
<ClInclude Include="..\..\source\parser\ImageCache.h">
<Filter>Parser Headers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\source\parser\parser.cpp">
Expand Down Expand Up @@ -93,5 +96,8 @@
<ClCompile Include="..\..\source\parser\symboltable.cpp">
<Filter>Parser Source</Filter>
</ClCompile>
<ClCompile Include="..\..\source\parser\ImageCache.cpp">
<Filter>Parser Source</Filter>
</ClCompile>
</ItemGroup>
</Project>