gobj: Implement copy.deepcopy() for Texture class

Actually ensures that the underlying RAM images are really fully unique.
This commit is contained in:
rdb 2022-12-19 16:22:33 +01:00
parent e67cd74725
commit 896346b99f
5 changed files with 58 additions and 0 deletions

View File

@ -72,6 +72,7 @@ Miscellaneous
* Fix support for `#pragma include <file.glsl>` in GLSL shaders
* Fix `ShaderBuffer.prepare()` not doing anything
* Implement deepcopy for PointerToArray
* Fix Texture deepcopy keeping a reference to the original RAM image
* Fix bf-cbc encryption no longer working when building with OpenSSL 3.0
* PandaNode bounds_type property was erroneously marked read-only
* Fix warnings when copying OdeTriMeshGeom objects

View File

@ -46,6 +46,7 @@
#include "pnmImage.h"
#include "pfmFile.h"
#include "asyncFuture.h"
#include "extension.h"
class TextureContext;
class FactoryParams;
@ -472,6 +473,8 @@ PUBLISHED:
MAKE_PROPERTY(keep_ram_image, get_keep_ram_image, set_keep_ram_image);
MAKE_PROPERTY(cacheable, is_cacheable);
EXTENSION(PT(Texture) __deepcopy__(PyObject *memo) const);
BLOCKING INLINE bool compress_ram_image(CompressionMode compression = CM_on,
QualityLevel quality_level = QL_default,
GraphicsStateGuardianBase *gsg = nullptr);
@ -1110,6 +1113,7 @@ private:
static TypeHandle _type_handle;
friend class Extension<Texture>;
friend class TextureContext;
friend class PreparedGraphicsObjects;
friend class TexturePool;

View File

@ -165,4 +165,32 @@ set_ram_image_as(PyObject *image, const std::string &provided_format) {
Dtool_Raise_ArgTypeError(image, 0, "Texture.set_ram_image_as", "CPTA_uchar or buffer");
}
/**
* A special Python method that is invoked by copy.deepcopy(tex). This makes
* sure that the copy has a unique copy of the RAM image.
*/
PT(Texture) Extension<Texture>::
__deepcopy__(PyObject *memo) const {
PT(Texture) copy = _this->make_copy();
{
Texture::CDWriter cdata(copy->_cycler, true);
for (Texture::RamImage &image : cdata->_ram_images) {
if (image._image.get_ref_count() > 1) {
PTA_uchar new_image;
new_image.v() = image._image.v();
image._image = std::move(new_image);
}
}
{
Texture::RamImage &image = cdata->_simple_ram_image;
if (image._image.get_ref_count() > 1) {
PTA_uchar new_image;
new_image.v() = image._image.v();
image._image = std::move(new_image);
}
}
}
return copy;
}
#endif // HAVE_PYTHON

View File

@ -32,6 +32,8 @@ public:
void set_ram_image(PyObject *image, Texture::CompressionMode compression = Texture::CM_off,
size_t page_size = 0);
void set_ram_image_as(PyObject *image, const std::string &provided_format);
PT(Texture) __deepcopy__(PyObject *memo) const;
};
#endif // HAVE_PYTHON

View File

@ -134,3 +134,26 @@ def test_texture_clear_half():
assert col.y == -inf
assert col.z == -inf
assert math.isnan(col.w)
def test_texture_deepcopy():
from copy import deepcopy
empty_tex = Texture("empty-texture")
empty_tex.setup_2d_texture(16, 16, Texture.T_unsigned_byte, Texture.F_rgba)
assert not empty_tex.has_ram_image()
empty_tex2 = deepcopy(empty_tex)
assert empty_tex2.name == empty_tex.name
assert not empty_tex2.has_ram_image()
tex = Texture("texture")
tex.setup_2d_texture(16, 16, Texture.T_unsigned_byte, Texture.F_rgba)
img = tex.make_ram_image()
assert tex.has_ram_image()
assert img.get_ref_count() == 2
tex2 = deepcopy(tex)
assert tex2.name == tex.name
assert tex2.has_ram_image()
img2 = tex2.get_ram_image()
assert img2.get_ref_count() == 2