From 55847bdcb375c1757229323c874b9dc3aa3b7911 Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Thu, 22 May 2025 16:46:57 +0300 Subject: [PATCH] gl_engine: fix memoty leak on target resize We must to remove offscreen render buffers during removing render target https://github.com/thorvg/thorvg/issues/3210 --- src/renderer/gl_engine/tvgGlRenderTarget.cpp | 35 +++++++++++--------- src/renderer/gl_engine/tvgGlRenderTarget.h | 6 ++-- src/renderer/gl_engine/tvgGlRenderer.cpp | 5 +-- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/renderer/gl_engine/tvgGlRenderTarget.cpp b/src/renderer/gl_engine/tvgGlRenderTarget.cpp index 47c2f831..9c2ae4a6 100644 --- a/src/renderer/gl_engine/tvgGlRenderTarget.cpp +++ b/src/renderer/gl_engine/tvgGlRenderTarget.cpp @@ -22,25 +22,18 @@ #include "tvgGlRenderTarget.h" -GlRenderTarget::GlRenderTarget(uint32_t width, uint32_t height): mWidth(width), mHeight(height) {} +GlRenderTarget::GlRenderTarget() {} GlRenderTarget::~GlRenderTarget() { - if (mFbo == 0) return; - GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0)); - GL_CHECK(glDeleteFramebuffers(1, &mFbo)); - - if (mColorTex != 0) { - GL_CHECK(glDeleteTextures(1, &mColorTex)); - } - if (mDepthStencilBuffer != 0) { - GL_CHECK(glDeleteRenderbuffers(1, &mDepthStencilBuffer)); - } + reset(); } -void GlRenderTarget::init(GLint resolveId) +void GlRenderTarget::init(uint32_t width, uint32_t height, GLint resolveId) { - if (mFbo != GL_INVALID_VALUE || mWidth == 0 || mHeight == 0) return; + if (mFbo != GL_INVALID_VALUE || width == 0 || height == 0) return; + mWidth = width; + mHeight = height; //TODO: fbo is used. maybe we can consider the direct rendering with resolveId as well. GL_CHECK(glGenFramebuffers(1, &mFbo)); @@ -82,6 +75,18 @@ void GlRenderTarget::init(GLint resolveId) GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, resolveId)); } +void GlRenderTarget::reset() +{ + if (mFbo == 0) return; + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0)); + GL_CHECK(glDeleteFramebuffers(1, &mFbo)); + GL_CHECK(glDeleteRenderbuffers(1, &mColorBuffer)); + GL_CHECK(glDeleteRenderbuffers(1, &mDepthStencilBuffer)); + GL_CHECK(glDeleteFramebuffers(1, &mResolveFbo)); + GL_CHECK(glDeleteTextures(1, &mColorTex)); + mFbo = GL_INVALID_VALUE; +} + GlRenderTargetPool::GlRenderTargetPool(uint32_t maxWidth, uint32_t maxHeight): mMaxWidth(maxWidth), mMaxHeight(maxHeight), mPool() {} GlRenderTargetPool::~GlRenderTargetPool() @@ -125,8 +130,8 @@ GlRenderTarget* GlRenderTargetPool::getRenderTarget(const RenderRegion& vp, GLui } } - auto rt = new GlRenderTarget(width, height); - rt->init(resolveId); + auto rt = new GlRenderTarget(); + rt->init(width, height, resolveId); rt->setViewport(vp); mPool.push(rt); return rt; diff --git a/src/renderer/gl_engine/tvgGlRenderTarget.h b/src/renderer/gl_engine/tvgGlRenderTarget.h index 2cc9733b..7577b35e 100644 --- a/src/renderer/gl_engine/tvgGlRenderTarget.h +++ b/src/renderer/gl_engine/tvgGlRenderTarget.h @@ -28,11 +28,11 @@ class GlRenderTarget { public: - GlRenderTarget() = default; - GlRenderTarget(uint32_t width, uint32_t height); + GlRenderTarget(); ~GlRenderTarget(); - void init(GLint resolveId); + void init(uint32_t width, uint32_t height, GLint resolveId); + void reset(); GLuint getFboId() { return mFbo; } GLuint getResolveFboId() { return mResolveFbo; } diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index e177854e..67bc60cb 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -52,6 +52,8 @@ void GlRenderer::flush() { clearDisposes(); + mRootTarget.reset(); + ARRAY_FOREACH(p, mComposePool) delete(*p); mComposePool.clear(); @@ -834,9 +836,8 @@ bool GlRenderer::target(void* context, int32_t id, uint32_t w, uint32_t h) currentContext(); - mRootTarget = GlRenderTarget(surface.w, surface.h); mRootTarget.setViewport({0, 0, static_cast(surface.w), static_cast(surface.h)}); - mRootTarget.init(mTargetFboId); + mRootTarget.init(surface.w, surface.h, mTargetFboId); return true; }