Browse Source

gobj: Implement texture modification tracking for individual pages

Part of #1168, GL implementation in following commit
rdb 4 years ago
parent
commit
494631ac54

+ 6 - 7
panda/src/gobj/texture.I

@@ -357,8 +357,6 @@ INLINE bool Texture::
 load(const PNMImage &pnmimage, const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   do_clear(cdata);
-  cdata->inc_properties_modified();
-  cdata->inc_image_modified();
   if (do_load_one(cdata, pnmimage, get_name(), 0, 0, options)) {
     bool generate_mipmaps = ((options.get_texture_flags() & LoaderOptions::TF_generate_mipmaps) != 0);
     consider_auto_process_ram_image(generate_mipmaps || uses_mipmaps(), true);
@@ -374,7 +372,7 @@ INLINE bool Texture::
 load(const PNMImage &pnmimage, int z, int n, const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   cdata->inc_properties_modified();
-  cdata->inc_image_modified();
+  cdata->inc_image_page_modified(z);
   if (do_load_one(cdata, pnmimage, get_name(), z, n, options)) {
     return true;
   }
@@ -388,8 +386,6 @@ INLINE bool Texture::
 load(const PfmFile &pfm, const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   do_clear(cdata);
-  cdata->inc_properties_modified();
-  cdata->inc_image_modified();
   if (do_load_one(cdata, pfm, get_name(), 0, 0, options)) {
     bool generate_mipmaps = ((options.get_texture_flags() & LoaderOptions::TF_generate_mipmaps) != 0);
     consider_auto_process_ram_image(generate_mipmaps || uses_mipmaps(), true);
@@ -405,7 +401,7 @@ INLINE bool Texture::
 load(const PfmFile &pfm, int z, int n, const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   cdata->inc_properties_modified();
-  cdata->inc_image_modified();
+  cdata->inc_image_page_modified(z);
   if (do_load_one(cdata, pfm, get_name(), z, n, options)) {
     return true;
   }
@@ -2460,11 +2456,14 @@ inc_properties_modified() {
 }
 
 /**
- *
+ * Marks the whole image as modified.
  */
 INLINE void Texture::CData::
 inc_image_modified() {
   ++_image_modified;
+  _modified_pages.resize(1);
+  _modified_pages[0]._z_end = (size_t)-1;
+  _modified_pages[0]._modified = _image_modified;
 }
 
 /**

+ 90 - 9
panda/src/gobj/texture.cxx

@@ -551,8 +551,6 @@ bool Texture::
 read(const Filename &fullpath, const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   do_clear(cdata);
-  cdata->inc_properties_modified();
-  cdata->inc_image_modified();
   return do_read(cdata, fullpath, Filename(), 0, 0, 0, 0, false, false,
                  options, nullptr);
 }
@@ -570,8 +568,6 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
      const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   do_clear(cdata);
-  cdata->inc_properties_modified();
-  cdata->inc_image_modified();
   return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
                  alpha_file_channel, 0, 0, false, false,
                  options, nullptr);
@@ -585,12 +581,15 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
  * the various parameters.
  */
 bool Texture::
-read(const Filename &fullpath, int z, int n,
-     bool read_pages, bool read_mipmaps,
+read(const Filename &fullpath, int z, int n, bool read_pages, bool read_mipmaps,
      const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   cdata->inc_properties_modified();
-  cdata->inc_image_modified();
+  if (read_pages) {
+    cdata->inc_image_modified();
+  } else {
+    cdata->inc_image_page_modified(z);
+  }
   return do_read(cdata, fullpath, Filename(), 0, 0, z, n, read_pages, read_mipmaps,
                  options, nullptr);
 }
@@ -655,7 +654,11 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
      const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   cdata->inc_properties_modified();
-  cdata->inc_image_modified();
+  if (read_pages) {
+    cdata->inc_image_modified();
+  } else {
+    cdata->inc_image_page_modified(z);
+  }
   return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
                  alpha_file_channel, z, n, read_pages, read_mipmaps,
                  options, record);
@@ -1422,6 +1425,39 @@ peek() {
   return nullptr;
 }
 
+/**
+ * Returns a SparseArray containing all the image pages that have been modified
+ * since the given UpdateSeq value.
+ */
+SparseArray Texture::
+get_image_modified_pages(UpdateSeq since, int n) const {
+  CDReader cdata(_cycler);
+
+  SparseArray result;
+  if (since == cdata->_image_modified) {
+    // Early-out since no range is more recent than _image_modified.
+    return result;
+  }
+
+  if (n > 0 && cdata->_texture_type == Texture::TT_3d_texture) {
+    // Don't bother handling this special case, just consider all mipmap pages
+    // modified.
+    result.set_range(0, do_get_expected_mipmap_z_size(cdata, n));
+    return result;
+  }
+
+  for (const ModifiedPageRange &range : cdata->_modified_pages) {
+    if (range._z_begin >= cdata->_z_size) {
+      break;
+    }
+    if (since < range._modified) {
+      result.set_range(range._z_begin, std::min(range._z_end, (size_t)cdata->_z_size) - range._z_begin);
+    }
+  }
+
+  return result;
+}
+
 /**
  * Indicates that the texture should be enqueued to be prepared in the
  * indicated prepared_objects at the beginning of the next frame.  This will
@@ -3541,7 +3577,7 @@ do_load_sub_image(CData *cdata, const PNMImage &image, int x, int y, int z, int
   // Flip y
   y = cdata->_y_size - (image.get_y_size() + y);
 
-  cdata->inc_image_modified();
+  cdata->inc_image_page_modified(z);
   do_modify_ram_mipmap_image(cdata, n);
   convert_from_pnmimage(cdata->_ram_images[n]._image,
                         do_get_expected_ram_mipmap_page_size(cdata, n),
@@ -10619,6 +10655,10 @@ CData() {
   _simple_ram_image._page_size = 0;
 
   _has_clear_color = false;
+
+  _modified_pages.resize(1);
+  _modified_pages[0]._z_end = (size_t)-1;
+  _modified_pages[0]._modified = _image_modified;
 }
 
 /**
@@ -10633,6 +10673,7 @@ CData(const Texture::CData &copy) {
   _properties_modified = copy._properties_modified;
   _image_modified = copy._image_modified;
   _simple_image_modified = copy._simple_image_modified;
+  _modified_pages = copy._modified_pages;
 }
 
 /**
@@ -10690,6 +10731,46 @@ do_assign(const Texture::CData *copy) {
   _simple_ram_image = copy->_simple_ram_image;
 }
 
+/**
+ * Marks a single page of the image as modified.
+ */
+void Texture::CData::
+inc_image_page_modified(int z) {
+  ++_image_modified;
+
+  ModifiedPageRanges::iterator it = _modified_pages.begin();
+  while (it != _modified_pages.end() && (*it)._z_end <= z) {
+    ++it;
+    continue;
+  }
+  nassertv(it != _modified_pages.end());
+
+  size_t orig_z_end = (*it)._z_end;
+  UpdateSeq orig_modified = (*it)._modified;
+
+  if (z > (*it)._z_begin) {
+    // Split prefix.
+    ModifiedPageRange copy(*it);
+    copy._z_end = z;
+    it = _modified_pages.insert(it, copy);
+    ++it;
+  }
+
+  (*it)._z_begin = z;
+  (*it)._z_end = z + 1;
+  (*it)._modified = _image_modified;
+
+  if (z + 1 < orig_z_end) {
+    // Split suffix.
+    ModifiedPageRange copy(*it);
+    copy._z_begin = z + 1;
+    copy._z_end = orig_z_end;
+    copy._modified = orig_modified;
+    ++it;
+    _modified_pages.insert(it, copy);
+  }
+}
+
 /**
  * Writes the contents of this object to the datagram for shipping out to a
  * Bam file.

+ 12 - 0
panda/src/gobj/texture.h

@@ -525,6 +525,8 @@ PUBLISHED:
   MAKE_PROPERTY(image_modified, get_image_modified);
   MAKE_PROPERTY(simple_image_modified, get_simple_image_modified);
 
+  SparseArray get_image_modified_pages(UpdateSeq since, int n = 0) const;
+
   INLINE bool has_auto_texture_scale() const;
   INLINE AutoTextureScale get_auto_texture_scale() const;
   INLINE void set_auto_texture_scale(AutoTextureScale scale);
@@ -932,6 +934,13 @@ private:
 protected:
   typedef pvector<RamImage> RamImages;
 
+  struct ModifiedPageRange {
+    size_t _z_begin = 0;
+    size_t _z_end;
+    UpdateSeq _modified;
+  };
+  typedef pvector<ModifiedPageRange> ModifiedPageRanges;
+
   // This is the data that must be cycled between pipeline stages.
   class EXPCL_PANDA_GOBJ CData : public CycleData {
   public:
@@ -949,6 +958,7 @@ protected:
     void do_assign(const CData *copy);
     INLINE void inc_properties_modified();
     INLINE void inc_image_modified();
+    void inc_image_page_modified(int z);
     INLINE void inc_simple_image_modified();
 
     Filename _filename;
@@ -1020,6 +1030,8 @@ protected:
     UpdateSeq _image_modified;
     UpdateSeq _simple_image_modified;
 
+    ModifiedPageRanges _modified_pages;
+
   public:
     static TypeHandle get_class_type() {
       return _type_handle;

+ 18 - 0
panda/src/gobj/textureContext.I

@@ -76,6 +76,15 @@ was_simple_image_modified() const {
   return _simple_image_modified != get_texture()->get_simple_image_modified();
 }
 
+/**
+ * Returns true if the given page of the texture image has been modified since
+ * the last time mark_loaded() was called.
+ */
+INLINE bool TextureContext::
+was_image_page_modified(int z, int n) const {
+  return get_texture()->get_image_modified_pages(_image_modified, n).get_bit(z);
+}
+
 /**
  * Returns a sequence number which is guaranteed to change at least every time
  * the texture properties (unrelated to the image) are modified.
@@ -103,6 +112,15 @@ get_simple_image_modified() const {
   return _simple_image_modified;
 }
 
+/**
+ * Returns a SparseArray indicating which pages of the texture have been
+ * modified since the last call to mark_loaded().
+ */
+INLINE SparseArray TextureContext::
+get_image_modified_pages(int n) const {
+  return get_texture()->get_image_modified_pages(_image_modified, n);
+}
+
 /**
  * Should be called (usually by a derived class) when the on-card size of this
  * object has changed.

+ 3 - 0
panda/src/gobj/textureContext.h

@@ -44,11 +44,14 @@ PUBLISHED:
   INLINE bool was_properties_modified() const;
   INLINE bool was_image_modified() const;
   INLINE bool was_simple_image_modified() const;
+  INLINE bool was_image_page_modified(int z, int n) const;
 
   INLINE UpdateSeq get_properties_modified() const;
   INLINE UpdateSeq get_image_modified() const;
   INLINE UpdateSeq get_simple_image_modified() const;
 
+  INLINE SparseArray get_image_modified_pages(int n = 0) const;
+
 public:
   INLINE void update_data_size_bytes(size_t new_data_size_bytes);
   INLINE void mark_loaded();