Browse Source

Allow a temporary/internal depth buffer to be used when a Canvas is active, similar to how temporary stencil buffers are allowed.

Syntax is setCanvas{canvas [, depth=true, stencil=true]} or setCanvas{canvas, depthstencil=true}.

--HG--
branch : minor
Alex Szpakowski 8 years ago
parent
commit
9fe81ad922

+ 35 - 5
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;

+ 15 - 5
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<RenderTarget> colors;
 		RenderTarget depthStencil;
-		bool useTemporaryStencil;
+		uint32 temporaryRTFlags;
 
 		RenderTargets()
 			: depthStencil(nullptr)
-			, useTemporaryStencil(false)
+			, temporaryRTFlags(0)
 		{}
 	};
 
@@ -337,11 +343,11 @@ public:
 	{
 		std::vector<RenderTargetStrongRef> 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<DisplayState> states;
 	std::vector<StackType> stackTypeStack;
 
+	std::vector<Canvas *> temporaryCanvases;
+
 	int canvasSwitchCount;
 
 	static const size_t MAX_USER_STACK_DEPTH = 64;

+ 4 - 4
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;

+ 24 - 40
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();

+ 0 - 5
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<bool> &colorbuffers, bool depthstencil);
-	love::graphics::Canvas *getCachedStencilBuffer(int w, int h, int samples);
 
 	void setDebug(bool enable);
 
 	std::unordered_map<uint32, GLuint> framebufferObjects;
-	std::vector<love::graphics::Canvas *> stencilBuffers;
-
 	QuadIndices *quadIndices;
-
 	bool windowHasStencil;
-
 	GLuint mainVAO;
 
 }; // Graphics

+ 10 - 2
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
 	{