Browse Source

Fix a freeze on Intel drivers when using mipmapped Canvases

Fixes #1585

Also disallow generateMipmaps on depth/stencil canvases because it's not really supported.
Alex Szpakowski 4 years ago
parent
commit
95ab4054ff

+ 3 - 0
src/modules/graphics/Canvas.cpp

@@ -69,6 +69,9 @@ Canvas::Canvas(const Settings &settings)
 		filter.mipmap = defaultMipmapFilter;
 	}
 
+	if (settings.mipmaps == MIPMAPS_AUTO && isPixelFormatDepthStencil(format))
+		throw love::Exception("Automatic mipmap generation cannot be used for depth/stencil Canvases.");
+
 	auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
 	const Graphics::Capabilities &caps = gfx->getCapabilities();
 

+ 17 - 17
src/modules/graphics/opengl/Canvas.cpp

@@ -67,19 +67,6 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo
 			if (texType == TEXTURE_VOLUME)
 				nlayers = std::max(layers >> mip, 1);
 
-			GLuint tempframebuffer = 0;
-			if (mip > 0)
-			{
-				// Some Intel drivers on Windows don't like reusing the same
-				// FBO for different sized attachments, so use a temporary one
-				// to clear smaller mips.
-				// https://github.com/love2d/love/issues/1585
-				glGenFramebuffers(1, &tempframebuffer);
-				gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, tempframebuffer);
-			}
-			else
-				gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, framebuffer);
-
 			for (int layer = nlayers - 1; layer >= 0; layer--)
 			{
 				for (int face = faces - 1; face >= 0; face--)
@@ -112,9 +99,6 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo
 					}
 				}
 			}
-
-			if (tempframebuffer != 0)
-				gl.deleteFramebuffer(tempframebuffer);
 		}
 	}
 
@@ -278,8 +262,18 @@ bool Canvas::loadVolatile()
 			return false;
 		}
 
+		// All mipmap levels need to be initialized - for color formats we can
+		// clear the base mip and use glGenerateMipmap after that's done. Depth
+		// and stencil formats don't always support glGenerateMipmap so we need
+		// to individually clear each mip level in that case. We avoid doing that
+		// for color formats because of an Intel driver bug:
+		// https://github.com/love2d/love/issues/1585
+		int clearmips = 1;
+		if (isPixelFormatDepthStencil(format))
+			clearmips = mipmapCount;
+
 		// Create a canvas-local FBO used for glReadPixels as well as MSAA blitting.
-		status = createFBO(fbo, texType, format, texture, texType == TEXTURE_VOLUME ? depth : layers, mipmapCount);
+		status = createFBO(fbo, texType, format, texture, texType == TEXTURE_VOLUME ? depth : layers, clearmips);
 
 		if (status != GL_FRAMEBUFFER_COMPLETE)
 		{
@@ -290,6 +284,9 @@ bool Canvas::loadVolatile()
 			}
 			return false;
 		}
+
+		if (clearmips < mipmapCount && getMipmapMode() != MIPMAPS_NONE)
+			generateMipmaps();
 	}
 
 	if (!isReadable() || actualSamples > 0)
@@ -488,6 +485,9 @@ void Canvas::generateMipmaps()
 	if (getMipmapCount() == 1 || getMipmapMode() == MIPMAPS_NONE)
 		throw love::Exception("generateMipmaps can only be called on a Canvas which was created with mipmaps enabled.");
 
+	if (isPixelFormatDepthStencil(format))
+		throw love::Exception("generateMipmaps cannot be called on a depth/stencil Canvas.");
+
 	gl.bindTextureToUnit(this, 0, false);
 
 	GLenum gltextype = OpenGL::getGLTextureType(texType);

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

@@ -587,10 +587,6 @@ void Graphics::endPass()
 		if (rt.canvas->getMipmapMode() == Canvas::MIPMAPS_AUTO && rt.mipmap == 0)
 			rt.canvas->generateMipmaps();
 	}
-
-	int dsmipmap = rts.depthStencil.mipmap;
-	if (depthstencil != nullptr && depthstencil->getMipmapMode() == Canvas::MIPMAPS_AUTO && dsmipmap == 0)
-		depthstencil->generateMipmaps();
 }
 
 void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth)