From cbcb1a86067633fb8a155478aed66677348b0ebd Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 3 Dec 2017 19:33:48 -0400 Subject: [PATCH] Allow a depth/stencil canvas to be active without a color canvas. --HG-- branch : minor --- src/modules/graphics/Graphics.cpp | 30 +++++++++--------- src/modules/graphics/Graphics.h | 10 ++++++ src/modules/graphics/opengl/Graphics.cpp | 39 +++++++++++++++++++++--- src/modules/graphics/wrap_Graphics.cpp | 9 +++--- 4 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 619605506..d8002f4f2 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -317,7 +317,7 @@ double Graphics::getCurrentDPIScale() const { if (states.back().renderTargets.colors.size() > 0) { - Canvas *c = states.back().renderTargets.colors[0].canvas; + Canvas *c = states.back().renderTargets.getFirstTarget().canvas.get(); return (double) c->getPixelHeight() / (double) c->getHeight(); } @@ -555,8 +555,6 @@ void Graphics::setCanvas(const RenderTargets &rts) if (ncanvases == 0 && rts.depthStencil.canvas == nullptr) return setCanvas(); - else if (ncanvases == 0) - throw love::Exception("At least one color render target is required when using a custom depth/stencil buffer."); const auto &prevRTs = state.renderTargets; @@ -592,20 +590,24 @@ void Graphics::setCanvas(const RenderTargets &rts) if (ncanvases > capabilities.limits[LIMIT_MULTI_CANVAS]) throw love::Exception("This system can't simultaneously render to %d canvases.", ncanvases); - love::graphics::Canvas *firstcanvas = rts.colors[0].canvas; + RenderTarget firsttarget = rts.getFirstTarget(); + love::graphics::Canvas *firstcanvas = firsttarget.canvas; bool multiformatsupported = capabilities.features[FEATURE_MULTI_CANVAS_FORMATS]; - PixelFormat firstformat = firstcanvas->getPixelFormat(); - if (isPixelFormatDepthStencil(firstformat)) + PixelFormat firstcolorformat = PIXELFORMAT_UNKNOWN; + if (!rts.colors.empty()) + firstcolorformat = rts.colors[0].canvas->getPixelFormat(); + + if (isPixelFormatDepthStencil(firstcolorformat)) throw love::Exception("Depth/stencil format Canvases must be used with the 'depthstencil' field of the table passed into setCanvas."); - if (rts.colors[0].mipmap < 0 || rts.colors[0].mipmap >= firstcanvas->getMipmapCount()) - throw love::Exception("Invalid mipmap level %d.", rts.colors[0].mipmap + 1); + if (firsttarget.mipmap < 0 || firsttarget.mipmap >= firstcanvas->getMipmapCount()) + throw love::Exception("Invalid mipmap level %d.", firsttarget.mipmap + 1); - bool hasSRGBcanvas = firstformat == PIXELFORMAT_sRGBA8; - int pixelw = firstcanvas->getPixelWidth(rts.colors[0].mipmap); - int pixelh = firstcanvas->getPixelHeight(rts.colors[0].mipmap); + bool hasSRGBcanvas = firstcolorformat == PIXELFORMAT_sRGBA8; + int pixelw = firstcanvas->getPixelWidth(firsttarget.mipmap); + int pixelh = firstcanvas->getPixelHeight(firsttarget.mipmap); for (int i = 1; i < ncanvases; i++) { @@ -619,7 +621,7 @@ void Graphics::setCanvas(const RenderTargets &rts) if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh) throw love::Exception("All canvases must have the same pixel dimensions."); - if (!multiformatsupported && format != firstformat) + if (!multiformatsupported && format != firstcolorformat) throw love::Exception("This system doesn't support multi-canvas rendering with different canvas formats."); if (c->getRequestedMSAA() != firstcanvas->getRequestedMSAA()) @@ -650,8 +652,8 @@ void Graphics::setCanvas(const RenderTargets &rts) throw love::Exception("Invalid mipmap level %d.", mip + 1); } - int w = firstcanvas->getWidth(rts.colors[0].mipmap); - int h = firstcanvas->getHeight(rts.colors[0].mipmap); + int w = firstcanvas->getWidth(firsttarget.mipmap); + int h = firstcanvas->getHeight(firsttarget.mipmap); flushStreamDraws(); setCanvasInternal(rts, w, h, pixelw, pixelh, hasSRGBcanvas); diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 885ffd728..2219579aa 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -347,6 +347,11 @@ public: : depthStencil(nullptr) , temporaryRTFlags(0) {} + + const RenderTarget &getFirstTarget() const + { + return colors.empty() ? depthStencil : colors[0]; + } }; struct RenderTargetsStrongRef @@ -359,6 +364,11 @@ public: : depthStencil(nullptr) , temporaryRTFlags(0) {} + + const RenderTargetStrongRef &getFirstTarget() const + { + return colors.empty() ? depthStencil : colors[0]; + } }; struct DefaultShaderCode diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index d554e288c..bdec13537 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -405,6 +405,7 @@ void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pix OpenGL::TempDebugGroup debuggroup("setCanvas(...)"); + flushStreamDraws(); endPass(); bindCachedFBO(rts); @@ -501,6 +502,32 @@ void Graphics::endPass() } } + if (depthstencil != nullptr && depthstencil->getMSAA() > 1 && depthstencil->isReadable()) + { + gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, ((Canvas *) depthstencil)->getFBO()); + + if (GLAD_APPLE_framebuffer_multisample) + glResolveMultisampleFramebufferAPPLE(); + else + { + int mip = rts.depthStencil.mipmap; + int w = depthstencil->getPixelWidth(mip); + int h = depthstencil->getPixelHeight(mip); + PixelFormat format = depthstencil->getPixelFormat(); + + GLbitfield mask = 0; + + if (isPixelFormatDepth(format)) + mask |= GL_DEPTH_BUFFER_BIT; + if (isPixelFormatStencil(format)) + mask |= GL_STENCIL_BUFFER_BIT; + + if (mask != 0) + glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, mask, GL_NEAREST); + } + + } + for (const auto &rt : rts.colors) { if (rt.canvas->getMipmapMode() == Canvas::MIPMAPS_AUTO && rt.mipmap == 0) @@ -709,11 +736,13 @@ void Graphics::bindCachedFBO(const RenderTargets &targets) } else { - int mip = targets.colors[0].mipmap; - int w = targets.colors[0].canvas->getPixelWidth(mip); - int h = targets.colors[0].canvas->getPixelHeight(mip); - int msaa = targets.colors[0].canvas->getMSAA(); - int reqmsaa = targets.colors[0].canvas->getRequestedMSAA(); + RenderTarget firstRT = targets.getFirstTarget(); + + int mip = firstRT.mipmap; + int w = firstRT.canvas->getPixelWidth(mip); + int h = firstRT.canvas->getPixelHeight(mip); + int msaa = firstRT.canvas->getMSAA(); + int reqmsaa = firstRT.canvas->getRequestedMSAA(); RenderTarget depthstencil = targets.depthStencil; diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 018ee2478..a336a67ee 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -300,11 +300,12 @@ int w_setCanvas(lua_State *L) uint32 tempstencilflag = Graphics::TEMPORARY_RT_STENCIL; lua_getfield(L, 1, "depthstencil"); - if (lua_istable(L, -1)) + int dstype = lua_type(L, -1); + if (dstype == LUA_TTABLE) targets.depthStencil = checkRenderTarget(L, -1); - else if (lua_isboolean(L, -1)) + else if (dstype == LUA_TBOOLEAN) targets.temporaryRTFlags |= luax_toboolean(L, -1) ? (tempdepthflag | tempstencilflag) : 0; - else if (!lua_isnoneornil(L, -1)) + else if (dstype != LUA_TNONE && dstype != LUA_TNIL) targets.depthStencil.canvas = luax_checkcanvas(L, -1); lua_pop(L, 1); @@ -342,7 +343,7 @@ int w_setCanvas(lua_State *L) } luax_catchexcept(L, [&]() { - if (targets.colors.size() > 0) + if (targets.getFirstTarget().canvas != nullptr) instance()->setCanvas(targets); else instance()->setCanvas();