diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 964909cda..571035ff9 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -315,7 +315,7 @@ void Graphics::restoreStateChecked(const DisplayState &s) canvaseschanged = true; } - if (sRTs.useTemporaryStencil != curRTs.useTemporaryStencil) + if (sRTs.temporaryRTFlags != curRTs.temporaryRTFlags) canvaseschanged = true; } @@ -403,14 +403,14 @@ love::graphics::Shader *Graphics::getShader() const return states.back().shader.get(); } -void Graphics::setCanvas(RenderTarget rt, bool useStencil) +void Graphics::setCanvas(RenderTarget rt, uint32 temporaryRTFlags) { if (rt.canvas == nullptr) return setCanvas(); RenderTargets rts; rts.colors.push_back(rt); - rts.useTemporaryStencil = useStencil; + rts.temporaryRTFlags = temporaryRTFlags; setCanvas(rts); } @@ -424,7 +424,7 @@ void Graphics::setCanvas(const RenderTargetsStrongRef &rts) targets.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap); targets.depthStencil = RenderTarget(rts.depthStencil.canvas, rts.depthStencil.slice, rts.depthStencil.mipmap); - targets.useTemporaryStencil = rts.useTemporaryStencil; + targets.temporaryRTFlags = rts.temporaryRTFlags; return setCanvas(targets); } @@ -440,7 +440,7 @@ Graphics::RenderTargets Graphics::getCanvas() const rts.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap); rts.depthStencil = RenderTarget(curRTs.depthStencil.canvas, curRTs.depthStencil.slice, curRTs.depthStencil.mipmap); - rts.useTemporaryStencil = curRTs.useTemporaryStencil; + rts.temporaryRTFlags = curRTs.temporaryRTFlags; return rts; } @@ -483,6 +483,36 @@ bool Graphics::isCanvasActive(Canvas *canvas, int slice) const return false; } +Canvas *Graphics::getTemporaryCanvas(PixelFormat format, int w, int h, int samples) +{ + love::graphics::Canvas *canvas = nullptr; + + for (Canvas *c : temporaryCanvases) + { + if (c->getPixelFormat() == format && c->getPixelWidth() == w + && c->getPixelHeight() == h && c->getRequestedMSAA() == samples) + { + canvas = c; + break; + } + } + + if (canvas == nullptr) + { + Canvas::Settings settings; + settings.format = format; + settings.width = w; + settings.height = h; + settings.msaa = samples; + + canvas = newCanvas(settings); + + temporaryCanvases.push_back(canvas); + } + + return canvas; +} + void Graphics::intersectScissor(const Rect &rect) { Rect currect = states.back().scissorRect; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index a21977961..56bd75221 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -193,6 +193,12 @@ public: STACK_MAX_ENUM }; + enum TemporaryRenderTargetFlags + { + TEMPORARY_RT_DEPTH = (1 << 0), + TEMPORARY_RT_STENCIL = (1 << 1), + }; + struct RendererInfo { std::string name; @@ -325,11 +331,11 @@ public: { std::vector colors; RenderTarget depthStencil; - bool useTemporaryStencil; + uint32 temporaryRTFlags; RenderTargets() : depthStencil(nullptr) - , useTemporaryStencil(false) + , temporaryRTFlags(0) {} }; @@ -337,11 +343,11 @@ public: { std::vector colors; RenderTargetStrongRef depthStencil; - bool useTemporaryStencil; + uint32 temporaryRTFlags; RenderTargetsStrongRef() : depthStencil(nullptr) - , useTemporaryStencil(false) + , temporaryRTFlags(0) {} }; @@ -465,7 +471,7 @@ public: Shader *getShader() const; - void setCanvas(RenderTarget rt, bool useStencil); + void setCanvas(RenderTarget rt, uint32 temporaryRTFlags); virtual void setCanvas(const RenderTargets &rts) = 0; void setCanvas(const RenderTargetsStrongRef &rts); virtual void setCanvas() = 0; @@ -860,6 +866,8 @@ protected: virtual void getAPIStats(int &drawcalls, int &shaderswitches) const = 0; + Canvas *getTemporaryCanvas(PixelFormat format, int w, int h, int samples); + void restoreState(const DisplayState &s); void restoreStateChecked(const DisplayState &s); @@ -891,6 +899,8 @@ protected: std::vector states; std::vector stackTypeStack; + std::vector temporaryCanvases; + int canvasSwitchCount; static const size_t MAX_USER_STACK_DEPTH = 64; diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index e8655ffaa..80c951d32 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -120,13 +120,9 @@ void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform) return; } - Color c = toColor(gfx->getColor()); - const Matrix4 &tm = gfx->getTransform(); bool is2D = tm.isAffine2DTransform(); - Matrix4 t(tm, localTransform); - Graphics::StreamDrawRequest req; req.formats[0] = vertex::getSinglePositionFormat(is2D); req.formats[1] = CommonFormat::STf_RGBAub; @@ -136,6 +132,8 @@ void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform) Graphics::StreamVertexData data = gfx->requestStreamDraw(req); + Matrix4 t(tm, localTransform); + if (is2D) t.transformXY((Vector2 *) data.stream[0], q->getVertexPositions(), 4); else @@ -144,6 +142,8 @@ void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform) const Vector2 *texcoords = q->getVertexTexCoords(); vertex::STf_RGBAub *vertexdata = (vertex::STf_RGBAub *) data.stream[1]; + Color c = toColor(gfx->getColor()); + for (int i = 0; i < 4; i++) { vertexdata[i].s = texcoords[i].x; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 2147a680b..3613a7a18 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -301,11 +301,11 @@ void Graphics::unSetMode() for (const auto &pair : framebufferObjects) gl.deleteFramebuffer(pair.second); - for (love::graphics::Canvas *c : stencilBuffers) + for (auto c : temporaryCanvases) c->release(); framebufferObjects.clear(); - stencilBuffers.clear(); + temporaryCanvases.clear(); if (mainVAO != 0) { @@ -513,7 +513,7 @@ void Graphics::setCanvas(const RenderTargets &rts) modified = true; } - if (rts.useTemporaryStencil != prevRTs.useTemporaryStencil) + if (rts.temporaryRTFlags != prevRTs.temporaryRTFlags) modified = true; if (!modified) @@ -614,7 +614,7 @@ void Graphics::setCanvas(const RenderTargets &rts) refs.colors.emplace_back(c.canvas, c.slice); refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.canvas, rts.depthStencil.slice); - refs.useTemporaryStencil = rts.useTemporaryStencil; + refs.temporaryRTFlags = rts.temporaryRTFlags; std::swap(state.renderTargets, refs); @@ -665,8 +665,8 @@ void Graphics::endPass() auto &rts = states.back().renderTargets; love::graphics::Canvas *depthstencil = rts.depthStencil.canvas.get(); - // Discard the stencil buffer if we're using an internal cached one. - if (depthstencil == nullptr && rts.useTemporaryStencil) + // Discard the depth/stencil buffer if we're using an internal cached one. + if (depthstencil == nullptr && (rts.temporaryRTFlags & (TEMPORARY_RT_DEPTH | TEMPORARY_RT_STENCIL)) != 0) discard({}, true); // Resolve MSAA buffers. MSAA is only supported for 2D render targets so we @@ -891,8 +891,8 @@ void Graphics::bindCachedFBO(const RenderTargets &targets) if (targets.depthStencil.canvas != nullptr) hashtargets[hashcount++] = targets.depthStencil; - else if (targets.useTemporaryStencil) - hashtargets[hashcount++] = RenderTarget(nullptr, -1, 0); + else if (targets.temporaryRTFlags != 0) + hashtargets[hashcount++] = RenderTarget(nullptr, -1, targets.temporaryRTFlags); uint32 hash = XXH32(hashtargets, sizeof(RenderTarget) * hashcount, 0); GLuint fbo = framebufferObjects[hash]; @@ -911,9 +911,22 @@ void Graphics::bindCachedFBO(const RenderTargets &targets) RenderTarget depthstencil = targets.depthStencil; - if (depthstencil.canvas == nullptr && targets.useTemporaryStencil) + if (depthstencil.canvas == nullptr && targets.temporaryRTFlags != 0) { - depthstencil.canvas = getCachedStencilBuffer(w, h, reqmsaa); + bool wantsdepth = (targets.temporaryRTFlags & TEMPORARY_RT_DEPTH) != 0; + bool wantsstencil = (targets.temporaryRTFlags & TEMPORARY_RT_STENCIL) != 0; + + PixelFormat dsformat = PIXELFORMAT_STENCIL8; + if (wantsdepth && wantsstencil) + dsformat = PIXELFORMAT_DEPTH24_STENCIL8; + else if (wantsdepth && isCanvasFormatSupported(PIXELFORMAT_DEPTH24, false)) + dsformat = PIXELFORMAT_DEPTH24; + else if (wantsdepth) + dsformat = PIXELFORMAT_DEPTH16; + else if (wantsstencil) + dsformat = PIXELFORMAT_STENCIL8; + + depthstencil.canvas = getTemporaryCanvas(dsformat, w, h, reqmsaa); depthstencil.slice = 0; } @@ -979,35 +992,6 @@ void Graphics::bindCachedFBO(const RenderTargets &targets) } } -love::graphics::Canvas *Graphics::getCachedStencilBuffer(int w, int h, int samples) -{ - love::graphics::Canvas *canvas = nullptr; - - for (love::graphics::Canvas *c : stencilBuffers) - { - if (c->getPixelWidth() == w && c->getPixelHeight() == h && c->getRequestedMSAA() == samples) - { - canvas = c; - break; - } - } - - if (canvas == nullptr) - { - Canvas::Settings settings; - settings.format = PIXELFORMAT_STENCIL8; - settings.width = w; - settings.height = h; - settings.msaa = samples; - - canvas = newCanvas(settings); - - stencilBuffers.push_back(canvas); - } - - return canvas; -} - void Graphics::present(void *screenshotCallbackData) { if (!isActive()) @@ -1167,7 +1151,7 @@ void Graphics::drawToStencilBuffer(StencilAction action, int value) if (!isCanvasActive() && !windowHasStencil) throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer."); - else if (isCanvasActive() && !rts.useTemporaryStencil && (dscanvas == nullptr || !isPixelFormatStencil(dscanvas->getPixelFormat()))) + else if (isCanvasActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dscanvas == nullptr || !isPixelFormatStencil(dscanvas->getPixelFormat()))) throw love::Exception("Drawing to the stencil buffer with a Canvas active requires either stencil=true or a custom stencil-type Canvas to be used, in setCanvas."); flushStreamDraws(); diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 9cf7db95a..019cbdce6 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -137,17 +137,12 @@ private: void endPass(); void bindCachedFBO(const RenderTargets &targets); void discard(OpenGL::FramebufferTarget target, const std::vector &colorbuffers, bool depthstencil); - love::graphics::Canvas *getCachedStencilBuffer(int w, int h, int samples); void setDebug(bool enable); std::unordered_map framebufferObjects; - std::vector stencilBuffers; - QuadIndices *quadIndices; - bool windowHasStencil; - GLuint mainVAO; }; // Graphics diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 7937f72c4..99a5902c3 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -294,15 +294,23 @@ int w_setCanvas(lua_State *L) lua_pop(L, 1); } + uint32 tempdepthflag = Graphics::TEMPORARY_RT_DEPTH; + uint32 tempstencilflag = Graphics::TEMPORARY_RT_STENCIL; + lua_getfield(L, 1, "depthstencil"); if (lua_istable(L, -1)) targets.depthStencil = checkRenderTarget(L, -1); + else if (lua_isboolean(L, -1)) + targets.temporaryRTFlags |= luax_toboolean(L, -1) ? (tempdepthflag | tempstencilflag) : 0; else if (!lua_isnoneornil(L, -1)) targets.depthStencil.canvas = luax_checkcanvas(L, -1); lua_pop(L, 1); - if (targets.depthStencil.canvas == nullptr) - targets.useTemporaryStencil = luax_boolflag(L, 1, "stencil", false); + if (targets.depthStencil.canvas == nullptr && (targets.temporaryRTFlags & tempdepthflag) == 0) + targets.temporaryRTFlags |= luax_boolflag(L, 1, "depth", false) ? tempdepthflag : 0; + + if (targets.depthStencil.canvas == nullptr && (targets.temporaryRTFlags & tempstencilflag) == 0) + targets.temporaryRTFlags |= luax_boolflag(L, 1, "stencil", false) ? tempstencilflag : 0; } else {