Fix reference counting of texture images. - Only unbind (orphan and release) images when the texture destructs. - Let images hold just one reference to the parent texture. - Check if textures and images only reference each other and garbage collect. Bug 26851951 Change-Id: I2b0bcc283bf545d948e91288c531eac7cc14d122 Reviewed-on: https://swiftshader-review.googlesource.com/4711 Tested-by: Nicolas Capens <capn@google.com> Reviewed-by: Alexis Hétu <sugoi@google.com> Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/Common/Version.h b/src/Common/Version.h index 7268708..ec9107a 100644 --- a/src/Common/Version.h +++ b/src/Common/Version.h
@@ -1,7 +1,7 @@ #define MAJOR_VERSION 3 #define MINOR_VERSION 2 #define BUILD_VERSION 10 -#define BUILD_REVISION 47661 +#define BUILD_REVISION 47663 #define STRINGIFY(x) #x #define MACRO_STRINGIFY(x) STRINGIFY(x)
diff --git a/src/OpenGL/common/Image.cpp b/src/OpenGL/common/Image.cpp index 73a8656..1396a52 100644 --- a/src/OpenGL/common/Image.cpp +++ b/src/OpenGL/common/Image.cpp
@@ -1132,27 +1132,29 @@ Image::~Image() { - ASSERT(!shared); - } - - void Image::addRef() - { if(parentTexture) { - return parentTexture->addRef(); + parentTexture->release(); } - Object::addRef(); + ASSERT(!shared); } void Image::release() { - if(parentTexture) - { - return parentTexture->release(); - } + int refs = dereference(); - Object::release(); + if(refs > 0) + { + if(parentTexture) + { + parentTexture->sweep(); + } + } + else + { + delete this; + } } void Image::unbind(const egl::Texture *parent)
diff --git a/src/OpenGL/common/Image.hpp b/src/OpenGL/common/Image.hpp index a019133..632e360 100644 --- a/src/OpenGL/common/Image.hpp +++ b/src/OpenGL/common/Image.hpp
@@ -42,6 +42,7 @@ { shared = false; Object::addRef(); + parentTexture->addRef(); } // 3D texture image @@ -52,6 +53,7 @@ { shared = false; Object::addRef(); + parentTexture->addRef(); } // Native EGL image @@ -146,7 +148,6 @@ void loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const UnpackInfo& unpackInfo, const void *input); void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels); - void addRef() override; void release() override; void unbind(const Texture *parent); // Break parent ownership and release bool isChildOf(const Texture *parent) const;
diff --git a/src/OpenGL/libEGL/Texture.hpp b/src/OpenGL/libEGL/Texture.hpp index 89f40bf..3805d97 100644 --- a/src/OpenGL/libEGL/Texture.hpp +++ b/src/OpenGL/libEGL/Texture.hpp
@@ -17,6 +17,22 @@ virtual void releaseTexImage() = 0; virtual sw::Resource *getResource() const = 0; + + virtual void sweep() = 0; // Garbage collect if no external references + + void release() override + { + int refs = dereference(); + + if(refs > 0) + { + sweep(); + } + else + { + delete this; + } + } }; }
diff --git a/src/OpenGL/libGLES_CM/Texture.cpp b/src/OpenGL/libGLES_CM/Texture.cpp index 9ee8989..bd3da9c 100644 --- a/src/OpenGL/libGLES_CM/Texture.cpp +++ b/src/OpenGL/libGLES_CM/Texture.cpp
@@ -387,6 +387,29 @@ } } +void Texture2D::sweep() +{ + int imageCount = 0; + + for(int i = 0; i < MIPMAP_LEVELS; i++) + { + if(image[i] && image[i]->isChildOf(this)) + { + if(!image[i]->hasSingleReference()) + { + return; + } + + imageCount++; + } + } + + if(imageCount == referenceCount) + { + destroy(); + } +} + GLenum Texture2D::getTarget() const { return GL_TEXTURE_2D; @@ -439,7 +462,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); } image[level] = new egl::Image(this, width, height, format, type); @@ -477,7 +500,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); image[level] = nullptr; } } @@ -494,7 +517,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); image[level] = nullptr; } } @@ -504,7 +527,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); } image[level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE); @@ -539,7 +562,7 @@ if(image[level]) { - image[level]->unbind(this); + image[level]->release(); } image[level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE); @@ -594,7 +617,7 @@ if(image[0]) { - image[0]->unbind(this); + image[0]->release(); } image[0] = sharedImage; @@ -689,7 +712,7 @@ { if(image[i]) { - image[i]->unbind(this); + image[i]->release(); } image[i] = new egl::Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
diff --git a/src/OpenGL/libGLES_CM/Texture.h b/src/OpenGL/libGLES_CM/Texture.h index 75b483b..4a49ddb 100644 --- a/src/OpenGL/libGLES_CM/Texture.h +++ b/src/OpenGL/libGLES_CM/Texture.h
@@ -129,6 +129,7 @@ void addProxyRef(const Renderbuffer *proxy) override; void releaseProxy(const Renderbuffer *proxy) override; + void sweep() override; virtual GLenum getTarget() const;
diff --git a/src/OpenGL/libGLESv2/Texture.cpp b/src/OpenGL/libGLESv2/Texture.cpp index 68ef704..c7877fa 100644 --- a/src/OpenGL/libGLESv2/Texture.cpp +++ b/src/OpenGL/libGLESv2/Texture.cpp
@@ -558,6 +558,29 @@ } } +void Texture2D::sweep() +{ + int imageCount = 0; + + for(int i = 0; i < MIPMAP_LEVELS; i++) + { + if(image[i] && image[i]->isChildOf(this)) + { + if(!image[i]->hasSingleReference()) + { + return; + } + + imageCount++; + } + } + + if(imageCount == referenceCount) + { + destroy(); + } +} + GLenum Texture2D::getTarget() const { return GL_TEXTURE_2D; @@ -610,7 +633,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); } image[level] = new egl::Image(this, width, height, format, type); @@ -648,7 +671,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); image[level] = nullptr; } } @@ -665,7 +688,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); image[level] = nullptr; } } @@ -675,7 +698,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); } GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); @@ -711,7 +734,7 @@ if(image[level]) { - image[level]->unbind(this); + image[level]->release(); } GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); @@ -788,7 +811,7 @@ if(image[0]) { - image[0]->unbind(this); + image[0]->release(); } image[0] = sharedImage; @@ -883,7 +906,7 @@ { if(image[i]) { - image[i]->unbind(this); + image[i]->release(); } image[i] = new egl::Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType()); @@ -1024,6 +1047,32 @@ } } +void TextureCubeMap::sweep() +{ + int imageCount = 0; + + for(int f = 0; f < 6; f++) + { + for(int i = 0; i < MIPMAP_LEVELS; i++) + { + if(image[f][i] && image[f][i]->isChildOf(this)) + { + if(!image[f][i]->hasSingleReference()) + { + return; + } + + imageCount++; + } + } + } + + if(imageCount == referenceCount) + { + destroy(); + } +} + GLenum TextureCubeMap::getTarget() const { return GL_TEXTURE_CUBE_MAP; @@ -1078,7 +1127,7 @@ if(image[face][level]) { - image[face][level]->unbind(this); + image[face][level]->release(); } GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); @@ -1220,7 +1269,7 @@ if(image[face][level]) { - image[face][level]->unbind(this); + image[face][level]->release(); } image[face][level] = new egl::Image(this, width, height, format, type); @@ -1247,7 +1296,7 @@ if(image[face][level]) { - image[face][level]->unbind(this); + image[face][level]->release(); } GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); @@ -1342,7 +1391,7 @@ { if(image[f][i]) { - image[f][i]->unbind(this); + image[f][i]->release(); } image[f][i] = new egl::Image(this, std::max(image[0][0]->getWidth() >> i, 1), std::max(image[0][0]->getHeight() >> i, 1), image[0][0]->getFormat(), image[0][0]->getType()); @@ -1462,6 +1511,29 @@ } } +void Texture3D::sweep() +{ + int imageCount = 0; + + for(int i = 0; i < MIPMAP_LEVELS; i++) + { + if(image[i] && image[i]->isChildOf(this)) + { + if(!image[i]->hasSingleReference()) + { + return; + } + + imageCount++; + } + } + + if(imageCount == referenceCount) + { + destroy(); + } +} + GLenum Texture3D::getTarget() const { return GL_TEXTURE_3D_OES; @@ -1520,7 +1592,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); } image[level] = new egl::Image(this, width, height, depth, format, type); @@ -1554,7 +1626,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); image[level] = nullptr; } } @@ -1571,7 +1643,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); image[level] = nullptr; } } @@ -1581,7 +1653,7 @@ { if(image[level]) { - image[level]->unbind(this); + image[level]->release(); } GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); @@ -1617,7 +1689,7 @@ if(image[level]) { - image[level]->unbind(this); + image[level]->release(); } GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); @@ -1691,7 +1763,7 @@ if(image[0]) { - image[0]->unbind(this); + image[0]->release(); } image[0] = sharedImage; @@ -1796,7 +1868,7 @@ { if(image[i]) { - image[i]->unbind(this); + image[i]->release(); } image[i] = new egl::Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), std::max(image[0]->getDepth() >> i, 1), image[0]->getFormat(), image[0]->getType()); @@ -1888,7 +1960,7 @@ { if(image[i]) { - image[i]->unbind(this); + image[i]->release(); } GLsizei w = std::max(image[0]->getWidth() >> i, 1);
diff --git a/src/OpenGL/libGLESv2/Texture.h b/src/OpenGL/libGLESv2/Texture.h index 30dc822..28d759c 100644 --- a/src/OpenGL/libGLESv2/Texture.h +++ b/src/OpenGL/libGLESv2/Texture.h
@@ -157,6 +157,7 @@ void addProxyRef(const Renderbuffer *proxy) override; void releaseProxy(const Renderbuffer *proxy) override; + void sweep() override; virtual GLenum getTarget() const; @@ -215,6 +216,7 @@ void addProxyRef(const Renderbuffer *proxy) override; void releaseProxy(const Renderbuffer *proxy) override; + void sweep() override; virtual GLenum getTarget() const; @@ -274,6 +276,7 @@ void addProxyRef(const Renderbuffer *proxy) override; void releaseProxy(const Renderbuffer *proxy) override; + void sweep() override; virtual GLenum getTarget() const;