Commit 35b16cf2 by Nicolas Capens

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/4711Tested-by: 's avatarNicolas Capens <capn@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <capn@google.com>
parent c3603631
#define MAJOR_VERSION 3 #define MAJOR_VERSION 3
#define MINOR_VERSION 2 #define MINOR_VERSION 2
#define BUILD_VERSION 10 #define BUILD_VERSION 10
#define BUILD_REVISION 47661 #define BUILD_REVISION 47663
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define MACRO_STRINGIFY(x) STRINGIFY(x) #define MACRO_STRINGIFY(x) STRINGIFY(x)
......
...@@ -1132,27 +1132,29 @@ namespace egl ...@@ -1132,27 +1132,29 @@ namespace egl
Image::~Image() Image::~Image()
{ {
ASSERT(!shared);
}
void Image::addRef()
{
if(parentTexture) if(parentTexture)
{ {
return parentTexture->addRef(); parentTexture->release();
} }
Object::addRef(); ASSERT(!shared);
} }
void Image::release() void Image::release()
{ {
if(parentTexture) int refs = dereference();
if(refs > 0)
{ {
return parentTexture->release(); if(parentTexture)
{
parentTexture->sweep();
}
}
else
{
delete this;
} }
Object::release();
} }
void Image::unbind(const egl::Texture *parent) void Image::unbind(const egl::Texture *parent)
......
...@@ -42,6 +42,7 @@ public: ...@@ -42,6 +42,7 @@ public:
{ {
shared = false; shared = false;
Object::addRef(); Object::addRef();
parentTexture->addRef();
} }
// 3D texture image // 3D texture image
...@@ -52,6 +53,7 @@ public: ...@@ -52,6 +53,7 @@ public:
{ {
shared = false; shared = false;
Object::addRef(); Object::addRef();
parentTexture->addRef();
} }
// Native EGL image // Native EGL image
...@@ -146,7 +148,6 @@ public: ...@@ -146,7 +148,6 @@ public:
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 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 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 release() override;
void unbind(const Texture *parent); // Break parent ownership and release void unbind(const Texture *parent); // Break parent ownership and release
bool isChildOf(const Texture *parent) const; bool isChildOf(const Texture *parent) const;
......
...@@ -17,6 +17,22 @@ public: ...@@ -17,6 +17,22 @@ public:
virtual void releaseTexImage() = 0; virtual void releaseTexImage() = 0;
virtual sw::Resource *getResource() const = 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;
}
}
}; };
} }
......
...@@ -387,6 +387,29 @@ void Texture2D::releaseProxy(const Renderbuffer *proxy) ...@@ -387,6 +387,29 @@ void Texture2D::releaseProxy(const Renderbuffer *proxy)
} }
} }
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 GLenum Texture2D::getTarget() const
{ {
return GL_TEXTURE_2D; return GL_TEXTURE_2D;
...@@ -439,7 +462,7 @@ void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum form ...@@ -439,7 +462,7 @@ void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum form
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
} }
image[level] = new egl::Image(this, width, height, format, type); image[level] = new egl::Image(this, width, height, format, type);
...@@ -477,7 +500,7 @@ void Texture2D::bindTexImage(egl::Surface *surface) ...@@ -477,7 +500,7 @@ void Texture2D::bindTexImage(egl::Surface *surface)
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
image[level] = nullptr; image[level] = nullptr;
} }
} }
...@@ -494,7 +517,7 @@ void Texture2D::releaseTexImage() ...@@ -494,7 +517,7 @@ void Texture2D::releaseTexImage()
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
image[level] = nullptr; image[level] = nullptr;
} }
} }
...@@ -504,7 +527,7 @@ void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GL ...@@ -504,7 +527,7 @@ void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GL
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
} }
image[level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE); image[level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE);
...@@ -539,7 +562,7 @@ void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei ...@@ -539,7 +562,7 @@ void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
} }
image[level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE); image[level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE);
...@@ -594,7 +617,7 @@ void Texture2D::setImage(egl::Image *sharedImage) ...@@ -594,7 +617,7 @@ void Texture2D::setImage(egl::Image *sharedImage)
if(image[0]) if(image[0])
{ {
image[0]->unbind(this); image[0]->release();
} }
image[0] = sharedImage; image[0] = sharedImage;
...@@ -689,7 +712,7 @@ void Texture2D::generateMipmaps() ...@@ -689,7 +712,7 @@ void Texture2D::generateMipmaps()
{ {
if(image[i]) 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()); 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());
......
...@@ -129,6 +129,7 @@ public: ...@@ -129,6 +129,7 @@ public:
void addProxyRef(const Renderbuffer *proxy) override; void addProxyRef(const Renderbuffer *proxy) override;
void releaseProxy(const Renderbuffer *proxy) override; void releaseProxy(const Renderbuffer *proxy) override;
void sweep() override;
virtual GLenum getTarget() const; virtual GLenum getTarget() const;
......
...@@ -558,6 +558,29 @@ void Texture2D::releaseProxy(const Renderbuffer *proxy) ...@@ -558,6 +558,29 @@ void Texture2D::releaseProxy(const Renderbuffer *proxy)
} }
} }
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 GLenum Texture2D::getTarget() const
{ {
return GL_TEXTURE_2D; return GL_TEXTURE_2D;
...@@ -610,7 +633,7 @@ void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum form ...@@ -610,7 +633,7 @@ void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum form
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
} }
image[level] = new egl::Image(this, width, height, format, type); image[level] = new egl::Image(this, width, height, format, type);
...@@ -648,7 +671,7 @@ void Texture2D::bindTexImage(egl::Surface *surface) ...@@ -648,7 +671,7 @@ void Texture2D::bindTexImage(egl::Surface *surface)
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
image[level] = nullptr; image[level] = nullptr;
} }
} }
...@@ -665,7 +688,7 @@ void Texture2D::releaseTexImage() ...@@ -665,7 +688,7 @@ void Texture2D::releaseTexImage()
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
image[level] = nullptr; image[level] = nullptr;
} }
} }
...@@ -675,7 +698,7 @@ void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GL ...@@ -675,7 +698,7 @@ void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GL
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
} }
GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
...@@ -711,7 +734,7 @@ void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei ...@@ -711,7 +734,7 @@ void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
} }
GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
...@@ -788,7 +811,7 @@ void Texture2D::setImage(egl::Image *sharedImage) ...@@ -788,7 +811,7 @@ void Texture2D::setImage(egl::Image *sharedImage)
if(image[0]) if(image[0])
{ {
image[0]->unbind(this); image[0]->release();
} }
image[0] = sharedImage; image[0] = sharedImage;
...@@ -883,7 +906,7 @@ void Texture2D::generateMipmaps() ...@@ -883,7 +906,7 @@ void Texture2D::generateMipmaps()
{ {
if(image[i]) 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()); 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::releaseProxy(const Renderbuffer *proxy) ...@@ -1024,6 +1047,32 @@ void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
} }
} }
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 GLenum TextureCubeMap::getTarget() const
{ {
return GL_TEXTURE_CUBE_MAP; return GL_TEXTURE_CUBE_MAP;
...@@ -1078,7 +1127,7 @@ void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum forma ...@@ -1078,7 +1127,7 @@ void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum forma
if(image[face][level]) if(image[face][level])
{ {
image[face][level]->unbind(this); image[face][level]->release();
} }
GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
...@@ -1220,7 +1269,7 @@ void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei ...@@ -1220,7 +1269,7 @@ void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei
if(image[face][level]) if(image[face][level])
{ {
image[face][level]->unbind(this); image[face][level]->release();
} }
image[face][level] = new egl::Image(this, width, height, format, type); image[face][level] = new egl::Image(this, width, height, format, type);
...@@ -1247,7 +1296,7 @@ void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint ...@@ -1247,7 +1296,7 @@ void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint
if(image[face][level]) if(image[face][level])
{ {
image[face][level]->unbind(this); image[face][level]->release();
} }
GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
...@@ -1342,7 +1391,7 @@ void TextureCubeMap::generateMipmaps() ...@@ -1342,7 +1391,7 @@ void TextureCubeMap::generateMipmaps()
{ {
if(image[f][i]) 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()); 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::releaseProxy(const Renderbuffer *proxy) ...@@ -1462,6 +1511,29 @@ void Texture3D::releaseProxy(const Renderbuffer *proxy)
} }
} }
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 GLenum Texture3D::getTarget() const
{ {
return GL_TEXTURE_3D_OES; return GL_TEXTURE_3D_OES;
...@@ -1520,7 +1592,7 @@ void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei dep ...@@ -1520,7 +1592,7 @@ void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei dep
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
} }
image[level] = new egl::Image(this, width, height, depth, format, type); image[level] = new egl::Image(this, width, height, depth, format, type);
...@@ -1554,7 +1626,7 @@ void Texture3D::bindTexImage(egl::Surface *surface) ...@@ -1554,7 +1626,7 @@ void Texture3D::bindTexImage(egl::Surface *surface)
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
image[level] = nullptr; image[level] = nullptr;
} }
} }
...@@ -1571,7 +1643,7 @@ void Texture3D::releaseTexImage() ...@@ -1571,7 +1643,7 @@ void Texture3D::releaseTexImage()
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
image[level] = nullptr; image[level] = nullptr;
} }
} }
...@@ -1581,7 +1653,7 @@ void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GL ...@@ -1581,7 +1653,7 @@ void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GL
{ {
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
} }
GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
...@@ -1617,7 +1689,7 @@ void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, ...@@ -1617,7 +1689,7 @@ void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z,
if(image[level]) if(image[level])
{ {
image[level]->unbind(this); image[level]->release();
} }
GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
...@@ -1691,7 +1763,7 @@ void Texture3D::setImage(egl::Image *sharedImage) ...@@ -1691,7 +1763,7 @@ void Texture3D::setImage(egl::Image *sharedImage)
if(image[0]) if(image[0])
{ {
image[0]->unbind(this); image[0]->release();
} }
image[0] = sharedImage; image[0] = sharedImage;
...@@ -1796,7 +1868,7 @@ void Texture3D::generateMipmaps() ...@@ -1796,7 +1868,7 @@ void Texture3D::generateMipmaps()
{ {
if(image[i]) 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()); 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 @@ void Texture2DArray::generateMipmaps() ...@@ -1888,7 +1960,7 @@ void Texture2DArray::generateMipmaps()
{ {
if(image[i]) if(image[i])
{ {
image[i]->unbind(this); image[i]->release();
} }
GLsizei w = std::max(image[0]->getWidth() >> i, 1); GLsizei w = std::max(image[0]->getWidth() >> i, 1);
......
...@@ -157,6 +157,7 @@ public: ...@@ -157,6 +157,7 @@ public:
void addProxyRef(const Renderbuffer *proxy) override; void addProxyRef(const Renderbuffer *proxy) override;
void releaseProxy(const Renderbuffer *proxy) override; void releaseProxy(const Renderbuffer *proxy) override;
void sweep() override;
virtual GLenum getTarget() const; virtual GLenum getTarget() const;
...@@ -215,6 +216,7 @@ public: ...@@ -215,6 +216,7 @@ public:
void addProxyRef(const Renderbuffer *proxy) override; void addProxyRef(const Renderbuffer *proxy) override;
void releaseProxy(const Renderbuffer *proxy) override; void releaseProxy(const Renderbuffer *proxy) override;
void sweep() override;
virtual GLenum getTarget() const; virtual GLenum getTarget() const;
...@@ -274,6 +276,7 @@ public: ...@@ -274,6 +276,7 @@ public:
void addProxyRef(const Renderbuffer *proxy) override; void addProxyRef(const Renderbuffer *proxy) override;
void releaseProxy(const Renderbuffer *proxy) override; void releaseProxy(const Renderbuffer *proxy) override;
void sweep() override;
virtual GLenum getTarget() const; virtual GLenum getTarget() const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment