diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index dcfa3b407..b8ec94e6e 100644 --- a/src/modules/graphics/Texture.cpp +++ b/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."); diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index 632523d8b..4d80bc5d4 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/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 - { - if (isReadable()) - createTexture(); - if (!isReadable() || actualSamples > 1) - createRenderbuffer(); + framebufferStatus = GL_FRAMEBUFFER_COMPLETE; + textureGLError = GL_NO_ERROR; - GLenum glerr = glGetError(); - if (glerr != GL_NO_ERROR) - throw love::Exception("Cannot create texture (OpenGL error: %s)", OpenGL::errorString(glerr)); + if (isReadable()) + createTexture(); + + if (!usingDefaultTexture && framebufferStatus == GL_FRAMEBUFFER_COMPLETE + && (!isReadable() || actualSamples > 1)) + { + 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; diff --git a/src/modules/graphics/opengl/Texture.h b/src/modules/graphics/opengl/Texture.h index 6699a586d..4f0d871d3 100644 --- a/src/modules/graphics/opengl/Texture.h +++ b/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;