POV-Ray / povray

The Persistence of Vision Raytracer: http://www.povray.org/
GNU Affero General Public License v3.0
1.35k stars 282 forks source link

Cahce large Image Maps when rendering animations #395

Open mlsomers opened 4 years ago

mlsomers commented 4 years ago

Summary

Parsing takes allot of time when loading huge image maps (height and color maps for planets for example). To speed up animation rendering these images could be cached for reuse.

Suggested Solution

I did an attempt of getting my feet wet in C++, not successful so far :-(

Here's some C# pseudo code of what I would like to do:

namespace pseudocode
{
  public class Parser // this would be pov_parser::Parser
  {
    public class Image { } // placeholder representing pov_base::Image

    // -- parser.h

    private struct ImageFileInfo // The Dictionary Value type
    {
      public DateTime LastModifiedDate;
      public Image Image;
    }

    private static Dictionary<string, ImageFileInfo> Cache = new Dictionary<string, ImageFileInfo>(); // static cache

    // -- parser.cpp

    // Replace the original Read_Image with a check if it is in the cache
    public Image Read_Image(int filetype, string filename, int options)
    {
      ImageFileInfo imageInfo;
      if (Cache.TryGetValue(filename, out imageInfo))
      {
        if(File.GetLastWriteTime(filename) == imageInfo.LastModifiedDate)
        return imageInfo.Image;
      }

      imageInfo = new ImageFileInfo { 
        LastModifiedDate = File.GetLastWriteTime(filename),
        Image = Original_Read_Image(filetype, filename, options)
      };

      Cache.Add(filename, imageInfo);
      return imageInfo.Image;
    }

    // Placeholder for the original Read_Image method...
    private Image Original_Read_Image(int filetype, string filename, int options) {
      return null;
    }

    // Allow UI to clear memory
    public void ClaerCache()
    {
      Cache.Clear();
    }
  }
}

This is my lousy attempt at C++ (for now omitting the LastWriteTime check)

parser.h:

+      static std::map<pov_base::UCS2, pov_base::Image> ImageCache;

       Image *Read_Image(int filetype, const UCS2 *filename, const ImageReadOptions& options);
+      Image *Original_Read_Image(int filetype, const UCS2* filename, const ImageReadOptions& options);

parser.cpp:

Image *Parser::Read_Image(int filetype, const UCS2* filename, const ImageReadOptions& options)
{
    std::map<UCS2, Image>::iterator idx = ImageCache.find(*filename);
    if (idx != ImageCache.end()) {
        Image& ret = ImageCache[*filename];
        return &ret;
    }

    Image *img = Original_Read_Image(filetype, filename, options);
    ImageCache[*filename] = *img;
    return img;
}

Image *Parser::Original_Read_Image(int filetype, const UCS2* filename, const ImageReadOptions& options)
{
    unsigned int stype;
    ...
}

So far I've been unable to figure out the pointer/reference stuff for filling the Cache, also I don't understand why the map is trying to create an instance... and how does the map know how to sort (C# uses a hash function for sorting).

Any way, even if I got this far I would have to find, and disable, the cleaning up code for the images, prevent them from being freed.

mlsomers commented 4 years ago

I have been making some progress...

static std::map<pov_base::UCS2, pov_base::Image*> ImageCache;

Image *Parser::Read_Image(int filetype, const UCS2* filename, const ImageReadOptions& options)
{
    std::map<pov_base::UCS2, pov_base::Image*>::iterator idx = ImageCache.find(*filename);
    if (idx != ImageCache.end()) {
        Image* ret = ImageCache[*filename];
        return ret;
    }

    Image *img = Original_Read_Image(filetype, filename, options);
    ImageCache[*filename] = img;
    return img;
}

I've also disabled the Destroy_... methods in most core\material files for the time being. It is leaking some memory off course, but insignificant compared to the huge benifit... I'll try to do a check on if the items are in cache or not later...

There is still one problem though, ImageCache.find(*filename) suffers from false positives (giving several planets in my scene identical surfaces). At first glance it looks like all files in the same directory are seen as the same file...

C++ is really hard to wrap my head around at times (to pointer or not to pointer is the question)... but the rewards are superb :-)

To be continued...

c-lipka commented 3 years ago

One of the issues that would have to be addressed is that of memory leakage - not in the sense that the software somehow forgets that it has ever allocated the memory, but in the sense that it still never releases it,, no matter what. Two scenarios in particular would have to be addressed: