From 6d6d805858a748a02f816691875131208a92c761 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 9 Jan 2016 23:40:04 -0400 Subject: [PATCH] Workaround for love.graphics.clear + love.graphics.setCanvas AMD driver bug, take two. --- src/modules/graphics/opengl/Graphics.cpp | 39 +++++++++--------------- src/modules/graphics/opengl/Graphics.h | 2 -- src/modules/graphics/opengl/OpenGL.cpp | 2 +- src/modules/graphics/opengl/OpenGL.h | 13 ++++---- src/modules/graphics/opengl/Shader.h | 5 +++ 5 files changed, 27 insertions(+), 34 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 2eb48e8b7..ec30c7438 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -438,27 +438,6 @@ 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); @@ -468,8 +447,13 @@ 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(); + if (gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current) + { + // This seems to be enough to fix the bug for me. Other methods I've + // tried (e.g. dummy draws) don't work in all cases. + glUseProgram(0); + glUseProgram(Shader::current->getProgram()); + } } void Graphics::clear(const std::vector &colors) @@ -535,8 +519,13 @@ void Graphics::clear(const std::vector &colors) glDrawBuffer(GL_COLOR_ATTACHMENT0); } - if (gl.bugs.clearRequiresDummyDraw) - dummyDraw(); + if (gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current) + { + // This seems to be enough to fix the bug for me. Other methods I've + // tried (e.g. dummy draws) don't work in all cases. + glUseProgram(0); + glUseProgram(Shader::current->getProgram()); + } } void Graphics::discard(const std::vector &colorbuffers, bool stencil) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index e50c2c839..d602af78f 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -518,8 +518,6 @@ private: void restoreState(const DisplayState &s); void restoreStateChecked(const DisplayState &s); - void dummyDraw(); - void checkSetDefaultFont(); StrongRef currentWindow; diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index b18b8aa96..387fcbdf2 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -95,7 +95,7 @@ bool OpenGL::initContext() #if defined(LOVE_WINDOWS) || defined(LOVE_LINUX) // See the comment in OpenGL.h. if (getVendor() == VENDOR_AMD) - bugs.clearRequiresDummyDraw = true; + bugs.clearRequiresDriverTextureStateUpdate = true; #endif contextInitialized = true; diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 51af13c1f..8ad9907c6 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -172,14 +172,15 @@ public: 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). + // glBindFramebuffer + glClear + glBindFramebuffer + draw(fbo_tex) won't + // work unless there's some kind of draw or state change which causes + // the texture's contents to update (just drawing the texture won't + // always do it). + // Activating shader program 0 and then activating the actual program + // seems to always 'fix' it for me. // Bug observed January 2016 with multiple AMD GPUs and driver versions. // https://love2d.org/forums/viewtopic.php?f=4&t=81496 - bool clearRequiresDummyDraw; + bool clearRequiresDriverTextureStateUpdate; } bugs; OpenGL(); diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index ed6429e37..042a696d8 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -194,6 +194,11 @@ public: const std::map &getBoundRetainables() const; + GLuint getProgram() const + { + return program; + } + static std::string getGLSLVersion(); static bool isSupported();