Browse Source

Allow a depth/stencil canvas to be active without a color canvas.

--HG--
branch : minor
Alex Szpakowski 7 years ago
parent
commit
cbcb1a8606

+ 16 - 14
src/modules/graphics/Graphics.cpp

@@ -317,7 +317,7 @@ double Graphics::getCurrentDPIScale() const
 {
 {
 	if (states.back().renderTargets.colors.size() > 0)
 	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();
 		return (double) c->getPixelHeight() / (double) c->getHeight();
 	}
 	}
 
 
@@ -555,8 +555,6 @@ void Graphics::setCanvas(const RenderTargets &rts)
 
 
 	if (ncanvases == 0 && rts.depthStencil.canvas == nullptr)
 	if (ncanvases == 0 && rts.depthStencil.canvas == nullptr)
 		return setCanvas();
 		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;
 	const auto &prevRTs = state.renderTargets;
 
 
@@ -592,20 +590,24 @@ void Graphics::setCanvas(const RenderTargets &rts)
 	if (ncanvases > capabilities.limits[LIMIT_MULTI_CANVAS])
 	if (ncanvases > capabilities.limits[LIMIT_MULTI_CANVAS])
 		throw love::Exception("This system can't simultaneously render to %d canvases.", ncanvases);
 		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];
 	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.");
 		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++)
 	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)
 		if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh)
 			throw love::Exception("All canvases must have the same pixel dimensions.");
 			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.");
 			throw love::Exception("This system doesn't support multi-canvas rendering with different canvas formats.");
 
 
 		if (c->getRequestedMSAA() != firstcanvas->getRequestedMSAA())
 		if (c->getRequestedMSAA() != firstcanvas->getRequestedMSAA())
@@ -650,8 +652,8 @@ void Graphics::setCanvas(const RenderTargets &rts)
 			throw love::Exception("Invalid mipmap level %d.", mip + 1);
 			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();
 	flushStreamDraws();
 	setCanvasInternal(rts, w, h, pixelw, pixelh, hasSRGBcanvas);
 	setCanvasInternal(rts, w, h, pixelw, pixelh, hasSRGBcanvas);

+ 10 - 0
src/modules/graphics/Graphics.h

@@ -347,6 +347,11 @@ public:
 			: depthStencil(nullptr)
 			: depthStencil(nullptr)
 			, temporaryRTFlags(0)
 			, temporaryRTFlags(0)
 		{}
 		{}
+
+		const RenderTarget &getFirstTarget() const
+		{
+			return colors.empty() ? depthStencil : colors[0];
+		}
 	};
 	};
 
 
 	struct RenderTargetsStrongRef
 	struct RenderTargetsStrongRef
@@ -359,6 +364,11 @@ public:
 			: depthStencil(nullptr)
 			: depthStencil(nullptr)
 			, temporaryRTFlags(0)
 			, temporaryRTFlags(0)
 		{}
 		{}
+
+		const RenderTargetStrongRef &getFirstTarget() const
+		{
+			return colors.empty() ? depthStencil : colors[0];
+		}
 	};
 	};
 
 
 	struct DefaultShaderCode
 	struct DefaultShaderCode

+ 34 - 5
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(...)");
 	OpenGL::TempDebugGroup debuggroup("setCanvas(...)");
 
 
+	flushStreamDraws();
 	endPass();
 	endPass();
 
 
 	bindCachedFBO(rts);
 	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)
 	for (const auto &rt : rts.colors)
 	{
 	{
 		if (rt.canvas->getMipmapMode() == Canvas::MIPMAPS_AUTO && rt.mipmap == 0)
 		if (rt.canvas->getMipmapMode() == Canvas::MIPMAPS_AUTO && rt.mipmap == 0)
@@ -709,11 +736,13 @@ void Graphics::bindCachedFBO(const RenderTargets &targets)
 	}
 	}
 	else
 	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;
 		RenderTarget depthstencil = targets.depthStencil;
 
 

+ 5 - 4
src/modules/graphics/wrap_Graphics.cpp

@@ -300,11 +300,12 @@ int w_setCanvas(lua_State *L)
 		uint32 tempstencilflag = Graphics::TEMPORARY_RT_STENCIL;
 		uint32 tempstencilflag = Graphics::TEMPORARY_RT_STENCIL;
 
 
 		lua_getfield(L, 1, "depthstencil");
 		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);
 			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;
 			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);
 			targets.depthStencil.canvas = luax_checkcanvas(L, -1);
 		lua_pop(L, 1);
 		lua_pop(L, 1);
 
 
@@ -342,7 +343,7 @@ int w_setCanvas(lua_State *L)
 	}
 	}
 
 
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
-		if (targets.colors.size() > 0)
+		if (targets.getFirstTarget().canvas != nullptr)
 			instance()->setCanvas(targets);
 			instance()->setCanvas(targets);
 		else
 		else
 			instance()->setCanvas();
 			instance()->setCanvas();