gobj: Implement texture modification tracking for individual pages

Part of #1168, GL implementation in following commit
This commit is contained in:
rdb 2021-07-04 16:36:26 +02:00
parent 77f486a07b
commit 494631ac54
5 changed files with 129 additions and 16 deletions

View File

@ -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;
}
/**

View File

@ -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.

View File

@ -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;

View File

@ -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.

View File

@ -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();