diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index ce3aa6cffe..223a86aab5 100644 --- a/panda/src/gobj/texture.I +++ b/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; } /** diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index d6c30296d9..c8c649bc36 100644 --- a/panda/src/gobj/texture.cxx +++ b/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 ©) { _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. diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index 7abdb17216..0254db323a 100644 --- a/panda/src/gobj/texture.h +++ b/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 RamImages; + struct ModifiedPageRange { + size_t _z_begin = 0; + size_t _z_end; + UpdateSeq _modified; + }; + typedef pvector 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; diff --git a/panda/src/gobj/textureContext.I b/panda/src/gobj/textureContext.I index 2c58bc7b07..a4be4a4935 100644 --- a/panda/src/gobj/textureContext.I +++ b/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. diff --git a/panda/src/gobj/textureContext.h b/panda/src/gobj/textureContext.h index 2962fd38c0..b531c49504 100644 --- a/panda/src/gobj/textureContext.h +++ b/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();