Browse Source

Added love.graphics.discard, which discards the contents of the screen (or currently active Canvas.)

Using it just after activating a Canvas can improve performance on many mobile devices, if the conditions for using it are right.

--HG--
branch : minor
Alex Szpakowski 10 years ago
parent
commit
b52b9c7a2b

+ 44 - 16
src/modules/graphics/opengl/Graphics.cpp

@@ -424,33 +424,61 @@ void Graphics::clear(Color c)
 	glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 }
 
-void Graphics::present()
+void Graphics::discard(bool color, bool stencil)
 {
-	if (!isActive())
+	if (!(GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility || GLAD_ES_VERSION_3_0 || GLAD_EXT_discard_framebuffer))
 		return;
 
-	// Make sure we don't have a canvas active.
-	std::vector<StrongRef<Canvas>> canvases = states.back().canvases;
-	setCanvas();
+	std::vector<GLenum> attachments;
+	attachments.reserve(3);
 
-	if (GLAD_ES_VERSION_3_0 || GLAD_EXT_discard_framebuffer)
+	// glDiscardFramebuffer uses different attachment enums for the default FBO.
+	if (!Canvas::current && gl.getDefaultFBO() == 0)
 	{
-		GLenum attachments[] = {GL_STENCIL, GL_DEPTH};
+		if (color)
+			attachments.push_back(GL_COLOR);
 
-		if (gl.getDefaultFBO() != 0)
+		if (stencil)
+		{
+			attachments.push_back(GL_STENCIL);
+			attachments.push_back(GL_DEPTH);
+		}
+	}
+	else
+	{
+		if (color)
 		{
-			// A non-zero FBO needs different attachment enums.
-			attachments[0] = GL_STENCIL_ATTACHMENT;
-			attachments[1] = GL_DEPTH_ATTACHMENT;
+			attachments.push_back(GL_COLOR_ATTACHMENT0);
+			for (int i = 0; i < (int) states.back().canvases.size() - 1; i++)
+				attachments.push_back(GL_COLOR_ATTACHMENT1 + i);
 		}
 
-		// Hint for the driver that it doesn't need to save these buffers.
-		if (GLAD_ES_VERSION_3_0)
-			glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
-		else if (GLAD_EXT_discard_framebuffer)
-			glDiscardFramebufferEXT(GL_FRAMEBUFFER, 2, attachments);
+		if (stencil)
+		{
+			attachments.push_back(GL_STENCIL_ATTACHMENT);
+			attachments.push_back(GL_DEPTH_ATTACHMENT);
+		}
 	}
 
+	// Hint for the driver that it doesn't need to save these buffers.
+	if (GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility || GLAD_ES_VERSION_3_0)
+		glInvalidateFramebuffer(GL_FRAMEBUFFER, (GLint) attachments.size(), &attachments[0]);
+	else if (GLAD_EXT_discard_framebuffer)
+		glDiscardFramebufferEXT(GL_FRAMEBUFFER, (GLint) attachments.size(), &attachments[0]);
+}
+
+void Graphics::present()
+{
+	if (!isActive())
+		return;
+
+	// Make sure we don't have a canvas active.
+	std::vector<StrongRef<Canvas>> canvases = states.back().canvases;
+	setCanvas();
+
+	// Discard the stencil buffer before swapping.
+	discard(false, true);
+
 #ifdef LOVE_IOS
 	// Hack: SDL's color renderbuffer needs to be bound when swapBuffers is called.
 	GLuint rbo = SDL_iPhoneGetViewRenderbuffer(SDL_GL_GetCurrentWindow());

+ 5 - 0
src/modules/graphics/opengl/Graphics.h

@@ -85,6 +85,11 @@ public:
 	 **/
 	void clear(Color c);
 
+	/**
+	 * Discards the contents of the screen.
+	 **/
+	void discard(bool color, bool stencil);
+
 	/**
 	 * Flips buffers. (Rendered geometry is presented on screen).
 	 **/

+ 9 - 0
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -61,6 +61,14 @@ int w_clear(lua_State *L)
 	return 0;
 }
 
+int w_discard(lua_State *L)
+{
+	bool color = luax_optboolean(L, 1, true);
+	bool stencil = luax_optboolean(L, 2, true);
+	instance()->discard(color, stencil);
+	return 0;
+}
+
 int w_present(lua_State *)
 {
 	instance()->present();
@@ -1465,6 +1473,7 @@ static const luaL_Reg functions[] =
 {
 	{ "reset", w_reset },
 	{ "clear", w_clear },
+	{ "discard", w_discard },
 	{ "present", w_present },
 
 	{ "newImage", w_newImage },

+ 1 - 0
src/modules/graphics/opengl/wrap_Graphics.h

@@ -42,6 +42,7 @@ namespace opengl
 
 int w_reset(lua_State *L);
 int w_clear(lua_State *L);
+int w_discard(lua_State *L);
 int w_present(lua_State *L);
 int w_isCreated(lua_State *L);
 int w_isActive(lua_State *L);