diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 2489b3d38..619605506 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -728,12 +728,14 @@ Canvas *Graphics::getTemporaryCanvas(PixelFormat format, int w, int h, int sampl { love::graphics::Canvas *canvas = nullptr; - for (Canvas *c : temporaryCanvases) + for (TemporaryCanvas &temp : temporaryCanvases) { + Canvas *c = temp.canvas; if (c->getPixelFormat() == format && c->getPixelWidth() == w && c->getPixelHeight() == h && c->getRequestedMSAA() == samples) { canvas = c; + temp.framesSinceUse = 0; break; } } @@ -748,7 +750,7 @@ Canvas *Graphics::getTemporaryCanvas(PixelFormat format, int w, int h, int sampl canvas = newCanvas(settings); - temporaryCanvases.push_back(canvas); + temporaryCanvases.emplace_back(canvas); } return canvas; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 0eef69fdc..55577e61d 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -880,6 +880,17 @@ protected: } }; + struct TemporaryCanvas + { + Canvas *canvas; + int framesSinceUse; + + TemporaryCanvas(Canvas *c) + : canvas(c) + , framesSinceUse(0) + {} + }; + virtual ShaderStage *newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) = 0; virtual Shader *newShaderInternal(ShaderStage *vertex, ShaderStage *pixel) = 0; virtual StreamBuffer *newStreamBuffer(BufferType type, size_t size) = 0; @@ -922,7 +933,7 @@ protected: std::vector states; std::vector stackTypeStack; - std::vector temporaryCanvases; + std::vector temporaryCanvases; int canvasSwitchCount; int drawCallsBatched; @@ -932,6 +943,7 @@ protected: Deprecations deprecations; static const size_t MAX_USER_STACK_DEPTH = 64; + static const int MAX_TEMPORARY_CANVAS_UNUSED_FRAMES = 16; private: diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 153394b0a..d554e288c 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -287,8 +287,8 @@ void Graphics::unSetMode() for (const auto &pair : framebufferObjects) gl.deleteFramebuffer(pair.second); - for (auto c : temporaryCanvases) - c->release(); + for (auto temp : temporaryCanvases) + temp.canvas->release(); framebufferObjects.clear(); temporaryCanvases.clear(); @@ -924,6 +924,19 @@ void Graphics::present(void *screenshotCallbackData) gl.stats.shaderSwitches = 0; canvasSwitchCount = 0; drawCallsBatched = 0; + + // This assumes temporary canvases will only be used within a render pass. + for (int i = (int) temporaryCanvases.size() - 1; i >= 0; i--) + { + if (temporaryCanvases[i].framesSinceUse >= MAX_TEMPORARY_CANVAS_UNUSED_FRAMES) + { + temporaryCanvases[i].canvas->release(); + temporaryCanvases[i] = temporaryCanvases.back(); + temporaryCanvases.pop_back(); + } + else + temporaryCanvases[i].framesSinceUse++; + } } void Graphics::setScissor(const Rect &rect)