Prechádzať zdrojové kódy

Better error checking in the GL texture backend

Alex Szpakowski 5 rokov pred
rodič
commit
4ec9cafdea

+ 2 - 2
src/modules/graphics/Texture.cpp

@@ -369,7 +369,7 @@ void Texture::drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &m)
 		throw love::Exception("Cannot render a Texture to itself.");
 
 	if (texType != TEXTURE_2D_ARRAY)
-		throw love::Exception("drawLayer can only be used with Array Textures!");
+		throw love::Exception("drawLayer can only be used with Array Textures.");
 
 	if (layer < 0 || layer >= layers)
 		throw love::Exception("Invalid layer: %d (Texture has %d layers)", layer + 1, layers);
@@ -811,7 +811,7 @@ bool Texture::Slices::validate() const
 	int mipcount = getMipmapCount(0);
 
 	if (slicecount == 0 || mipcount == 0)
-		throw love::Exception("At least one ImageData or CompressedImageData is required!");
+		throw love::Exception("At least one ImageData or CompressedImageData is required.");
 
 	if (textureType == TEXTURE_CUBE && slicecount != 6)
 		throw love::Exception("Cube textures must have exactly 6 sides.");

+ 36 - 28
src/modules/graphics/opengl/Texture.cpp

@@ -106,9 +106,8 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo
 	return status;
 }
 
-static bool newRenderbuffer(int width, int height, int &samples, PixelFormat pixelformat, GLuint &buffer)
+static GLenum newRenderbuffer(int width, int height, int &samples, PixelFormat pixelformat, GLuint &buffer)
 {
-	int reqsamples = samples;
 	bool unusedSRGB = false;
 	OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, true, unusedSRGB);
 
@@ -145,13 +144,16 @@ static bool newRenderbuffer(int width, int height, int &samples, PixelFormat pix
 	}
 
 	if (samples > 1)
+	{
 		glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
+		samples = std::max(1, samples);
+	}
 
 	glBindRenderbuffer(GL_RENDERBUFFER, 0);
 
 	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 
-	if (status == GL_FRAMEBUFFER_COMPLETE && (reqsamples <= 1 || samples > 1))
+	if (status == GL_FRAMEBUFFER_COMPLETE)
 	{
 		if (isPixelFormatDepthStencil(pixelformat))
 		{
@@ -183,7 +185,7 @@ static bool newRenderbuffer(int width, int height, int &samples, PixelFormat pix
 	gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo);
 	gl.deleteFramebuffer(fbo);
 
-	return status == GL_FRAMEBUFFER_COMPLETE;
+	return status;
 }
 
 Texture::Texture(const Settings &settings, const Slices *data)
@@ -193,11 +195,19 @@ Texture::Texture(const Settings &settings, const Slices *data)
 	, texture(0)
 	, renderbuffer(0)
 	, framebufferStatus(GL_FRAMEBUFFER_COMPLETE)
+	, textureGLError(GL_NO_ERROR)
 	, actualSamples(1)
 {
 	if (data != nullptr)
 		slices = *data;
-	loadVolatile();
+
+	if (!loadVolatile())
+	{
+		if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE)
+			throw love::Exception("Cannot create Texture (OpenGL framebuffer error: %s)", OpenGL::framebufferStatusString(framebufferStatus));
+		if (textureGLError != GL_NO_ERROR)
+			throw love::Exception("Cannot create Texture (OpenGL error: %s)", OpenGL::errorString(textureGLError));
+	}
 }
 
 Texture::~Texture()
@@ -205,7 +215,7 @@ Texture::~Texture()
 	unloadVolatile();
 }
 
-bool Texture::createTexture()
+void Texture::createTexture()
 {
 	// The base class handles some validation. For example, if ImageData is
 	// given then it must exist for all mip levels, a render target can't use
@@ -235,7 +245,7 @@ bool Texture::createTexture()
 		for (int slice = 0; slice < slices; slice++)
 			uploadByteData(PIXELFORMAT_RGBA8_UNORM, px, sizeof(px), 0, slice, rect, nullptr);
 
-		return true;
+		return;
 	}
 
 	GLenum gltype = OpenGL::getGLTextureType(texType);
@@ -254,6 +264,11 @@ bool Texture::createTexture()
 	else if (texType == TEXTURE_CUBE)
 		slicecount = 6;
 
+	// For a couple flimsy reasons, we don't initialize the texture here if it's
+	// compressed. I need to verify that getPixelFormatSliceSize will return the
+	// correct value for all compressed texture formats, and I also vaguely
+	// remember some driver issues on some old Android systems, maybe...
+	// For now, the base class enforces data on init for compressed textures.
 	if (!isCompressed())
 		gl.rawTexStorage(texType, mipcount, format, sRGB, pixelWidth, pixelHeight, texType == TEXTURE_VOLUME ? depth : layers);
 
@@ -322,16 +337,6 @@ bool Texture::createTexture()
 	// so generateMipmaps here is fine - when they aren't already initialized.
 	if (getMipmapCount() > 1 && slices.getMipmapCount() <= 1)
 		generateMipmaps();
-
-	return true;
-}
-
-bool Texture::createRenderbuffer()
-{
-	if (isReadable() && actualSamples <= 1)
-		return true;
-
-	return newRenderbuffer(pixelWidth, pixelHeight, actualSamples, format, renderbuffer);
 }
 
 bool Texture::loadVolatile()
@@ -353,21 +358,24 @@ bool Texture::loadVolatile()
 
 	while (glGetError() != GL_NO_ERROR); // Clear errors.
 
-	try
+	framebufferStatus = GL_FRAMEBUFFER_COMPLETE;
+	textureGLError = GL_NO_ERROR;
+
+	if (isReadable())
+		createTexture();
+
+	if (!usingDefaultTexture && framebufferStatus == GL_FRAMEBUFFER_COMPLETE
+		&& (!isReadable() || actualSamples > 1))
 	{
-		if (isReadable())
-			createTexture();
-		if (!isReadable() || actualSamples > 1)
-			createRenderbuffer();
-
-		GLenum glerr = glGetError();
-		if (glerr != GL_NO_ERROR)
-			throw love::Exception("Cannot create texture (OpenGL error: %s)", OpenGL::errorString(glerr));
+		framebufferStatus = newRenderbuffer(pixelWidth, pixelHeight, actualSamples, format, renderbuffer);
 	}
-	catch (love::Exception &)
+
+	textureGLError = glGetError();
+
+	if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE || textureGLError != GL_NO_ERROR)
 	{
 		unloadVolatile();
-		throw;
+		return false;
 	}
 
 	int64 memsize = 0;

+ 2 - 2
src/modules/graphics/opengl/Texture.h

@@ -58,8 +58,7 @@ public:
 
 private:
 
-	bool createTexture();
-	bool createRenderbuffer();
+	void createTexture();
 
 	void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override;
 
@@ -71,6 +70,7 @@ private:
 	GLuint renderbuffer;
 
 	GLenum framebufferStatus;
+	GLenum textureGLError;
 
 	int actualSamples;