Browse Source

Added a workaround for an AMD driver bug where setCanvas + clear + setCanvas doesn't work.

Alex Szpakowski 9 years ago
parent
commit
4f093e7fac

+ 27 - 0
src/modules/graphics/opengl/Graphics.cpp

@@ -438,6 +438,27 @@ void Graphics::reset()
 	origin();
 }
 
+void Graphics::dummyDraw()
+{
+	gl.prepareDraw();
+
+	// Draw a triangle using a single vertex position indexed 3 times. The
+	// triangle will be degenerate and won't be rasterized (so the pixel shader
+	// won't be run), and an index array with a single vertex is used so the
+	// vertex shader can't prevent the triangle from being degenerate by using
+	// gl_VertexID.
+	// NOTE: This code will have to be changed to use a vertex and index buffer,
+	// for it to work with a Core Profile GL3 backend. But the bug should be
+	// re-tested in that case as well.
+	const GLfloat vertex[] = {0.0f, 0.0f};
+	const GLushort indices[] = {0, 0, 0};
+
+	gl.useVertexAttribArrays(ATTRIBFLAG_POS);
+	glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, vertex);
+
+	gl.drawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices);
+}
+
 void Graphics::clear(Colorf c)
 {
 	Colorf nc = Colorf(c.r/255.0f, c.g/255.0f, c.b/255.0f, c.a/255.0f);
@@ -446,6 +467,9 @@ void Graphics::clear(Colorf c)
 
 	glClearColor(nc.r, nc.g, nc.b, nc.a);
 	glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	if (gl.bugs.clearRequiresDummyDraw)
+		dummyDraw();
 }
 
 void Graphics::clear(const std::vector<OptionalColorf> &colors)
@@ -510,6 +534,9 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors)
 		else
 			glDrawBuffer(GL_COLOR_ATTACHMENT0);
 	}
+
+	if (gl.bugs.clearRequiresDummyDraw)
+		dummyDraw();
 }
 
 void Graphics::discard(const std::vector<bool> &colorbuffers, bool stencil)

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

@@ -518,6 +518,8 @@ private:
 	void restoreState(const DisplayState &s);
 	void restoreStateChecked(const DisplayState &s);
 
+	void dummyDraw();
+
 	void checkSetDefaultFont();
 
 	StrongRef<love::window::Window> currentWindow;

+ 8 - 0
src/modules/graphics/opengl/OpenGL.cpp

@@ -90,6 +90,14 @@ bool OpenGL::initContext()
 	initVendor();
 	initMatrices();
 
+	bugs = {};
+
+#if defined(LOVE_WINDOWS) || defined(LOVE_LINUX)
+	// See the comment in OpenGL.h.
+	if (getVendor() == VENDOR_AMD)
+		bugs.clearRequiresDummyDraw = true;
+#endif
+
 	contextInitialized = true;
 
 	return true;

+ 13 - 0
src/modules/graphics/opengl/OpenGL.h

@@ -169,6 +169,19 @@ public:
 		int    framebufferBinds;
 	} stats;
 
+	struct Bugs
+	{
+		// On AMD's Windows (and probably Linux) drivers,
+		// glBindFramebuffer + glClear + glBindFramebuffer won't work unless
+		// there's a draw in between the glBindFramebuffer calls (or unless
+		// there's some other thing that causes the driver to avoid the buggy
+		// "fast path", e.g. if the scissor test is active and its rectangle
+		// doesn't cover the whole framebuffer).
+		// Bug observed January 2016 with multiple AMD GPUs and driver versions.
+		// https://love2d.org/forums/viewtopic.php?f=4&t=81496
+		bool clearRequiresDummyDraw;
+	} bugs;
+
 	OpenGL();
 
 	/**