From 6c447ab4f60e605d4a54e40defee58f5e7d8d24e Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 1 Feb 2020 23:54:51 -0400 Subject: [PATCH 01/31] Clean up some common Image and Canvas code. --- src/modules/graphics/Canvas.cpp | 2 +- src/modules/graphics/Graphics.cpp | 2 +- src/modules/graphics/Graphics.h | 12 +- src/modules/graphics/Image.cpp | 2 +- src/modules/graphics/opengl/Canvas.cpp | 146 +---------------------- src/modules/graphics/opengl/Canvas.h | 27 ----- src/modules/graphics/opengl/Graphics.cpp | 126 +++++++++++++++++-- src/modules/graphics/opengl/Graphics.h | 8 +- src/modules/graphics/opengl/Image.cpp | 5 - src/modules/graphics/opengl/Image.h | 2 - src/modules/graphics/wrap_Graphics.cpp | 9 +- 11 files changed, 140 insertions(+), 201 deletions(-) diff --git a/src/modules/graphics/Canvas.cpp b/src/modules/graphics/Canvas.cpp index ce384450c..aeca38809 100644 --- a/src/modules/graphics/Canvas.cpp +++ b/src/modules/graphics/Canvas.cpp @@ -72,7 +72,7 @@ Canvas::Canvas(const Settings &settings) auto gfx = Module::getInstance(Module::M_GRAPHICS); const Graphics::Capabilities &caps = gfx->getCapabilities(); - if (!gfx->isCanvasFormatSupported(format, readable)) + if (!gfx->isPixelFormatSupported(format, true, readable, false)) { const char *fstr = "rgba8"; const char *readablestr = ""; diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 835344e29..d3863cf33 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -694,7 +694,7 @@ void Graphics::setCanvas(const RenderTargets &rts) PixelFormat dsformat = PIXELFORMAT_STENCIL8; if (wantsdepth && wantsstencil) dsformat = PIXELFORMAT_DEPTH24_UNORM_STENCIL8; - else if (wantsdepth && isCanvasFormatSupported(PIXELFORMAT_DEPTH24_UNORM, false)) + else if (wantsdepth && isPixelFormatSupported(PIXELFORMAT_DEPTH24_UNORM, true, false, false)) dsformat = PIXELFORMAT_DEPTH24_UNORM; else if (wantsdepth) dsformat = PIXELFORMAT_DEPTH16_UNORM; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index e8f146cf1..4a035cb8d 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -785,12 +785,14 @@ public: const Capabilities &getCapabilities() const; /** - * Gets whether the specified pixel format is supported by Canvases or - * Images. + * Converts PIXELFORMAT_NORMAL and PIXELFORMAT_HDR into a real format. **/ - virtual bool isCanvasFormatSupported(PixelFormat format) const = 0; - virtual bool isCanvasFormatSupported(PixelFormat format, bool readable) const = 0; - virtual bool isImageFormatSupported(PixelFormat format, bool sRGB = false) const = 0; + virtual PixelFormat getSizedFormat(PixelFormat format) const = 0; + + /** + * Gets whether the specified pixel format is supported. + **/ + virtual bool isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB = false) = 0; /** * Gets the renderer used by love.graphics. diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index 2f155832a..46cac2e5a 100644 --- a/src/modules/graphics/Image.cpp +++ b/src/modules/graphics/Image.cpp @@ -79,7 +79,7 @@ Image::~Image() void Image::init(PixelFormat fmt, int w, int h, const Settings &settings) { Graphics *gfx = Module::getInstance(Module::M_GRAPHICS); - if (gfx != nullptr && !gfx->isImageFormatSupported(fmt, sRGB)) + if (gfx != nullptr && !gfx->isPixelFormatSupported(fmt, false, true, sRGB)) { const char *str; if (love::getConstant(fmt, str)) diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 8a91ab577..029513261 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -196,7 +196,9 @@ Canvas::Canvas(const Settings &settings) , renderbuffer(0) , actualSamples(0) { - format = getSizedFormat(format); + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (gfx != nullptr) + format = gfx->getSizedFormat(format); initQuad(); loadVolatile(); @@ -474,153 +476,11 @@ void Canvas::generateMipmaps() glGenerateMipmap(gltextype); } -PixelFormat Canvas::getSizedFormat(PixelFormat format) -{ - switch (format) - { - case PIXELFORMAT_NORMAL: - if (isGammaCorrect()) - return PIXELFORMAT_sRGBA8_UNORM; - else if (!OpenGL::isPixelFormatSupported(PIXELFORMAT_RGBA8_UNORM, true, true, false)) - // 32-bit render targets don't have guaranteed support on GLES2. - return PIXELFORMAT_RGBA4_UNORM; - else - return PIXELFORMAT_RGBA8_UNORM; - case PIXELFORMAT_HDR: - return PIXELFORMAT_RGBA16_FLOAT; - default: - return format; - } -} - -bool Canvas::isSupported() -{ - return GLAD_ES_VERSION_2_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object || GLAD_EXT_framebuffer_object; -} - bool Canvas::isMultiFormatMultiCanvasSupported() { return gl.getMaxRenderTargets() > 1 && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object); } -Canvas::SupportedFormat Canvas::supportedFormats[] = {}; -Canvas::SupportedFormat Canvas::checkedFormats[] = {}; - -bool Canvas::isFormatSupported(PixelFormat format) -{ - return isFormatSupported(format, !isPixelFormatDepthStencil(format)); -} - -bool Canvas::isFormatSupported(PixelFormat format, bool readable) -{ - if (!isSupported()) - return false; - - const char *fstr = "?"; - love::getConstant(format, fstr); - - bool supported = true; - format = getSizedFormat(format); - - if (!OpenGL::isPixelFormatSupported(format, true, readable, false)) - return false; - - if (checkedFormats[format].get(readable)) - return supportedFormats[format].get(readable); - - // Even though we might have the necessary OpenGL version or extension, - // drivers are still allowed to throw FRAMEBUFFER_UNSUPPORTED when attaching - // a texture to a FBO whose format the driver doesn't like. So we should - // test with an actual FBO. - GLuint texture = 0; - GLuint renderbuffer = 0; - - // Avoid the test for depth/stencil formats - not every GL version - // guarantees support for depth/stencil-only render targets (which we would - // need for the test below to work), and we already do some finagling in - // convertPixelFormat to try to use the best-supported internal - // depth/stencil format for a particular driver. - if (isPixelFormatDepthStencil(format)) - { - checkedFormats[format].set(readable, true); - supportedFormats[format].set(readable, true); - return true; - } - - bool unusedSRGB = false; - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, readable, unusedSRGB); - - GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL); - - GLuint fbo = 0; - glGenFramebuffers(1, &fbo); - gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, fbo); - - // Make sure at least something is bound to a color attachment. I believe - // this is required on ES2 but I'm not positive. - if (isPixelFormatDepthStencil(format)) - gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, gl.getDefaultTexture(TEXTURE_2D), 0, 0, 0); - - if (readable) - { - glGenTextures(1, &texture); - gl.bindTextureToUnit(TEXTURE_2D, texture, 0, false); - - Texture::Filter f; - f.min = f.mag = Texture::FILTER_NEAREST; - gl.setTextureFilter(TEXTURE_2D, f); - - Texture::Wrap w; - gl.setTextureWrap(TEXTURE_2D, w); - - unusedSRGB = false; - gl.rawTexStorage(TEXTURE_2D, 1, format, unusedSRGB, 1, 1); - } - else - { - glGenRenderbuffers(1, &renderbuffer); - glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, fmt.internalformat, 1, 1); - } - - for (GLenum attachment : fmt.framebufferAttachments) - { - if (attachment == GL_NONE) - continue; - - if (readable) - gl.framebufferTexture(attachment, TEXTURE_2D, texture, 0, 0, 0); - else - glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, renderbuffer); - } - - supported = glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE; - - gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo); - gl.deleteFramebuffer(fbo); - - if (texture != 0) - gl.deleteTexture(texture); - - if (renderbuffer != 0) - glDeleteRenderbuffers(1, &renderbuffer); - - // Cache the result so we don't do this for every isFormatSupported call. - checkedFormats[format].set(readable, true); - supportedFormats[format].set(readable, supported); - - return supported; -} - -void Canvas::resetFormatSupport() -{ - for (int i = 0; i < (int)PIXELFORMAT_MAX_ENUM; i++) - { - checkedFormats[i].readable = false; - checkedFormats[i].nonreadable = false; - } -} - } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 317d9eeea..8543c3503 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -71,34 +71,10 @@ public: return fbo; } - static PixelFormat getSizedFormat(PixelFormat format); - static bool isSupported(); static bool isMultiFormatMultiCanvasSupported(); - static bool isFormatSupported(PixelFormat format, bool readable); - static bool isFormatSupported(PixelFormat format); - static void resetFormatSupport(); private: - struct SupportedFormat - { - bool readable = false; - bool nonreadable = false; - - bool get(bool getreadable) - { - return getreadable ? readable : nonreadable; - } - - void set(bool setreadable, bool val) - { - if (setreadable) - readable = val; - else - nonreadable = val; - } - }; - GLuint fbo; GLuint texture; @@ -108,9 +84,6 @@ private: int actualSamples; - static SupportedFormat supportedFormats[PIXELFORMAT_MAX_ENUM]; - static SupportedFormat checkedFormats[PIXELFORMAT_MAX_ENUM]; - }; // Canvas } // opengl diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index d636ed1eb..b443718fa 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -91,9 +91,9 @@ static GLenum getGLBlendFactor(BlendFactor factor) Graphics::Graphics() : windowHasStencil(false) , mainVAO(0) + , supportedFormats() { gl = OpenGL(); - Canvas::resetFormatSupport(); auto window = getInstance(M_WINDOW); @@ -1388,19 +1388,127 @@ void Graphics::initCapabilities() capabilities.textureTypes[i] = gl.isTextureTypeSupported((TextureType) i); } -bool Graphics::isCanvasFormatSupported(PixelFormat format) const +PixelFormat Graphics::getSizedFormat(PixelFormat format) const { - return Canvas::isFormatSupported(format); + switch (format) + { + case PIXELFORMAT_NORMAL: + if (isGammaCorrect()) + return PIXELFORMAT_sRGBA8_UNORM; + else if (!OpenGL::isPixelFormatSupported(PIXELFORMAT_RGBA8_UNORM, true, true, false)) + // 32-bit render targets don't have guaranteed support on GLES2. + return PIXELFORMAT_RGBA4_UNORM; + else + return PIXELFORMAT_RGBA8_UNORM; + case PIXELFORMAT_HDR: + return PIXELFORMAT_RGBA16_FLOAT; + default: + return format; + } } -bool Graphics::isCanvasFormatSupported(PixelFormat format, bool readable) const +bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB) { - return Canvas::isFormatSupported(format, readable); -} + format = getSizedFormat(format); -bool Graphics::isImageFormatSupported(PixelFormat format, bool sRGB) const -{ - return Image::isFormatSupported(format, sRGB); + if (sRGB && format == PIXELFORMAT_RGBA8_UNORM) + { + format = PIXELFORMAT_sRGBA8_UNORM; + sRGB = false; + } + + OptionalBool &supported = supportedFormats[format][rendertarget ? 1 : 0][readable ? 1 : 0][sRGB ? 1 : 0]; + + if (supported.hasValue) + return supported.value; + + if (!OpenGL::isPixelFormatSupported(format, rendertarget, readable, sRGB)) + { + supported.set(false); + return supported.value; + } + + if (!rendertarget) + { + supported.set(true); + return supported.value; + } + + // Even though we might have the necessary OpenGL version or extension, + // drivers are still allowed to throw FRAMEBUFFER_UNSUPPORTED when attaching + // a texture to a FBO whose format the driver doesn't like. So we should + // test with an actual FBO. + GLuint texture = 0; + GLuint renderbuffer = 0; + + // Avoid the test for depth/stencil formats - not every GL version + // guarantees support for depth/stencil-only render targets (which we would + // need for the test below to work), and we already do some finagling in + // convertPixelFormat to try to use the best-supported internal + // depth/stencil format for a particular driver. + if (isPixelFormatDepthStencil(format)) + { + supported.set(true); + return true; + } + + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, readable, sRGB); + + GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL); + + GLuint fbo = 0; + glGenFramebuffers(1, &fbo); + gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, fbo); + + // Make sure at least something is bound to a color attachment. I believe + // this is required on ES2 but I'm not positive. + if (isPixelFormatDepthStencil(format)) + gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, gl.getDefaultTexture(TEXTURE_2D), 0, 0, 0); + + if (readable) + { + glGenTextures(1, &texture); + gl.bindTextureToUnit(TEXTURE_2D, texture, 0, false); + + Texture::Filter f; + f.min = f.mag = Texture::FILTER_NEAREST; + gl.setTextureFilter(TEXTURE_2D, f); + + Texture::Wrap w; + gl.setTextureWrap(TEXTURE_2D, w); + + gl.rawTexStorage(TEXTURE_2D, 1, format, sRGB, 1, 1); + } + else + { + glGenRenderbuffers(1, &renderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); + glRenderbufferStorage(GL_RENDERBUFFER, fmt.internalformat, 1, 1); + } + + for (GLenum attachment : fmt.framebufferAttachments) + { + if (attachment == GL_NONE) + continue; + + if (readable) + gl.framebufferTexture(attachment, TEXTURE_2D, texture, 0, 0, 0); + else + glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, renderbuffer); + } + + supported.set(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo); + gl.deleteFramebuffer(fbo); + + if (texture != 0) + gl.deleteTexture(texture); + + if (renderbuffer != 0) + glDeleteRenderbuffers(1, &renderbuffer); + + return supported.value; } Shader::Language Graphics::getShaderLanguageTarget() const diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 4e68acd2d..7255ddfc2 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -104,9 +104,8 @@ public: void setWireframe(bool enable) override; - bool isCanvasFormatSupported(PixelFormat format) const override; - bool isCanvasFormatSupported(PixelFormat format, bool readable) const override; - bool isImageFormatSupported(PixelFormat format, bool sRGB) const override; + PixelFormat getSizedFormat(PixelFormat format) const override; + bool isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB = false) override; Renderer getRenderer() const override; RendererInfo getRendererInfo() const override; @@ -153,6 +152,9 @@ private: bool windowHasStencil; GLuint mainVAO; + // [rendertarget][readable][srgb] + OptionalBool supportedFormats[PIXELFORMAT_MAX_ENUM][2][2][2]; + }; // Graphics } // opengl diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 5bdddeeb3..f8477f9ba 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -351,11 +351,6 @@ bool Image::setMipmapSharpness(float sharpness) return true; } -bool Image::isFormatSupported(PixelFormat pixelformat, bool sRGB) -{ - return OpenGL::isPixelFormatSupported(pixelformat, false, true, sRGB); -} - } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index a1b203cfb..ac4045e3f 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -54,8 +54,6 @@ public: bool setMipmapSharpness(float sharpness) override; - static bool isFormatSupported(PixelFormat pixelformat, bool sRGB); - private: void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) override; diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index f42938b1f..451d04f82 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -2282,14 +2282,14 @@ int w_getCanvasFormats(lua_State *L) { supported = [](PixelFormat format) -> bool { - return instance()->isCanvasFormatSupported(format, true); + return instance()->isPixelFormatSupported(format, true, true, false); }; } else { supported = [](PixelFormat format) -> bool { - return instance()->isCanvasFormatSupported(format, false); + return instance()->isPixelFormatSupported(format, true, false, false); }; } } @@ -2297,7 +2297,8 @@ int w_getCanvasFormats(lua_State *L) { supported = [](PixelFormat format) -> bool { - return instance()->isCanvasFormatSupported(format); + bool readable = !isPixelFormatDepthStencil(format); + return instance()->isPixelFormatSupported(format, true, readable, false); }; } @@ -2308,7 +2309,7 @@ int w_getImageFormats(lua_State *L) { const auto supported = [](PixelFormat format) -> bool { - return instance()->isImageFormatSupported(format); + return instance()->isPixelFormatSupported(format, false, true, false); }; const auto ignore = [](PixelFormat format) -> bool From e0ffdfc1bac676ba790f9bafa5ea93a5f1dba84c Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 2 Feb 2020 01:21:27 -0400 Subject: [PATCH 02/31] Move some OpenGL-specific Image code into the GL backend --- src/modules/graphics/Image.cpp | 26 +++++++------------------- src/modules/graphics/Image.h | 4 +--- src/modules/graphics/opengl/Image.cpp | 26 +++++++++++++++++++------- src/modules/graphics/opengl/Image.h | 4 +++- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index 46cac2e5a..273055769 100644 --- a/src/modules/graphics/Image.cpp +++ b/src/modules/graphics/Image.cpp @@ -36,7 +36,6 @@ int Image::imageCount = 0; Image::Image(const Slices &data, const Settings &settings, bool validatedata) : Texture(data.getTextureType()) , settings(settings) - , data(data) , mipmapsType(settings.mipmaps ? MIPMAPS_GENERATED : MIPMAPS_NONE) , sRGB(isGammaCorrect() && !settings.linear) , usingDefaultTexture(false) @@ -63,11 +62,11 @@ Image::Image(const Slices &slices, const Settings &settings) : Image(slices, settings, true) { if (texType == TEXTURE_2D_ARRAY) - this->layers = data.getSliceCount(); + this->layers = slices.getSliceCount(); else if (texType == TEXTURE_VOLUME) - this->depth = data.getSliceCount(); + this->depth = slices.getSliceCount(); - love::image::ImageDataBase *slice = data.get(0, 0); + love::image::ImageDataBase *slice = slices.get(0, 0); init(slice->getFormat(), slice->getWidth(), slice->getHeight(), settings); } @@ -121,7 +120,7 @@ void Image::uploadImageData(love::image::ImageDataBase *d, int level, int slice, lock.setLock(id->getMutex()); Rect rect = {x, y, d->getWidth(), d->getHeight()}; - uploadByteData(d->getFormat(), d->getData(), d->getSize(), level, slice, rect); + uploadByteData(d->getFormat(), d->getData(), d->getSize(), level, slice, rect, d); } void Image::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps) @@ -154,19 +153,8 @@ void Image::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, throw love::Exception("Invalid rectangle dimensions (x=%d, y=%d, w=%d, h=%d) for %dx%d Image.", rect.x, rect.y, rect.w, rect.h, mipw, miph); } - love::image::ImageDataBase *oldd = data.get(slice, mipmap); - - if (oldd == nullptr) - throw love::Exception("Image does not store ImageData!"); - - Rect currect = {0, 0, oldd->getWidth(), oldd->getHeight()}; - - // We can only replace the internal Data (used when reloading due to setMode) - // if the dimensions match. We also don't currently support partial updates - // of compressed textures. - if (rect == currect) - data.set(slice, mipmap, d); - else if (isPixelFormatCompressed(d->getFormat())) + // We don't currently support partial updates of compressed textures. + if (isPixelFormatCompressed(d->getFormat()) && (rect.x != 0 || rect.y != 0 || rect.w != mipw || rect.h != miph)) throw love::Exception("Compressed textures only support replacing the entire Image."); Graphics::flushStreamDrawsGlobal(); @@ -181,7 +169,7 @@ void Image::replacePixels(const void *data, size_t size, int slice, int mipmap, { Graphics::flushStreamDrawsGlobal(); - uploadByteData(format, data, size, mipmap, slice, rect); + uploadByteData(format, data, size, mipmap, slice, rect, nullptr); if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1) generateMipmaps(); diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Image.h index 9cb070137..e04533616 100644 --- a/src/modules/graphics/Image.h +++ b/src/modules/graphics/Image.h @@ -113,15 +113,13 @@ protected: Image(TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings); void uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y); - virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) = 0; + virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) = 0; virtual void generateMipmaps() = 0; // The settings used to initialize this Image. Settings settings; - Slices data; - MipmapsType mipmapsType; bool sRGB; diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index f8477f9ba..c9f4d93bf 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -35,6 +35,7 @@ namespace opengl Image::Image(TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings) : love::graphics::Image(textype, format, width, height, slices, settings) + , slices(textype) , texture(0) { loadVolatile(); @@ -42,6 +43,7 @@ Image::Image(TextureType textype, PixelFormat format, int width, int height, int Image::Image(const Slices &slices, const Settings &settings) : love::graphics::Image(slices, settings) + , slices(slices) , texture(0) { loadVolatile(); @@ -85,7 +87,7 @@ void Image::loadDefaultTexture() int slices = texType == TEXTURE_CUBE ? 6 : 1; Rect rect = {0, 0, 2, 2}; for (int slice = 0; slice < slices; slice++) - uploadByteData(PIXELFORMAT_RGBA8_UNORM, px, sizeof(px), 0, slice, rect); + uploadByteData(PIXELFORMAT_RGBA8_UNORM, px, sizeof(px), 0, slice, rect, nullptr); } void Image::loadData() @@ -120,8 +122,8 @@ void Image::loadData() if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) { - for (int slice = 0; slice < data.getSliceCount(mip); slice++) - mipsize += data.get(slice, mip)->getSize(); + for (int slice = 0; slice < slices.getSliceCount(mip); slice++) + mipsize += slices.get(slice, mip)->getSize(); } GLenum gltarget = OpenGL::getGLTextureType(texType); @@ -130,7 +132,7 @@ void Image::loadData() for (int slice = 0; slice < slicecount; slice++) { - love::image::ImageDataBase *id = data.get(slice, mip); + love::image::ImageDataBase *id = slices.get(slice, mip); if (id != nullptr) uploadImageData(id, mip, slice, 0, 0); @@ -147,8 +149,18 @@ void Image::loadData() generateMipmaps(); } -void Image::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) +void Image::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd) { + love::image::ImageDataBase *oldd = slices.get(slice, level); + + // We can only replace the internal Data (used when reloading due to setMode) + // if the dimensions match. + if (imgd != nullptr && oldd != nullptr && oldd->getWidth() == imgd->getWidth() + && oldd->getHeight() == imgd->getHeight()) + { + slices.set(slice, level, imgd); + } + OpenGL::TempDebugGroup debuggroup("Image data upload"); gl.bindTextureToUnit(this, 0, false); @@ -242,8 +254,8 @@ bool Image::loadVolatile() int64 memsize = 0; - for (int slice = 0; slice < data.getSliceCount(0); slice++) - memsize += data.get(slice, 0)->getSize(); + for (int slice = 0; slice < slices.getSliceCount(0); slice++) + memsize += slices.get(slice, 0)->getSize(); if (getMipmapCount() > 1) memsize *= 1.33334; diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index ac4045e3f..1f6b853af 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -56,12 +56,14 @@ public: private: - void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) override; + void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override; void generateMipmaps() override; void loadDefaultTexture(); void loadData(); + Slices slices; + // OpenGL texture identifier. GLuint texture; From f24b1aa37749f28bb77ce354c28aa4499f67a47a Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 2 Feb 2020 13:50:37 -0400 Subject: [PATCH 03/31] Move internal Slices class from Image to Texture --- src/modules/graphics/Graphics.h | 2 +- src/modules/graphics/Image.cpp | 166 +---------------------- src/modules/graphics/Image.h | 39 ------ src/modules/graphics/Texture.cpp | 159 ++++++++++++++++++++++ src/modules/graphics/Texture.h | 39 ++++++ src/modules/graphics/opengl/Graphics.cpp | 2 +- src/modules/graphics/opengl/Graphics.h | 2 +- src/modules/graphics/wrap_Graphics.cpp | 10 +- 8 files changed, 208 insertions(+), 211 deletions(-) diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 4a035cb8d..155467885 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -429,7 +429,7 @@ public: // Implements Module. virtual ModuleType getModuleType() const { return M_GRAPHICS; } - virtual Image *newImage(const Image::Slices &data, const Image::Settings &settings) = 0; + virtual Image *newImage(const Texture::Slices &data, const Image::Settings &settings) = 0; virtual Image *newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) = 0; Quad *newQuad(Quad::Viewport v, double sw, double sh); diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index 273055769..bf19212dc 100644 --- a/src/modules/graphics/Image.cpp +++ b/src/modules/graphics/Image.cpp @@ -40,7 +40,7 @@ Image::Image(const Slices &data, const Settings &settings, bool validatedata) , sRGB(isGammaCorrect() && !settings.linear) , usingDefaultTexture(false) { - if (validatedata && data.validate() == MIPMAPS_DATA) + if (validatedata && data.validate() && data.getMipmapCount() > 1) mipmapsType = MIPMAPS_DATA; } @@ -182,7 +182,7 @@ bool Image::isCompressed() const bool Image::isFormatLinear() const { - return isGammaCorrect() && !sRGB; + return isGammaCorrect() && !sRGB && format != PIXELFORMAT_sRGBA8_UNORM; } Image::MipmapsType Image::getMipmapsType() const @@ -190,168 +190,6 @@ Image::MipmapsType Image::getMipmapsType() const return mipmapsType; } -Image::Slices::Slices(TextureType textype) - : textureType(textype) -{ -} - -void Image::Slices::clear() -{ - data.clear(); -} - -void Image::Slices::set(int slice, int mipmap, love::image::ImageDataBase *d) -{ - if (textureType == TEXTURE_VOLUME) - { - if (mipmap >= (int) data.size()) - data.resize(mipmap + 1); - - if (slice >= (int) data[mipmap].size()) - data[mipmap].resize(slice + 1); - - data[mipmap][slice].set(d); - } - else - { - if (slice >= (int) data.size()) - data.resize(slice + 1); - - if (mipmap >= (int) data[slice].size()) - data[slice].resize(mipmap + 1); - - data[slice][mipmap].set(d); - } -} - -love::image::ImageDataBase *Image::Slices::get(int slice, int mipmap) const -{ - if (slice < 0 || slice >= getSliceCount(mipmap)) - return nullptr; - - if (mipmap < 0 || mipmap >= getMipmapCount(slice)) - return nullptr; - - if (textureType == TEXTURE_VOLUME) - return data[mipmap][slice].get(); - else - return data[slice][mipmap].get(); -} - -void Image::Slices::add(love::image::CompressedImageData *cdata, int startslice, int startmip, bool addallslices, bool addallmips) -{ - int slicecount = addallslices ? cdata->getSliceCount() : 1; - int mipcount = addallmips ? cdata->getMipmapCount() : 1; - - for (int mip = 0; mip < mipcount; mip++) - { - for (int slice = 0; slice < slicecount; slice++) - set(startslice + slice, startmip + mip, cdata->getSlice(slice, mip)); - } -} - -int Image::Slices::getSliceCount(int mip) const -{ - if (textureType == TEXTURE_VOLUME) - { - if (mip < 0 || mip >= (int) data.size()) - return 0; - - return (int) data[mip].size(); - } - else - return (int) data.size(); -} - -int Image::Slices::getMipmapCount(int slice) const -{ - if (textureType == TEXTURE_VOLUME) - return (int) data.size(); - else - { - if (slice < 0 || slice >= (int) data.size()) - return 0; - - return data[slice].size(); - } -} - -Image::MipmapsType Image::Slices::validate() const -{ - int slicecount = getSliceCount(); - int mipcount = getMipmapCount(0); - - if (slicecount == 0 || mipcount == 0) - 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."); - - image::ImageDataBase *firstdata = get(0, 0); - - int w = firstdata->getWidth(); - int h = firstdata->getHeight(); - int depth = textureType == TEXTURE_VOLUME ? slicecount : 1; - PixelFormat format = firstdata->getFormat(); - - int expectedmips = Texture::getTotalMipmapCount(w, h, depth); - - if (mipcount != expectedmips && mipcount != 1) - throw love::Exception("Image does not have all required mipmap levels (expected %d, got %d)", expectedmips, mipcount); - - if (textureType == TEXTURE_CUBE && w != h) - throw love::Exception("Cube images must have equal widths and heights for each cube face."); - - int mipw = w; - int miph = h; - int mipslices = slicecount; - - for (int mip = 0; mip < mipcount; mip++) - { - if (textureType == TEXTURE_VOLUME) - { - slicecount = getSliceCount(mip); - - if (slicecount != mipslices) - throw love::Exception("Invalid number of image data layers in mipmap level %d (expected %d, got %d)", mip+1, mipslices, slicecount); - } - - for (int slice = 0; slice < slicecount; slice++) - { - auto slicedata = get(slice, mip); - - if (slicedata == nullptr) - throw love::Exception("Missing image data (slice %d, mipmap level %d)", slice+1, mip+1); - - int realw = slicedata->getWidth(); - int realh = slicedata->getHeight(); - - if (getMipmapCount(slice) != mipcount) - throw love::Exception("All Image layers must have the same mipmap count."); - - if (mipw != realw) - throw love::Exception("Width of image data (slice %d, mipmap level %d) is incorrect (expected %d, got %d)", slice+1, mip+1, mipw, realw); - - if (miph != realh) - throw love::Exception("Height of image data (slice %d, mipmap level %d) is incorrect (expected %d, got %d)", slice+1, mip+1, miph, realh); - - if (format != slicedata->getFormat()) - throw love::Exception("All Image slices and mipmaps must have the same pixel format."); - } - - mipw = std::max(mipw / 2, 1); - miph = std::max(miph / 2, 1); - - if (textureType == TEXTURE_VOLUME) - mipslices = std::max(mipslices / 2, 1); - } - - if (mipcount > 1) - return MIPMAPS_DATA; - else - return MIPMAPS_NONE; -} - bool Image::getConstant(const char *in, SettingType &out) { return settingTypes.find(in, out); diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Image.h index e04533616..a8aeabb7c 100644 --- a/src/modules/graphics/Image.h +++ b/src/modules/graphics/Image.h @@ -24,8 +24,6 @@ #include "common/config.h" #include "common/StringMap.h" #include "common/math.h" -#include "image/ImageData.h" -#include "image/CompressedImageData.h" #include "Texture.h" namespace love @@ -39,13 +37,6 @@ public: static love::Type type; - enum MipmapsType - { - MIPMAPS_NONE, - MIPMAPS_DATA, - MIPMAPS_GENERATED, - }; - enum SettingType { SETTING_MIPMAPS, @@ -61,36 +52,6 @@ public: float dpiScale = 1.0f; }; - struct Slices - { - public: - - Slices(TextureType textype); - - void clear(); - void set(int slice, int mipmap, love::image::ImageDataBase *data); - love::image::ImageDataBase *get(int slice, int mipmap) const; - - void add(love::image::CompressedImageData *cdata, int startslice, int startmip, bool addallslices, bool addallmips); - - int getSliceCount(int mip = 0) const; - int getMipmapCount(int slice = 0) const; - - MipmapsType validate() const; - - TextureType getTextureType() const { return textureType; } - - private: - - TextureType textureType; - - // For 2D/Cube/2DArray texture types, each element in the data array has - // an array of mipmap levels. For 3D texture types, each mipmap level - // has an array of layers. - std::vector>> data; - - }; // Slices - virtual ~Image(); void replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps); diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index cbbbf0b75..f54addfdb 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -382,6 +382,165 @@ bool Texture::validateDimensions(bool throwException) const return success; } +Texture::Slices::Slices(TextureType textype) + : textureType(textype) +{ +} + +void Texture::Slices::clear() +{ + data.clear(); +} + +void Texture::Slices::set(int slice, int mipmap, love::image::ImageDataBase *d) +{ + if (textureType == TEXTURE_VOLUME) + { + if (mipmap >= (int) data.size()) + data.resize(mipmap + 1); + + if (slice >= (int) data[mipmap].size()) + data[mipmap].resize(slice + 1); + + data[mipmap][slice].set(d); + } + else + { + if (slice >= (int) data.size()) + data.resize(slice + 1); + + if (mipmap >= (int) data[slice].size()) + data[slice].resize(mipmap + 1); + + data[slice][mipmap].set(d); + } +} + +love::image::ImageDataBase *Texture::Slices::get(int slice, int mipmap) const +{ + if (slice < 0 || slice >= getSliceCount(mipmap)) + return nullptr; + + if (mipmap < 0 || mipmap >= getMipmapCount(slice)) + return nullptr; + + if (textureType == TEXTURE_VOLUME) + return data[mipmap][slice].get(); + else + return data[slice][mipmap].get(); +} + +void Texture::Slices::add(love::image::CompressedImageData *cdata, int startslice, int startmip, bool addallslices, bool addallmips) +{ + int slicecount = addallslices ? cdata->getSliceCount() : 1; + int mipcount = addallmips ? cdata->getMipmapCount() : 1; + + for (int mip = 0; mip < mipcount; mip++) + { + for (int slice = 0; slice < slicecount; slice++) + set(startslice + slice, startmip + mip, cdata->getSlice(slice, mip)); + } +} + +int Texture::Slices::getSliceCount(int mip) const +{ + if (textureType == TEXTURE_VOLUME) + { + if (mip < 0 || mip >= (int) data.size()) + return 0; + + return (int) data[mip].size(); + } + else + return (int) data.size(); +} + +int Texture::Slices::getMipmapCount(int slice) const +{ + if (textureType == TEXTURE_VOLUME) + return (int) data.size(); + else + { + if (slice < 0 || slice >= (int) data.size()) + return 0; + + return data[slice].size(); + } +} + +bool Texture::Slices::validate() const +{ + int slicecount = getSliceCount(); + int mipcount = getMipmapCount(0); + + if (slicecount == 0 || mipcount == 0) + 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."); + + image::ImageDataBase *firstdata = get(0, 0); + + int w = firstdata->getWidth(); + int h = firstdata->getHeight(); + int depth = textureType == TEXTURE_VOLUME ? slicecount : 1; + PixelFormat format = firstdata->getFormat(); + + int expectedmips = Texture::getTotalMipmapCount(w, h, depth); + + if (mipcount != expectedmips && mipcount != 1) + throw love::Exception("Image does not have all required mipmap levels (expected %d, got %d)", expectedmips, mipcount); + + if (textureType == TEXTURE_CUBE && w != h) + throw love::Exception("Cube images must have equal widths and heights for each cube face."); + + int mipw = w; + int miph = h; + int mipslices = slicecount; + + for (int mip = 0; mip < mipcount; mip++) + { + if (textureType == TEXTURE_VOLUME) + { + slicecount = getSliceCount(mip); + + if (slicecount != mipslices) + throw love::Exception("Invalid number of image data layers in mipmap level %d (expected %d, got %d)", mip+1, mipslices, slicecount); + } + + for (int slice = 0; slice < slicecount; slice++) + { + auto slicedata = get(slice, mip); + + if (slicedata == nullptr) + throw love::Exception("Missing image data (slice %d, mipmap level %d)", slice+1, mip+1); + + int realw = slicedata->getWidth(); + int realh = slicedata->getHeight(); + + if (getMipmapCount(slice) != mipcount) + throw love::Exception("All Image layers must have the same mipmap count."); + + if (mipw != realw) + throw love::Exception("Width of image data (slice %d, mipmap level %d) is incorrect (expected %d, got %d)", slice+1, mip+1, mipw, realw); + + if (miph != realh) + throw love::Exception("Height of image data (slice %d, mipmap level %d) is incorrect (expected %d, got %d)", slice+1, mip+1, miph, realh); + + if (format != slicedata->getFormat()) + throw love::Exception("All Image slices and mipmaps must have the same pixel format."); + } + + mipw = std::max(mipw / 2, 1); + miph = std::max(miph / 2, 1); + + if (textureType == TEXTURE_VOLUME) + mipslices = std::max(mipslices / 2, 1); + } + + return true; +} + bool Texture::getConstant(const char *in, TextureType &out) { return texTypes.find(in, out); diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index c308e8fc2..42239d3df 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -33,6 +33,8 @@ #include "vertex.h" #include "renderstate.h" #include "Resource.h" +#include "image/ImageData.h" +#include "image/CompressedImageData.h" // C #include @@ -96,6 +98,43 @@ public: WrapMode r = WRAP_CLAMP; }; + enum MipmapsType + { + MIPMAPS_NONE, + MIPMAPS_DATA, + MIPMAPS_GENERATED, + }; + + struct Slices + { + public: + + Slices(TextureType textype); + + void clear(); + void set(int slice, int mipmap, love::image::ImageDataBase *data); + love::image::ImageDataBase *get(int slice, int mipmap) const; + + void add(love::image::CompressedImageData *cdata, int startslice, int startmip, bool addallslices, bool addallmips); + + int getSliceCount(int mip = 0) const; + int getMipmapCount(int slice = 0) const; + + bool validate() const; + + TextureType getTextureType() const { return textureType; } + + private: + + TextureType textureType; + + // For 2D/Cube/2DArray texture types, each element in the data array has + // an array of mipmap levels. For 3D texture types, each mipmap level + // has an array of layers. + std::vector>> data; + + }; // Slices + static Filter defaultFilter; static FilterMode defaultMipmapFilter; static float defaultMipmapSharpness; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index b443718fa..e7a821385 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -130,7 +130,7 @@ love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t return CreateStreamBuffer(type, size); } -love::graphics::Image *Graphics::newImage(const Image::Slices &data, const Image::Settings &settings) +love::graphics::Image *Graphics::newImage(const Texture::Slices &data, const Image::Settings &settings) { return new Image(data, settings); } diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 7255ddfc2..9dbdb3033 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -60,7 +60,7 @@ public: // Implements Module. const char *getName() const override; - love::graphics::Image *newImage(const Image::Slices &data, const Image::Settings &settings) override; + love::graphics::Image *newImage(const Texture::Slices &data, const Image::Settings &settings) override; love::graphics::Image *newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) override; love::graphics::Canvas *newCanvas(const Canvas::Settings &settings) override; love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override; diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 451d04f82..327ec5fe8 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -757,7 +757,7 @@ getImageData(lua_State *L, int idx, bool allowcompressed, float *dpiscale) return std::make_pair(idata, cdata); } -static int w__pushNewImage(lua_State *L, Image::Slices &slices, const Image::Settings &settings) +static int w__pushNewImage(lua_State *L, Texture::Slices &slices, const Image::Settings &settings) { StrongRef i; luax_catchexcept(L, @@ -773,7 +773,7 @@ int w_newCubeImage(lua_State *L) { luax_checkgraphicscreated(L); - Image::Slices slices(TEXTURE_CUBE); + Texture::Slices slices(TEXTURE_CUBE); bool dpiscaleset = false; Image::Settings settings = w__optImageSettings(L, 2, dpiscaleset); @@ -867,7 +867,7 @@ int w_newArrayImage(lua_State *L) { luax_checkgraphicscreated(L); - Image::Slices slices(TEXTURE_2D_ARRAY); + Texture::Slices slices(TEXTURE_2D_ARRAY); bool dpiscaleset = false; Image::Settings settings = w__optImageSettings(L, 2, dpiscaleset); @@ -933,7 +933,7 @@ int w_newVolumeImage(lua_State *L) auto imagemodule = Module::getInstance(Module::M_IMAGE); - Image::Slices slices(TEXTURE_VOLUME); + Texture::Slices slices(TEXTURE_VOLUME); bool dpiscaleset = false; Image::Settings settings = w__optImageSettings(L, 2, dpiscaleset); @@ -1004,7 +1004,7 @@ int w_newImage(lua_State *L) { luax_checkgraphicscreated(L); - Image::Slices slices(TEXTURE_2D); + Texture::Slices slices(TEXTURE_2D); bool dpiscaleset = false; Image::Settings settings = w__optImageSettings(L, 2, dpiscaleset); From f9248d478c5dbc7d9fd66fffcfaeae06ca8da330 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 2 Feb 2020 22:26:28 -0400 Subject: [PATCH 04/31] Refactor sampler state parameters for textures. --- src/modules/graphics/Canvas.cpp | 3 - src/modules/graphics/Font.cpp | 24 ++- src/modules/graphics/Font.h | 8 +- src/modules/graphics/Graphics.cpp | 38 +--- src/modules/graphics/Graphics.h | 23 +-- src/modules/graphics/Image.cpp | 3 - src/modules/graphics/Shader.cpp | 2 +- src/modules/graphics/Texture.cpp | 244 +++++++++++++---------- src/modules/graphics/Texture.h | 114 +++++------ src/modules/graphics/Video.cpp | 29 ++- src/modules/graphics/Video.h | 6 +- src/modules/graphics/opengl/Canvas.cpp | 108 +--------- src/modules/graphics/opengl/Canvas.h | 5 +- src/modules/graphics/opengl/Graphics.cpp | 9 +- src/modules/graphics/opengl/Image.cpp | 79 ++------ src/modules/graphics/opengl/Image.h | 5 +- src/modules/graphics/opengl/OpenGL.cpp | 164 +++++++++------ src/modules/graphics/opengl/OpenGL.h | 13 +- src/modules/graphics/opengl/Shader.cpp | 3 +- src/modules/graphics/wrap_Font.cpp | 22 +- src/modules/graphics/wrap_Graphics.cpp | 51 ++--- src/modules/graphics/wrap_Texture.cpp | 83 ++++---- src/modules/graphics/wrap_Video.cpp | 22 +- 23 files changed, 473 insertions(+), 585 deletions(-) diff --git a/src/modules/graphics/Canvas.cpp b/src/modules/graphics/Canvas.cpp index aeca38809..008851615 100644 --- a/src/modules/graphics/Canvas.cpp +++ b/src/modules/graphics/Canvas.cpp @@ -64,10 +64,7 @@ Canvas::Canvas(const Settings &settings) throw love::Exception("Non-readable and MSAA textures cannot have mipmaps."); if (settings.mipmaps != MIPMAPS_NONE) - { mipmapCount = getTotalMipmapCount(pixelWidth, pixelHeight, depth); - filter.mipmap = defaultMipmapFilter; - } auto gfx = Module::getInstance(Module::M_GRAPHICS); const Graphics::Capabilities &caps = gfx->getCapabilities(); diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index f94adaa05..df325dd73 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -47,18 +47,20 @@ int Font::fontCount = 0; const vertex::CommonFormat Font::vertexFormat = vertex::CommonFormat::XYf_STus_RGBAub; -Font::Font(love::font::Rasterizer *r, const Texture::Filter &f) +Font::Font(love::font::Rasterizer *r, const SamplerState &s) : rasterizers({r}) , height(r->getHeight()) , lineHeight(1) , textureWidth(128) , textureHeight(128) - , filter(f) + , samplerState() , dpiScale(r->getDPIScale()) , useSpacesAsTab(false) , textureCacheID(0) { - filter.mipmap = Texture::FILTER_NONE; + samplerState.minFilter = s.minFilter; + samplerState.magFilter = s.magFilter; + samplerState.maxAnisotropy = s.maxAnisotropy; // Try to find the best texture size match for the font size. default to the // largest texture size if no rough match is found. @@ -150,7 +152,7 @@ void Font::createTexture() Image::Settings settings; image = gfx->newImage(TEXTURE_2D, pixelFormat, size.width, size.height, 1, settings); - image->setFilter(filter); + image->setSamplerState(samplerState); { size_t bpp = getPixelFormatSize(pixelFormat); @@ -918,17 +920,19 @@ float Font::getLineHeight() const return lineHeight; } -void Font::setFilter(const Texture::Filter &f) +void Font::setSamplerState(const SamplerState &s) { - for (const auto &image : images) - image->setFilter(f); + samplerState.minFilter = s.minFilter; + samplerState.magFilter = s.magFilter; + samplerState.maxAnisotropy = s.maxAnisotropy; - filter = f; + for (const auto &image : images) + image->setSamplerState(samplerState); } -const Texture::Filter &Font::getFilter() const +const SamplerState &Font::getSamplerState() const { - return filter; + return samplerState; } int Font::getAscent() const diff --git a/src/modules/graphics/Font.h b/src/modules/graphics/Font.h index dbca1920c..20f5bc5c8 100644 --- a/src/modules/graphics/Font.h +++ b/src/modules/graphics/Font.h @@ -96,7 +96,7 @@ public: int vertexcount; }; - Font(love::font::Rasterizer *r, const Texture::Filter &filter); + Font(love::font::Rasterizer *r, const SamplerState &samplerState); virtual ~Font(); @@ -158,8 +158,8 @@ public: **/ float getLineHeight() const; - void setFilter(const Texture::Filter &f); - const Texture::Filter &getFilter() const; + void setSamplerState(const SamplerState &s); + const SamplerState &getSamplerState() const; // Extra font metrics int getAscent() const; @@ -227,7 +227,7 @@ private: PixelFormat pixelFormat; - Texture::Filter filter; + SamplerState samplerState; float dpiScale; diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index d3863cf33..fcdb70cee 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -184,19 +184,19 @@ Quad *Graphics::newQuad(Quad::Viewport v, double sw, double sh) return new Quad(v, sw, sh); } -Font *Graphics::newFont(love::font::Rasterizer *data, const Texture::Filter &filter) +Font *Graphics::newFont(love::font::Rasterizer *data) { - return new Font(data, filter); + return new Font(data, states.back().defaultSamplerState); } -Font *Graphics::newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting, const Texture::Filter &filter) +Font *Graphics::newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting) { auto fontmodule = Module::getInstance(M_FONT); if (!fontmodule) throw love::Exception("Font module has not been loaded."); StrongRef r(fontmodule->newTrueTypeRasterizer(size, hinting), Acquire::NORETAIN); - return newFont(r.get(), filter); + return newFont(r.get()); } Video *Graphics::newVideo(love::video::VideoStream *stream, float dpiscale) @@ -402,8 +402,7 @@ void Graphics::restoreState(const DisplayState &s) setColorMask(s.colorMask); setWireframe(s.wireframe); - setDefaultFilter(s.defaultFilter); - setDefaultMipmapFilter(s.defaultMipmapFilter, s.defaultMipmapSharpness); + setDefaultSamplerState(s.defaultSamplerState); } void Graphics::restoreStateChecked(const DisplayState &s) @@ -479,8 +478,7 @@ void Graphics::restoreStateChecked(const DisplayState &s) if (s.wireframe != cur.wireframe) setWireframe(s.wireframe); - setDefaultFilter(s.defaultFilter); - setDefaultMipmapFilter(s.defaultMipmapFilter, s.defaultMipmapSharpness); + setDefaultSamplerState(s.defaultSamplerState); } Colorf Graphics::getColor() const @@ -923,30 +921,14 @@ const BlendState &Graphics::getBlendState() const return states.back().blend; } -void Graphics::setDefaultFilter(const Texture::Filter &f) +void Graphics::setDefaultSamplerState(const SamplerState &s) { - Texture::defaultFilter = f; - states.back().defaultFilter = f; + states.back().defaultSamplerState = s; } -const Texture::Filter &Graphics::getDefaultFilter() const +const SamplerState &Graphics::getDefaultSamplerState() const { - return Texture::defaultFilter; -} - -void Graphics::setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness) -{ - Texture::defaultMipmapFilter = filter; - Texture::defaultMipmapSharpness = sharpness; - - states.back().defaultMipmapFilter = filter; - states.back().defaultMipmapSharpness = sharpness; -} - -void Graphics::getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const -{ - *filter = Texture::defaultMipmapFilter; - *sharpness = Texture::defaultMipmapSharpness; + return states.back().defaultSamplerState; } void Graphics::setLineWidth(float width) diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 155467885..151be6f08 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -433,8 +433,8 @@ public: virtual Image *newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) = 0; Quad *newQuad(Quad::Viewport v, double sw, double sh); - Font *newFont(love::font::Rasterizer *data, const Texture::Filter &filter = Texture::defaultFilter); - Font *newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting, const Texture::Filter &filter = Texture::defaultFilter); + Font *newFont(love::font::Rasterizer *data); + Font *newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting); Video *newVideo(love::video::VideoStream *stream, float dpiscale); SpriteBatch *newSpriteBatch(Texture *texture, int size, vertex::Usage usage); @@ -620,20 +620,14 @@ public: const BlendState &getBlendState() const; /** - * Sets the default filter for images, canvases, and fonts. + * Sets the default sampler state for images, canvases, and fonts. **/ - void setDefaultFilter(const Texture::Filter &f); + void setDefaultSamplerState(const SamplerState &s); /** - * Gets the default filter for images, canvases, and fonts. + * Gets the default sampler state for images, canvases, and fonts. **/ - const Texture::Filter &getDefaultFilter() const; - - /** - * Default Image mipmap filter mode and sharpness values. - **/ - void setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness); - void getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const; + const SamplerState &getDefaultSamplerState() const; /** * Sets the line width. @@ -920,10 +914,7 @@ protected: bool wireframe = false; - Texture::Filter defaultFilter = Texture::Filter(); - - Texture::FilterMode defaultMipmapFilter = Texture::FILTER_LINEAR; - float defaultMipmapSharpness = 0.0f; + SamplerState defaultSamplerState = SamplerState(); }; struct StreamBufferState diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index bf19212dc..83d423dae 100644 --- a/src/modules/graphics/Image.cpp +++ b/src/modules/graphics/Image.cpp @@ -103,9 +103,6 @@ void Image::init(PixelFormat fmt, int w, int h, const Settings &settings) mipmapCount = mipmapsType == MIPMAPS_NONE ? 1 : getTotalMipmapCount(w, h, depth); - if (mipmapCount > 1) - filter.mipmap = defaultMipmapFilter; - initQuad(); ++imageCount; diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index 4692a82b3..f94b952f6 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -125,7 +125,7 @@ void Shader::checkMainTexture(Texture *tex) const if (!tex->isReadable()) throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader."); - checkMainTextureType(tex->getTextureType(), tex->getDepthSampleMode().hasValue); + checkMainTextureType(tex->getTextureType(), tex->getSamplerState().depthSampleMode.hasValue); } bool Shader::validate(ShaderStage *vertex, ShaderStage *pixel, std::string &err) diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index f54addfdb..1866aae50 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -33,11 +33,129 @@ namespace love namespace graphics { -love::Type Texture::type("Texture", &Drawable::type); +uint64 SamplerState::toKey() const +{ + union { float f; uint32 i; } conv; + conv.f = lodBias; -Texture::Filter Texture::defaultFilter; -Texture::FilterMode Texture::defaultMipmapFilter = Texture::FILTER_LINEAR; -float Texture::defaultMipmapSharpness = 0.0f; + return (minFilter << 0) | (magFilter << 1) | (mipmapFilter << 2) + | (wrapU << 4) | (wrapV << 7) | (wrapW << 10) + | (maxAnisotropy << 12) | (minLod << 16) | (maxLod << 20) + | (depthSampleMode.hasValue << 24) | (depthSampleMode.value << 25) + | ((uint64)conv.i << 32); +} + +SamplerState SamplerState::fromKey(uint64 key) +{ + const uint32 BITS_1 = 0x1; + const uint32 BITS_2 = 0x3; + const uint32 BITS_3 = 0x7; + const uint32 BITS_4 = 0xF; + + SamplerState s; + + s.minFilter = (FilterMode) ((key >> 0) & BITS_1); + s.magFilter = (FilterMode) ((key >> 1) & BITS_1); + s.mipmapFilter = (MipmapFilterMode) ((key >> 2) & BITS_2); + + s.wrapU = (WrapMode) ((key >> 4 ) & BITS_3); + s.wrapV = (WrapMode) ((key >> 7 ) & BITS_3); + s.wrapW = (WrapMode) ((key >> 10) & BITS_3); + + s.maxAnisotropy = (key >> 12) & BITS_4; + + s.minLod = (key >> 16) & BITS_4; + s.maxLod = (key >> 20) & BITS_4; + + s.depthSampleMode.hasValue = ((key >> 24) & BITS_1) != 0; + s.depthSampleMode.value = (CompareMode) ((key >> 25) & BITS_4); + + union { float f; uint32 i; } conv; + conv.i = (uint32) (key >> 32); + s.lodBias = conv.f; + + return s; +} + +bool SamplerState::isClampZeroOrOne(WrapMode w) +{ + return w == WRAP_CLAMP_ONE || w == WRAP_CLAMP_ZERO; +} + +static StringMap::Entry filterModeEntries[] = +{ + { "linear", SamplerState::FILTER_LINEAR }, + { "nearest", SamplerState::FILTER_NEAREST }, +}; + +static StringMap filterModes(filterModeEntries, sizeof(filterModeEntries)); + +static StringMap::Entry mipmapFilterModeEntries[] = +{ + { "none", SamplerState::MIPMAP_FILTER_NONE }, + { "linear", SamplerState::MIPMAP_FILTER_LINEAR }, + { "nearest", SamplerState::MIPMAP_FILTER_NEAREST }, +}; + +static StringMap mipmapFilterModes(mipmapFilterModeEntries, sizeof(mipmapFilterModeEntries)); + +static StringMap::Entry wrapModeEntries[] = +{ + { "clamp", SamplerState::WRAP_CLAMP }, + { "clampzero", SamplerState::WRAP_CLAMP_ZERO }, + { "clampone", SamplerState::WRAP_CLAMP_ONE }, + { "repeat", SamplerState::WRAP_REPEAT }, + { "mirroredrepeat", SamplerState::WRAP_MIRRORED_REPEAT }, +}; + +static StringMap wrapModes(wrapModeEntries, sizeof(wrapModeEntries)); + +bool SamplerState::getConstant(const char *in, FilterMode &out) +{ + return filterModes.find(in, out); +} + +bool SamplerState::getConstant(FilterMode in, const char *&out) +{ + return filterModes.find(in, out); +} + +std::vector SamplerState::getConstants(FilterMode) +{ + return filterModes.getNames(); +} + +bool SamplerState::getConstant(const char *in, MipmapFilterMode &out) +{ + return mipmapFilterModes.find(in, out); +} + +bool SamplerState::getConstant(MipmapFilterMode in, const char *&out) +{ + return mipmapFilterModes.find(in, out); +} + +std::vector SamplerState::getConstants(MipmapFilterMode) +{ + return mipmapFilterModes.getNames(); +} + +bool SamplerState::getConstant(const char *in, WrapMode &out) +{ + return wrapModes.find(in, out); +} + +bool SamplerState::getConstant(WrapMode in, const char *&out) +{ + return wrapModes.find(in, out); +} + +std::vector SamplerState::getConstants(WrapMode) +{ + return wrapModes.getNames(); +} + +love::Type Texture::type("Texture", &Drawable::type); int64 Texture::totalGraphicsMemory = 0; Texture::Texture(TextureType texType) @@ -51,11 +169,12 @@ Texture::Texture(TextureType texType) , mipmapCount(1) , pixelWidth(0) , pixelHeight(0) - , filter(defaultFilter) - , wrap() - , mipmapSharpness(defaultMipmapSharpness) + , samplerState() , graphicsMemorySize(0) { + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (gfx != nullptr) + samplerState = gfx->getDefaultSamplerState(); } Texture::~Texture() @@ -252,45 +371,25 @@ float Texture::getDPIScale() const return (float) pixelHeight / (float) height; } -void Texture::setFilter(const Filter &f) +void Texture::setSamplerState(const SamplerState &s) { - if (!validateFilter(f, getMipmapCount() > 1)) - { - if (f.mipmap != FILTER_NONE && getMipmapCount() == 1) - throw love::Exception("Non-mipmapped texture cannot have mipmap filtering."); - else - throw love::Exception("Invalid texture filter."); - } + if (s.depthSampleMode.hasValue && (!readable || !isPixelFormatDepthStencil(format))) + throw love::Exception("Only readable depth textures can have a depth sample compare mode."); Graphics::flushStreamDrawsGlobal(); - filter = f; + samplerState = s; + + if (samplerState.mipmapFilter != SamplerState::MIPMAP_FILTER_NONE && getMipmapCount() == 1) + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; + + if (texType == TEXTURE_CUBE) + samplerState.wrapU = samplerState.wrapV = samplerState.wrapW = SamplerState::WRAP_CLAMP; } -const Texture::Filter &Texture::getFilter() const +const SamplerState &Texture::getSamplerState() const { - return filter; -} - -const Texture::Wrap &Texture::getWrap() const -{ - return wrap; -} - -float Texture::getMipmapSharpness() const -{ - return mipmapSharpness; -} - -void Texture::setDepthSampleMode(Optional mode) -{ - if (mode.hasValue && (!readable || !isPixelFormatDepthStencil(format))) - throw love::Exception("Only readable depth textures can have a depth sample compare mode."); -} - -Optional Texture::getDepthSampleMode() const -{ - return depthCompareMode; + return samplerState; } Quad *Texture::getQuad() const @@ -298,23 +397,6 @@ Quad *Texture::getQuad() const return quad; } -bool Texture::validateFilter(const Filter &f, bool mipmapsAllowed) -{ - if (!mipmapsAllowed && f.mipmap != FILTER_NONE) - return false; - - if (f.mag != FILTER_LINEAR && f.mag != FILTER_NEAREST) - return false; - - if (f.min != FILTER_LINEAR && f.min != FILTER_NEAREST) - return false; - - if (f.mipmap != FILTER_LINEAR && f.mipmap != FILTER_NEAREST && f.mipmap != FILTER_NONE) - return false; - - return true; -} - int Texture::getTotalMipmapCount(int w, int h) { return (int) log2(std::max(w, h)) + 1; @@ -556,36 +638,6 @@ std::vector Texture::getConstants(TextureType) return texTypes.getNames(); } -bool Texture::getConstant(const char *in, FilterMode &out) -{ - return filterModes.find(in, out); -} - -bool Texture::getConstant(FilterMode in, const char *&out) -{ - return filterModes.find(in, out); -} - -std::vector Texture::getConstants(FilterMode) -{ - return filterModes.getNames(); -} - -bool Texture::getConstant(const char *in, WrapMode &out) -{ - return wrapModes.find(in, out); -} - -bool Texture::getConstant(WrapMode in, const char *&out) -{ - return wrapModes.find(in, out); -} - -std::vector Texture::getConstants(WrapMode) -{ - return wrapModes.getNames(); -} - StringMap::Entry Texture::texTypeEntries[] = { { "2d", TEXTURE_2D }, @@ -596,25 +648,5 @@ StringMap::Entry Texture::texTypeEntries[] = StringMap Texture::texTypes(Texture::texTypeEntries, sizeof(Texture::texTypeEntries)); -StringMap::Entry Texture::filterModeEntries[] = -{ - { "linear", FILTER_LINEAR }, - { "nearest", FILTER_NEAREST }, - { "none", FILTER_NONE }, -}; - -StringMap Texture::filterModes(Texture::filterModeEntries, sizeof(Texture::filterModeEntries)); - -StringMap::Entry Texture::wrapModeEntries[] = -{ - { "clamp", WRAP_CLAMP }, - { "clampzero", WRAP_CLAMP_ZERO }, - { "clampone", WRAP_CLAMP_ONE }, - { "repeat", WRAP_REPEAT }, - { "mirroredrepeat", WRAP_MIRRORED_REPEAT }, -}; - -StringMap Texture::wrapModes(Texture::wrapModeEntries, sizeof(Texture::wrapModeEntries)); - } // graphics } // love diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 42239d3df..ee0c7c654 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -55,16 +55,8 @@ enum TextureType TEXTURE_MAX_ENUM }; -/** - * Base class for 2D textures. All textures can be drawn with Quads, have a - * width and height, and have filter and wrap modes. - **/ -class Texture : public Drawable, public Resource +struct SamplerState { -public: - - static love::Type type; - enum WrapMode { WRAP_CLAMP, @@ -77,26 +69,63 @@ public: enum FilterMode { - FILTER_NONE, FILTER_LINEAR, FILTER_NEAREST, FILTER_MAX_ENUM }; - struct Filter + enum MipmapFilterMode { - FilterMode min = FILTER_LINEAR; - FilterMode mag = FILTER_LINEAR; - FilterMode mipmap = FILTER_NONE; - float anisotropy = 1.0f; + MIPMAP_FILTER_NONE, + MIPMAP_FILTER_LINEAR, + MIPMAP_FILTER_NEAREST, + MIPMAP_FILTER_MAX_ENUM }; - struct Wrap - { - WrapMode s = WRAP_CLAMP; - WrapMode t = WRAP_CLAMP; - WrapMode r = WRAP_CLAMP; - }; + FilterMode minFilter = FILTER_LINEAR; + FilterMode magFilter = FILTER_LINEAR; + MipmapFilterMode mipmapFilter = MIPMAP_FILTER_NONE; + + WrapMode wrapU = WRAP_CLAMP; + WrapMode wrapV = WRAP_CLAMP; + WrapMode wrapW = WRAP_CLAMP; + + float lodBias = 0.0f; + + uint8 maxAnisotropy = 1; + + uint8 minLod = 0; + uint8 maxLod = LOVE_UINT8_MAX; + + Optional depthSampleMode; + + uint64 toKey() const; + static SamplerState fromKey(uint64 key); + + static bool isClampZeroOrOne(WrapMode w); + + static bool getConstant(const char *in, FilterMode &out); + static bool getConstant(FilterMode in, const char *&out); + static std::vector getConstants(FilterMode); + + static bool getConstant(const char *in, MipmapFilterMode &out); + static bool getConstant(MipmapFilterMode in, const char *&out); + static std::vector getConstants(MipmapFilterMode); + + static bool getConstant(const char *in, WrapMode &out); + static bool getConstant(WrapMode in, const char *&out); + static std::vector getConstants(WrapMode); +}; + +/** + * Base class for 2D textures. All textures can be drawn with Quads, have a + * width and height, and have filter and wrap modes. + **/ +class Texture : public Drawable, public Resource +{ +public: + + static love::Type type; enum MipmapsType { @@ -135,10 +164,6 @@ public: }; // Slices - static Filter defaultFilter; - static FilterMode defaultMipmapFilter; - static float defaultMipmapSharpness; - static int64 totalGraphicsMemory; Texture(TextureType texType); @@ -173,40 +198,18 @@ public: float getDPIScale() const; - virtual void setFilter(const Filter &f); - virtual const Filter &getFilter() const; - - virtual bool setWrap(const Wrap &w) = 0; - virtual const Wrap &getWrap() const; - - // Sets the mipmap texture LOD bias (sharpness) value. - virtual bool setMipmapSharpness(float sharpness) = 0; - float getMipmapSharpness() const; - - virtual void setDepthSampleMode(Optional mode = Optional()); - Optional getDepthSampleMode() const; + virtual void setSamplerState(const SamplerState &s); + const SamplerState &getSamplerState() const; Quad *getQuad() const; - static bool validateFilter(const Filter &f, bool mipmapsAllowed); - static int getTotalMipmapCount(int w, int h); static int getTotalMipmapCount(int w, int h, int d); - static bool isClampZeroOrOne(WrapMode w) { return w == WRAP_CLAMP_ZERO || w == WRAP_CLAMP_ONE; } - static bool getConstant(const char *in, TextureType &out); static bool getConstant(TextureType in, const char *&out); static std::vector getConstants(TextureType); - static bool getConstant(const char *in, FilterMode &out); - static bool getConstant(FilterMode in, const char *&out); - static std::vector getConstants(FilterMode); - - static bool getConstant(const char *in, WrapMode &out); - static bool getConstant(WrapMode in, const char *&out); - static std::vector getConstants(WrapMode); - protected: void initQuad(); @@ -229,12 +232,7 @@ protected: int pixelWidth; int pixelHeight; - Filter filter; - Wrap wrap; - - float mipmapSharpness; - - Optional depthCompareMode; + SamplerState samplerState; StrongRef quad; @@ -245,12 +243,6 @@ private: static StringMap::Entry texTypeEntries[]; static StringMap texTypes; - static StringMap::Entry filterModeEntries[]; - static StringMap filterModes; - - static StringMap::Entry wrapModeEntries[]; - static StringMap wrapModes; - }; // Texture } // graphics diff --git a/src/modules/graphics/Video.cpp b/src/modules/graphics/Video.cpp index 201670f6b..b27d3c856 100644 --- a/src/modules/graphics/Video.cpp +++ b/src/modules/graphics/Video.cpp @@ -35,9 +35,14 @@ Video::Video(Graphics *gfx, love::video::VideoStream *stream, float dpiscale) : stream(stream) , width(stream->getWidth() / dpiscale) , height(stream->getHeight() / dpiscale) - , filter(Texture::defaultFilter) + , samplerState() { - filter.mipmap = Texture::FILTER_NONE; + const SamplerState &defaultSampler = gfx->getDefaultSamplerState(); + samplerState.minFilter = defaultSampler.minFilter; + samplerState.magFilter = defaultSampler.magFilter; + samplerState.wrapU = defaultSampler.wrapU; + samplerState.wrapV = defaultSampler.wrapV; + samplerState.maxAnisotropy = defaultSampler.maxAnisotropy; stream->fillBackBuffer(); @@ -74,15 +79,13 @@ Video::Video(Graphics *gfx, love::video::VideoStream *stream, float dpiscale) const unsigned char *data[3] = {frame->yplane, frame->cbplane, frame->crplane}; - Texture::Wrap wrap; // Clamp wrap mode. Image::Settings settings; for (int i = 0; i < 3; i++) { Image *img = gfx->newImage(TEXTURE_2D, PIXELFORMAT_R8_UNORM, widths[i], heights[i], 1, settings); - img->setFilter(filter); - img->setWrap(wrap); + img->setSamplerState(samplerState); size_t bpp = getPixelFormatSize(PIXELFORMAT_R8_UNORM); size_t size = bpp * widths[i] * heights[i]; @@ -200,17 +203,21 @@ int Video::getPixelHeight() const return stream->getHeight(); } -void Video::setFilter(const Texture::Filter &f) +void Video::setSamplerState(const SamplerState &s) { - for (const auto &image : images) - image->setFilter(f); + samplerState.minFilter = s.minFilter; + samplerState.magFilter = s.magFilter; + samplerState.wrapU = s.wrapU; + samplerState.wrapV = s.wrapV; + samplerState.maxAnisotropy = s.maxAnisotropy; - filter = f; + for (const auto &image : images) + image->setSamplerState(samplerState); } -const Texture::Filter &Video::getFilter() const +const SamplerState &Video::getSamplerState() const { - return filter; + return samplerState; } } // graphics diff --git a/src/modules/graphics/Video.h b/src/modules/graphics/Video.h index d307d3e79..65db27c32 100644 --- a/src/modules/graphics/Video.h +++ b/src/modules/graphics/Video.h @@ -58,8 +58,8 @@ public: int getPixelWidth() const; int getPixelHeight() const; - void setFilter(const Texture::Filter &f); - const Texture::Filter &getFilter() const; + void setSamplerState(const SamplerState &s); + const SamplerState &getSamplerState() const; private: @@ -70,7 +70,7 @@ private: int width; int height; - Texture::Filter filter; + SamplerState samplerState; Vertex vertices[4]; diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 029513261..f3555d1d9 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -239,10 +239,7 @@ bool Canvas::loadVolatile() if (GLAD_ANGLE_texture_usage) glTexParameteri(gltype, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE); - setFilter(filter); - setWrap(wrap); - setMipmapSharpness(mipmapSharpness); - setDepthSampleMode(depthCompareMode); + setSamplerState(samplerState); while (glGetError() != GL_NO_ERROR) /* Clear the error buffer. */; @@ -320,113 +317,30 @@ void Canvas::unloadVolatile() setGraphicsMemorySize(0); } -void Canvas::setFilter(const Texture::Filter &f) +void Canvas::setSamplerState(const SamplerState &s) { - Texture::setFilter(f); + Texture::setSamplerState(s); + + if (samplerState.depthSampleMode.hasValue && !gl.isDepthCompareSampleSupported()) + throw love::Exception("Depth comparison sampling in shaders is not supported on this system."); if (!OpenGL::hasTextureFilteringSupport(getPixelFormat())) { - filter.mag = filter.min = FILTER_NEAREST; + samplerState.magFilter = samplerState.minFilter = SamplerState::FILTER_NEAREST; - if (filter.mipmap == FILTER_LINEAR) - filter.mipmap = FILTER_NEAREST; + if (samplerState.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NEAREST; } - gl.bindTextureToUnit(this, 0, false); - gl.setTextureFilter(texType, filter); -} - -bool Canvas::setWrap(const Texture::Wrap &w) -{ - Graphics::flushStreamDrawsGlobal(); - - bool success = true; - bool forceclamp = texType == TEXTURE_CUBE; - wrap = w; - // If we only have limited NPOT support then the wrap mode must be CLAMP. if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight) || depth != nextP2(depth))) { - forceclamp = true; - } - - if (forceclamp) - { - if (wrap.s != WRAP_CLAMP || wrap.t != WRAP_CLAMP || wrap.r != WRAP_CLAMP) - success = false; - - wrap.s = wrap.t = wrap.r = WRAP_CLAMP; - } - - if (!gl.isClampZeroOneTextureWrapSupported()) - { - if (isClampZeroOrOne(wrap.s)) wrap.s = WRAP_CLAMP; - if (isClampZeroOrOne(wrap.t)) wrap.t = WRAP_CLAMP; - if (isClampZeroOrOne(wrap.r)) wrap.r = WRAP_CLAMP; + samplerState.wrapU = samplerState.wrapV = samplerState.wrapW = SamplerState::WRAP_CLAMP; } gl.bindTextureToUnit(this, 0, false); - gl.setTextureWrap(texType, wrap); - - return success; -} - -bool Canvas::setMipmapSharpness(float sharpness) -{ - if (!gl.isSamplerLODBiasSupported()) - return false; - - Graphics::flushStreamDrawsGlobal(); - - float maxbias = gl.getMaxLODBias(); - if (maxbias > 0.01f) - maxbias -= 0.0f; - - mipmapSharpness = std::min(std::max(sharpness, -maxbias), maxbias); - - gl.bindTextureToUnit(this, 0, false); - - // negative bias is sharper - glTexParameterf(gl.getGLTextureType(texType), GL_TEXTURE_LOD_BIAS, -mipmapSharpness); - - return true; -} - -void Canvas::setDepthSampleMode(Optional mode) -{ - Texture::setDepthSampleMode(mode); - - bool supported = gl.isDepthCompareSampleSupported(); - - if (mode.hasValue) - { - if (!supported) - throw love::Exception("Depth comparison sampling in shaders is not supported on this system."); - - Graphics::flushStreamDrawsGlobal(); - - gl.bindTextureToUnit(texType, texture, 0, false); - GLenum gltextype = OpenGL::getGLTextureType(texType); - - // See the comment in renderstate.h - GLenum glmode = OpenGL::getGLCompareMode(getReversedCompareMode(mode.value)); - - glTexParameteri(gltextype, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(gltextype, GL_TEXTURE_COMPARE_FUNC, glmode); - - } - else if (isPixelFormatDepth(format) && supported) - { - Graphics::flushStreamDrawsGlobal(); - - gl.bindTextureToUnit(texType, texture, 0, false); - GLenum gltextype = OpenGL::getGLTextureType(texType); - - glTexParameteri(gltextype, GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - - depthCompareMode = mode; + gl.setSamplerState(texType, samplerState); } ptrdiff_t Canvas::getHandle() const diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 8543c3503..bb45edf7b 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -47,10 +47,7 @@ public: void unloadVolatile() override; // Implements Texture. - void setFilter(const Texture::Filter &f) override; - bool setWrap(const Texture::Wrap &w) override; - bool setMipmapSharpness(float sharpness) override; - void setDepthSampleMode(Optional mode) override; + void setSamplerState(const SamplerState &s) override; ptrdiff_t getHandle() const override; love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect) override; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index e7a821385..18b227e0a 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1470,12 +1470,9 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, boo glGenTextures(1, &texture); gl.bindTextureToUnit(TEXTURE_2D, texture, 0, false); - Texture::Filter f; - f.min = f.mag = Texture::FILTER_NEAREST; - gl.setTextureFilter(TEXTURE_2D, f); - - Texture::Wrap w; - gl.setTextureWrap(TEXTURE_2D, w); + SamplerState s; + s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST; + gl.setSamplerState(TEXTURE_2D, s); gl.rawTexStorage(TEXTURE_2D, 1, format, sRGB, 1, 1); } diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index c9f4d93bf..ac5bdd50e 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -75,7 +75,7 @@ void Image::loadDefaultTexture() usingDefaultTexture = true; gl.bindTextureToUnit(this, 0, false); - setFilter(filter); + setSamplerState(samplerState); bool isSRGB = false; gl.rawTexStorage(texType, 1, PIXELFORMAT_RGBA8_UNORM, isSRGB, 2, 2, 1); @@ -204,7 +204,7 @@ bool Image::loadVolatile() && mipmapsType != MIPMAPS_DATA) { mipmapsType = MIPMAPS_NONE; - filter.mipmap = FILTER_NONE; + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; } } @@ -213,7 +213,7 @@ bool Image::loadVolatile() && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight))) { mipmapsType = MIPMAPS_NONE; - filter.mipmap = FILTER_NONE; + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; } glGenTextures(1, &texture); @@ -226,9 +226,7 @@ bool Image::loadVolatile() return true; } - setFilter(filter); - setWrap(wrap); - setMipmapSharpness(mipmapSharpness); + setSamplerState(samplerState); GLenum gltextype = OpenGL::getGLTextureType(texType); @@ -282,85 +280,34 @@ ptrdiff_t Image::getHandle() const return texture; } -void Image::setFilter(const Texture::Filter &f) +void Image::setSamplerState(const SamplerState &s) { - Texture::setFilter(f); + Texture::setSamplerState(s); if (!OpenGL::hasTextureFilteringSupport(getPixelFormat())) { - filter.mag = filter.min = FILTER_NEAREST; + samplerState.magFilter = samplerState.minFilter = SamplerState::FILTER_NEAREST; - if (filter.mipmap == FILTER_LINEAR) - filter.mipmap = FILTER_NEAREST; + if (samplerState.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NEAREST; } // We don't want filtering or (attempted) mipmaps on the default texture. if (usingDefaultTexture) { - filter.mipmap = FILTER_NONE; - filter.min = filter.mag = FILTER_NEAREST; + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; + samplerState.minFilter = samplerState.magFilter = SamplerState::FILTER_NEAREST; } - gl.bindTextureToUnit(this, 0, false); - gl.setTextureFilter(texType, filter); -} - -bool Image::setWrap(const Texture::Wrap &w) -{ - Graphics::flushStreamDrawsGlobal(); - - bool success = true; - bool forceclamp = texType == TEXTURE_CUBE; - wrap = w; - // If we only have limited NPOT support then the wrap mode must be CLAMP. if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight) || depth != nextP2(depth))) { - forceclamp = true; - } - - if (forceclamp) - { - if (wrap.s != WRAP_CLAMP || wrap.t != WRAP_CLAMP || wrap.r != WRAP_CLAMP) - success = false; - - wrap.s = wrap.t = wrap.r = WRAP_CLAMP; - } - - if (!gl.isClampZeroOneTextureWrapSupported()) - { - if (isClampZeroOrOne(wrap.s)) wrap.s = WRAP_CLAMP; - if (isClampZeroOrOne(wrap.t)) wrap.t = WRAP_CLAMP; - if (isClampZeroOrOne(wrap.r)) wrap.r = WRAP_CLAMP; + samplerState.wrapU = samplerState.wrapV = samplerState.wrapW = SamplerState::WRAP_CLAMP; } gl.bindTextureToUnit(this, 0, false); - gl.setTextureWrap(texType, wrap); - - return success; -} - -bool Image::setMipmapSharpness(float sharpness) -{ - if (!gl.isSamplerLODBiasSupported()) - return false; - - Graphics::flushStreamDrawsGlobal(); - - float maxbias = gl.getMaxLODBias(); - - if (maxbias > 0.01f) - maxbias -= 0.01f; - - mipmapSharpness = std::min(std::max(sharpness, -maxbias), maxbias); - - gl.bindTextureToUnit(this, 0, false); - - // negative bias is sharper - glTexParameterf(gl.getGLTextureType(texType), GL_TEXTURE_LOD_BIAS, -mipmapSharpness); - - return true; + gl.setSamplerState(texType, samplerState); } } // opengl diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index 1f6b853af..124e1bbf5 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -49,10 +49,7 @@ public: ptrdiff_t getHandle() const override; - void setFilter(const Texture::Filter &f) override; - bool setWrap(const Texture::Wrap &w) override; - - bool setMipmapSharpness(float sharpness) override; + void setSamplerState(const SamplerState &s) override; private: diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 28862602e..17dbb2860 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -502,11 +502,9 @@ void OpenGL::createDefaultTexture() // untextured primitives vs images. const GLubyte pix[] = {255, 255, 255, 255}; - Texture::Filter filter; - filter.min = filter.mag = Texture::FILTER_NEAREST; - - Texture::Wrap wrap; - wrap.s = wrap.t = wrap.r = Texture::WRAP_CLAMP; + SamplerState s; + s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST; + s.wrapU = s.wrapV = s.wrapW = SamplerState::WRAP_CLAMP; for (int i = 0; i < TEXTURE_MAX_ENUM; i++) { @@ -522,8 +520,7 @@ void OpenGL::createDefaultTexture() glGenTextures(1, &state.defaultTexture[type]); bindTextureToUnit(type, state.defaultTexture[type], 0, false); - setTextureWrap(type, wrap); - setTextureFilter(type, filter); + setSamplerState(type, s); bool isSRGB = false; rawTexStorage(type, 1, PIXELFORMAT_RGBA8_UNORM, isSRGB, 1, 1); @@ -1050,52 +1047,19 @@ void OpenGL::deleteTexture(GLuint texture) glDeleteTextures(1, &texture); } -void OpenGL::setTextureFilter(TextureType target, graphics::Texture::Filter &f) -{ - GLint gmin = f.min == Texture::FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; - GLint gmag = f.mag == Texture::FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; - - if (f.mipmap != Texture::FILTER_NONE) - { - if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_NEAREST) - gmin = GL_NEAREST_MIPMAP_NEAREST; - else if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_LINEAR) - gmin = GL_NEAREST_MIPMAP_LINEAR; - else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_NEAREST) - gmin = GL_LINEAR_MIPMAP_NEAREST; - else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_LINEAR) - gmin = GL_LINEAR_MIPMAP_LINEAR; - else - gmin = GL_LINEAR; - } - - GLenum gltarget = getGLTextureType(target); - - glTexParameteri(gltarget, GL_TEXTURE_MIN_FILTER, gmin); - glTexParameteri(gltarget, GL_TEXTURE_MAG_FILTER, gmag); - - if (GLAD_EXT_texture_filter_anisotropic) - { - f.anisotropy = std::min(std::max(f.anisotropy, 1.0f), maxAnisotropy); - glTexParameterf(gltarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, f.anisotropy); - } - else - f.anisotropy = 1.0f; -} - -GLint OpenGL::getGLWrapMode(Texture::WrapMode wmode) +GLint OpenGL::getGLWrapMode(SamplerState::WrapMode wmode) { switch (wmode) { - case Texture::WRAP_CLAMP: + case SamplerState::WRAP_CLAMP: default: return GL_CLAMP_TO_EDGE; - case Texture::WRAP_CLAMP_ZERO: - case Texture::WRAP_CLAMP_ONE: + case SamplerState::WRAP_CLAMP_ZERO: + case SamplerState::WRAP_CLAMP_ONE: return GL_CLAMP_TO_BORDER; - case Texture::WRAP_REPEAT: + case SamplerState::WRAP_REPEAT: return GL_REPEAT; - case Texture::WRAP_MIRRORED_REPEAT: + case SamplerState::WRAP_MIRRORED_REPEAT: return GL_MIRRORED_REPEAT; } } @@ -1125,29 +1089,111 @@ GLint OpenGL::getGLCompareMode(CompareMode mode) } } -static bool isClampOne(Texture::WrapMode mode) +static bool isClampOne(SamplerState::WrapMode mode) { - return mode == Texture::WRAP_CLAMP_ONE; + return mode == SamplerState::WRAP_CLAMP_ONE; } -void OpenGL::setTextureWrap(TextureType target, const graphics::Texture::Wrap &w) +void OpenGL::setSamplerState(TextureType target, SamplerState &s) { - GLenum textype = getGLTextureType(target); + GLenum gltarget = getGLTextureType(target); - if (Texture::isClampZeroOrOne(w.s) || Texture::isClampZeroOrOne(w.t) || Texture::isClampZeroOrOne(w.r)) + GLint gmin = s.minFilter == SamplerState::FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; + GLint gmag = s.magFilter == SamplerState::FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; + + if (s.mipmapFilter != SamplerState::MIPMAP_FILTER_NONE) { - GLfloat c[] = {0.0f, 0.0f, 0.0f, 0.0f}; - if (isClampOne(w.s) || isClampOne(w.t) || isClampOne(w.r)) - c[0] = c[1] = c[2] = c[3] = 1.0f; - - glTexParameterfv(textype, GL_TEXTURE_BORDER_COLOR, c); + if (s.minFilter == SamplerState::FILTER_NEAREST && s.mipmapFilter == SamplerState::MIPMAP_FILTER_NEAREST) + gmin = GL_NEAREST_MIPMAP_NEAREST; + else if (s.minFilter == SamplerState::FILTER_NEAREST && s.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) + gmin = GL_NEAREST_MIPMAP_LINEAR; + else if (s.minFilter == SamplerState::FILTER_LINEAR && s.mipmapFilter == SamplerState::MIPMAP_FILTER_NEAREST) + gmin = GL_LINEAR_MIPMAP_NEAREST; + else if (s.minFilter == SamplerState::FILTER_LINEAR && s.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) + gmin = GL_LINEAR_MIPMAP_LINEAR; } - glTexParameteri(textype, GL_TEXTURE_WRAP_S, getGLWrapMode(w.s)); - glTexParameteri(textype, GL_TEXTURE_WRAP_T, getGLWrapMode(w.t)); + glTexParameteri(gltarget, GL_TEXTURE_MIN_FILTER, gmin); + glTexParameteri(gltarget, GL_TEXTURE_MAG_FILTER, gmag); + + if (!isClampZeroOneTextureWrapSupported()) + { + if (SamplerState::isClampZeroOrOne(s.wrapU)) s.wrapU = SamplerState::WRAP_CLAMP; + if (SamplerState::isClampZeroOrOne(s.wrapV)) s.wrapV = SamplerState::WRAP_CLAMP; + if (SamplerState::isClampZeroOrOne(s.wrapW)) s.wrapW = SamplerState::WRAP_CLAMP; + } + + if (SamplerState::isClampZeroOrOne(s.wrapU) || SamplerState::isClampZeroOrOne(s.wrapV) || SamplerState::isClampZeroOrOne(s.wrapW)) + { + GLfloat c[] = {0.0f, 0.0f, 0.0f, 0.0f}; + if (isClampOne(s.wrapU) || isClampOne(s.wrapU) || isClampOne(s.wrapV)) + c[0] = c[1] = c[2] = c[3] = 1.0f; + + glTexParameterfv(gltarget, GL_TEXTURE_BORDER_COLOR, c); + } + + glTexParameteri(gltarget, GL_TEXTURE_WRAP_S, getGLWrapMode(s.wrapU)); + glTexParameteri(gltarget, GL_TEXTURE_WRAP_T, getGLWrapMode(s.wrapV)); if (target == TEXTURE_VOLUME) - glTexParameteri(textype, GL_TEXTURE_WRAP_R, getGLWrapMode(w.r)); + glTexParameteri(gltarget, GL_TEXTURE_WRAP_R, getGLWrapMode(s.wrapW)); + + if (isSamplerLODBiasSupported()) + { + float maxbias = getMaxLODBias(); + if (maxbias > 0.01f) + maxbias -= 0.01f; + + s.lodBias = std::min(std::max(s.lodBias, -maxbias), maxbias); + + glTexParameterf(gltarget, GL_TEXTURE_LOD_BIAS, s.lodBias); + } + else + { + s.lodBias = 0.0f; + } + + if (GLAD_EXT_texture_filter_anisotropic) + { + uint8 maxAniso = (uint8) std::min(maxAnisotropy, (float)LOVE_UINT8_MAX); + s.maxAnisotropy = std::min(std::max(s.maxAnisotropy, (uint8)1), maxAniso); + glTexParameteri(gltarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, s.maxAnisotropy); + } + else + { + s.maxAnisotropy = 1; + } + + if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0) + { + glTexParameterf(gltarget, GL_TEXTURE_MIN_LOD, (float)s.minLod); + glTexParameterf(gltarget, GL_TEXTURE_MAX_LOD, (float)s.maxLod); + } + else + { + s.minLod = 0; + s.maxLod = LOVE_UINT8_MAX; + } + + if (isDepthCompareSampleSupported()) + { + if (s.depthSampleMode.hasValue) + { + // See the comment in renderstate.h + GLenum glmode = getGLCompareMode(getReversedCompareMode(s.depthSampleMode.value)); + + glTexParameteri(gltarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(gltarget, GL_TEXTURE_COMPARE_FUNC, glmode); + } + else + { + glTexParameteri(gltarget, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + } + else + { + s.depthSampleMode.hasValue = false; + } } bool OpenGL::rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, bool &isSRGB, int width, int height, int depth) diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 8dd975cec..29b7da1ee 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -329,16 +329,9 @@ public: void deleteTexture(GLuint texture); /** - * Sets the texture filter mode for the currently bound texture. - * The anisotropy parameter of the argument is set to the actual amount of - * anisotropy that was used. + * Sets sampler state parameters for the currently bound texture. **/ - void setTextureFilter(TextureType target, graphics::Texture::Filter &f); - - /** - * Sets the texture wrap mode for the currently bound texture. - **/ - void setTextureWrap(TextureType target, const graphics::Texture::Wrap &w); + void setSamplerState(TextureType target, SamplerState &s); /** * Equivalent to glTexStorage2D/3D on platforms that support it. Equivalent @@ -407,7 +400,7 @@ public: static GLenum getGLVertexDataType(vertex::DataType type, GLboolean &normalized, bool &intformat); static GLenum getGLBufferUsage(vertex::Usage usage); static GLenum getGLTextureType(TextureType type); - static GLint getGLWrapMode(Texture::WrapMode wmode); + static GLint getGLWrapMode(SamplerState::WrapMode wmode); static GLint getGLCompareMode(CompareMode mode); static TextureFormat convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB); diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index fca5e22c7..cb175e082 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -588,6 +588,7 @@ void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count if (tex != nullptr) { + const SamplerState &sampler = tex->getSamplerState(); if (!tex->isReadable()) { if (internalUpdate) @@ -595,7 +596,7 @@ void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count else throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader."); } - else if (info->isDepthSampler != tex->getDepthSampleMode().hasValue) + else if (info->isDepthSampler != sampler.depthSampleMode.hasValue) { if (internalUpdate) continue; diff --git a/src/modules/graphics/wrap_Font.cpp b/src/modules/graphics/wrap_Font.cpp index 115a84348..468d67fe2 100644 --- a/src/modules/graphics/wrap_Font.cpp +++ b/src/modules/graphics/wrap_Font.cpp @@ -139,33 +139,33 @@ int w_Font_getLineHeight(lua_State *L) int w_Font_setFilter(lua_State *L) { Font *t = luax_checkfont(L, 1); - Texture::Filter f = t->getFilter(); + SamplerState s = t->getSamplerState(); const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Texture::getConstant(minstr, f.min)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.min), minstr); - if (!Texture::getConstant(magstr, f.mag)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.mag), magstr); + if (!SamplerState::getConstant(minstr, s.minFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.minFilter), minstr); + if (!SamplerState::getConstant(magstr, s.magFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.magFilter), magstr); - f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); + s.maxAnisotropy = std::min(std::max(1, (int) luaL_optnumber(L, 4, 1.0)), LOVE_UINT8_MAX); - luax_catchexcept(L, [&](){ t->setFilter(f); }); + luax_catchexcept(L, [&](){ t->setSamplerState(s); }); return 0; } int w_Font_getFilter(lua_State *L) { Font *t = luax_checkfont(L, 1); - const Texture::Filter f = t->getFilter(); + const SamplerState &s = t->getSamplerState(); const char *minstr; const char *magstr; - Texture::getConstant(f.min, minstr); - Texture::getConstant(f.mag, magstr); + SamplerState::getConstant(s.minFilter, minstr); + SamplerState::getConstant(s.magFilter, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - lua_pushnumber(L, f.anisotropy); + lua_pushnumber(L, s.maxAnisotropy); return 3; } diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 327ec5fe8..f262b9a0a 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -1102,7 +1102,7 @@ int w_newFont(lua_State *L) love::font::Rasterizer *rasterizer = luax_checktype(L, 1); luax_catchexcept(L, [&]() { - font = instance()->newFont(rasterizer, instance()->getDefaultFilter()); } + font = instance()->newFont(rasterizer); } ); // Push the type. @@ -1115,9 +1115,6 @@ int w_newImageFont(lua_State *L) { luax_checkgraphicscreated(L); - // filter for glyphs - Texture::Filter filter = instance()->getDefaultFilter(); - // Convert to Rasterizer if necessary. if (!luax_istype(L, 1, love::font::Rasterizer::type)) { @@ -1133,7 +1130,7 @@ int w_newImageFont(lua_State *L) love::font::Rasterizer *rasterizer = luax_checktype(L, 1); // Create the font. - Font *font = instance()->newFont(rasterizer, filter); + Font *font = instance()->newFont(rasterizer); // Push the type. luax_pushtype(L, font); @@ -1935,69 +1932,65 @@ int w_getBlendState(lua_State *L) int w_setDefaultFilter(lua_State *L) { - Texture::Filter f; + SamplerState s = instance()->getDefaultSamplerState(); const char *minstr = luaL_checkstring(L, 1); const char *magstr = luaL_optstring(L, 2, minstr); - if (!Texture::getConstant(minstr, f.min)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.min), minstr); - if (!Texture::getConstant(magstr, f.mag)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.mag), magstr); + if (!SamplerState::getConstant(minstr, s.minFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.minFilter), minstr); + if (!SamplerState::getConstant(magstr, s.magFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.magFilter), magstr); - f.anisotropy = (float) luaL_optnumber(L, 3, 1.0); - - instance()->setDefaultFilter(f); + s.maxAnisotropy = std::min(std::max(1, (int) luaL_optnumber(L, 3, 1.0)), LOVE_UINT8_MAX); + instance()->setDefaultSamplerState(s); return 0; } int w_getDefaultFilter(lua_State *L) { - const Texture::Filter &f = instance()->getDefaultFilter(); + const SamplerState &s = instance()->getDefaultSamplerState(); const char *minstr; const char *magstr; - if (!Texture::getConstant(f.min, minstr)) + if (!SamplerState::getConstant(s.minFilter, minstr)) return luaL_error(L, "Unknown minification filter mode"); - if (!Texture::getConstant(f.mag, magstr)) + if (!SamplerState::getConstant(s.magFilter, magstr)) return luaL_error(L, "Unknown magnification filter mode"); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - lua_pushnumber(L, f.anisotropy); + lua_pushnumber(L, s.maxAnisotropy); return 3; } int w_setDefaultMipmapFilter(lua_State *L) { - Texture::FilterMode filter = Texture::FILTER_NONE; + SamplerState s = instance()->getDefaultSamplerState(); + s.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; if (!lua_isnoneornil(L, 1)) { const char *str = luaL_checkstring(L, 1); - if (!Texture::getConstant(str, filter)) - return luax_enumerror(L, "filter mode", Texture::getConstants(filter), str); + if (!SamplerState::getConstant(str, s.mipmapFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.mipmapFilter), str); } - float sharpness = (float) luaL_optnumber(L, 2, 0); - - instance()->setDefaultMipmapFilter(filter, sharpness); + s.lodBias = -((float) luaL_optnumber(L, 2, 0.0)); + instance()->setDefaultSamplerState(s); return 0; } int w_getDefaultMipmapFilter(lua_State *L) { - Texture::FilterMode filter; - float sharpness; - - instance()->getDefaultMipmapFilter(&filter, &sharpness); + const SamplerState &s = instance()->getDefaultSamplerState(); const char *str; - if (Texture::getConstant(filter, str)) + if (SamplerState::getConstant(s.mipmapFilter, str)) lua_pushstring(L, str); else lua_pushnil(L); - lua_pushnumber(L, sharpness); + lua_pushnumber(L, -s.lodBias); return 2; } diff --git a/src/modules/graphics/wrap_Texture.cpp b/src/modules/graphics/wrap_Texture.cpp index a41af87c1..9189a3101 100644 --- a/src/modules/graphics/wrap_Texture.cpp +++ b/src/modules/graphics/wrap_Texture.cpp @@ -132,111 +132,111 @@ int w_Texture_getDPIScale(lua_State *L) int w_Texture_setFilter(lua_State *L) { Texture *t = luax_checktexture(L, 1); - Texture::Filter f = t->getFilter(); + SamplerState s = t->getSamplerState(); const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Texture::getConstant(minstr, f.min)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.min), minstr); - if (!Texture::getConstant(magstr, f.mag)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.mag), magstr); + if (!SamplerState::getConstant(minstr, s.minFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.minFilter), minstr); + if (!SamplerState::getConstant(magstr, s.magFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.magFilter), magstr); - f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); + s.maxAnisotropy = std::min(std::max(1, (int) luaL_optnumber(L, 4, 1.0)), LOVE_UINT8_MAX); - luax_catchexcept(L, [&](){ t->setFilter(f); }); + luax_catchexcept(L, [&](){ t->setSamplerState(s); }); return 0; } int w_Texture_getFilter(lua_State *L) { Texture *t = luax_checktexture(L, 1); - const Texture::Filter f = t->getFilter(); + const SamplerState &s = t->getSamplerState(); const char *minstr = nullptr; const char *magstr = nullptr; - if (!Texture::getConstant(f.min, minstr)) + if (!SamplerState::getConstant(s.minFilter, minstr)) return luaL_error(L, "Unknown filter mode."); - if (!Texture::getConstant(f.mag, magstr)) + if (!SamplerState::getConstant(s.magFilter, magstr)) return luaL_error(L, "Unknown filter mode."); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - lua_pushnumber(L, f.anisotropy); + lua_pushnumber(L, s.maxAnisotropy); return 3; } int w_Texture_setMipmapFilter(lua_State *L) { Texture *t = luax_checktexture(L, 1); - Texture::Filter f = t->getFilter(); + SamplerState s = t->getSamplerState(); + // Mipmapping is disabled if no argument is given. if (lua_isnoneornil(L, 2)) - f.mipmap = Texture::FILTER_NONE; // mipmapping is disabled if no argument is given + s.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; else { const char *mipmapstr = luaL_checkstring(L, 2); - if (!Texture::getConstant(mipmapstr, f.mipmap)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.mipmap), mipmapstr); + if (!SamplerState::getConstant(mipmapstr, s.mipmapFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.mipmapFilter), mipmapstr); } - luax_catchexcept(L, [&](){ t->setFilter(f); }); - t->setMipmapSharpness((float) luaL_optnumber(L, 3, 0.0)); + s.lodBias = -((float) luaL_optnumber(L, 3, 0.0)); + luax_catchexcept(L, [&](){ t->setSamplerState(s); }); return 0; } int w_Texture_getMipmapFilter(lua_State *L) { Texture *t = luax_checktexture(L, 1); - - const Texture::Filter &f = t->getFilter(); + const SamplerState &s = t->getSamplerState(); const char *mipmapstr; - if (Texture::getConstant(f.mipmap, mipmapstr)) + if (SamplerState::getConstant(s.mipmapFilter, mipmapstr)) lua_pushstring(L, mipmapstr); else lua_pushnil(L); // only return a mipmap filter if mipmapping is enabled - lua_pushnumber(L, t->getMipmapSharpness()); + lua_pushnumber(L, -s.lodBias); return 2; } int w_Texture_setWrap(lua_State *L) { Texture *t = luax_checktexture(L, 1); - Texture::Wrap w; + SamplerState s = t->getSamplerState(); const char *sstr = luaL_checkstring(L, 2); const char *tstr = luaL_optstring(L, 3, sstr); const char *rstr = luaL_optstring(L, 4, sstr); - if (!Texture::getConstant(sstr, w.s)) - return luax_enumerror(L, "wrap mode", Texture::getConstants(w.s), sstr); - if (!Texture::getConstant(tstr, w.t)) - return luax_enumerror(L, "wrap mode", Texture::getConstants(w.t), tstr); - if (!Texture::getConstant(rstr, w.r)) - return luax_enumerror(L, "wrap mode", Texture::getConstants(w.r), rstr); + if (!SamplerState::getConstant(sstr, s.wrapU)) + return luax_enumerror(L, "wrap mode", SamplerState::getConstants(s.wrapU), sstr); + if (!SamplerState::getConstant(tstr, s.wrapV)) + return luax_enumerror(L, "wrap mode", SamplerState::getConstants(s.wrapV), tstr); + if (!SamplerState::getConstant(rstr, s.wrapW)) + return luax_enumerror(L, "wrap mode", SamplerState::getConstants(s.wrapW), rstr); - luax_pushboolean(L, t->setWrap(w)); + luax_catchexcept(L, [&](){ t->setSamplerState(s); }); return 1; } int w_Texture_getWrap(lua_State *L) { Texture *t = luax_checktexture(L, 1); - const Texture::Wrap w = t->getWrap(); + const SamplerState &s = t->getSamplerState(); const char *sstr = nullptr; const char *tstr = nullptr; const char *rstr = nullptr; - if (!Texture::getConstant(w.s, sstr)) + if (!SamplerState::getConstant(s.wrapU, sstr)) return luaL_error(L, "Unknown wrap mode."); - if (!Texture::getConstant(w.t, tstr)) + if (!SamplerState::getConstant(s.wrapV, tstr)) return luaL_error(L, "Unknown wrap mode."); - if (!Texture::getConstant(w.r, rstr)) + if (!SamplerState::getConstant(s.wrapW, rstr)) return luaL_error(L, "Unknown wrap mode."); lua_pushstring(L, sstr); @@ -267,30 +267,31 @@ int w_Texture_isReadable(lua_State *L) int w_Texture_setDepthSampleMode(lua_State *L) { Texture *t = luax_checktexture(L, 1); + SamplerState s = t->getSamplerState(); - Optional mode; + s.depthSampleMode.hasValue = false; if (!lua_isnoneornil(L, 2)) { const char *str = luaL_checkstring(L, 2); - mode.hasValue = true; - if (!getConstant(str, mode.value)) - return luax_enumerror(L, "compare mode", getConstants(mode.value), str); + s.depthSampleMode.hasValue = true; + if (!getConstant(str, s.depthSampleMode.value)) + return luax_enumerror(L, "compare mode", getConstants(s.depthSampleMode.value), str); } - luax_catchexcept(L, [&]() { t->setDepthSampleMode(mode); }); + luax_catchexcept(L, [&](){ t->setSamplerState(s); }); return 0; } int w_Texture_getDepthSampleMode(lua_State *L) { Texture *t = luax_checktexture(L, 1); - Optional mode = t->getDepthSampleMode(); + const SamplerState &s = t->getSamplerState(); - if (mode.hasValue) + if (s.depthSampleMode.hasValue) { const char *str = nullptr; - if (!getConstant(mode.value, str)) + if (!getConstant(s.depthSampleMode.value, str)) return luaL_error(L, "Unknown compare mode."); lua_pushstring(L, str); } diff --git a/src/modules/graphics/wrap_Video.cpp b/src/modules/graphics/wrap_Video.cpp index 712330dbe..32d8b08ac 100644 --- a/src/modules/graphics/wrap_Video.cpp +++ b/src/modules/graphics/wrap_Video.cpp @@ -113,38 +113,38 @@ int w_Video_getPixelDimensions(lua_State *L) int w_Video_setFilter(lua_State *L) { Video *video = luax_checkvideo(L, 1); - Texture::Filter f = video->getFilter(); + SamplerState s = video->getSamplerState(); const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Texture::getConstant(minstr, f.min)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.min), minstr); - if (!Texture::getConstant(magstr, f.mag)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.mag), magstr); + if (!SamplerState::getConstant(minstr, s.minFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.minFilter), minstr); + if (!SamplerState::getConstant(magstr, s.magFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.magFilter), magstr); - f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); + s.maxAnisotropy = std::min(std::max(1, (int) luaL_optnumber(L, 4, 1.0)), LOVE_UINT8_MAX); - luax_catchexcept(L, [&](){ video->setFilter(f); }); + luax_catchexcept(L, [&](){ video->setSamplerState(s); }); return 0; } int w_Video_getFilter(lua_State *L) { Video *video = luax_checkvideo(L, 1); - const Texture::Filter f = video->getFilter(); + const SamplerState &s = video->getSamplerState(); const char *minstr = nullptr; const char *magstr = nullptr; - if (!Texture::getConstant(f.min, minstr)) + if (!SamplerState::getConstant(s.minFilter, minstr)) return luaL_error(L, "Unknown filter mode."); - if (!Texture::getConstant(f.mag, magstr)) + if (!SamplerState::getConstant(s.magFilter, magstr)) return luaL_error(L, "Unknown filter mode."); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - lua_pushnumber(L, f.anisotropy); + lua_pushnumber(L, s.maxAnisotropy); return 3; } From b46b3ed5524c7de6427077a1fe21abdafbf069f8 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 3 Feb 2020 19:02:58 -0400 Subject: [PATCH 05/31] Move some Canvas code to Texture, devirtualize Texture::draw. --- src/common/pixelformat.cpp | 14 +++++ src/common/pixelformat.h | 10 ++++ src/modules/graphics/Canvas.cpp | 31 +++-------- src/modules/graphics/Canvas.h | 6 --- src/modules/graphics/Graphics.cpp | 15 +++--- src/modules/graphics/Graphics.h | 9 ++-- src/modules/graphics/Image.cpp | 20 ++----- src/modules/graphics/Image.h | 6 --- src/modules/graphics/Texture.cpp | 26 +++++++++ src/modules/graphics/Texture.h | 14 ++++- src/modules/graphics/opengl/Canvas.cpp | 67 ++++++++++-------------- src/modules/graphics/opengl/Canvas.h | 2 - src/modules/graphics/opengl/Graphics.cpp | 10 ++-- src/modules/graphics/opengl/Graphics.h | 2 +- src/modules/graphics/opengl/Image.cpp | 17 +++--- src/modules/graphics/opengl/Image.h | 2 +- src/modules/graphics/opengl/OpenGL.cpp | 5 ++ src/modules/graphics/opengl/OpenGL.h | 1 + src/modules/graphics/wrap_Graphics.cpp | 7 +-- 19 files changed, 136 insertions(+), 128 deletions(-) diff --git a/src/common/pixelformat.cpp b/src/common/pixelformat.cpp index 0177cc824..0048236b4 100644 --- a/src/common/pixelformat.cpp +++ b/src/common/pixelformat.cpp @@ -137,6 +137,20 @@ bool isPixelFormatStencil(PixelFormat format) return format == PIXELFORMAT_STENCIL8 || format == PIXELFORMAT_DEPTH24_UNORM_STENCIL8 || format == PIXELFORMAT_DEPTH32_FLOAT_STENCIL8; } +PixelFormat getSRGBPixelFormat(PixelFormat format) +{ + if (format == PIXELFORMAT_RGBA8_UNORM) + return PIXELFORMAT_sRGBA8_UNORM; + return format; +} + +PixelFormat getLinearPixelFormat(PixelFormat format) +{ + if (format == PIXELFORMAT_sRGBA8_UNORM) + return PIXELFORMAT_RGBA8_UNORM; + return format; +} + size_t getPixelFormatSize(PixelFormat format) { switch (format) diff --git a/src/common/pixelformat.h b/src/common/pixelformat.h index b1657d92e..40f1be664 100644 --- a/src/common/pixelformat.h +++ b/src/common/pixelformat.h @@ -132,6 +132,16 @@ bool isPixelFormatDepth(PixelFormat format); **/ bool isPixelFormatStencil(PixelFormat format); +/** + * Gets the sRGB version of a linear pixel format, if applicable. + **/ +PixelFormat getSRGBPixelFormat(PixelFormat format); + +/** + * Gets the linear version of a sRGB pixel format, if applicable. + **/ +PixelFormat getLinearPixelFormat(PixelFormat format); + /** * Gets the size in bytes of the specified pixel format. * NOTE: Currently returns 0 for compressed formats. diff --git a/src/modules/graphics/Canvas.cpp b/src/modules/graphics/Canvas.cpp index 008851615..88cd98b5a 100644 --- a/src/modules/graphics/Canvas.cpp +++ b/src/modules/graphics/Canvas.cpp @@ -27,13 +27,15 @@ namespace graphics { love::Type Canvas::type("Canvas", &Texture::type); -int Canvas::canvasCount = 0; Canvas::Canvas(const Settings &settings) : Texture(settings.type) { this->settings = settings; + renderTarget = true; + sRGB = false; + width = settings.width; height = settings.height; pixelWidth = (int) ((width * settings.dpiScale) + 0.5); @@ -69,7 +71,7 @@ Canvas::Canvas(const Settings &settings) auto gfx = Module::getInstance(Module::M_GRAPHICS); const Graphics::Capabilities &caps = gfx->getCapabilities(); - if (!gfx->isPixelFormatSupported(format, true, readable, false)) + if (!gfx->isPixelFormatSupported(format, renderTarget, readable, sRGB)) { const char *fstr = "rgba8"; const char *readablestr = ""; @@ -93,13 +95,10 @@ Canvas::Canvas(const Settings &settings) } validateDimensions(true); - - canvasCount++; } Canvas::~Canvas() { - canvasCount--; } Canvas::MipmapMode Canvas::getMipmapMode() const @@ -131,12 +130,10 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *module, int sli } Graphics *gfx = Module::getInstance(Module::M_GRAPHICS); - if (gfx != nullptr && gfx->isCanvasActive(this)) + if (gfx != nullptr && gfx->isRenderTargetActive(this)) throw love::Exception("Canvas:newImageData cannot be called while that Canvas is currently active."); - PixelFormat dataformat = getPixelFormat(); - if (dataformat == PIXELFORMAT_sRGBA8_UNORM) - dataformat = PIXELFORMAT_RGBA8_UNORM; + PixelFormat dataformat = getLinearPixelFormat(getPixelFormat()); if (!image::ImageData::validPixelFormat(dataformat)) { @@ -148,22 +145,6 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *module, int sli return module->newImageData(r.w, r.h, dataformat); } -void Canvas::draw(Graphics *gfx, Quad *q, const Matrix4 &t) -{ - if (gfx->isCanvasActive(this)) - throw love::Exception("Cannot render a Canvas to itself!"); - - Texture::draw(gfx, q, t); -} - -void Canvas::drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m) -{ - if (gfx->isCanvasActive(this, layer)) - throw love::Exception("Cannot render a Canvas to itself!"); - - Texture::drawLayer(gfx, layer, quad, m); -} - bool Canvas::getConstant(const char *in, MipmapMode &out) { return mipmapModes.find(in, out); diff --git a/src/modules/graphics/Canvas.h b/src/modules/graphics/Canvas.h index 8171f5f54..05e5a844d 100644 --- a/src/modules/graphics/Canvas.h +++ b/src/modules/graphics/Canvas.h @@ -81,16 +81,10 @@ public: int getRequestedMSAA() const; virtual love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect); - virtual void generateMipmaps() = 0; virtual int getMSAA() const = 0; virtual ptrdiff_t getRenderTargetHandle() const = 0; - void draw(Graphics *gfx, Quad *q, const Matrix4 &t) override; - void drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &t) override; - - static int canvasCount; - static bool getConstant(const char *in, MipmapMode &out); static bool getConstant(MipmapMode in, const char *&out); static std::vector getConstants(MipmapMode); diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index fcdb70cee..5ae9493dd 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -761,33 +761,33 @@ bool Graphics::isCanvasActive() const return !rts.colors.empty() || rts.depthStencil.canvas != nullptr; } -bool Graphics::isCanvasActive(love::graphics::Canvas *canvas) const +bool Graphics::isRenderTargetActive(Texture *texture) const { const auto &rts = states.back().renderTargets; for (const auto &rt : rts.colors) { - if (rt.canvas.get() == canvas) + if (rt.canvas.get() == texture) return true; } - if (rts.depthStencil.canvas.get() == canvas) + if (rts.depthStencil.canvas.get() == texture) return true; return false; } -bool Graphics::isCanvasActive(Canvas *canvas, int slice) const +bool Graphics::isRenderTargetActive(Texture *texture, int slice) const { const auto &rts = states.back().renderTargets; for (const auto &rt : rts.colors) { - if (rt.canvas.get() == canvas && rt.slice == slice) + if (rt.canvas.get() == texture && rt.slice == slice) return true; } - if (rts.depthStencil.canvas.get() == canvas && rts.depthStencil.slice == slice) + if (rts.depthStencil.canvas.get() == texture && rts.depthStencil.slice == slice) return true; return false; @@ -1593,8 +1593,7 @@ Graphics::Stats Graphics::getStats() const stats.canvasSwitches = canvasSwitchCount; stats.drawCallsBatched = drawCallsBatched; - stats.canvases = Canvas::canvasCount; - stats.images = Image::imageCount; + stats.textures = Texture::textureCount; stats.fonts = Font::fontCount; stats.textureMemory = Texture::totalGraphicsMemory; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 151be6f08..cac7a6edc 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -202,8 +202,7 @@ public: int drawCallsBatched; int canvasSwitches; int shaderSwitches; - int canvases; - int images; + int textures; int fonts; int64 textureMemory; }; @@ -551,8 +550,8 @@ public: RenderTargets getCanvas() const; bool isCanvasActive() const; - bool isCanvasActive(Canvas *canvas) const; - bool isCanvasActive(Canvas *canvas, int slice) const; + bool isRenderTargetActive(Texture *texture) const; + bool isRenderTargetActive(Texture *texture, int slice) const; /** * Scissor defines a box such that everything outside that box is discarded @@ -781,7 +780,7 @@ public: /** * Converts PIXELFORMAT_NORMAL and PIXELFORMAT_HDR into a real format. **/ - virtual PixelFormat getSizedFormat(PixelFormat format) const = 0; + virtual PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable, bool sRGB) const = 0; /** * Gets whether the specified pixel format is supported. diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index 83d423dae..99d89d98e 100644 --- a/src/modules/graphics/Image.cpp +++ b/src/modules/graphics/Image.cpp @@ -31,15 +31,14 @@ namespace graphics love::Type Image::type("Image", &Texture::type); -int Image::imageCount = 0; - Image::Image(const Slices &data, const Settings &settings, bool validatedata) : Texture(data.getTextureType()) , settings(settings) , mipmapsType(settings.mipmaps ? MIPMAPS_GENERATED : MIPMAPS_NONE) - , sRGB(isGammaCorrect() && !settings.linear) , usingDefaultTexture(false) { + renderTarget = false; + sRGB = isGammaCorrect() && !settings.linear; if (validatedata && data.validate() && data.getMipmapCount() > 1) mipmapsType = MIPMAPS_DATA; } @@ -72,13 +71,12 @@ Image::Image(const Slices &slices, const Settings &settings) Image::~Image() { - --imageCount; } void Image::init(PixelFormat fmt, int w, int h, const Settings &settings) { Graphics *gfx = Module::getInstance(Module::M_GRAPHICS); - if (gfx != nullptr && !gfx->isPixelFormatSupported(fmt, false, true, sRGB)) + if (gfx != nullptr && !gfx->isPixelFormatSupported(fmt, renderTarget, readable, sRGB)) { const char *str; if (love::getConstant(fmt, str)) @@ -104,8 +102,6 @@ void Image::init(PixelFormat fmt, int w, int h, const Settings &settings) mipmapCount = mipmapsType == MIPMAPS_NONE ? 1 : getTotalMipmapCount(w, h, depth); initQuad(); - - ++imageCount; } void Image::uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y) @@ -172,16 +168,6 @@ void Image::replacePixels(const void *data, size_t size, int slice, int mipmap, generateMipmaps(); } -bool Image::isCompressed() const -{ - return isPixelFormatCompressed(format); -} - -bool Image::isFormatLinear() const -{ - return isGammaCorrect() && !sRGB && format != PIXELFORMAT_sRGBA8_UNORM; -} - Image::MipmapsType Image::getMipmapsType() const { return mipmapsType; diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Image.h index a8aeabb7c..0d4f1139c 100644 --- a/src/modules/graphics/Image.h +++ b/src/modules/graphics/Image.h @@ -58,11 +58,8 @@ public: void replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps); bool isFormatLinear() const; - bool isCompressed() const; MipmapsType getMipmapsType() const; - static int imageCount; - static bool getConstant(const char *in, SettingType &out); static bool getConstant(SettingType in, const char *&out); static const char *getConstant(SettingType in); @@ -76,13 +73,10 @@ protected: void uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y); virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) = 0; - virtual void generateMipmaps() = 0; - // The settings used to initialize this Image. Settings settings; MipmapsType mipmapsType; - bool sRGB; // True if the image wasn't able to be properly created and it had to fall // back to a default texture. diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 1866aae50..3ac2ba8e9 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -156,12 +156,15 @@ std::vector SamplerState::getConstants(WrapMode) } love::Type Texture::type("Texture", &Drawable::type); +int Texture::textureCount = 0; int64 Texture::totalGraphicsMemory = 0; Texture::Texture(TextureType texType) : texType(texType) , format(PIXELFORMAT_UNKNOWN) + , renderTarget(false) , readable(true) + , sRGB(false) , width(0) , height(0) , depth(1) @@ -175,10 +178,12 @@ Texture::Texture(TextureType texType) auto gfx = Module::getInstance(Module::M_GRAPHICS); if (gfx != nullptr) samplerState = gfx->getDefaultSamplerState(); + ++textureCount; } Texture::~Texture() { + --textureCount; setGraphicsMemorySize(0); } @@ -207,11 +212,26 @@ PixelFormat Texture::getPixelFormat() const return format; } +bool Texture::isRenderTarget() const +{ + return renderTarget; +} + bool Texture::isReadable() const { return readable; } +bool Texture::isCompressed() const +{ + return isPixelFormatCompressed(format); +} + +bool Texture::isFormatLinear() const +{ + return isGammaCorrect() && !sRGB && format != PIXELFORMAT_sRGBA8_UNORM; +} + bool Texture::isValidSlice(int slice) const { if (slice < 0) @@ -241,6 +261,9 @@ void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform) if (!readable) throw love::Exception("Textures with non-readable formats cannot be drawn."); + if (renderTarget && gfx->isRenderTargetActive(this)) + throw love::Exception("Cannot render a Texture to itself."); + if (texType == TEXTURE_2D_ARRAY) { drawLayer(gfx, q->getLayer(), q, localTransform); @@ -291,6 +314,9 @@ void Texture::drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &m) if (!readable) throw love::Exception("Textures with non-readable formats cannot be drawn."); + if (renderTarget && gfx->isRenderTargetActive(this, layer)) + 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!"); diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index ee0c7c654..c93a28d04 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -126,6 +126,7 @@ class Texture : public Drawable, public Resource public: static love::Type type; + static int textureCount; enum MipmapsType { @@ -175,16 +176,20 @@ public: /** * Draws the texture using the specified transformation with a Quad applied. **/ - virtual void draw(Graphics *gfx, Quad *quad, const Matrix4 &m); + void draw(Graphics *gfx, Quad *quad, const Matrix4 &m); void drawLayer(Graphics *gfx, int layer, const Matrix4 &m); - virtual void drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m); + void drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m); TextureType getTextureType() const; PixelFormat getPixelFormat() const; + bool isRenderTarget() const; bool isReadable() const; + bool isCompressed() const; + bool isFormatLinear() const; + bool isValidSlice(int slice) const; int getWidth(int mip = 0) const; @@ -201,6 +206,8 @@ public: virtual void setSamplerState(const SamplerState &s); const SamplerState &getSamplerState() const; + virtual void generateMipmaps() = 0; + Quad *getQuad() const; static int getTotalMipmapCount(int w, int h); @@ -220,8 +227,11 @@ protected: TextureType texType; PixelFormat format; + bool renderTarget; bool readable; + bool sRGB; + int width; int height; diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index f3555d1d9..7ee5faf3e 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -31,7 +31,7 @@ namespace graphics namespace opengl { -static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat format, GLuint texture, int layers, int nb_mips) +static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat format, GLuint texture, int layers) { // get currently bound fbo to reset to it later GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL); @@ -60,42 +60,35 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo // Make sure all faces and layers of the texture are initialized to // transparent black. This is unfortunately probably pretty slow for // 2D-array and 3D textures with a lot of layers... - for (int mip = nb_mips - 1; mip >= 0; mip--) + for (int layer = layers - 1; layer >= 0; layer--) { - int nlayers = layers; - if (texType == TEXTURE_VOLUME) - nlayers = std::max(layers >> mip, 1); - - for (int layer = nlayers - 1; layer >= 0; layer--) + for (int face = faces - 1; face >= 0; face--) { - for (int face = faces - 1; face >= 0; face--) + for (GLenum attachment : fmt.framebufferAttachments) { - for (GLenum attachment : fmt.framebufferAttachments) - { - if (attachment == GL_NONE) - continue; + if (attachment == GL_NONE) + continue; - gl.framebufferTexture(attachment, texType, texture, mip, layer, face); - } + gl.framebufferTexture(attachment, texType, texture, 0, layer, face); + } - if (isPixelFormatDepthStencil(format)) - { - bool hadDepthWrites = gl.hasDepthWrites(); - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); + if (isPixelFormatDepthStencil(format)) + { + bool hadDepthWrites = gl.hasDepthWrites(); + if (!hadDepthWrites) // glDepthMask also affects glClear. + gl.setDepthWrites(true); - gl.clearDepth(1.0); - glClearStencil(0); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.clearDepth(1.0); + glClearStencil(0); + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - if (!hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); - } - else - { - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - } + if (!hadDepthWrites) + gl.setDepthWrites(hadDepthWrites); + } + else + { + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); } } } @@ -198,7 +191,7 @@ Canvas::Canvas(const Settings &settings) { auto gfx = Module::getInstance(Module::M_GRAPHICS); if (gfx != nullptr) - format = gfx->getSizedFormat(format); + format = gfx->getSizedFormat(format, renderTarget, readable, sRGB); initQuad(); loadVolatile(); @@ -259,8 +252,8 @@ bool Canvas::loadVolatile() return false; } - // 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); + // Create a local FBO used for glReadPixels as well as MSAA blitting. + status = createFBO(fbo, texType, format, texture, texType == TEXTURE_VOLUME ? depth : layers); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -287,6 +280,9 @@ bool Canvas::loadVolatile() setGraphicsMemorySize(memsize); + if (getMipmapCount() > 1) + generateMipmaps(); + return true; } @@ -390,11 +386,6 @@ void Canvas::generateMipmaps() glGenerateMipmap(gltextype); } -bool Canvas::isMultiFormatMultiCanvasSupported() -{ - return gl.getMaxRenderTargets() > 1 && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object); -} - } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index bb45edf7b..deb6b8e48 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -68,8 +68,6 @@ public: return fbo; } - static bool isMultiFormatMultiCanvasSupported(); - private: GLuint fbo; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 18b227e0a..0b961c0ba 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1362,7 +1362,7 @@ void Graphics::getAPIStats(int &shaderswitches) const void Graphics::initCapabilities() { - capabilities.features[FEATURE_MULTI_CANVAS_FORMATS] = Canvas::isMultiFormatMultiCanvasSupported(); + capabilities.features[FEATURE_MULTI_CANVAS_FORMATS] = gl.isMultiFormatMRTSupported(); capabilities.features[FEATURE_CLAMP_ZERO] = gl.isClampZeroOneTextureWrapSupported(); capabilities.features[FEATURE_BLENDMINMAX] = GLAD_VERSION_1_4 || GLAD_ES_VERSION_3_0 || GLAD_EXT_blend_minmax; capabilities.features[FEATURE_LIGHTEN] = capabilities.features[FEATURE_BLENDMINMAX]; @@ -1388,14 +1388,14 @@ void Graphics::initCapabilities() capabilities.textureTypes[i] = gl.isTextureTypeSupported((TextureType) i); } -PixelFormat Graphics::getSizedFormat(PixelFormat format) const +PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable, bool sRGB) const { switch (format) { case PIXELFORMAT_NORMAL: if (isGammaCorrect()) return PIXELFORMAT_sRGBA8_UNORM; - else if (!OpenGL::isPixelFormatSupported(PIXELFORMAT_RGBA8_UNORM, true, true, false)) + else if (!OpenGL::isPixelFormatSupported(PIXELFORMAT_RGBA8_UNORM, rendertarget, readable, sRGB)) // 32-bit render targets don't have guaranteed support on GLES2. return PIXELFORMAT_RGBA4_UNORM; else @@ -1409,14 +1409,14 @@ PixelFormat Graphics::getSizedFormat(PixelFormat format) const bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB) { - format = getSizedFormat(format); - if (sRGB && format == PIXELFORMAT_RGBA8_UNORM) { format = PIXELFORMAT_sRGBA8_UNORM; sRGB = false; } + format = getSizedFormat(format, rendertarget, readable, sRGB); + OptionalBool &supported = supportedFormats[format][rendertarget ? 1 : 0][readable ? 1 : 0][sRGB ? 1 : 0]; if (supported.hasValue) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 9dbdb3033..837390585 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -104,7 +104,7 @@ public: void setWireframe(bool enable) override; - PixelFormat getSizedFormat(PixelFormat format) const override; + PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable, bool sRGB) const override; bool isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB = false) override; Renderer getRenderer() const override; RendererInfo getRendererInfo() const override; diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index ac5bdd50e..a724b003b 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -105,9 +105,6 @@ void Image::loadData() if (!isCompressed()) gl.rawTexStorage(texType, mipcount, format, sRGB, pixelWidth, pixelHeight, texType == TEXTURE_VOLUME ? depth : layers); - if (mipmapsType == MIPMAPS_GENERATED) - mipcount = 1; - int w = pixelWidth; int h = pixelHeight; int d = depth; @@ -123,17 +120,23 @@ void Image::loadData() if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) { for (int slice = 0; slice < slices.getSliceCount(mip); slice++) - mipsize += slices.get(slice, mip)->getSize(); + { + auto id = slices.get(slice, mip); + if (id != nullptr) + mipsize += id->getSize(); + } } - GLenum gltarget = OpenGL::getGLTextureType(texType); - glCompressedTexImage3D(gltarget, mip, fmt.internalformat, w, h, d, 0, mipsize, nullptr); + if (mipsize > 0) + { + GLenum gltarget = OpenGL::getGLTextureType(texType); + glCompressedTexImage3D(gltarget, mip, fmt.internalformat, w, h, d, 0, mipsize, nullptr); + } } for (int slice = 0; slice < slicecount; slice++) { love::image::ImageDataBase *id = slices.get(slice, mip); - if (id != nullptr) uploadImageData(id, mip, slice, 0, 0); } diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index 124e1bbf5..5820d380c 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -50,11 +50,11 @@ public: ptrdiff_t getHandle() const override; void setSamplerState(const SamplerState &s) override; + void generateMipmaps() override; private: void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override; - void generateMipmaps() override; void loadDefaultTexture(); void loadData(); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 17dbb2860..31b5a8d85 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -1328,6 +1328,11 @@ bool OpenGL::isBaseVertexSupported() const return baseVertexSupported; } +bool OpenGL::isMultiFormatMRTSupported() const +{ + return getMaxRenderTargets() > 1 && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object); +} + int OpenGL::getMax2DTextureSize() const { return std::max(max2DTextureSize, 1); diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 29b7da1ee..9e7b26f55 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -347,6 +347,7 @@ public: bool isDepthCompareSampleSupported() const; bool isSamplerLODBiasSupported() const; bool isBaseVertexSupported() const; + bool isMultiFormatMRTSupported() const; /** * Returns the maximum supported width or height of a texture. diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index f262b9a0a..e15629d4a 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -2394,11 +2394,8 @@ int w_getStats(lua_State *L) lua_pushinteger(L, stats.shaderSwitches); lua_setfield(L, -2, "shaderswitches"); - lua_pushinteger(L, stats.canvases); - lua_setfield(L, -2, "canvases"); - - lua_pushinteger(L, stats.images); - lua_setfield(L, -2, "images"); + lua_pushinteger(L, stats.textures); + lua_setfield(L, -2, "textures"); lua_pushinteger(L, stats.fonts); lua_setfield(L, -2, "fonts"); From 323f86f31ef24e65e4ed1e7d9cee9e0168ff38f2 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 3 Feb 2020 19:15:24 -0400 Subject: [PATCH 06/31] Fix link error. Move a couple Lua wrappers from Image to Texture. --- src/modules/graphics/Image.h | 1 - src/modules/graphics/wrap_Image.cpp | 16 ---------------- src/modules/graphics/wrap_Texture.cpp | 16 ++++++++++++++++ 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Image.h index 0d4f1139c..4341e6308 100644 --- a/src/modules/graphics/Image.h +++ b/src/modules/graphics/Image.h @@ -57,7 +57,6 @@ public: void replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps); void replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps); - bool isFormatLinear() const; MipmapsType getMipmapsType() const; static bool getConstant(const char *in, SettingType &out); diff --git a/src/modules/graphics/wrap_Image.cpp b/src/modules/graphics/wrap_Image.cpp index 1d7da4773..db04b5b42 100644 --- a/src/modules/graphics/wrap_Image.cpp +++ b/src/modules/graphics/wrap_Image.cpp @@ -31,20 +31,6 @@ Image *luax_checkimage(lua_State *L, int idx) return luax_checktype(L, idx); } -int w_Image_isFormatLinear(lua_State *L) -{ - Image *i = luax_checkimage(L, 1); - luax_pushboolean(L, i->isFormatLinear()); - return 1; -} - -int w_Image_isCompressed(lua_State *L) -{ - Image *i = luax_checkimage(L, 1); - luax_pushboolean(L, i->isCompressed()); - return 1; -} - int w_Image_replacePixels(lua_State *L) { Image *i = luax_checkimage(L, 1); @@ -76,8 +62,6 @@ int w_Image_replacePixels(lua_State *L) static const luaL_Reg w_Image_functions[] = { - { "isFormatLinear", w_Image_isFormatLinear }, - { "isCompressed", w_Image_isCompressed }, { "replacePixels", w_Image_replacePixels }, { 0, 0 } }; diff --git a/src/modules/graphics/wrap_Texture.cpp b/src/modules/graphics/wrap_Texture.cpp index 9189a3101..51fb438ae 100644 --- a/src/modules/graphics/wrap_Texture.cpp +++ b/src/modules/graphics/wrap_Texture.cpp @@ -129,6 +129,20 @@ int w_Texture_getDPIScale(lua_State *L) return 1; } +int w_Texture_isFormatLinear(lua_State *L) +{ + Texture *t = luax_checktexture(L, 1); + luax_pushboolean(L, t->isFormatLinear()); + return 1; +} + +int w_Texture_isCompressed(lua_State *L) +{ + Texture *t = luax_checktexture(L, 1); + luax_pushboolean(L, t->isCompressed()); + return 1; +} + int w_Texture_setFilter(lua_State *L) { Texture *t = luax_checktexture(L, 1); @@ -314,6 +328,8 @@ const luaL_Reg w_Texture_functions[] = { "getPixelHeight", w_Texture_getPixelHeight }, { "getPixelDimensions", w_Texture_getPixelDimensions }, { "getDPIScale", w_Texture_getDPIScale }, + { "isFormatLinear", w_Texture_isFormatLinear }, + { "isCompressed", w_Texture_isCompressed }, { "setFilter", w_Texture_setFilter }, { "getFilter", w_Texture_getFilter }, { "setMipmapFilter", w_Texture_setMipmapFilter }, From fc0d60a96d8b0fab68c3784a94c9888ddffebe91 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 3 Feb 2020 19:26:11 -0400 Subject: [PATCH 07/31] Move Canvas:getMSAA to Texture:getMSAA. --- src/modules/graphics/Canvas.cpp | 6 +----- src/modules/graphics/Canvas.h | 4 ---- src/modules/graphics/Texture.cpp | 6 ++++++ src/modules/graphics/Texture.h | 7 +++++++ src/modules/graphics/opengl/Image.h | 2 ++ src/modules/graphics/wrap_Canvas.cpp | 8 -------- src/modules/graphics/wrap_Texture.cpp | 8 ++++++++ 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/modules/graphics/Canvas.cpp b/src/modules/graphics/Canvas.cpp index 88cd98b5a..5c3ebe857 100644 --- a/src/modules/graphics/Canvas.cpp +++ b/src/modules/graphics/Canvas.cpp @@ -35,6 +35,7 @@ Canvas::Canvas(const Settings &settings) renderTarget = true; sRGB = false; + requestedMSAA = settings.msaa; width = settings.width; height = settings.height; @@ -106,11 +107,6 @@ Canvas::MipmapMode Canvas::getMipmapMode() const return settings.mipmaps; } -int Canvas::getRequestedMSAA() const -{ - return settings.msaa; -} - love::image::ImageData *Canvas::newImageData(love::image::Image *module, int slice, int mipmap, const Rect &r) { if (!isReadable()) diff --git a/src/modules/graphics/Canvas.h b/src/modules/graphics/Canvas.h index 05e5a844d..ac2a72e73 100644 --- a/src/modules/graphics/Canvas.h +++ b/src/modules/graphics/Canvas.h @@ -78,13 +78,9 @@ public: virtual ~Canvas(); MipmapMode getMipmapMode() const; - int getRequestedMSAA() const; virtual love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect); - virtual int getMSAA() const = 0; - virtual ptrdiff_t getRenderTargetHandle() const = 0; - static bool getConstant(const char *in, MipmapMode &out); static bool getConstant(MipmapMode in, const char *&out); static std::vector getConstants(MipmapMode); diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 3ac2ba8e9..35b846258 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -172,6 +172,7 @@ Texture::Texture(TextureType texType) , mipmapCount(1) , pixelWidth(0) , pixelHeight(0) + , requestedMSAA(1) , samplerState() , graphicsMemorySize(0) { @@ -397,6 +398,11 @@ float Texture::getDPIScale() const return (float) pixelHeight / (float) height; } +int Texture::getRequestedMSAA() const +{ + return requestedMSAA; +} + void Texture::setSamplerState(const SamplerState &s) { if (s.depthSampleMode.hasValue && (!readable || !isPixelFormatDepthStencil(format))) diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index c93a28d04..1ab277632 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -181,6 +181,8 @@ public: void drawLayer(Graphics *gfx, int layer, const Matrix4 &m); void drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m); + virtual ptrdiff_t getRenderTargetHandle() const = 0; + TextureType getTextureType() const; PixelFormat getPixelFormat() const; @@ -203,6 +205,9 @@ public: float getDPIScale() const; + int getRequestedMSAA() const; + virtual int getMSAA() const = 0; + virtual void setSamplerState(const SamplerState &s); const SamplerState &getSamplerState() const; @@ -242,6 +247,8 @@ protected: int pixelWidth; int pixelHeight; + int requestedMSAA; + SamplerState samplerState; StrongRef quad; diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index 5820d380c..c660903c2 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -48,7 +48,9 @@ public: void unloadVolatile() override; ptrdiff_t getHandle() const override; + ptrdiff_t getRenderTargetHandle() const override { return 0; } + int getMSAA() const override { return 1; } void setSamplerState(const SamplerState &s) override; void generateMipmaps() override; diff --git a/src/modules/graphics/wrap_Canvas.cpp b/src/modules/graphics/wrap_Canvas.cpp index fa020f485..5394d7c82 100644 --- a/src/modules/graphics/wrap_Canvas.cpp +++ b/src/modules/graphics/wrap_Canvas.cpp @@ -31,13 +31,6 @@ Canvas *luax_checkcanvas(lua_State *L, int idx) return luax_checktype(L, idx); } -int w_Canvas_getMSAA(lua_State *L) -{ - Canvas *canvas = luax_checkcanvas(L, 1); - lua_pushinteger(L, canvas->getMSAA()); - return 1; -} - int w_Canvas_renderTo(lua_State *L) { Graphics::RenderTarget rt(luax_checkcanvas(L, 1)); @@ -135,7 +128,6 @@ int w_Canvas_getMipmapMode(lua_State *L) static const luaL_Reg w_Canvas_functions[] = { - { "getMSAA", w_Canvas_getMSAA }, { "renderTo", w_Canvas_renderTo }, { "newImageData", w_Canvas_newImageData }, { "generateMipmaps", w_Canvas_generateMipmaps }, diff --git a/src/modules/graphics/wrap_Texture.cpp b/src/modules/graphics/wrap_Texture.cpp index 51fb438ae..af45ca44d 100644 --- a/src/modules/graphics/wrap_Texture.cpp +++ b/src/modules/graphics/wrap_Texture.cpp @@ -143,6 +143,13 @@ int w_Texture_isCompressed(lua_State *L) return 1; } +int w_Texture_getMSAA(lua_State *L) +{ + Texture *t = luax_checktexture(L, 1); + lua_pushinteger(L, t->getMSAA()); + return 1; +} + int w_Texture_setFilter(lua_State *L) { Texture *t = luax_checktexture(L, 1); @@ -330,6 +337,7 @@ const luaL_Reg w_Texture_functions[] = { "getDPIScale", w_Texture_getDPIScale }, { "isFormatLinear", w_Texture_isFormatLinear }, { "isCompressed", w_Texture_isCompressed }, + { "getMSAA", w_Texture_getMSAA }, { "setFilter", w_Texture_setFilter }, { "getFilter", w_Texture_getFilter }, { "setMipmapFilter", w_Texture_setMipmapFilter }, From 63c5df6aa73be0a5de83df995b0a3721fdf0ecbe Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 3 Feb 2020 23:05:46 -0400 Subject: [PATCH 08/31] Begin unification of Canvases and Images. --- src/modules/graphics/Canvas.cpp | 26 +----- src/modules/graphics/Canvas.h | 20 +---- src/modules/graphics/Graphics.cpp | 103 ++++++++++++----------- src/modules/graphics/Graphics.h | 44 +++++----- src/modules/graphics/Image.cpp | 36 ++++---- src/modules/graphics/Image.h | 8 +- src/modules/graphics/Texture.cpp | 24 ++++++ src/modules/graphics/Texture.h | 11 ++- src/modules/graphics/opengl/Canvas.cpp | 7 +- src/modules/graphics/opengl/Graphics.cpp | 79 +++++++++-------- src/modules/graphics/opengl/Graphics.h | 2 +- src/modules/graphics/opengl/Image.cpp | 20 +---- src/modules/graphics/opengl/OpenGL.cpp | 4 +- src/modules/graphics/wrap_Canvas.cpp | 18 ++-- src/modules/graphics/wrap_Graphics.cpp | 32 +++---- src/modules/graphics/wrap_Image.cpp | 2 +- 16 files changed, 211 insertions(+), 225 deletions(-) diff --git a/src/modules/graphics/Canvas.cpp b/src/modules/graphics/Canvas.cpp index 5c3ebe857..2866b0121 100644 --- a/src/modules/graphics/Canvas.cpp +++ b/src/modules/graphics/Canvas.cpp @@ -102,7 +102,7 @@ Canvas::~Canvas() { } -Canvas::MipmapMode Canvas::getMipmapMode() const +Texture::MipmapsMode Canvas::getMipmapsMode() const { return settings.mipmaps; } @@ -141,21 +141,6 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *module, int sli return module->newImageData(r.w, r.h, dataformat); } -bool Canvas::getConstant(const char *in, MipmapMode &out) -{ - return mipmapModes.find(in, out); -} - -bool Canvas::getConstant(MipmapMode in, const char *&out) -{ - return mipmapModes.find(in, out); -} - -std::vector Canvas::getConstants(MipmapMode) -{ - return mipmapModes.getNames(); -} - bool Canvas::getConstant(const char *in, SettingType &out) { return settingTypes.find(in, out); @@ -178,15 +163,6 @@ std::vector Canvas::getConstants(SettingType) return settingTypes.getNames(); } -StringMap::Entry Canvas::mipmapEntries[] = -{ - { "none", MIPMAPS_NONE }, - { "manual", MIPMAPS_MANUAL }, - { "auto", MIPMAPS_AUTO }, -}; - -StringMap Canvas::mipmapModes(Canvas::mipmapEntries, sizeof(Canvas::mipmapEntries)); - StringMap::Entry Canvas::settingTypeEntries[] = { // Width / height / layers are currently omittted because they're separate diff --git a/src/modules/graphics/Canvas.h b/src/modules/graphics/Canvas.h index ac2a72e73..d683e9d5d 100644 --- a/src/modules/graphics/Canvas.h +++ b/src/modules/graphics/Canvas.h @@ -39,14 +39,6 @@ public: static love::Type type; - enum MipmapMode - { - MIPMAPS_NONE, - MIPMAPS_MANUAL, - MIPMAPS_AUTO, - MIPMAPS_MAX_ENUM - }; - enum SettingType { SETTING_WIDTH, @@ -66,7 +58,7 @@ public: int width = 1; int height = 1; int layers = 1; // depth for 3D textures - MipmapMode mipmaps = MIPMAPS_NONE; + MipmapsMode mipmaps = MIPMAPS_NONE; PixelFormat format = PIXELFORMAT_NORMAL; TextureType type = TEXTURE_2D; float dpiScale = 1.0f; @@ -77,14 +69,10 @@ public: Canvas(const Settings &settings); virtual ~Canvas(); - MipmapMode getMipmapMode() const; + MipmapsMode getMipmapsMode() const; virtual love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect); - static bool getConstant(const char *in, MipmapMode &out); - static bool getConstant(MipmapMode in, const char *&out); - static std::vector getConstants(MipmapMode); - static bool getConstant(const char *in, SettingType &out); static bool getConstant(SettingType in, const char *&out); static const char *getConstant(SettingType in); @@ -96,8 +84,8 @@ protected: private: - static StringMap::Entry mipmapEntries[]; - static StringMap mipmapModes; + static StringMap::Entry mipmapEntries[]; + static StringMap mipmapModes; static StringMap::Entry settingTypeEntries[]; static StringMap settingTypes; diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 5ae9493dd..c0a5a2f1f 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -116,7 +116,7 @@ Graphics::Graphics() , writingToStencil(false) , streamBufferState() , projectionMatrix() - , canvasSwitchCount(0) + , renderTargetSwitchCount(0) , drawCalls(0) , drawCallsBatched(0) , quadIndexBuffer(nullptr) @@ -335,8 +335,8 @@ int Graphics::getPixelHeight() const double Graphics::getCurrentDPIScale() const { const auto &rt = states.back().renderTargets.getFirstTarget(); - if (rt.canvas.get()) - return rt.canvas->getDPIScale(); + if (rt.texture.get()) + return rt.texture->getDPIScale(); return getScreenDPIScale(); } @@ -545,7 +545,7 @@ love::graphics::Shader *Graphics::getShader() const void Graphics::setCanvas(RenderTarget rt, uint32 temporaryRTFlags) { - if (rt.canvas == nullptr) + if (rt.texture == nullptr) return setCanvas(); RenderTargets rts; @@ -561,9 +561,9 @@ void Graphics::setCanvas(const RenderTargetsStrongRef &rts) targets.colors.reserve(rts.colors.size()); for (const auto &rt : rts.colors) - targets.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap); + targets.colors.emplace_back(rt.texture.get(), rt.slice, rt.mipmap); - targets.depthStencil = RenderTarget(rts.depthStencil.canvas, rts.depthStencil.slice, rts.depthStencil.mipmap); + targets.depthStencil = RenderTarget(rts.depthStencil.texture, rts.depthStencil.slice, rts.depthStencil.mipmap); targets.temporaryRTFlags = rts.temporaryRTFlags; return setCanvas(targets); @@ -575,9 +575,9 @@ void Graphics::setCanvas(const RenderTargets &rts) int ncanvases = (int) rts.colors.size(); RenderTarget firsttarget = rts.getFirstTarget(); - love::graphics::Canvas *firstcanvas = firsttarget.canvas; + Texture *firsttex = firsttarget.texture; - if (firstcanvas == nullptr) + if (firsttex == nullptr) return setCanvas(); const auto &prevRTs = state.renderTargets; @@ -612,29 +612,35 @@ void Graphics::setCanvas(const RenderTargets &rts) PixelFormat firstcolorformat = PIXELFORMAT_UNKNOWN; if (!rts.colors.empty()) - firstcolorformat = rts.colors[0].canvas->getPixelFormat(); + firstcolorformat = rts.colors[0].texture->getPixelFormat(); + + if (!firsttex->isRenderTarget()) + throw love::Exception("Texture must be created as a render target to be used in setCanvas."); if (isPixelFormatDepthStencil(firstcolorformat)) throw love::Exception("Depth/stencil format Canvases must be used with the 'depthstencil' field of the table passed into setCanvas."); - if (firsttarget.mipmap < 0 || firsttarget.mipmap >= firstcanvas->getMipmapCount()) + if (firsttarget.mipmap < 0 || firsttarget.mipmap >= firsttex->getMipmapCount()) throw love::Exception("Invalid mipmap level %d.", firsttarget.mipmap + 1); - if (!firstcanvas->isValidSlice(firsttarget.slice)) + if (!firsttex->isValidSlice(firsttarget.slice)) throw love::Exception("Invalid slice index: %d.", firsttarget.slice + 1); bool hasSRGBcanvas = firstcolorformat == PIXELFORMAT_sRGBA8_UNORM; - int pixelw = firstcanvas->getPixelWidth(firsttarget.mipmap); - int pixelh = firstcanvas->getPixelHeight(firsttarget.mipmap); - int reqmsaa = firstcanvas->getRequestedMSAA(); + int pixelw = firsttex->getPixelWidth(firsttarget.mipmap); + int pixelh = firsttex->getPixelHeight(firsttarget.mipmap); + int reqmsaa = firsttex->getRequestedMSAA(); for (int i = 1; i < ncanvases; i++) { - love::graphics::Canvas *c = rts.colors[i].canvas; + Texture *c = rts.colors[i].texture; PixelFormat format = c->getPixelFormat(); int mip = rts.colors[i].mipmap; int slice = rts.colors[i].slice; + if (!c->isRenderTarget()) + throw love::Exception("Texture must be created as a render target to be used in setCanvas."); + if (mip < 0 || mip >= c->getMipmapCount()) throw love::Exception("Invalid mipmap level %d.", mip + 1); @@ -657,20 +663,23 @@ void Graphics::setCanvas(const RenderTargets &rts) hasSRGBcanvas = true; } - if (rts.depthStencil.canvas != nullptr) + if (rts.depthStencil.texture != nullptr) { - love::graphics::Canvas *c = rts.depthStencil.canvas; + Texture *c = rts.depthStencil.texture; int mip = rts.depthStencil.mipmap; int slice = rts.depthStencil.slice; + if (!c->isRenderTarget()) + throw love::Exception("Texture must be created as a render target to be used in setCanvas."); + if (!isPixelFormatDepthStencil(c->getPixelFormat())) - throw love::Exception("Only depth/stencil format Canvases can be used with the 'depthstencil' field of the table passed into setCanvas."); + throw love::Exception("Only depth/stencil format Texture can be used with the 'depthstencil' field of the table passed into setCanvas."); if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh) - throw love::Exception("All canvases must have the same pixel dimensions."); + throw love::Exception("All Textures must have the same pixel dimensions."); - if (c->getRequestedMSAA() != firstcanvas->getRequestedMSAA()) - throw love::Exception("All Canvases must have the same MSAA value."); + if (c->getRequestedMSAA() != firsttex->getRequestedMSAA()) + throw love::Exception("All Textures must have the same MSAA value."); if (mip < 0 || mip >= c->getMipmapCount()) throw love::Exception("Invalid mipmap level %d.", mip + 1); @@ -679,12 +688,12 @@ void Graphics::setCanvas(const RenderTargets &rts) throw love::Exception("Invalid slice index: %d.", slice + 1); } - int w = firstcanvas->getWidth(firsttarget.mipmap); - int h = firstcanvas->getHeight(firsttarget.mipmap); + int w = firsttex->getWidth(firsttarget.mipmap); + int h = firsttex->getHeight(firsttarget.mipmap); flushStreamDraws(); - if (rts.depthStencil.canvas == nullptr && rts.temporaryRTFlags != 0) + if (rts.depthStencil.texture == nullptr && rts.temporaryRTFlags != 0) { bool wantsdepth = (rts.temporaryRTFlags & TEMPORARY_RT_DEPTH) != 0; bool wantsstencil = (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) != 0; @@ -703,7 +712,7 @@ void Graphics::setCanvas(const RenderTargets &rts) // we don't want to directly store it in the main graphics state. RenderTargets realRTs = rts; - realRTs.depthStencil.canvas = getTemporaryCanvas(dsformat, pixelw, pixelh, reqmsaa); + realRTs.depthStencil.texture = getTemporaryTexture(dsformat, pixelw, pixelh, reqmsaa); realRTs.depthStencil.slice = 0; setCanvasInternal(realRTs, w, h, pixelw, pixelh, hasSRGBcanvas); @@ -715,28 +724,28 @@ void Graphics::setCanvas(const RenderTargets &rts) refs.colors.reserve(rts.colors.size()); for (auto c : rts.colors) - refs.colors.emplace_back(c.canvas, c.slice, c.mipmap); + refs.colors.emplace_back(c.texture, c.slice, c.mipmap); - refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.canvas, rts.depthStencil.slice); + refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.texture, rts.depthStencil.slice); refs.temporaryRTFlags = rts.temporaryRTFlags; std::swap(state.renderTargets, refs); - canvasSwitchCount++; + renderTargetSwitchCount++; } void Graphics::setCanvas() { DisplayState &state = states.back(); - if (state.renderTargets.colors.empty() && state.renderTargets.depthStencil.canvas == nullptr) + if (state.renderTargets.colors.empty() && state.renderTargets.depthStencil.texture == nullptr) return; flushStreamDraws(); setCanvasInternal(RenderTargets(), width, height, pixelWidth, pixelHeight, isGammaCorrect()); state.renderTargets = RenderTargetsStrongRef(); - canvasSwitchCount++; + renderTargetSwitchCount++; } Graphics::RenderTargets Graphics::getCanvas() const @@ -747,9 +756,9 @@ Graphics::RenderTargets Graphics::getCanvas() const rts.colors.reserve(curRTs.colors.size()); for (const auto &rt : curRTs.colors) - rts.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap); + rts.colors.emplace_back(rt.texture.get(), rt.slice, rt.mipmap); - rts.depthStencil = RenderTarget(curRTs.depthStencil.canvas, curRTs.depthStencil.slice, curRTs.depthStencil.mipmap); + rts.depthStencil = RenderTarget(curRTs.depthStencil.texture, curRTs.depthStencil.slice, curRTs.depthStencil.mipmap); rts.temporaryRTFlags = curRTs.temporaryRTFlags; return rts; @@ -758,7 +767,7 @@ Graphics::RenderTargets Graphics::getCanvas() const bool Graphics::isCanvasActive() const { const auto &rts = states.back().renderTargets; - return !rts.colors.empty() || rts.depthStencil.canvas != nullptr; + return !rts.colors.empty() || rts.depthStencil.texture != nullptr; } bool Graphics::isRenderTargetActive(Texture *texture) const @@ -767,11 +776,11 @@ bool Graphics::isRenderTargetActive(Texture *texture) const for (const auto &rt : rts.colors) { - if (rt.canvas.get() == texture) + if (rt.texture.get() == texture) return true; } - if (rts.depthStencil.canvas.get() == texture) + if (rts.depthStencil.texture.get() == texture) return true; return false; @@ -783,33 +792,33 @@ bool Graphics::isRenderTargetActive(Texture *texture, int slice) const for (const auto &rt : rts.colors) { - if (rt.canvas.get() == texture && rt.slice == slice) + if (rt.texture.get() == texture && rt.slice == slice) return true; } - if (rts.depthStencil.canvas.get() == texture && rts.depthStencil.slice == slice) + if (rts.depthStencil.texture.get() == texture && rts.depthStencil.slice == slice) return true; return false; } -Canvas *Graphics::getTemporaryCanvas(PixelFormat format, int w, int h, int samples) +Texture *Graphics::getTemporaryTexture(PixelFormat format, int w, int h, int samples) { - love::graphics::Canvas *canvas = nullptr; + Texture *texture = nullptr; - for (TemporaryCanvas &temp : temporaryCanvases) + for (TemporaryTexture &temp : temporaryTextures) { - Canvas *c = temp.canvas; + Texture *c = temp.texture; if (c->getPixelFormat() == format && c->getPixelWidth() == w && c->getPixelHeight() == h && c->getRequestedMSAA() == samples) { - canvas = c; + texture = c; temp.framesSinceUse = 0; break; } } - if (canvas == nullptr) + if (texture == nullptr) { Canvas::Settings settings; settings.format = format; @@ -817,12 +826,12 @@ Canvas *Graphics::getTemporaryCanvas(PixelFormat format, int w, int h, int sampl settings.height = h; settings.msaa = samples; - canvas = newCanvas(settings); + texture = newCanvas(settings); - temporaryCanvases.emplace_back(canvas); + temporaryTextures.emplace_back(texture); } - return canvas; + return texture; } void Graphics::intersectScissor(const Rect &rect) @@ -1591,7 +1600,7 @@ Graphics::Stats Graphics::getStats() const if (streamBufferState.vertexCount > 0) stats.drawCalls++; - stats.canvasSwitches = canvasSwitchCount; + stats.renderTargetSwitches = renderTargetSwitchCount; stats.drawCallsBatched = drawCallsBatched; stats.textures = Texture::textureCount; stats.fonts = Font::fontCount; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index cac7a6edc..cf4429e3b 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -200,7 +200,7 @@ public: { int drawCalls; int drawCallsBatched; - int canvasSwitches; + int renderTargetSwitches; int shaderSwitches; int textures; int fonts; @@ -315,53 +315,53 @@ public: struct RenderTarget { - Canvas *canvas; + Texture *texture; int slice; int mipmap; - RenderTarget(Canvas *canvas, int slice = 0, int mipmap = 0) - : canvas(canvas) + RenderTarget(Texture *texture, int slice = 0, int mipmap = 0) + : texture(texture) , slice(slice) , mipmap(mipmap) {} RenderTarget() - : canvas(nullptr) + : texture(nullptr) , slice(0) , mipmap(0) {} bool operator != (const RenderTarget &other) const { - return canvas != other.canvas || slice != other.slice || mipmap != other.mipmap; + return texture != other.texture || slice != other.slice || mipmap != other.mipmap; } bool operator != (const RenderTargetStrongRef &other) const { - return canvas != other.canvas.get() || slice != other.slice || mipmap != other.mipmap; + return texture != other.texture.get() || slice != other.slice || mipmap != other.mipmap; } }; struct RenderTargetStrongRef { - StrongRef canvas; + StrongRef texture; int slice = 0; int mipmap = 0; - RenderTargetStrongRef(Canvas *canvas, int slice = 0, int mipmap = 0) - : canvas(canvas) + RenderTargetStrongRef(Texture *texture, int slice = 0, int mipmap = 0) + : texture(texture) , slice(slice) , mipmap(mipmap) {} bool operator != (const RenderTargetStrongRef &other) const { - return canvas.get() != other.canvas.get() || slice != other.slice || mipmap != other.mipmap; + return texture.get() != other.texture.get() || slice != other.slice || mipmap != other.mipmap; } bool operator != (const RenderTarget &other) const { - return canvas.get() != other.canvas || slice != other.slice || mipmap != other.mipmap; + return texture.get() != other.texture || slice != other.slice || mipmap != other.mipmap; } }; @@ -619,12 +619,12 @@ public: const BlendState &getBlendState() const; /** - * Sets the default sampler state for images, canvases, and fonts. + * Sets the default sampler state for textures, videos, and fonts. **/ void setDefaultSamplerState(const SamplerState &s); /** - * Gets the default sampler state for images, canvases, and fonts. + * Gets the default sampler state for textures, videos, and fonts. **/ const SamplerState &getDefaultSamplerState() const; @@ -939,13 +939,13 @@ protected: } }; - struct TemporaryCanvas + struct TemporaryTexture { - Canvas *canvas; + Texture *texture; int framesSinceUse; - TemporaryCanvas(Canvas *c) - : canvas(c) + TemporaryTexture(Texture *tex) + : texture(tex) , framesSinceUse(0) {} }; @@ -961,7 +961,7 @@ protected: void createQuadIndexBuffer(); - Canvas *getTemporaryCanvas(PixelFormat format, int w, int h, int samples); + Texture *getTemporaryTexture(PixelFormat format, int w, int h, int samples); void restoreState(const DisplayState &s); void restoreStateChecked(const DisplayState &s); @@ -994,9 +994,9 @@ protected: std::vector states; std::vector stackTypeStack; - std::vector temporaryCanvases; + std::vector temporaryTextures; - int canvasSwitchCount; + int renderTargetSwitchCount; int drawCalls; int drawCallsBatched; @@ -1007,7 +1007,7 @@ protected: Deprecations deprecations; static const size_t MAX_USER_STACK_DEPTH = 128; - static const int MAX_TEMPORARY_CANVAS_UNUSED_FRAMES = 16; + static const int MAX_TEMPORARY_TEXTURE_UNUSED_FRAMES = 16; private: diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index 99d89d98e..f7fd92529 100644 --- a/src/modules/graphics/Image.cpp +++ b/src/modules/graphics/Image.cpp @@ -31,20 +31,17 @@ namespace graphics love::Type Image::type("Image", &Texture::type); -Image::Image(const Slices &data, const Settings &settings, bool validatedata) - : Texture(data.getTextureType()) +Image::Image(TextureType textype, const Settings &settings) + : Texture(textype) , settings(settings) - , mipmapsType(settings.mipmaps ? MIPMAPS_GENERATED : MIPMAPS_NONE) , usingDefaultTexture(false) { renderTarget = false; sRGB = isGammaCorrect() && !settings.linear; - if (validatedata && data.validate() && data.getMipmapCount() > 1) - mipmapsType = MIPMAPS_DATA; } Image::Image(TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings) - : Image(Slices(textype), settings, false) + : Image(textype, settings) { if (isPixelFormatCompressed(format)) throw love::Exception("This constructor is only supported for non-compressed pixel formats."); @@ -54,26 +51,30 @@ Image::Image(TextureType textype, PixelFormat format, int width, int height, int else if (textype == TEXTURE_VOLUME) depth = slices; - init(format, width, height, settings); + init(format, width, height, 1, settings); } Image::Image(const Slices &slices, const Settings &settings) - : Image(slices, settings, true) + : Image(slices.getTextureType(), settings) { + int dataMipmaps = 1; + if (slices.validate() && slices.getMipmapCount() > 1) + dataMipmaps = slices.getMipmapCount(); + if (texType == TEXTURE_2D_ARRAY) this->layers = slices.getSliceCount(); else if (texType == TEXTURE_VOLUME) this->depth = slices.getSliceCount(); love::image::ImageDataBase *slice = slices.get(0, 0); - init(slice->getFormat(), slice->getWidth(), slice->getHeight(), settings); + init(slice->getFormat(), slice->getWidth(), slice->getHeight(), dataMipmaps, settings); } Image::~Image() { } -void Image::init(PixelFormat fmt, int w, int h, const Settings &settings) +void Image::init(PixelFormat fmt, int w, int h, int dataMipmaps, const Settings &settings) { Graphics *gfx = Module::getInstance(Module::M_GRAPHICS); if (gfx != nullptr && !gfx->isPixelFormatSupported(fmt, renderTarget, readable, sRGB)) @@ -96,10 +97,10 @@ void Image::init(PixelFormat fmt, int w, int h, const Settings &settings) format = fmt; - if (isCompressed() && mipmapsType == MIPMAPS_GENERATED) - mipmapsType = MIPMAPS_NONE; - - mipmapCount = mipmapsType == MIPMAPS_NONE ? 1 : getTotalMipmapCount(w, h, depth); + if (!settings.mipmaps || (isCompressed() && dataMipmaps <= 1)) + mipmapCount = 1; + else + mipmapCount = getTotalMipmapCount(w, h, depth); initQuad(); } @@ -125,7 +126,7 @@ void Image::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, if (d->getFormat() != getPixelFormat()) throw love::Exception("Pixel formats must match."); - if (mipmap < 0 || (mipmapsType != MIPMAPS_DATA && mipmap > 0) || mipmap >= getMipmapCount()) + if (mipmap < 0 || mipmap >= getMipmapCount()) throw love::Exception("Invalid image mipmap index %d.", mipmap + 1); if (slice < 0 || (texType == TEXTURE_CUBE && slice >= 6) @@ -168,11 +169,6 @@ void Image::replacePixels(const void *data, size_t size, int slice, int mipmap, generateMipmaps(); } -Image::MipmapsType Image::getMipmapsType() const -{ - return mipmapsType; -} - bool Image::getConstant(const char *in, SettingType &out) { return settingTypes.find(in, out); diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Image.h index 4341e6308..1fd9fdd07 100644 --- a/src/modules/graphics/Image.h +++ b/src/modules/graphics/Image.h @@ -57,8 +57,6 @@ public: void replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps); void replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps); - MipmapsType getMipmapsType() const; - static bool getConstant(const char *in, SettingType &out); static bool getConstant(SettingType in, const char *&out); static const char *getConstant(SettingType in); @@ -75,17 +73,15 @@ protected: // The settings used to initialize this Image. Settings settings; - MipmapsType mipmapsType; - // True if the image wasn't able to be properly created and it had to fall // back to a default texture. bool usingDefaultTexture; private: - Image(const Slices &data, const Settings &settings, bool validatedata); + Image(TextureType textype, const Settings &settings); - void init(PixelFormat fmt, int w, int h, const Settings &settings); + void init(PixelFormat fmt, int w, int h, int dataMipmaps, const Settings &settings); static StringMap::Entry settingTypeEntries[]; static StringMap settingTypes; diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 35b846258..bf380e32d 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -680,5 +680,29 @@ StringMap::Entry Texture::texTypeEntries[] = StringMap Texture::texTypes(Texture::texTypeEntries, sizeof(Texture::texTypeEntries)); +static StringMap::Entry mipmapEntries[] = +{ + { "none", Texture::MIPMAPS_NONE }, + { "manual", Texture::MIPMAPS_MANUAL }, + { "auto", Texture::MIPMAPS_AUTO }, +}; + +static StringMap mipmapModes(mipmapEntries, sizeof(mipmapEntries)); + +bool Texture::getConstant(const char *in, MipmapsMode &out) +{ + return mipmapModes.find(in, out); +} + +bool Texture::getConstant(MipmapsMode in, const char *&out) +{ + return mipmapModes.find(in, out); +} + +std::vector Texture::getConstants(MipmapsMode) +{ + return mipmapModes.getNames(); +} + } // graphics } // love diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 1ab277632..011d8a04f 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -128,11 +128,12 @@ public: static love::Type type; static int textureCount; - enum MipmapsType + enum MipmapsMode { MIPMAPS_NONE, - MIPMAPS_DATA, - MIPMAPS_GENERATED, + MIPMAPS_MANUAL, + MIPMAPS_AUTO, + MIPMAPS_MAX_ENUM }; struct Slices @@ -222,6 +223,10 @@ public: static bool getConstant(TextureType in, const char *&out); static std::vector getConstants(TextureType); + static bool getConstant(const char *in, MipmapsMode &out); + static bool getConstant(MipmapsMode in, const char *&out); + static std::vector getConstants(MipmapsMode); + protected: void initQuad(); diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 7ee5faf3e..0a20ed94a 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -373,8 +373,11 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *module, int sli 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 (getMipmapCount() == 1 || getMipmapsMode() == MIPMAPS_NONE) + throw love::Exception("generateMipmaps can only be called on a Texture which was created with mipmaps enabled."); + + if (isPixelFormatCompressed(format)) + throw love::Exception("generateMipmaps cannot be called on a compressed Texture."); gl.bindTextureToUnit(this, 0, false); diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 0b961c0ba..f020e28ec 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -234,7 +234,7 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b // Set whether drawing converts input from linear -> sRGB colorspace. if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB - || GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB) + || GLAD_ES_VERSION_3_0) { if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control) gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, isGammaCorrect()); @@ -312,11 +312,11 @@ void Graphics::unSetMode() for (const auto &pair : framebufferObjects) gl.deleteFramebuffer(pair.second); - for (auto temp : temporaryCanvases) - temp.canvas->release(); + for (auto temp : temporaryTextures) + temp.texture->release(); framebufferObjects.clear(); - temporaryCanvases.clear(); + temporaryTextures.clear(); if (mainVAO != 0) { @@ -518,7 +518,7 @@ void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pix flushStreamDraws(); endPass(); - bool iswindow = rts.getFirstTarget().canvas == nullptr; + bool iswindow = rts.getFirstTarget().texture == nullptr; vertex::Winding vertexwinding = state.winding; if (iswindow) @@ -560,7 +560,7 @@ void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pix void Graphics::endPass() { auto &rts = states.back().renderTargets; - love::graphics::Canvas *depthstencil = rts.depthStencil.canvas.get(); + love::graphics::Texture *depthstencil = rts.depthStencil.texture.get(); // Discard the depth/stencil buffer if we're using an internal cached one. if (depthstencil == nullptr && (rts.temporaryRTFlags & (TEMPORARY_RT_DEPTH | TEMPORARY_RT_STENCIL)) != 0) @@ -568,15 +568,16 @@ void Graphics::endPass() // Resolve MSAA buffers. MSAA is only supported for 2D render targets so we // don't have to worry about resolving to slices. - if (rts.colors.size() > 0 && rts.colors[0].canvas->getMSAA() > 1) + if (rts.colors.size() > 0 && rts.colors[0].texture->getMSAA() > 1) { int mip = rts.colors[0].mipmap; - int w = rts.colors[0].canvas->getPixelWidth(mip); - int h = rts.colors[0].canvas->getPixelHeight(mip); + int w = rts.colors[0].texture->getPixelWidth(mip); + int h = rts.colors[0].texture->getPixelHeight(mip); for (int i = 0; i < (int) rts.colors.size(); i++) { - Canvas *c = (Canvas *) rts.colors[i].canvas.get(); + // FIXME + Canvas *c = (Canvas *) rts.colors[i].texture.get(); if (!c->isReadable()) continue; @@ -619,13 +620,14 @@ void Graphics::endPass() for (const auto &rt : rts.colors) { - if (rt.canvas->getMipmapMode() == Canvas::MIPMAPS_AUTO && rt.mipmap == 0) - rt.canvas->generateMipmaps(); + // TODO +// if (rt.texture->getMipmapMode() == Canvas::MIPMAPS_AUTO && rt.mipmap == 0) +// rt.texture->generateMipmaps(); } - int dsmipmap = rts.depthStencil.mipmap; - if (depthstencil != nullptr && depthstencil->getMipmapMode() == Canvas::MIPMAPS_AUTO && dsmipmap == 0) - depthstencil->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) @@ -818,25 +820,28 @@ void Graphics::discard(OpenGL::FramebufferTarget target, const std::vector glDiscardFramebufferEXT(gltarget, (GLint) attachments.size(), &attachments[0]); } -void Graphics::cleanupCanvas(Canvas *canvas) +void Graphics::cleanupCanvas(Canvas *texture) { + if (!texture->isRenderTarget()) + return; + for (auto it = framebufferObjects.begin(); it != framebufferObjects.end(); /**/) { - bool hascanvas = false; + bool hastexture = false; const auto &rts = it->first; for (const RenderTarget &rt : rts.colors) { - if (rt.canvas == canvas) + if (rt.texture == texture) { - hascanvas = true; + hastexture = true; break; } } - hascanvas = hascanvas || rts.depthStencil.canvas == canvas; + hastexture = hastexture || rts.depthStencil.texture == texture; - if (hascanvas) + if (hastexture) { if (isCreated()) gl.deleteFramebuffer(it->second); @@ -857,8 +862,8 @@ void Graphics::bindCachedFBO(const RenderTargets &targets) } else { - int msaa = targets.getFirstTarget().canvas->getMSAA(); - bool hasDS = targets.depthStencil.canvas != nullptr; + int msaa = targets.getFirstTarget().texture->getMSAA(); + bool hasDS = targets.depthStencil.texture != nullptr; glGenFramebuffers(1, &fbo); gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, fbo); @@ -868,9 +873,9 @@ void Graphics::bindCachedFBO(const RenderTargets &targets) auto attachCanvas = [&](const RenderTarget &rt) { - bool renderbuffer = msaa > 1 || !rt.canvas->isReadable(); + bool renderbuffer = msaa > 1 || !rt.texture->isReadable(); bool srgb = false; - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(rt.canvas->getPixelFormat(), renderbuffer, srgb); + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(rt.texture->getPixelFormat(), renderbuffer, srgb); if (fmt.framebufferAttachments[0] == GL_COLOR_ATTACHMENT0) { @@ -879,7 +884,7 @@ void Graphics::bindCachedFBO(const RenderTargets &targets) ncolortargets++; } - GLuint handle = (GLuint) rt.canvas->getRenderTargetHandle(); + GLuint handle = (GLuint) rt.texture->getRenderTargetHandle(); for (GLenum attachment : fmt.framebufferAttachments) { @@ -889,7 +894,7 @@ void Graphics::bindCachedFBO(const RenderTargets &targets) glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, handle); else { - TextureType textype = rt.canvas->getTextureType(); + TextureType textype = rt.texture->getTextureType(); int layer = textype == TEXTURE_CUBE ? 0 : rt.slice; int face = textype == TEXTURE_CUBE ? rt.slice : 0; @@ -1056,20 +1061,20 @@ void Graphics::present(void *screenshotCallbackData) // Reset the per-frame stat counts. drawCalls = 0; gl.stats.shaderSwitches = 0; - canvasSwitchCount = 0; + renderTargetSwitchCount = 0; drawCallsBatched = 0; - // This assumes temporary canvases will only be used within a render pass. - for (int i = (int) temporaryCanvases.size() - 1; i >= 0; i--) + // This assumes temporary textures will only be used within a render pass. + for (int i = (int) temporaryTextures.size() - 1; i >= 0; i--) { - if (temporaryCanvases[i].framesSinceUse >= MAX_TEMPORARY_CANVAS_UNUSED_FRAMES) + if (temporaryTextures[i].framesSinceUse >= MAX_TEMPORARY_TEXTURE_UNUSED_FRAMES) { - temporaryCanvases[i].canvas->release(); - temporaryCanvases[i] = temporaryCanvases.back(); - temporaryCanvases.pop_back(); + temporaryTextures[i].texture->release(); + temporaryTextures[i] = temporaryTextures.back(); + temporaryTextures.pop_back(); } else - temporaryCanvases[i].framesSinceUse++; + temporaryTextures[i].framesSinceUse++; } } @@ -1111,11 +1116,11 @@ void Graphics::setScissor() void Graphics::drawToStencilBuffer(StencilAction action, int value) { const auto &rts = states.back().renderTargets; - love::graphics::Canvas *dscanvas = rts.depthStencil.canvas.get(); + love::graphics::Texture *dstexture = rts.depthStencil.texture.get(); if (!isCanvasActive() && !windowHasStencil) throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer."); - else if (isCanvasActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dscanvas == nullptr || !isPixelFormatStencil(dscanvas->getPixelFormat()))) + else if (isCanvasActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat()))) throw love::Exception("Drawing to the stencil buffer with a Canvas active requires either stencil=true or a custom stencil-type Canvas to be used, in setCanvas."); flushStreamDraws(); diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 837390585..3a711d2c1 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -126,7 +126,7 @@ private: for (size_t i = 0; i < rts.colors.size(); i++) hashtargets[hashcount++] = rts.colors[i]; - if (rts.depthStencil.canvas != nullptr) + if (rts.depthStencil.texture != nullptr) hashtargets[hashcount++] = rts.depthStencil; else if (rts.temporaryRTFlags != 0) hashtargets[hashcount++] = RenderTarget(nullptr, -1, rts.temporaryRTFlags); diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index a724b003b..95750aad5 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -148,7 +148,7 @@ void Image::loadData() d = std::max(d / 2, 1); } - if (mipmapsType == MIPMAPS_GENERATED) + if (getMipmapCount() > 1 && slices.getMipmapCount() <= 1) generateMipmaps(); } @@ -200,22 +200,11 @@ bool Image::loadVolatile() OpenGL::TempDebugGroup debuggroup("Image load"); - if (!isCompressed()) - { - // GL_EXT_sRGB doesn't support glGenerateMipmap for sRGB textures. - if (sRGB && (GLAD_ES_VERSION_2_0 && GLAD_EXT_sRGB && !GLAD_ES_VERSION_3_0) - && mipmapsType != MIPMAPS_DATA) - { - mipmapsType = MIPMAPS_NONE; - samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; - } - } - // NPOT textures don't support mipmapping without full NPOT support. if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight))) { - mipmapsType = MIPMAPS_NONE; + mipmapCount = 1; samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; } @@ -231,11 +220,6 @@ bool Image::loadVolatile() setSamplerState(samplerState); - GLenum gltextype = OpenGL::getGLTextureType(texType); - - if (mipmapsType == MIPMAPS_NONE && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0)) - glTexParameteri(gltextype, GL_TEXTURE_MAX_LEVEL, 0); - while (glGetError() != GL_NO_ERROR); // Clear errors. try diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 31b5a8d85..984140633 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -1794,10 +1794,10 @@ bool OpenGL::isPixelFormatSupported(PixelFormat pixelformat, bool rendertarget, && (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB)); } else - return GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB; + return GLAD_ES_VERSION_3_0; } else - return GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB; + return GLAD_ES_VERSION_3_0 || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB; case PIXELFORMAT_R16_UNORM: case PIXELFORMAT_RG16_UNORM: return GLAD_VERSION_3_0 diff --git a/src/modules/graphics/wrap_Canvas.cpp b/src/modules/graphics/wrap_Canvas.cpp index 5394d7c82..ee2b3be24 100644 --- a/src/modules/graphics/wrap_Canvas.cpp +++ b/src/modules/graphics/wrap_Canvas.cpp @@ -37,7 +37,7 @@ int w_Canvas_renderTo(lua_State *L) int startidx = 2; - if (rt.canvas->getTextureType() != TEXTURE_2D) + if (rt.texture->getTextureType() != TEXTURE_2D) { rt.slice = (int) luaL_checkinteger(L, 2) - 1; startidx++; @@ -53,10 +53,10 @@ int w_Canvas_renderTo(lua_State *L) Graphics::RenderTargets oldtargets = graphics->getCanvas(); for (auto c : oldtargets.colors) - c.canvas->retain(); + c.texture->retain(); - if (oldtargets.depthStencil.canvas != nullptr) - oldtargets.depthStencil.canvas->retain(); + if (oldtargets.depthStencil.texture != nullptr) + oldtargets.depthStencil.texture->retain(); luax_catchexcept(L, [&](){ graphics->setCanvas(rt, false); }); @@ -66,10 +66,10 @@ int w_Canvas_renderTo(lua_State *L) graphics->setCanvas(oldtargets); for (auto c : oldtargets.colors) - c.canvas->release(); + c.texture->release(); - if (oldtargets.depthStencil.canvas != nullptr) - oldtargets.depthStencil.canvas->release(); + if (oldtargets.depthStencil.texture != nullptr) + oldtargets.depthStencil.texture->release(); if (status != 0) return lua_error(L); @@ -119,8 +119,8 @@ int w_Canvas_getMipmapMode(lua_State *L) { Canvas *c = luax_checkcanvas(L, 1); const char *str; - if (!Canvas::getConstant(c->getMipmapMode(), str)) - return luax_enumerror(L, "mipmap mode", Canvas::getConstants(Canvas::MIPMAPS_MAX_ENUM), str); + if (!Texture::getConstant(c->getMipmapsMode(), str)) + return luax_enumerror(L, "mipmap mode", Texture::getConstants(Texture::MIPMAPS_MAX_ENUM), str); lua_pushstring(L, str); return 1; diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index e15629d4a..4b11756d5 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -252,7 +252,7 @@ static Graphics::RenderTarget checkRenderTarget(lua_State *L, int idx) Graphics::RenderTarget target(luax_checkcanvas(L, -1), 0); lua_pop(L, 1); - TextureType type = target.canvas->getTextureType(); + TextureType type = target.texture->getTextureType(); if (type == TEXTURE_2D_ARRAY || type == TEXTURE_VOLUME) target.slice = luax_checkintflag(L, idx, "layer") - 1; else if (type == TEXTURE_CUBE) @@ -294,7 +294,7 @@ int w_setCanvas(lua_State *L) { targets.colors.emplace_back(luax_checkcanvas(L, -1), 0); - if (targets.colors.back().canvas->getTextureType() != TEXTURE_2D) + if (targets.colors.back().texture->getTextureType() != TEXTURE_2D) return luaL_error(L, "Non-2D canvases must use the table-of-tables variant of setCanvas."); } @@ -311,13 +311,13 @@ int w_setCanvas(lua_State *L) else if (dstype == LUA_TBOOLEAN) targets.temporaryRTFlags |= luax_toboolean(L, -1) ? (tempdepthflag | tempstencilflag) : 0; else if (dstype != LUA_TNONE && dstype != LUA_TNIL) - targets.depthStencil.canvas = luax_checkcanvas(L, -1); + targets.depthStencil.texture = luax_checkcanvas(L, -1); lua_pop(L, 1); - if (targets.depthStencil.canvas == nullptr && (targets.temporaryRTFlags & tempdepthflag) == 0) + if (targets.depthStencil.texture == nullptr && (targets.temporaryRTFlags & tempdepthflag) == 0) targets.temporaryRTFlags |= luax_boolflag(L, 1, "depth", false) ? tempdepthflag : 0; - if (targets.depthStencil.canvas == nullptr && (targets.temporaryRTFlags & tempstencilflag) == 0) + if (targets.depthStencil.texture == nullptr && (targets.temporaryRTFlags & tempstencilflag) == 0) targets.temporaryRTFlags |= luax_boolflag(L, 1, "stencil", false) ? tempstencilflag : 0; } else @@ -325,7 +325,7 @@ int w_setCanvas(lua_State *L) for (int i = 1; i <= lua_gettop(L); i++) { Graphics::RenderTarget target(luax_checkcanvas(L, i), 0); - TextureType type = target.canvas->getTextureType(); + TextureType type = target.texture->getTextureType(); if (i == 1 && type != TEXTURE_2D) { @@ -348,7 +348,7 @@ int w_setCanvas(lua_State *L) } luax_catchexcept(L, [&]() { - if (targets.getFirstTarget().canvas != nullptr) + if (targets.getFirstTarget().texture != nullptr) instance()->setCanvas(targets); else instance()->setCanvas(); @@ -361,10 +361,10 @@ static void pushRenderTarget(lua_State *L, const Graphics::RenderTarget &rt) { lua_createtable(L, 1, 2); - luax_pushtype(L, rt.canvas); + luax_pushtype(L, rt.texture); lua_rawseti(L, -2, 1); - TextureType type = rt.canvas->getTextureType(); + TextureType type = rt.texture->getTextureType(); if (type == TEXTURE_2D_ARRAY || type == TEXTURE_VOLUME) { @@ -392,13 +392,13 @@ int w_getCanvas(lua_State *L) return 1; } - bool shouldUseTablesVariant = targets.depthStencil.canvas != nullptr; + bool shouldUseTablesVariant = targets.depthStencil.texture != nullptr; if (!shouldUseTablesVariant) { for (const auto &rt : targets.colors) { - if (rt.mipmap != 0 || rt.canvas->getTextureType() != TEXTURE_2D) + if (rt.mipmap != 0 || rt.texture->getTextureType() != TEXTURE_2D) { shouldUseTablesVariant = true; break; @@ -416,7 +416,7 @@ int w_getCanvas(lua_State *L) lua_rawseti(L, -2, i + 1); } - if (targets.depthStencil.canvas != nullptr) + if (targets.depthStencil.texture != nullptr) { pushRenderTarget(L, targets.depthStencil); lua_setfield(L, -2, "depthstencil"); @@ -427,7 +427,7 @@ int w_getCanvas(lua_State *L) else { for (const auto &rt : targets.colors) - luax_pushtype(L, rt.canvas); + luax_pushtype(L, rt.texture); return ntargets; } @@ -1240,8 +1240,8 @@ int w_newCanvas(lua_State *L) if (!lua_isnoneornil(L, -1)) { const char *str = luaL_checkstring(L, -1); - if (!Canvas::getConstant(str, settings.mipmaps)) - return luax_enumerror(L, "Canvas mipmap mode", Canvas::getConstants(settings.mipmaps), str); + if (!Texture::getConstant(str, settings.mipmaps)) + return luax_enumerror(L, "Texture mipmap mode", Texture::getConstants(settings.mipmaps), str); } lua_pop(L, 1); } @@ -2388,7 +2388,7 @@ int w_getStats(lua_State *L) lua_pushinteger(L, stats.drawCallsBatched); lua_setfield(L, -2, "drawcallsbatched"); - lua_pushinteger(L, stats.canvasSwitches); + lua_pushinteger(L, stats.renderTargetSwitches); lua_setfield(L, -2, "canvasswitches"); lua_pushinteger(L, stats.shaderSwitches); diff --git a/src/modules/graphics/wrap_Image.cpp b/src/modules/graphics/wrap_Image.cpp index db04b5b42..a58105438 100644 --- a/src/modules/graphics/wrap_Image.cpp +++ b/src/modules/graphics/wrap_Image.cpp @@ -40,7 +40,7 @@ int w_Image_replacePixels(lua_State *L) int mipmap = 0; int x = 0; int y = 0; - bool reloadmipmaps = i->getMipmapsType() == Image::MIPMAPS_GENERATED; + bool reloadmipmaps = false; // TODO i->getMipmapsSource() == Texture::MIPMAPS_SOURCE_GENERATED; if (i->getTextureType() != TEXTURE_2D) slice = (int) luaL_checkinteger(L, 3) - 1; From 4716211c149814451445ef8d221c4d9cd18eb835 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Feb 2020 19:05:43 -0400 Subject: [PATCH 09/31] Move replacePixels from Image to Texture --- src/modules/graphics/Image.cpp | 65 ---------------- src/modules/graphics/Image.h | 10 --- src/modules/graphics/Texture.cpp | 82 ++++++++++++++++++++ src/modules/graphics/Texture.h | 14 +++- src/modules/graphics/opengl/Canvas.cpp | 31 ++++++++ src/modules/graphics/opengl/Canvas.h | 2 + src/modules/graphics/wrap_Canvas.cpp | 8 -- src/modules/graphics/wrap_Image.cpp | 30 ------- src/modules/graphics/wrap_Mesh.cpp | 9 +-- src/modules/graphics/wrap_ParticleSystem.cpp | 11 +-- src/modules/graphics/wrap_SpriteBatch.cpp | 11 +-- src/modules/graphics/wrap_Texture.cpp | 38 +++++++++ 12 files changed, 168 insertions(+), 143 deletions(-) diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index f7fd92529..ed3ca5d47 100644 --- a/src/modules/graphics/Image.cpp +++ b/src/modules/graphics/Image.cpp @@ -34,7 +34,6 @@ love::Type Image::type("Image", &Texture::type); Image::Image(TextureType textype, const Settings &settings) : Texture(textype) , settings(settings) - , usingDefaultTexture(false) { renderTarget = false; sRGB = isGammaCorrect() && !settings.linear; @@ -105,70 +104,6 @@ void Image::init(PixelFormat fmt, int w, int h, int dataMipmaps, const Settings initQuad(); } -void Image::uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y) -{ - love::image::ImageData *id = dynamic_cast(d); - - love::thread::EmptyLock lock; - if (id != nullptr) - lock.setLock(id->getMutex()); - - Rect rect = {x, y, d->getWidth(), d->getHeight()}; - uploadByteData(d->getFormat(), d->getData(), d->getSize(), level, slice, rect, d); -} - -void Image::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps) -{ - // No effect if the texture hasn't been created yet. - if (getHandle() == 0 || usingDefaultTexture) - return; - - if (d->getFormat() != getPixelFormat()) - throw love::Exception("Pixel formats must match."); - - if (mipmap < 0 || mipmap >= getMipmapCount()) - throw love::Exception("Invalid image mipmap index %d.", mipmap + 1); - - if (slice < 0 || (texType == TEXTURE_CUBE && slice >= 6) - || (texType == TEXTURE_VOLUME && slice >= getDepth(mipmap)) - || (texType == TEXTURE_2D_ARRAY && slice >= getLayerCount())) - { - throw love::Exception("Invalid image slice index %d.", slice + 1); - } - - Rect rect = {x, y, d->getWidth(), d->getHeight()}; - - int mipw = getPixelWidth(mipmap); - int miph = getPixelHeight(mipmap); - - if (rect.x < 0 || rect.y < 0 || rect.w <= 0 || rect.h <= 0 - || (rect.x + rect.w) > mipw || (rect.y + rect.h) > miph) - { - throw love::Exception("Invalid rectangle dimensions (x=%d, y=%d, w=%d, h=%d) for %dx%d Image.", rect.x, rect.y, rect.w, rect.h, mipw, miph); - } - - // We don't currently support partial updates of compressed textures. - if (isPixelFormatCompressed(d->getFormat()) && (rect.x != 0 || rect.y != 0 || rect.w != mipw || rect.h != miph)) - throw love::Exception("Compressed textures only support replacing the entire Image."); - - Graphics::flushStreamDrawsGlobal(); - - uploadImageData(d, mipmap, slice, x, y); - - if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1) - generateMipmaps(); -} - -void Image::replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps) -{ - Graphics::flushStreamDrawsGlobal(); - - uploadByteData(format, data, size, mipmap, slice, rect, nullptr); - - if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1) - generateMipmaps(); -} - bool Image::getConstant(const char *in, SettingType &out) { return settingTypes.find(in, out); diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Image.h index 1fd9fdd07..9893f7d8f 100644 --- a/src/modules/graphics/Image.h +++ b/src/modules/graphics/Image.h @@ -54,9 +54,6 @@ public: virtual ~Image(); - void replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps); - void replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps); - static bool getConstant(const char *in, SettingType &out); static bool getConstant(SettingType in, const char *&out); static const char *getConstant(SettingType in); @@ -67,16 +64,9 @@ protected: Image(const Slices &data, const Settings &settings); Image(TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings); - void uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y); - virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) = 0; - // The settings used to initialize this Image. Settings settings; - // True if the image wasn't able to be properly created and it had to fall - // back to a default texture. - bool usingDefaultTexture; - private: Image(TextureType textype, const Settings &settings); diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index bf380e32d..7d3185489 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -175,6 +175,7 @@ Texture::Texture(TextureType texType) , requestedMSAA(1) , samplerState() , graphicsMemorySize(0) + , usingDefaultTexture(false) { auto gfx = Module::getInstance(Module::M_GRAPHICS); if (gfx != nullptr) @@ -358,6 +359,87 @@ void Texture::drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &m) } } +void Texture::uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y) +{ + love::image::ImageData *id = dynamic_cast(d); + + love::thread::EmptyLock lock; + if (id != nullptr) + lock.setLock(id->getMutex()); + + Rect rect = {x, y, d->getWidth(), d->getHeight()}; + uploadByteData(d->getFormat(), d->getData(), d->getSize(), level, slice, rect, d); +} + +void Texture::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps) +{ + if (!isReadable()) + throw love::Exception("replacePixels can only be called on readable Textures."); + + if (getMSAA() > 1) + throw love::Exception("replacePixels cannot be called on a MSAA Texture."); + + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (gfx != nullptr && gfx->isRenderTargetActive(this)) + throw love::Exception("replacePixels cannot be called on this Texture while it's an active render target."); + + // No effect if the texture hasn't been created yet. + if (getHandle() == 0 || usingDefaultTexture) + return; + + if (d->getFormat() != getPixelFormat()) + throw love::Exception("Pixel formats must match."); + + if (mipmap < 0 || mipmap >= getMipmapCount()) + throw love::Exception("Invalid texture mipmap index %d.", mipmap + 1); + + if (slice < 0 || (texType == TEXTURE_CUBE && slice >= 6) + || (texType == TEXTURE_VOLUME && slice >= getDepth(mipmap)) + || (texType == TEXTURE_2D_ARRAY && slice >= getLayerCount())) + { + throw love::Exception("Invalid texture slice index %d.", slice + 1); + } + + Rect rect = {x, y, d->getWidth(), d->getHeight()}; + + int mipw = getPixelWidth(mipmap); + int miph = getPixelHeight(mipmap); + + if (rect.x < 0 || rect.y < 0 || rect.w <= 0 || rect.h <= 0 + || (rect.x + rect.w) > mipw || (rect.y + rect.h) > miph) + { + throw love::Exception("Invalid rectangle dimensions (x=%d, y=%d, w=%d, h=%d) for %dx%d Texture.", rect.x, rect.y, rect.w, rect.h, mipw, miph); + } + + // We don't currently support partial updates of compressed textures. + if (isPixelFormatCompressed(d->getFormat()) && (rect.x != 0 || rect.y != 0 || rect.w != mipw || rect.h != miph)) + throw love::Exception("Compressed textures only support replacing the entire Texture."); + + Graphics::flushStreamDrawsGlobal(); + + uploadImageData(d, mipmap, slice, x, y); + + if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1) + generateMipmaps(); +} + +void Texture::replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps) +{ + if (!isReadable() || getMSAA() > 1) + return; + + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (gfx != nullptr && gfx->isRenderTargetActive(this)) + return; + + Graphics::flushStreamDrawsGlobal(); + + uploadByteData(format, data, size, mipmap, slice, rect, nullptr); + + if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1) + generateMipmaps(); +} + int Texture::getWidth(int mip) const { return std::max(width >> mip, 1); diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 011d8a04f..c6823e707 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -182,6 +182,11 @@ public: void drawLayer(Graphics *gfx, int layer, const Matrix4 &m); void drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m); + void replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps); + void replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps); + + virtual void generateMipmaps() = 0; + virtual ptrdiff_t getRenderTargetHandle() const = 0; TextureType getTextureType() const; @@ -212,8 +217,6 @@ public: virtual void setSamplerState(const SamplerState &s); const SamplerState &getSamplerState() const; - virtual void generateMipmaps() = 0; - Quad *getQuad() const; static int getTotalMipmapCount(int w, int h); @@ -232,6 +235,9 @@ protected: void initQuad(); void setGraphicsMemorySize(int64 size); + void uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y); + virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) = 0; + bool validateDimensions(bool throwException) const; TextureType texType; @@ -260,6 +266,10 @@ protected: int64 graphicsMemorySize; + // True if the image wasn't able to be properly created and it had to fall + // back to a default texture. + bool usingDefaultTexture; + private: static StringMap::Entry texTypeEntries[]; diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 0a20ed94a..a00fc4594 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -389,6 +389,37 @@ void Canvas::generateMipmaps() glGenerateMipmap(gltextype); } +void Canvas::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase */*imgd*/) +{ + OpenGL::TempDebugGroup debuggroup("Texture data upload"); + + gl.bindTextureToUnit(this, 0, false); + + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, false, sRGB); + GLenum gltarget = OpenGL::getGLTextureType(texType); + + if (texType == TEXTURE_CUBE) + gltarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice; + + if (isPixelFormatCompressed(pixelformat)) + { + if (r.x != 0 || r.y != 0) + throw love::Exception("x and y parameters must be 0 for compressed images."); + + if (texType == TEXTURE_2D || texType == TEXTURE_CUBE) + glCompressedTexImage2D(gltarget, level, fmt.internalformat, r.w, r.h, 0, size, data); + else if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) + glCompressedTexSubImage3D(gltarget, level, 0, 0, slice, r.w, r.h, 1, fmt.internalformat, size, data); + } + else + { + if (texType == TEXTURE_2D || texType == TEXTURE_CUBE) + glTexSubImage2D(gltarget, level, r.x, r.y, r.w, r.h, fmt.externalformat, fmt.type, data); + else if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) + glTexSubImage3D(gltarget, level, r.x, r.y, slice, r.w, r.h, 1, fmt.externalformat, fmt.type, data); + } +} + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index deb6b8e48..d1bc3cb1c 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -70,6 +70,8 @@ public: private: + void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override; + GLuint fbo; GLuint texture; diff --git a/src/modules/graphics/wrap_Canvas.cpp b/src/modules/graphics/wrap_Canvas.cpp index ee2b3be24..d62f582f3 100644 --- a/src/modules/graphics/wrap_Canvas.cpp +++ b/src/modules/graphics/wrap_Canvas.cpp @@ -108,13 +108,6 @@ int w_Canvas_newImageData(lua_State *L) return 1; } -int w_Canvas_generateMipmaps(lua_State *L) -{ - Canvas *c = luax_checkcanvas(L, 1); - luax_catchexcept(L, [&]() { c->generateMipmaps(); }); - return 0; -} - int w_Canvas_getMipmapMode(lua_State *L) { Canvas *c = luax_checkcanvas(L, 1); @@ -130,7 +123,6 @@ static const luaL_Reg w_Canvas_functions[] = { { "renderTo", w_Canvas_renderTo }, { "newImageData", w_Canvas_newImageData }, - { "generateMipmaps", w_Canvas_generateMipmaps }, { "getMipmapMode", w_Canvas_getMipmapMode }, { 0, 0 } }; diff --git a/src/modules/graphics/wrap_Image.cpp b/src/modules/graphics/wrap_Image.cpp index a58105438..177a2866d 100644 --- a/src/modules/graphics/wrap_Image.cpp +++ b/src/modules/graphics/wrap_Image.cpp @@ -31,38 +31,8 @@ Image *luax_checkimage(lua_State *L, int idx) return luax_checktype(L, idx); } -int w_Image_replacePixels(lua_State *L) -{ - Image *i = luax_checkimage(L, 1); - love::image::ImageData *id = luax_checktype(L, 2); - - int slice = 0; - int mipmap = 0; - int x = 0; - int y = 0; - bool reloadmipmaps = false; // TODO i->getMipmapsSource() == Texture::MIPMAPS_SOURCE_GENERATED; - - if (i->getTextureType() != TEXTURE_2D) - slice = (int) luaL_checkinteger(L, 3) - 1; - - mipmap = (int) luaL_optinteger(L, 4, 1) - 1; - - if (!lua_isnoneornil(L, 5)) - { - x = (int) luaL_checkinteger(L, 5); - y = (int) luaL_checkinteger(L, 6); - - if (reloadmipmaps) - reloadmipmaps = luax_optboolean(L, 7, reloadmipmaps); - } - - luax_catchexcept(L, [&](){ i->replacePixels(id, slice, mipmap, x, y, reloadmipmaps); }); - return 0; -} - static const luaL_Reg w_Image_functions[] = { - { "replacePixels", w_Image_replacePixels }, { 0, 0 } }; diff --git a/src/modules/graphics/wrap_Mesh.cpp b/src/modules/graphics/wrap_Mesh.cpp index 9e238dec1..5f1814f56 100644 --- a/src/modules/graphics/wrap_Mesh.cpp +++ b/src/modules/graphics/wrap_Mesh.cpp @@ -552,14 +552,7 @@ int w_Mesh_getTexture(lua_State *L) if (tex == nullptr) return 0; - // FIXME: big hack right here. - if (dynamic_cast(tex) != nullptr) - luax_pushtype(L, Image::type, tex); - else if (dynamic_cast(tex) != nullptr) - luax_pushtype(L, Canvas::type, tex); - else - return luaL_error(L, "Unable to determine texture type."); - + luax_pushtype(L, tex); return 1; } diff --git a/src/modules/graphics/wrap_ParticleSystem.cpp b/src/modules/graphics/wrap_ParticleSystem.cpp index 8c6c29dda..637dcc710 100644 --- a/src/modules/graphics/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/wrap_ParticleSystem.cpp @@ -62,16 +62,7 @@ int w_ParticleSystem_setTexture(lua_State *L) int w_ParticleSystem_getTexture(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); - Texture *tex = t->getTexture(); - - // FIXME: big hack right here. - if (dynamic_cast(tex) != nullptr) - luax_pushtype(L, Image::type, tex); - else if (dynamic_cast(tex) != nullptr) - luax_pushtype(L, Canvas::type, tex); - else - return luaL_error(L, "Unable to determine texture type."); - + luax_pushtype(L, t->getTexture()); return 1; } diff --git a/src/modules/graphics/wrap_SpriteBatch.cpp b/src/modules/graphics/wrap_SpriteBatch.cpp index 7986f042e..c98bd5d71 100644 --- a/src/modules/graphics/wrap_SpriteBatch.cpp +++ b/src/modules/graphics/wrap_SpriteBatch.cpp @@ -153,16 +153,7 @@ int w_SpriteBatch_setTexture(lua_State *L) int w_SpriteBatch_getTexture(lua_State *L) { SpriteBatch *t = luax_checkspritebatch(L, 1); - Texture *tex = t->getTexture(); - - // FIXME: big hack right here. - if (dynamic_cast(tex) != nullptr) - luax_pushtype(L, Image::type, tex); - else if (dynamic_cast(tex) != nullptr) - luax_pushtype(L, Canvas::type, tex); - else - return luaL_error(L, "Unable to determine texture type."); - + luax_pushtype(L, t->getTexture()); return 1; } diff --git a/src/modules/graphics/wrap_Texture.cpp b/src/modules/graphics/wrap_Texture.cpp index af45ca44d..f4bcb653a 100644 --- a/src/modules/graphics/wrap_Texture.cpp +++ b/src/modules/graphics/wrap_Texture.cpp @@ -322,6 +322,42 @@ int w_Texture_getDepthSampleMode(lua_State *L) return 1; } +int w_Texture_generateMipmaps(lua_State *L) +{ + Texture *t = luax_checktexture(L, 1); + luax_catchexcept(L, [&]() { t->generateMipmaps(); }); + return 0; +} + +int w_Texture_replacePixels(lua_State *L) +{ + Texture *t = luax_checktexture(L, 1); + love::image::ImageData *id = luax_checktype(L, 2); + + int slice = 0; + int mipmap = 0; + int x = 0; + int y = 0; + bool reloadmipmaps = false; // TODO i->getMipmapsSource() == Texture::MIPMAPS_SOURCE_GENERATED; + + if (t->getTextureType() != TEXTURE_2D) + slice = (int) luaL_checkinteger(L, 3) - 1; + + mipmap = (int) luaL_optinteger(L, 4, 1) - 1; + + if (!lua_isnoneornil(L, 5)) + { + x = (int) luaL_checkinteger(L, 5); + y = (int) luaL_checkinteger(L, 6); + + if (reloadmipmaps) + reloadmipmaps = luax_optboolean(L, 7, reloadmipmaps); + } + + luax_catchexcept(L, [&](){ t->replacePixels(id, slice, mipmap, x, y, reloadmipmaps); }); + return 0; +} + const luaL_Reg w_Texture_functions[] = { { "getTextureType", w_Texture_getTextureType }, @@ -348,6 +384,8 @@ const luaL_Reg w_Texture_functions[] = { "isReadable", w_Texture_isReadable }, { "getDepthSampleMode", w_Texture_getDepthSampleMode }, { "setDepthSampleMode", w_Texture_setDepthSampleMode }, + { "generateMipmaps", w_Texture_generateMipmaps }, + { "replacePixels", w_Texture_replacePixels }, { 0, 0 } }; From 4104c136cfc05b3c3c59d30590fb74ad2522bf3f Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Feb 2020 19:19:37 -0400 Subject: [PATCH 10/31] Move Canvas:newImageData to Texture:newImageData --- src/modules/graphics/Canvas.cpp | 34 ------------------------ src/modules/graphics/Canvas.h | 2 -- src/modules/graphics/Texture.cpp | 37 +++++++++++++++++++++++++++ src/modules/graphics/Texture.h | 3 +++ src/modules/graphics/wrap_Canvas.cpp | 31 ---------------------- src/modules/graphics/wrap_Texture.cpp | 31 ++++++++++++++++++++++ 6 files changed, 71 insertions(+), 67 deletions(-) diff --git a/src/modules/graphics/Canvas.cpp b/src/modules/graphics/Canvas.cpp index 2866b0121..a4ac24f70 100644 --- a/src/modules/graphics/Canvas.cpp +++ b/src/modules/graphics/Canvas.cpp @@ -107,40 +107,6 @@ Texture::MipmapsMode Canvas::getMipmapsMode() const return settings.mipmaps; } -love::image::ImageData *Canvas::newImageData(love::image::Image *module, int slice, int mipmap, const Rect &r) -{ - if (!isReadable()) - throw love::Exception("Canvas:newImageData cannot be called on non-readable Canvases."); - - if (isPixelFormatDepthStencil(getPixelFormat())) - throw love::Exception("Canvas:newImageData cannot be called on Canvases with depth/stencil pixel formats."); - - if (r.x < 0 || r.y < 0 || r.w <= 0 || r.h <= 0 || (r.x + r.w) > getPixelWidth(mipmap) || (r.y + r.h) > getPixelHeight(mipmap)) - throw love::Exception("Invalid rectangle dimensions."); - - if (slice < 0 || (texType == TEXTURE_VOLUME && slice >= getDepth(mipmap)) - || (texType == TEXTURE_2D_ARRAY && slice >= layers) - || (texType == TEXTURE_CUBE && slice >= 6)) - { - throw love::Exception("Invalid slice index."); - } - - Graphics *gfx = Module::getInstance(Module::M_GRAPHICS); - if (gfx != nullptr && gfx->isRenderTargetActive(this)) - throw love::Exception("Canvas:newImageData cannot be called while that Canvas is currently active."); - - PixelFormat dataformat = getLinearPixelFormat(getPixelFormat()); - - if (!image::ImageData::validPixelFormat(dataformat)) - { - const char *formatname = "unknown"; - love::getConstant(dataformat, formatname); - throw love::Exception("ImageData with the '%s' pixel format is not supported.", formatname); - } - - return module->newImageData(r.w, r.h, dataformat); -} - bool Canvas::getConstant(const char *in, SettingType &out) { return settingTypes.find(in, out); diff --git a/src/modules/graphics/Canvas.h b/src/modules/graphics/Canvas.h index d683e9d5d..9b18ef7e2 100644 --- a/src/modules/graphics/Canvas.h +++ b/src/modules/graphics/Canvas.h @@ -71,8 +71,6 @@ public: MipmapsMode getMipmapsMode() const; - virtual love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect); - static bool getConstant(const char *in, SettingType &out); static bool getConstant(SettingType in, const char *&out); static const char *getConstant(SettingType in); diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 7d3185489..4aaa6a972 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -440,6 +440,43 @@ void Texture::replacePixels(const void *data, size_t size, int slice, int mipmap generateMipmaps(); } +love::image::ImageData *Texture::newImageData(love::image::Image *module, int slice, int mipmap, const Rect &r) +{ + if (!isReadable()) + throw love::Exception("Texture:newImageData cannot be called on non-readable Textures."); + + if (!isRenderTarget()) + throw love::Exception("Texture:newImageData can only be called on render target Textures."); + + if (isPixelFormatDepthStencil(getPixelFormat())) + throw love::Exception("Texture:newImageData cannot be called on Textures with depth/stencil pixel formats."); + + if (r.x < 0 || r.y < 0 || r.w <= 0 || r.h <= 0 || (r.x + r.w) > getPixelWidth(mipmap) || (r.y + r.h) > getPixelHeight(mipmap)) + throw love::Exception("Invalid rectangle dimensions."); + + if (slice < 0 || (texType == TEXTURE_VOLUME && slice >= getDepth(mipmap)) + || (texType == TEXTURE_2D_ARRAY && slice >= layers) + || (texType == TEXTURE_CUBE && slice >= 6)) + { + throw love::Exception("Invalid slice index."); + } + + Graphics *gfx = Module::getInstance(Module::M_GRAPHICS); + if (gfx != nullptr && gfx->isRenderTargetActive(this)) + throw love::Exception("Texture:newImageData cannot be called while that Texture is an active render target."); + + PixelFormat dataformat = getLinearPixelFormat(getPixelFormat()); + + if (!image::ImageData::validPixelFormat(dataformat)) + { + const char *formatname = "unknown"; + love::getConstant(dataformat, formatname); + throw love::Exception("ImageData with the '%s' pixel format is not supported.", formatname); + } + + return module->newImageData(r.w, r.h, dataformat); +} + int Texture::getWidth(int mip) const { return std::max(width >> mip, 1); diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index c6823e707..eb4716c66 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -34,6 +34,7 @@ #include "renderstate.h" #include "Resource.h" #include "image/ImageData.h" +#include "image/Image.h" #include "image/CompressedImageData.h" // C @@ -187,6 +188,8 @@ public: virtual void generateMipmaps() = 0; + virtual love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect); + virtual ptrdiff_t getRenderTargetHandle() const = 0; TextureType getTextureType() const; diff --git a/src/modules/graphics/wrap_Canvas.cpp b/src/modules/graphics/wrap_Canvas.cpp index d62f582f3..40e493c1e 100644 --- a/src/modules/graphics/wrap_Canvas.cpp +++ b/src/modules/graphics/wrap_Canvas.cpp @@ -78,36 +78,6 @@ int w_Canvas_renderTo(lua_State *L) return 0; } -int w_Canvas_newImageData(lua_State *L) -{ - Canvas *canvas = luax_checkcanvas(L, 1); - love::image::Image *image = luax_getmodule(L, love::image::Image::type); - - int slice = 0; - int mipmap = 0; - Rect rect = {0, 0, canvas->getPixelWidth(), canvas->getPixelHeight()}; - - if (canvas->getTextureType() != TEXTURE_2D) - slice = (int) luaL_checkinteger(L, 2) - 1; - - mipmap = (int) luaL_optinteger(L, 3, 1) - 1; - - if (!lua_isnoneornil(L, 4)) - { - rect.x = (int) luaL_checkinteger(L, 4); - rect.y = (int) luaL_checkinteger(L, 5); - rect.w = (int) luaL_checkinteger(L, 6); - rect.h = (int) luaL_checkinteger(L, 7); - } - - love::image::ImageData *img = nullptr; - luax_catchexcept(L, [&](){ img = canvas->newImageData(image, slice, mipmap, rect); }); - - luax_pushtype(L, img); - img->release(); - return 1; -} - int w_Canvas_getMipmapMode(lua_State *L) { Canvas *c = luax_checkcanvas(L, 1); @@ -122,7 +92,6 @@ int w_Canvas_getMipmapMode(lua_State *L) static const luaL_Reg w_Canvas_functions[] = { { "renderTo", w_Canvas_renderTo }, - { "newImageData", w_Canvas_newImageData }, { "getMipmapMode", w_Canvas_getMipmapMode }, { 0, 0 } }; diff --git a/src/modules/graphics/wrap_Texture.cpp b/src/modules/graphics/wrap_Texture.cpp index f4bcb653a..87143887c 100644 --- a/src/modules/graphics/wrap_Texture.cpp +++ b/src/modules/graphics/wrap_Texture.cpp @@ -358,6 +358,36 @@ int w_Texture_replacePixels(lua_State *L) return 0; } +int w_Texture_newImageData(lua_State *L) +{ + Texture *t = luax_checktexture(L, 1); + love::image::Image *image = luax_getmodule(L, love::image::Image::type); + + int slice = 0; + int mipmap = 0; + Rect rect = {0, 0, t->getPixelWidth(), t->getPixelHeight()}; + + if (t->getTextureType() != TEXTURE_2D) + slice = (int) luaL_checkinteger(L, 2) - 1; + + mipmap = (int) luaL_optinteger(L, 3, 1) - 1; + + if (!lua_isnoneornil(L, 4)) + { + rect.x = (int) luaL_checkinteger(L, 4); + rect.y = (int) luaL_checkinteger(L, 5); + rect.w = (int) luaL_checkinteger(L, 6); + rect.h = (int) luaL_checkinteger(L, 7); + } + + love::image::ImageData *img = nullptr; + luax_catchexcept(L, [&](){ img = t->newImageData(image, slice, mipmap, rect); }); + + luax_pushtype(L, img); + img->release(); + return 1; +} + const luaL_Reg w_Texture_functions[] = { { "getTextureType", w_Texture_getTextureType }, @@ -386,6 +416,7 @@ const luaL_Reg w_Texture_functions[] = { "setDepthSampleMode", w_Texture_setDepthSampleMode }, { "generateMipmaps", w_Texture_generateMipmaps }, { "replacePixels", w_Texture_replacePixels }, + { "newImageData", w_Texture_newImageData }, { 0, 0 } }; From 0304bdf450f3a90cad7bf63d5892004f4a69f694 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Feb 2020 19:56:19 -0400 Subject: [PATCH 11/31] Move getMipmapMode from Canvas to Texture --- src/modules/graphics/Canvas.cpp | 10 +++------- src/modules/graphics/Canvas.h | 5 ----- src/modules/graphics/Image.cpp | 3 ++- src/modules/graphics/Texture.cpp | 6 ++++++ src/modules/graphics/Texture.h | 3 +++ src/modules/graphics/wrap_Canvas.cpp | 12 ------------ src/modules/graphics/wrap_Texture.cpp | 13 ++++++++++++- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/modules/graphics/Canvas.cpp b/src/modules/graphics/Canvas.cpp index a4ac24f70..c13b1e038 100644 --- a/src/modules/graphics/Canvas.cpp +++ b/src/modules/graphics/Canvas.cpp @@ -37,6 +37,7 @@ Canvas::Canvas(const Settings &settings) sRGB = false; requestedMSAA = settings.msaa; + mipmapsMode = settings.mipmaps; width = settings.width; height = settings.height; pixelWidth = (int) ((width * settings.dpiScale) + 0.5); @@ -63,10 +64,10 @@ Canvas::Canvas(const Settings &settings) if (readable && isPixelFormatDepthStencil(format) && settings.msaa > 1) throw love::Exception("Readable depth/stencil Canvases with MSAA are not currently supported."); - if ((!readable || settings.msaa > 1) && settings.mipmaps != MIPMAPS_NONE) + if ((!readable || settings.msaa > 1) && mipmapsMode != MIPMAPS_NONE) throw love::Exception("Non-readable and MSAA textures cannot have mipmaps."); - if (settings.mipmaps != MIPMAPS_NONE) + if (mipmapsMode != MIPMAPS_NONE) mipmapCount = getTotalMipmapCount(pixelWidth, pixelHeight, depth); auto gfx = Module::getInstance(Module::M_GRAPHICS); @@ -102,11 +103,6 @@ Canvas::~Canvas() { } -Texture::MipmapsMode Canvas::getMipmapsMode() const -{ - return settings.mipmaps; -} - bool Canvas::getConstant(const char *in, SettingType &out) { return settingTypes.find(in, out); diff --git a/src/modules/graphics/Canvas.h b/src/modules/graphics/Canvas.h index 9b18ef7e2..9c77152b2 100644 --- a/src/modules/graphics/Canvas.h +++ b/src/modules/graphics/Canvas.h @@ -69,8 +69,6 @@ public: Canvas(const Settings &settings); virtual ~Canvas(); - MipmapsMode getMipmapsMode() const; - static bool getConstant(const char *in, SettingType &out); static bool getConstant(SettingType in, const char *&out); static const char *getConstant(SettingType in); @@ -82,9 +80,6 @@ protected: private: - static StringMap::Entry mipmapEntries[]; - static StringMap mipmapModes; - static StringMap::Entry settingTypeEntries[]; static StringMap settingTypes; diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index ed3ca5d47..63d3694b7 100644 --- a/src/modules/graphics/Image.cpp +++ b/src/modules/graphics/Image.cpp @@ -90,13 +90,14 @@ void Image::init(PixelFormat fmt, int w, int h, int dataMipmaps, const Settings pixelWidth = w; pixelHeight = h; + mipmapsMode = settings.mipmaps ? MIPMAPS_MANUAL : MIPMAPS_NONE; width = (int) (pixelWidth / settings.dpiScale + 0.5); height = (int) (pixelHeight / settings.dpiScale + 0.5); format = fmt; - if (!settings.mipmaps || (isCompressed() && dataMipmaps <= 1)) + if (mipmapsMode == MIPMAPS_NONE || (isCompressed() && dataMipmaps <= 1)) mipmapCount = 1; else mipmapCount = getTotalMipmapCount(w, h, depth); diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 4aaa6a972..2f0131f00 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -164,6 +164,7 @@ Texture::Texture(TextureType texType) , format(PIXELFORMAT_UNKNOWN) , renderTarget(false) , readable(true) + , mipmapsMode(MIPMAPS_NONE) , sRGB(false) , width(0) , height(0) @@ -214,6 +215,11 @@ PixelFormat Texture::getPixelFormat() const return format; } +Texture::MipmapsMode Texture::getMipmapsMode() const +{ + return mipmapsMode; +} + bool Texture::isRenderTarget() const { return renderTarget; diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index eb4716c66..57172898a 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -194,6 +194,7 @@ public: TextureType getTextureType() const; PixelFormat getPixelFormat() const; + MipmapsMode getMipmapsMode() const; bool isRenderTarget() const; bool isReadable() const; @@ -249,6 +250,8 @@ protected: bool renderTarget; bool readable; + MipmapsMode mipmapsMode; + bool sRGB; int width; diff --git a/src/modules/graphics/wrap_Canvas.cpp b/src/modules/graphics/wrap_Canvas.cpp index 40e493c1e..167db507a 100644 --- a/src/modules/graphics/wrap_Canvas.cpp +++ b/src/modules/graphics/wrap_Canvas.cpp @@ -78,21 +78,9 @@ int w_Canvas_renderTo(lua_State *L) return 0; } -int w_Canvas_getMipmapMode(lua_State *L) -{ - Canvas *c = luax_checkcanvas(L, 1); - const char *str; - if (!Texture::getConstant(c->getMipmapsMode(), str)) - return luax_enumerror(L, "mipmap mode", Texture::getConstants(Texture::MIPMAPS_MAX_ENUM), str); - - lua_pushstring(L, str); - return 1; -} - static const luaL_Reg w_Canvas_functions[] = { { "renderTo", w_Canvas_renderTo }, - { "getMipmapMode", w_Canvas_getMipmapMode }, { 0, 0 } }; diff --git a/src/modules/graphics/wrap_Texture.cpp b/src/modules/graphics/wrap_Texture.cpp index 87143887c..a216a1139 100644 --- a/src/modules/graphics/wrap_Texture.cpp +++ b/src/modules/graphics/wrap_Texture.cpp @@ -322,6 +322,16 @@ int w_Texture_getDepthSampleMode(lua_State *L) return 1; } +int w_Texture_getMipmapMode(lua_State *L) +{ + Texture *t = luax_checktexture(L, 1); + const char *str; + if (!Texture::getConstant(t->getMipmapsMode(), str)) + return luax_enumerror(L, "mipmap mode", Texture::getConstants(Texture::MIPMAPS_MAX_ENUM), str); + lua_pushstring(L, str); + return 1; +} + int w_Texture_generateMipmaps(lua_State *L) { Texture *t = luax_checktexture(L, 1); @@ -338,7 +348,7 @@ int w_Texture_replacePixels(lua_State *L) int mipmap = 0; int x = 0; int y = 0; - bool reloadmipmaps = false; // TODO i->getMipmapsSource() == Texture::MIPMAPS_SOURCE_GENERATED; + bool reloadmipmaps = t->getMipmapsMode() == Texture::MIPMAPS_AUTO; if (t->getTextureType() != TEXTURE_2D) slice = (int) luaL_checkinteger(L, 3) - 1; @@ -412,6 +422,7 @@ const luaL_Reg w_Texture_functions[] = { "getWrap", w_Texture_getWrap }, { "getFormat", w_Texture_getFormat }, { "isReadable", w_Texture_isReadable }, + { "getMipmapMode", w_Texture_getMipmapMode }, { "getDepthSampleMode", w_Texture_getDepthSampleMode }, { "setDepthSampleMode", w_Texture_setDepthSampleMode }, { "generateMipmaps", w_Texture_generateMipmaps }, From 61a5f0c7e2da9df945bbd90c56497a9ba1cce866 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Feb 2020 20:05:31 -0400 Subject: [PATCH 12/31] Move Canvas:renderTo to Texture:renderTo. --- src/modules/graphics/wrap_Canvas.cpp | 48 ---------------------- src/modules/graphics/wrap_Texture.cpp | 59 +++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 48 deletions(-) diff --git a/src/modules/graphics/wrap_Canvas.cpp b/src/modules/graphics/wrap_Canvas.cpp index 167db507a..5aad53644 100644 --- a/src/modules/graphics/wrap_Canvas.cpp +++ b/src/modules/graphics/wrap_Canvas.cpp @@ -31,56 +31,8 @@ Canvas *luax_checkcanvas(lua_State *L, int idx) return luax_checktype(L, idx); } -int w_Canvas_renderTo(lua_State *L) -{ - Graphics::RenderTarget rt(luax_checkcanvas(L, 1)); - - int startidx = 2; - - if (rt.texture->getTextureType() != TEXTURE_2D) - { - rt.slice = (int) luaL_checkinteger(L, 2) - 1; - startidx++; - } - - luaL_checktype(L, startidx, LUA_TFUNCTION); - - auto graphics = Module::getInstance(Module::M_GRAPHICS); - - if (graphics) - { - // Save the current render targets so we can restore them when we're done. - Graphics::RenderTargets oldtargets = graphics->getCanvas(); - - for (auto c : oldtargets.colors) - c.texture->retain(); - - if (oldtargets.depthStencil.texture != nullptr) - oldtargets.depthStencil.texture->retain(); - - luax_catchexcept(L, [&](){ graphics->setCanvas(rt, false); }); - - lua_settop(L, 2); // make sure the function is on top of the stack - int status = lua_pcall(L, 0, 0, 0); - - graphics->setCanvas(oldtargets); - - for (auto c : oldtargets.colors) - c.texture->release(); - - if (oldtargets.depthStencil.texture != nullptr) - oldtargets.depthStencil.texture->release(); - - if (status != 0) - return lua_error(L); - } - - return 0; -} - static const luaL_Reg w_Canvas_functions[] = { - { "renderTo", w_Canvas_renderTo }, { 0, 0 } }; diff --git a/src/modules/graphics/wrap_Texture.cpp b/src/modules/graphics/wrap_Texture.cpp index a216a1139..a27b55c54 100644 --- a/src/modules/graphics/wrap_Texture.cpp +++ b/src/modules/graphics/wrap_Texture.cpp @@ -19,6 +19,7 @@ **/ #include "wrap_Texture.h" +#include "Graphics.h" namespace love { @@ -398,6 +399,63 @@ int w_Texture_newImageData(lua_State *L) return 1; } +int w_Texture_renderTo(lua_State *L) +{ + Graphics::RenderTarget rt(luax_checktexture(L, 1)); + + int startidx = 2; + + if (rt.texture->getTextureType() != TEXTURE_2D) + { + rt.slice = (int) luaL_checkinteger(L, 2) - 1; + startidx++; + } + + luaL_checktype(L, startidx, LUA_TFUNCTION); + + auto graphics = Module::getInstance(Module::M_GRAPHICS); + + if (graphics) + { + // Save the current render targets so we can restore them when we're done. + Graphics::RenderTargets oldtargets = graphics->getCanvas(); + + for (auto c : oldtargets.colors) + c.texture->retain(); + + if (oldtargets.depthStencil.texture != nullptr) + oldtargets.depthStencil.texture->retain(); + + luax_catchexcept(L, + [&]() { graphics->setCanvas(rt, 0); }, + [&](bool err) + { + if (err) + { + for (auto c : oldtargets.colors) + c.texture->release(); + } + } + ); + + lua_settop(L, 2); // make sure the function is on top of the stack + int status = lua_pcall(L, 0, 0, 0); + + graphics->setCanvas(oldtargets); + + for (auto c : oldtargets.colors) + c.texture->release(); + + if (oldtargets.depthStencil.texture != nullptr) + oldtargets.depthStencil.texture->release(); + + if (status != 0) + return lua_error(L); + } + + return 0; +} + const luaL_Reg w_Texture_functions[] = { { "getTextureType", w_Texture_getTextureType }, @@ -428,6 +486,7 @@ const luaL_Reg w_Texture_functions[] = { "generateMipmaps", w_Texture_generateMipmaps }, { "replacePixels", w_Texture_replacePixels }, { "newImageData", w_Texture_newImageData }, + { "renderTo", w_Texture_renderTo }, { 0, 0 } }; From c3b77e0a92fec3324108cedb9b561f2d790ae742 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Feb 2020 20:09:46 -0400 Subject: [PATCH 13/31] Remove wrap_Canvas and wrap_Image files --- CMakeLists.txt | 4 -- .../xcode/liblove.xcodeproj/project.pbxproj | 20 --------- src/modules/graphics/wrap_Canvas.cpp | 45 ------------------- src/modules/graphics/wrap_Canvas.h | 38 ---------------- src/modules/graphics/wrap_Graphics.cpp | 10 ++--- src/modules/graphics/wrap_Graphics.h | 3 +- src/modules/graphics/wrap_Image.cpp | 45 ------------------- src/modules/graphics/wrap_Image.h | 37 --------------- 8 files changed, 5 insertions(+), 197 deletions(-) delete mode 100644 src/modules/graphics/wrap_Canvas.cpp delete mode 100644 src/modules/graphics/wrap_Canvas.h delete mode 100644 src/modules/graphics/wrap_Image.cpp delete mode 100644 src/modules/graphics/wrap_Image.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 72953c5e4..52d259cb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -559,14 +559,10 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT src/modules/graphics/Video.h src/modules/graphics/Volatile.cpp src/modules/graphics/Volatile.h - src/modules/graphics/wrap_Canvas.cpp - src/modules/graphics/wrap_Canvas.h src/modules/graphics/wrap_Font.cpp src/modules/graphics/wrap_Font.h src/modules/graphics/wrap_Graphics.cpp src/modules/graphics/wrap_Graphics.h - src/modules/graphics/wrap_Image.cpp - src/modules/graphics/wrap_Image.h src/modules/graphics/wrap_Mesh.cpp src/modules/graphics/wrap_Mesh.h src/modules/graphics/wrap_ParticleSystem.cpp diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 79bc992f1..44419670b 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -790,9 +790,6 @@ FA1BA0A71E16F20600AA2803 /* Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0A51E16F20600AA2803 /* Canvas.cpp */; }; FA1BA0A81E16F20600AA2803 /* Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0A51E16F20600AA2803 /* Canvas.cpp */; }; FA1BA0A91E16F20600AA2803 /* Canvas.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1BA0A61E16F20600AA2803 /* Canvas.h */; }; - FA1BA0AC1E16F9EE00AA2803 /* wrap_Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0AA1E16F9EE00AA2803 /* wrap_Canvas.cpp */; }; - FA1BA0AD1E16F9EE00AA2803 /* wrap_Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0AA1E16F9EE00AA2803 /* wrap_Canvas.cpp */; }; - FA1BA0AE1E16F9EE00AA2803 /* wrap_Canvas.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1BA0AB1E16F9EE00AA2803 /* wrap_Canvas.h */; }; FA1BA0B11E16FD0800AA2803 /* Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */; }; FA1BA0B21E16FD0800AA2803 /* Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */; }; FA1BA0B31E16FD0800AA2803 /* Shader.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1BA0B01E16FD0800AA2803 /* Shader.h */; }; @@ -1063,9 +1060,6 @@ FADF54161E3DA08E00012CC0 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF54141E3DA08E00012CC0 /* Image.cpp */; }; FADF54171E3DA08E00012CC0 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF54141E3DA08E00012CC0 /* Image.cpp */; }; FADF54181E3DA08E00012CC0 /* Image.h in Headers */ = {isa = PBXBuildFile; fileRef = FADF54151E3DA08E00012CC0 /* Image.h */; }; - FADF541B1E3DA46C00012CC0 /* wrap_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF54191E3DA46C00012CC0 /* wrap_Image.cpp */; }; - FADF541C1E3DA46C00012CC0 /* wrap_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF54191E3DA46C00012CC0 /* wrap_Image.cpp */; }; - FADF541D1E3DA46C00012CC0 /* wrap_Image.h in Headers */ = {isa = PBXBuildFile; fileRef = FADF541A1E3DA46C00012CC0 /* wrap_Image.h */; }; FADF54201E3DA52C00012CC0 /* wrap_ParticleSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF541E1E3DA52C00012CC0 /* wrap_ParticleSystem.cpp */; }; FADF54211E3DA52C00012CC0 /* wrap_ParticleSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF541E1E3DA52C00012CC0 /* wrap_ParticleSystem.cpp */; }; FADF54221E3DA52C00012CC0 /* wrap_ParticleSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = FADF541F1E3DA52C00012CC0 /* wrap_ParticleSystem.h */; }; @@ -1807,8 +1801,6 @@ FA1BA0A11E16D97500AA2803 /* wrap_Font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Font.h; sourceTree = ""; }; FA1BA0A51E16F20600AA2803 /* Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Canvas.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; FA1BA0A61E16F20600AA2803 /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Canvas.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - FA1BA0AA1E16F9EE00AA2803 /* wrap_Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = wrap_Canvas.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - FA1BA0AB1E16F9EE00AA2803 /* wrap_Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Canvas.h; sourceTree = ""; }; FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Shader.cpp; sourceTree = ""; }; FA1BA0B01E16FD0800AA2803 /* Shader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shader.h; sourceTree = ""; }; FA1BA0B51E17043400AA2803 /* wrap_Shader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Shader.cpp; sourceTree = ""; }; @@ -2011,8 +2003,6 @@ FADF540C1E3D7CDD00012CC0 /* wrap_Video.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = wrap_Video.lua; sourceTree = ""; }; FADF54141E3DA08E00012CC0 /* Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Image.cpp; sourceTree = ""; }; FADF54151E3DA08E00012CC0 /* Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = ""; }; - FADF54191E3DA46C00012CC0 /* wrap_Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Image.cpp; sourceTree = ""; }; - FADF541A1E3DA46C00012CC0 /* wrap_Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Image.h; sourceTree = ""; }; FADF541E1E3DA52C00012CC0 /* wrap_ParticleSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_ParticleSystem.cpp; sourceTree = ""; }; FADF541F1E3DA52C00012CC0 /* wrap_ParticleSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_ParticleSystem.h; sourceTree = ""; }; FADF54231E3DA5BA00012CC0 /* Mesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mesh.cpp; sourceTree = ""; }; @@ -2879,16 +2869,12 @@ FADF54061E3D78F700012CC0 /* Video.h */, FA0B7BC01A95902C000E1D17 /* Volatile.cpp */, FA0B7BC11A95902C000E1D17 /* Volatile.h */, - FA1BA0AA1E16F9EE00AA2803 /* wrap_Canvas.cpp */, - FA1BA0AB1E16F9EE00AA2803 /* wrap_Canvas.h */, FA1BA0A01E16D97500AA2803 /* wrap_Font.cpp */, FA1BA0A11E16D97500AA2803 /* wrap_Font.h */, FADF54391E3DAFF700012CC0 /* wrap_Graphics.cpp */, FADF543A1E3DAFF700012CC0 /* wrap_Graphics.h */, FADF54371E3DAFBA00012CC0 /* wrap_Graphics.lua */, FA665DC321C34C900074BBD6 /* wrap_GraphicsShader.lua */, - FADF54191E3DA46C00012CC0 /* wrap_Image.cpp */, - FADF541A1E3DA46C00012CC0 /* wrap_Image.h */, FADF54281E3DAADA00012CC0 /* wrap_Mesh.cpp */, FADF54291E3DAADA00012CC0 /* wrap_Mesh.h */, FADF541E1E3DA52C00012CC0 /* wrap_ParticleSystem.cpp */, @@ -3936,7 +3922,6 @@ FAF140A51E20934C00F898D2 /* Scan.h in Headers */, FA0B7CE11A95902C000E1D17 /* Source.h in Headers */, FA24348621D401CB00B8918A /* attribute.h in Headers */, - FA1BA0AE1E16F9EE00AA2803 /* wrap_Canvas.h in Headers */, FAF140901E20934C00F898D2 /* PpContext.h in Headers */, FA0B7E621A95902C000E1D17 /* wrap_Physics.h in Headers */, FA0B7DF01A95902C000E1D17 /* Mouse.h in Headers */, @@ -3974,7 +3959,6 @@ FAB17BE81ABFAA9000F9BA27 /* lz4.h in Headers */, FA0B7E6B1A95902C000E1D17 /* wrap_PulleyJoint.h in Headers */, FA0B7E051A95902C000E1D17 /* Contact.h in Headers */, - FADF541D1E3DA46C00012CC0 /* wrap_Image.h in Headers */, FA1BA0A91E16F20600AA2803 /* Canvas.h in Headers */, FA0B7A691A958EA3000E1D17 /* b2Island.h in Headers */, FA4F2BE41DE6650600CA37D7 /* Transform.h in Headers */, @@ -4349,7 +4333,6 @@ FA0B7ECC1A95902C000E1D17 /* wrap_Channel.cpp in Sources */, FA0B7E6D1A95902C000E1D17 /* wrap_RevoluteJoint.cpp in Sources */, FA0B7A5F1A958EA3000E1D17 /* b2Body.cpp in Sources */, - FADF541C1E3DA46C00012CC0 /* wrap_Image.cpp in Sources */, FACA02FA1F5E397B0084B28F /* DataModule.cpp in Sources */, FA0B7E641A95902C000E1D17 /* wrap_PolygonShape.cpp in Sources */, FA4F2C031DE936C200CA37D7 /* auxiliar.c in Sources */, @@ -4641,7 +4624,6 @@ FA0B7DBF1A95902C000E1D17 /* JoystickModule.cpp in Sources */, FAB2D5AB1AABDD8A008224A4 /* TrueTypeRasterizer.cpp in Sources */, FA0B7A9F1A958EA3000E1D17 /* b2PrismaticJoint.cpp in Sources */, - FA1BA0AD1E16F9EE00AA2803 /* wrap_Canvas.cpp in Sources */, FAF6C9FB23C2DE2900D7B5BC /* disassemble.cpp in Sources */, FAE64A822071363100BC7981 /* physfs_archiver_grp.c in Sources */, FAF6C9F323C2DE2900D7B5BC /* SPVRemapper.cpp in Sources */, @@ -4750,7 +4732,6 @@ FA0B7E6C1A95902C000E1D17 /* wrap_RevoluteJoint.cpp in Sources */, FA0B7A5E1A958EA3000E1D17 /* b2Body.cpp in Sources */, FA0B7E631A95902C000E1D17 /* wrap_PolygonShape.cpp in Sources */, - FADF541B1E3DA46C00012CC0 /* wrap_Image.cpp in Sources */, FAC7CD7B1FE35E95006A60C7 /* physfs_platform_unix.c in Sources */, FACA02F01F5E396B0084B28F /* DataModule.cpp in Sources */, FA0B7E721A95902C000E1D17 /* wrap_Shape.cpp in Sources */, @@ -5043,7 +5024,6 @@ FA0B7E5A1A95902C000E1D17 /* wrap_MotorJoint.cpp in Sources */, FA0B7AA71A958EA3000E1D17 /* b2RopeJoint.cpp in Sources */, FA0B7DD61A95902C000E1D17 /* MathModule.cpp in Sources */, - FA1BA0AC1E16F9EE00AA2803 /* wrap_Canvas.cpp in Sources */, FAC7CD8A1FE35E95006A60C7 /* physfs_byteorder.c in Sources */, FA0B7D0F1A95902C000E1D17 /* BMFontRasterizer.cpp in Sources */, FA0B7E9A1A95902C000E1D17 /* VorbisDecoder.cpp in Sources */, diff --git a/src/modules/graphics/wrap_Canvas.cpp b/src/modules/graphics/wrap_Canvas.cpp deleted file mode 100644 index 5aad53644..000000000 --- a/src/modules/graphics/wrap_Canvas.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2006-2020 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "wrap_Canvas.h" -#include "Graphics.h" - -namespace love -{ -namespace graphics -{ - -Canvas *luax_checkcanvas(lua_State *L, int idx) -{ - return luax_checktype(L, idx); -} - -static const luaL_Reg w_Canvas_functions[] = -{ - { 0, 0 } -}; - -extern "C" int luaopen_canvas(lua_State *L) -{ - return luax_register_type(L, &Canvas::type, w_Texture_functions, w_Canvas_functions, nullptr); -} - -} // graphics -} // love diff --git a/src/modules/graphics/wrap_Canvas.h b/src/modules/graphics/wrap_Canvas.h deleted file mode 100644 index a56eb083c..000000000 --- a/src/modules/graphics/wrap_Canvas.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2006-2020 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#pragma once - -// LOVE -#include "common/runtime.h" -#include "Canvas.h" -#include "wrap_Texture.h" - -namespace love -{ -namespace graphics -{ - -//see Canvas.h -Canvas *luax_checkcanvas(lua_State *L, int idx); -extern "C" int luaopen_canvas(lua_State *L); - -} // graphics -} // love diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 4b11756d5..d6c979061 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -249,7 +249,7 @@ int w_getDPIScale(lua_State *L) static Graphics::RenderTarget checkRenderTarget(lua_State *L, int idx) { lua_rawgeti(L, idx, 1); - Graphics::RenderTarget target(luax_checkcanvas(L, -1), 0); + Graphics::RenderTarget target(luax_checktexture(L, -1), 0); lua_pop(L, 1); TextureType type = target.texture->getTextureType(); @@ -292,7 +292,7 @@ int w_setCanvas(lua_State *L) targets.colors.push_back(checkRenderTarget(L, -1)); else { - targets.colors.emplace_back(luax_checkcanvas(L, -1), 0); + targets.colors.emplace_back(luax_checktexture(L, -1), 0); if (targets.colors.back().texture->getTextureType() != TEXTURE_2D) return luaL_error(L, "Non-2D canvases must use the table-of-tables variant of setCanvas."); @@ -311,7 +311,7 @@ int w_setCanvas(lua_State *L) else if (dstype == LUA_TBOOLEAN) targets.temporaryRTFlags |= luax_toboolean(L, -1) ? (tempdepthflag | tempstencilflag) : 0; else if (dstype != LUA_TNONE && dstype != LUA_TNIL) - targets.depthStencil.texture = luax_checkcanvas(L, -1); + targets.depthStencil.texture = luax_checktexture(L, -1); lua_pop(L, 1); if (targets.depthStencil.texture == nullptr && (targets.temporaryRTFlags & tempdepthflag) == 0) @@ -324,7 +324,7 @@ int w_setCanvas(lua_State *L) { for (int i = 1; i <= lua_gettop(L); i++) { - Graphics::RenderTarget target(luax_checkcanvas(L, i), 0); + Graphics::RenderTarget target(luax_checktexture(L, i), 0); TextureType type = target.texture->getTextureType(); if (i == 1 && type != TEXTURE_2D) @@ -3123,11 +3123,9 @@ static const lua_CFunction types[] = luaopen_drawable, luaopen_texture, luaopen_font, - luaopen_image, luaopen_quad, luaopen_spritebatch, luaopen_particlesystem, - luaopen_canvas, luaopen_shader, luaopen_mesh, luaopen_text, diff --git a/src/modules/graphics/wrap_Graphics.h b/src/modules/graphics/wrap_Graphics.h index 7359ef652..afd4240ec 100644 --- a/src/modules/graphics/wrap_Graphics.h +++ b/src/modules/graphics/wrap_Graphics.h @@ -23,11 +23,10 @@ // LOVE #include "common/config.h" #include "wrap_Font.h" -#include "wrap_Image.h" +#include "wrap_Texture.h" #include "wrap_Quad.h" #include "wrap_SpriteBatch.h" #include "wrap_ParticleSystem.h" -#include "wrap_Canvas.h" #include "wrap_Shader.h" #include "wrap_Mesh.h" #include "wrap_Text.h" diff --git a/src/modules/graphics/wrap_Image.cpp b/src/modules/graphics/wrap_Image.cpp deleted file mode 100644 index 177a2866d..000000000 --- a/src/modules/graphics/wrap_Image.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2006-2020 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -// LOVE -#include "wrap_Image.h" - -namespace love -{ -namespace graphics -{ - -Image *luax_checkimage(lua_State *L, int idx) -{ - return luax_checktype(L, idx); -} - -static const luaL_Reg w_Image_functions[] = -{ - { 0, 0 } -}; - -extern "C" int luaopen_image(lua_State *L) -{ - return luax_register_type(L, &Image::type, w_Texture_functions, w_Image_functions, nullptr); -} - -} // graphics -} // love diff --git a/src/modules/graphics/wrap_Image.h b/src/modules/graphics/wrap_Image.h deleted file mode 100644 index ed3697bdd..000000000 --- a/src/modules/graphics/wrap_Image.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2006-2020 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#pragma once - -// LOVE -#include "common/runtime.h" -#include "Image.h" -#include "wrap_Texture.h" - -namespace love -{ -namespace graphics -{ - -Image *luax_checkimage(lua_State *L, int idx); -extern "C" int luaopen_image(lua_State *L); - -} // graphics -} // love From b71eaf73cc722e24fc351bbbd5d4317a06c744a7 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Feb 2020 20:52:57 -0400 Subject: [PATCH 14/31] Replaced some references to Image and Canvas with Texture. --- src/modules/graphics/Font.cpp | 28 ++++++++++---------- src/modules/graphics/Font.h | 4 +-- src/modules/graphics/Graphics.h | 6 ++--- src/modules/graphics/Video.cpp | 16 +++++------ src/modules/graphics/Video.h | 4 +-- src/modules/graphics/opengl/Canvas.cpp | 4 +-- src/modules/graphics/opengl/Graphics.cpp | 8 +++--- src/modules/graphics/opengl/Graphics.h | 8 +++--- src/modules/graphics/wrap_Graphics.cpp | 10 +++---- src/modules/graphics/wrap_Mesh.cpp | 3 +-- src/modules/graphics/wrap_ParticleSystem.cpp | 3 +-- src/modules/graphics/wrap_SpriteBatch.cpp | 3 +-- 12 files changed, 47 insertions(+), 50 deletions(-) diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index df325dd73..46730e969 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -125,7 +125,7 @@ bool Font::loadVolatile() { textureCacheID++; glyphs.clear(); - images.clear(); + textures.clear(); createTexture(); return true; } @@ -135,7 +135,7 @@ void Font::createTexture() auto gfx = Module::getInstance(Module::M_GRAPHICS); gfx->flushStreamDraws(); - Image *image = nullptr; + Texture *texture = nullptr; TextureSize size = {textureWidth, textureHeight}; TextureSize nextsize = getNextTextureSize(); bool recreatetexture = false; @@ -143,16 +143,16 @@ void Font::createTexture() // If we have an existing texture already, we'll try replacing it with a // larger-sized one rather than creating a second one. Having a single // texture reduces texture switches and draw calls when rendering. - if ((nextsize.width > size.width || nextsize.height > size.height) && !images.empty()) + if ((nextsize.width > size.width || nextsize.height > size.height) && !textures.empty()) { recreatetexture = true; size = nextsize; - images.pop_back(); + textures.pop_back(); } Image::Settings settings; - image = gfx->newImage(TEXTURE_2D, pixelFormat, size.width, size.height, 1, settings); - image->setSamplerState(samplerState); + texture = gfx->newImage(TEXTURE_2D, pixelFormat, size.width, size.height, 1, settings); + texture->setSamplerState(samplerState); { size_t bpp = getPixelFormatSize(pixelFormat); @@ -170,10 +170,10 @@ void Font::createTexture() } Rect rect = {0, 0, size.width, size.height}; - image->replacePixels(emptydata.data(), emptydata.size(), 0, 0, rect, false); + texture->replacePixels(emptydata.data(), emptydata.size(), 0, 0, rect, false); } - images.emplace_back(image, Acquire::NORETAIN); + textures.emplace_back(texture, Acquire::NORETAIN); textureWidth = size.width; textureHeight = size.height; @@ -200,7 +200,7 @@ void Font::createTexture() void Font::unloadVolatile() { glyphs.clear(); - images.clear(); + textures.clear(); } love::font::GlyphData *Font::getRasterizerGlyphData(uint32 glyph) @@ -268,11 +268,11 @@ const Font::Glyph &Font::addGlyph(uint32 glyph) // Don't waste space for empty glyphs. if (w > 0 && h > 0) { - Image *image = images.back(); - g.texture = image; + Texture *texture = textures.back(); + g.texture = texture; Rect rect = {textureX, textureY, gd->getWidth(), gd->getHeight()}; - image->replacePixels(gd->getData(), gd->getSize(), 0, 0, rect, false); + texture->replacePixels(gd->getData(), gd->getSize(), 0, 0, rect, false); double tX = (double) textureX, tY = (double) textureY; double tWidth = (double) textureWidth, tHeight = (double) textureHeight; @@ -926,8 +926,8 @@ void Font::setSamplerState(const SamplerState &s) samplerState.magFilter = s.magFilter; samplerState.maxAnisotropy = s.maxAnisotropy; - for (const auto &image : images) - image->setSamplerState(samplerState); + for (const auto &texture : textures) + texture->setSamplerState(samplerState); } const SamplerState &Font::getSamplerState() const diff --git a/src/modules/graphics/Font.h b/src/modules/graphics/Font.h index 20f5bc5c8..b1bbee8d7 100644 --- a/src/modules/graphics/Font.h +++ b/src/modules/graphics/Font.h @@ -33,7 +33,7 @@ #include "common/Vector.h" #include "font/Rasterizer.h" -#include "Image.h" +#include "Texture.h" #include "vertex.h" #include "Volatile.h" @@ -217,7 +217,7 @@ private: int textureWidth; int textureHeight; - std::vector> images; + std::vector> textures; // maps glyphs to glyph texture information std::unordered_map glyphs; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index cf4429e3b..24a42bf29 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -428,8 +428,8 @@ public: // Implements Module. virtual ModuleType getModuleType() const { return M_GRAPHICS; } - virtual Image *newImage(const Texture::Slices &data, const Image::Settings &settings) = 0; - virtual Image *newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) = 0; + virtual Texture *newImage(const Texture::Slices &data, const Image::Settings &settings) = 0; + virtual Texture *newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) = 0; Quad *newQuad(Quad::Viewport v, double sw, double sh); Font *newFont(love::font::Rasterizer *data); @@ -439,7 +439,7 @@ public: SpriteBatch *newSpriteBatch(Texture *texture, int size, vertex::Usage usage); ParticleSystem *newParticleSystem(Texture *texture, int size); - virtual Canvas *newCanvas(const Canvas::Settings &settings) = 0; + virtual Texture *newCanvas(const Canvas::Settings &settings) = 0; ShaderStage *newShaderStage(ShaderStage::StageType stage, const std::string &source); Shader *newShader(const std::string &vertex, const std::string &pixel); diff --git a/src/modules/graphics/Video.cpp b/src/modules/graphics/Video.cpp index b27d3c856..fe5207961 100644 --- a/src/modules/graphics/Video.cpp +++ b/src/modules/graphics/Video.cpp @@ -83,17 +83,17 @@ Video::Video(Graphics *gfx, love::video::VideoStream *stream, float dpiscale) for (int i = 0; i < 3; i++) { - Image *img = gfx->newImage(TEXTURE_2D, PIXELFORMAT_R8_UNORM, widths[i], heights[i], 1, settings); + Texture *tex = gfx->newImage(TEXTURE_2D, PIXELFORMAT_R8_UNORM, widths[i], heights[i], 1, settings); - img->setSamplerState(samplerState); + tex->setSamplerState(samplerState); size_t bpp = getPixelFormatSize(PIXELFORMAT_R8_UNORM); size_t size = bpp * widths[i] * heights[i]; Rect rect = {0, 0, widths[i], heights[i]}; - img->replacePixels(data[i], size, 0, 0, rect, false); + tex->replacePixels(data[i], size, 0, 0, rect, false); - images[i].set(img, Acquire::NORETAIN); + textures[i].set(tex, Acquire::NORETAIN); } } @@ -143,7 +143,7 @@ void Video::draw(Graphics *gfx, const Matrix4 &m) } if (Shader::current != nullptr) - Shader::current->setVideoTextures(images[0], images[1], images[2]); + Shader::current->setVideoTextures(textures[0], textures[1], textures[2]); gfx->flushStreamDraws(); } @@ -168,7 +168,7 @@ void Video::update() size_t size = bpp * widths[i] * heights[i]; Rect rect = {0, 0, widths[i], heights[i]}; - images[i]->replacePixels(data[i], size, 0, 0, rect, false); + textures[i]->replacePixels(data[i], size, 0, 0, rect, false); } } } @@ -211,8 +211,8 @@ void Video::setSamplerState(const SamplerState &s) samplerState.wrapV = s.wrapV; samplerState.maxAnisotropy = s.maxAnisotropy; - for (const auto &image : images) - image->setSamplerState(samplerState); + for (const auto &texture : textures) + texture->setSamplerState(samplerState); } const SamplerState &Video::getSamplerState() const diff --git a/src/modules/graphics/Video.h b/src/modules/graphics/Video.h index 65db27c32..871d8eb2e 100644 --- a/src/modules/graphics/Video.h +++ b/src/modules/graphics/Video.h @@ -23,7 +23,7 @@ // LOVE #include "common/math.h" #include "Drawable.h" -#include "Image.h" +#include "Texture.h" #include "vertex.h" #include "video/VideoStream.h" #include "audio/Source.h" @@ -74,7 +74,7 @@ private: Vertex vertices[4]; - StrongRef images[3]; + StrongRef textures[3]; StrongRef source; }; // Video diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index a00fc4594..56de9ca81 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -288,13 +288,13 @@ bool Canvas::loadVolatile() void Canvas::unloadVolatile() { - if (fbo != 0 || renderbuffer != 0 || texture != 0) + if (isRenderTarget() && (fbo != 0 || renderbuffer != 0 || texture != 0)) { // This is a bit ugly, but we need some way to destroy the cached FBO // when this Canvas' texture is destroyed. auto gfx = Module::getInstance(Module::M_GRAPHICS); if (gfx != nullptr) - gfx->cleanupCanvas(this); + gfx->cleanupRenderTexture(this); } if (fbo != 0) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index f020e28ec..d61f7f57e 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -130,17 +130,17 @@ love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t return CreateStreamBuffer(type, size); } -love::graphics::Image *Graphics::newImage(const Texture::Slices &data, const Image::Settings &settings) +love::graphics::Texture *Graphics::newImage(const Texture::Slices &data, const Image::Settings &settings) { return new Image(data, settings); } -love::graphics::Image *Graphics::newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) +love::graphics::Texture *Graphics::newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) { return new Image(textype, format, width, height, slices, settings); } -love::graphics::Canvas *Graphics::newCanvas(const Canvas::Settings &settings) +love::graphics::Texture *Graphics::newCanvas(const Canvas::Settings &settings) { return new Canvas(settings); } @@ -820,7 +820,7 @@ void Graphics::discard(OpenGL::FramebufferTarget target, const std::vector glDiscardFramebufferEXT(gltarget, (GLint) attachments.size(), &attachments[0]); } -void Graphics::cleanupCanvas(Canvas *texture) +void Graphics::cleanupRenderTexture(Texture *texture) { if (!texture->isRenderTarget()) return; diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 3a711d2c1..5745f8e99 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -60,9 +60,9 @@ public: // Implements Module. const char *getName() const override; - love::graphics::Image *newImage(const Texture::Slices &data, const Image::Settings &settings) override; - love::graphics::Image *newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) override; - love::graphics::Canvas *newCanvas(const Canvas::Settings &settings) override; + love::graphics::Texture *newImage(const Texture::Slices &data, const Image::Settings &settings) override; + love::graphics::Texture *newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) override; + love::graphics::Texture *newCanvas(const Canvas::Settings &settings) override; love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override; void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override; @@ -112,7 +112,7 @@ public: Shader::Language getShaderLanguageTarget() const override; // Internal use. - void cleanupCanvas(Canvas *canvas); + void cleanupRenderTexture(Texture *texture); private: diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index d6c979061..da1d1fdea 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -759,7 +759,7 @@ getImageData(lua_State *L, int idx, bool allowcompressed, float *dpiscale) static int w__pushNewImage(lua_State *L, Texture::Slices &slices, const Image::Settings &settings) { - StrongRef i; + StrongRef i; luax_catchexcept(L, [&]() { i.set(instance()->newImage(slices, settings), Acquire::NORETAIN); }, [&](bool) { slices.clear(); } @@ -1246,11 +1246,11 @@ int w_newCanvas(lua_State *L) lua_pop(L, 1); } - Canvas *canvas = nullptr; - luax_catchexcept(L, [&](){ canvas = instance()->newCanvas(settings); }); + Texture *texture = nullptr; + luax_catchexcept(L, [&](){ texture = instance()->newCanvas(settings); }); - luax_pushtype(L, canvas); - canvas->release(); + luax_pushtype(L, texture); + texture->release(); return 1; } diff --git a/src/modules/graphics/wrap_Mesh.cpp b/src/modules/graphics/wrap_Mesh.cpp index 5f1814f56..3c9de2f5f 100644 --- a/src/modules/graphics/wrap_Mesh.cpp +++ b/src/modules/graphics/wrap_Mesh.cpp @@ -20,8 +20,7 @@ // LOVE #include "wrap_Mesh.h" -#include "Image.h" -#include "Canvas.h" +#include "Texture.h" #include "wrap_Texture.h" // C++ diff --git a/src/modules/graphics/wrap_ParticleSystem.cpp b/src/modules/graphics/wrap_ParticleSystem.cpp index 637dcc710..7458941fb 100644 --- a/src/modules/graphics/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/wrap_ParticleSystem.cpp @@ -22,8 +22,7 @@ #include "wrap_ParticleSystem.h" #include "common/Vector.h" -#include "Image.h" -#include "Canvas.h" +#include "Texture.h" #include "wrap_Texture.h" // C diff --git a/src/modules/graphics/wrap_SpriteBatch.cpp b/src/modules/graphics/wrap_SpriteBatch.cpp index c98bd5d71..420ece908 100644 --- a/src/modules/graphics/wrap_SpriteBatch.cpp +++ b/src/modules/graphics/wrap_SpriteBatch.cpp @@ -20,8 +20,7 @@ // LOVE #include "wrap_SpriteBatch.h" -#include "Image.h" -#include "Canvas.h" +#include "Texture.h" #include "wrap_Texture.h" namespace love From 258129738f547d80e66536e161cd5b566c3a46c8 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Feb 2020 22:06:55 -0400 Subject: [PATCH 15/31] Remove graphics::Canvas and graphics::Image --- CMakeLists.txt | 4 - .../xcode/liblove.xcodeproj/project.pbxproj | 20 -- src/modules/graphics/Canvas.cpp | 144 ------------- src/modules/graphics/Canvas.h | 89 -------- src/modules/graphics/Font.cpp | 7 +- src/modules/graphics/Graphics.cpp | 2 +- src/modules/graphics/Graphics.h | 7 +- src/modules/graphics/Image.cpp | 140 ------------- src/modules/graphics/Image.h | 82 -------- src/modules/graphics/Texture.cpp | 197 +++++++++++++++--- src/modules/graphics/Texture.h | 44 +++- src/modules/graphics/Video.cpp | 7 +- src/modules/graphics/opengl/Canvas.cpp | 4 +- src/modules/graphics/opengl/Canvas.h | 4 +- src/modules/graphics/opengl/Graphics.cpp | 11 +- src/modules/graphics/opengl/Graphics.h | 5 +- src/modules/graphics/opengl/Image.cpp | 16 +- src/modules/graphics/opengl/Image.h | 7 +- src/modules/graphics/wrap_Graphics.cpp | 41 ++-- 19 files changed, 254 insertions(+), 577 deletions(-) delete mode 100644 src/modules/graphics/Canvas.cpp delete mode 100644 src/modules/graphics/Canvas.h delete mode 100644 src/modules/graphics/Image.cpp delete mode 100644 src/modules/graphics/Image.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 52d259cb6..1413f57ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -518,8 +518,6 @@ source_group("modules\\font\\freetype" FILES ${LOVE_SRC_MODULE_FONT_FREETYPE}) set(LOVE_SRC_MODULE_GRAPHICS_ROOT src/modules/graphics/Buffer.cpp src/modules/graphics/Buffer.h - src/modules/graphics/Canvas.cpp - src/modules/graphics/Canvas.h src/modules/graphics/Deprecations.cpp src/modules/graphics/Deprecations.h src/modules/graphics/Drawable.cpp @@ -528,8 +526,6 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT src/modules/graphics/Font.h src/modules/graphics/Graphics.cpp src/modules/graphics/Graphics.h - src/modules/graphics/Image.cpp - src/modules/graphics/Image.h src/modules/graphics/Mesh.cpp src/modules/graphics/Mesh.h src/modules/graphics/ParticleSystem.cpp diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 44419670b..73496ae8a 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -787,9 +787,6 @@ FA1BA0A21E16D97500AA2803 /* wrap_Font.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0A01E16D97500AA2803 /* wrap_Font.cpp */; }; FA1BA0A31E16D97500AA2803 /* wrap_Font.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0A01E16D97500AA2803 /* wrap_Font.cpp */; }; FA1BA0A41E16D97500AA2803 /* wrap_Font.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1BA0A11E16D97500AA2803 /* wrap_Font.h */; }; - FA1BA0A71E16F20600AA2803 /* Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0A51E16F20600AA2803 /* Canvas.cpp */; }; - FA1BA0A81E16F20600AA2803 /* Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0A51E16F20600AA2803 /* Canvas.cpp */; }; - FA1BA0A91E16F20600AA2803 /* Canvas.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1BA0A61E16F20600AA2803 /* Canvas.h */; }; FA1BA0B11E16FD0800AA2803 /* Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */; }; FA1BA0B21E16FD0800AA2803 /* Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */; }; FA1BA0B31E16FD0800AA2803 /* Shader.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1BA0B01E16FD0800AA2803 /* Shader.h */; }; @@ -1057,9 +1054,6 @@ FADF540E1E3D7CDD00012CC0 /* wrap_Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF540A1E3D7CDD00012CC0 /* wrap_Video.cpp */; }; FADF540F1E3D7CDD00012CC0 /* wrap_Video.h in Headers */ = {isa = PBXBuildFile; fileRef = FADF540B1E3D7CDD00012CC0 /* wrap_Video.h */; }; FADF54101E3D7CDD00012CC0 /* wrap_Video.lua in Resources */ = {isa = PBXBuildFile; fileRef = FADF540C1E3D7CDD00012CC0 /* wrap_Video.lua */; }; - FADF54161E3DA08E00012CC0 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF54141E3DA08E00012CC0 /* Image.cpp */; }; - FADF54171E3DA08E00012CC0 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF54141E3DA08E00012CC0 /* Image.cpp */; }; - FADF54181E3DA08E00012CC0 /* Image.h in Headers */ = {isa = PBXBuildFile; fileRef = FADF54151E3DA08E00012CC0 /* Image.h */; }; FADF54201E3DA52C00012CC0 /* wrap_ParticleSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF541E1E3DA52C00012CC0 /* wrap_ParticleSystem.cpp */; }; FADF54211E3DA52C00012CC0 /* wrap_ParticleSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF541E1E3DA52C00012CC0 /* wrap_ParticleSystem.cpp */; }; FADF54221E3DA52C00012CC0 /* wrap_ParticleSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = FADF541F1E3DA52C00012CC0 /* wrap_ParticleSystem.h */; }; @@ -1799,8 +1793,6 @@ FA1BA09C1E16CFCE00AA2803 /* Font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Font.h; sourceTree = ""; }; FA1BA0A01E16D97500AA2803 /* wrap_Font.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Font.cpp; sourceTree = ""; }; FA1BA0A11E16D97500AA2803 /* wrap_Font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Font.h; sourceTree = ""; }; - FA1BA0A51E16F20600AA2803 /* Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Canvas.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - FA1BA0A61E16F20600AA2803 /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Canvas.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Shader.cpp; sourceTree = ""; }; FA1BA0B01E16FD0800AA2803 /* Shader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shader.h; sourceTree = ""; }; FA1BA0B51E17043400AA2803 /* wrap_Shader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Shader.cpp; sourceTree = ""; }; @@ -2001,8 +1993,6 @@ FADF540A1E3D7CDD00012CC0 /* wrap_Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Video.cpp; sourceTree = ""; }; FADF540B1E3D7CDD00012CC0 /* wrap_Video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Video.h; sourceTree = ""; }; FADF540C1E3D7CDD00012CC0 /* wrap_Video.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = wrap_Video.lua; sourceTree = ""; }; - FADF54141E3DA08E00012CC0 /* Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Image.cpp; sourceTree = ""; }; - FADF54151E3DA08E00012CC0 /* Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = ""; }; FADF541E1E3DA52C00012CC0 /* wrap_ParticleSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_ParticleSystem.cpp; sourceTree = ""; }; FADF541F1E3DA52C00012CC0 /* wrap_ParticleSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_ParticleSystem.h; sourceTree = ""; }; FADF54231E3DA5BA00012CC0 /* Mesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mesh.cpp; sourceTree = ""; }; @@ -2827,8 +2817,6 @@ children = ( FADF53F61E3C7ACD00012CC0 /* Buffer.cpp */, FADF53F71E3C7ACD00012CC0 /* Buffer.h */, - FA1BA0A51E16F20600AA2803 /* Canvas.cpp */, - FA1BA0A61E16F20600AA2803 /* Canvas.h */, FA9D53AA1F5307E900125C6B /* Deprecations.cpp */, FA9D53AB1F5307E900125C6B /* Deprecations.h */, FA9D8DDC1DEF842A002CD881 /* Drawable.cpp */, @@ -2837,8 +2825,6 @@ FA1BA09C1E16CFCE00AA2803 /* Font.h */, FA0B7B8A1A95902C000E1D17 /* Graphics.cpp */, FA0B7B8B1A95902C000E1D17 /* Graphics.h */, - FADF54141E3DA08E00012CC0 /* Image.cpp */, - FADF54151E3DA08E00012CC0 /* Image.h */, FADF54231E3DA5BA00012CC0 /* Mesh.cpp */, FADF54241E3DA5BA00012CC0 /* Mesh.h */, FA0B7B8C1A95902C000E1D17 /* opengl */, @@ -3959,7 +3945,6 @@ FAB17BE81ABFAA9000F9BA27 /* lz4.h in Headers */, FA0B7E6B1A95902C000E1D17 /* wrap_PulleyJoint.h in Headers */, FA0B7E051A95902C000E1D17 /* Contact.h in Headers */, - FA1BA0A91E16F20600AA2803 /* Canvas.h in Headers */, FA0B7A691A958EA3000E1D17 /* b2Island.h in Headers */, FA4F2BE41DE6650600CA37D7 /* Transform.h in Headers */, FA0B7E0E1A95902C000E1D17 /* Fixture.h in Headers */, @@ -4037,7 +4022,6 @@ FA0B7A601A958EA3000E1D17 /* b2Body.h in Headers */, FA0B7EAB1A95902C000E1D17 /* wrap_Sound.h in Headers */, FA0B7B2C1A958EA3000E1D17 /* checked.h in Headers */, - FADF54181E3DA08E00012CC0 /* Image.h in Headers */, FA0B7D2A1A95902C000E1D17 /* wrap_GlyphData.h in Headers */, FACA02F11F5E396B0084B28F /* DataModule.h in Headers */, FA0B7E741A95902C000E1D17 /* wrap_Shape.h in Headers */, @@ -4645,9 +4629,7 @@ FA0B7EAD1A95902C000E1D17 /* wrap_SoundData.cpp in Sources */, FA0B7E2E1A95902C000E1D17 /* RopeJoint.cpp in Sources */, FA0B7CE01A95902C000E1D17 /* Source.cpp in Sources */, - FADF54171E3DA08E00012CC0 /* Image.cpp in Sources */, FA0B7ECF1A95902C000E1D17 /* wrap_LuaThread.cpp in Sources */, - FA1BA0A81E16F20600AA2803 /* Canvas.cpp in Sources */, FA0B7AA51A958EA3000E1D17 /* b2RevoluteJoint.cpp in Sources */, FA0B7EA11A95902C000E1D17 /* Sound.cpp in Sources */, FA0B7DE61A95902C000E1D17 /* Cursor.cpp in Sources */, @@ -5044,9 +5026,7 @@ FA4F2BE31DE6650600CA37D7 /* Transform.cpp in Sources */, FA0B7EA01A95902C000E1D17 /* Sound.cpp in Sources */, FA0B7DE51A95902C000E1D17 /* Cursor.cpp in Sources */, - FADF54161E3DA08E00012CC0 /* Image.cpp in Sources */, FA0B7EDB1A95902D000E1D17 /* Touch.cpp in Sources */, - FA1BA0A71E16F20600AA2803 /* Canvas.cpp in Sources */, FA0B7CE81A95902C000E1D17 /* Event.cpp in Sources */, FA0B7ACF1A958EA3000E1D17 /* peer.c in Sources */, FA0B7ADE1A958EA3000E1D17 /* lodepng.cpp in Sources */, diff --git a/src/modules/graphics/Canvas.cpp b/src/modules/graphics/Canvas.cpp deleted file mode 100644 index c13b1e038..000000000 --- a/src/modules/graphics/Canvas.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Copyright (c) 2006-2020 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "Canvas.h" -#include "Graphics.h" - -namespace love -{ -namespace graphics -{ - -love::Type Canvas::type("Canvas", &Texture::type); - -Canvas::Canvas(const Settings &settings) - : Texture(settings.type) -{ - this->settings = settings; - - renderTarget = true; - sRGB = false; - requestedMSAA = settings.msaa; - - mipmapsMode = settings.mipmaps; - width = settings.width; - height = settings.height; - pixelWidth = (int) ((width * settings.dpiScale) + 0.5); - pixelHeight = (int) ((height * settings.dpiScale) + 0.5); - - format = settings.format; - - if (texType == TEXTURE_VOLUME) - depth = settings.layers; - else if (texType == TEXTURE_2D_ARRAY) - layers = settings.layers; - - if (width <= 0 || height <= 0 || layers <= 0) - throw love::Exception("Canvas dimensions must be greater than 0."); - - if (texType != TEXTURE_2D && settings.msaa > 1) - throw love::Exception("MSAA is only supported for Canvases with the 2D texture type."); - - if (settings.readable.hasValue) - readable = settings.readable.value; - else - readable = !isPixelFormatDepthStencil(format); - - if (readable && isPixelFormatDepthStencil(format) && settings.msaa > 1) - throw love::Exception("Readable depth/stencil Canvases with MSAA are not currently supported."); - - if ((!readable || settings.msaa > 1) && mipmapsMode != MIPMAPS_NONE) - throw love::Exception("Non-readable and MSAA textures cannot have mipmaps."); - - if (mipmapsMode != MIPMAPS_NONE) - mipmapCount = getTotalMipmapCount(pixelWidth, pixelHeight, depth); - - auto gfx = Module::getInstance(Module::M_GRAPHICS); - const Graphics::Capabilities &caps = gfx->getCapabilities(); - - if (!gfx->isPixelFormatSupported(format, renderTarget, readable, sRGB)) - { - const char *fstr = "rgba8"; - const char *readablestr = ""; - if (readable != !isPixelFormatDepthStencil(format)) - readablestr = readable ? " readable" : " non-readable"; - love::getConstant(format, fstr); - throw love::Exception("The %s%s canvas format is not supported by your graphics drivers.", fstr, readablestr); - } - - if (getRequestedMSAA() > 1 && texType != TEXTURE_2D) - throw love::Exception("MSAA is only supported for 2D texture types."); - - if (!readable && texType != TEXTURE_2D) - throw love::Exception("Non-readable pixel formats are only supported for 2D texture types."); - - if (!caps.textureTypes[texType]) - { - const char *textypestr = "unknown"; - Texture::getConstant(texType, textypestr); - throw love::Exception("%s textures are not supported on this system!", textypestr); - } - - validateDimensions(true); -} - -Canvas::~Canvas() -{ -} - -bool Canvas::getConstant(const char *in, SettingType &out) -{ - return settingTypes.find(in, out); -} - -bool Canvas::getConstant(SettingType in, const char *&out) -{ - return settingTypes.find(in, out); -} - -const char *Canvas::getConstant(SettingType in) -{ - const char *name = nullptr; - getConstant(in, name); - return name; -} - -std::vector Canvas::getConstants(SettingType) -{ - return settingTypes.getNames(); -} - -StringMap::Entry Canvas::settingTypeEntries[] = -{ - // Width / height / layers are currently omittted because they're separate - // arguments to newCanvas in the wrapper code. - { "mipmaps", SETTING_MIPMAPS }, - { "format", SETTING_FORMAT }, - { "type", SETTING_TYPE }, - { "dpiscale", SETTING_DPI_SCALE }, - { "msaa", SETTING_MSAA }, - { "readable", SETTING_READABLE }, -}; - -StringMap Canvas::settingTypes(Canvas::settingTypeEntries, sizeof(Canvas::settingTypeEntries)); - -} // graphics -} // love - diff --git a/src/modules/graphics/Canvas.h b/src/modules/graphics/Canvas.h deleted file mode 100644 index 9c77152b2..000000000 --- a/src/modules/graphics/Canvas.h +++ /dev/null @@ -1,89 +0,0 @@ -/** -* Copyright (c) 2006-2020 LOVE Development Team -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -**/ - -#pragma once - -#include "image/Image.h" -#include "image/ImageData.h" -#include "Texture.h" -#include "common/Optional.h" -#include "common/StringMap.h" - -namespace love -{ -namespace graphics -{ - -class Graphics; - -class Canvas : public Texture -{ -public: - - static love::Type type; - - enum SettingType - { - SETTING_WIDTH, - SETTING_HEIGHT, - SETTING_LAYERS, - SETTING_MIPMAPS, - SETTING_FORMAT, - SETTING_TYPE, - SETTING_DPI_SCALE, - SETTING_MSAA, - SETTING_READABLE, - SETTING_MAX_ENUM - }; - - struct Settings - { - int width = 1; - int height = 1; - int layers = 1; // depth for 3D textures - MipmapsMode mipmaps = MIPMAPS_NONE; - PixelFormat format = PIXELFORMAT_NORMAL; - TextureType type = TEXTURE_2D; - float dpiScale = 1.0f; - int msaa = 0; - OptionalBool readable; - }; - - Canvas(const Settings &settings); - virtual ~Canvas(); - - static bool getConstant(const char *in, SettingType &out); - static bool getConstant(SettingType in, const char *&out); - static const char *getConstant(SettingType in); - static std::vector getConstants(SettingType); - -protected: - - Settings settings; - -private: - - static StringMap::Entry settingTypeEntries[]; - static StringMap settingTypes; - -}; // Canvas - -} // graphics -} // love diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index 46730e969..97f82572a 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -150,8 +150,11 @@ void Font::createTexture() textures.pop_back(); } - Image::Settings settings; - texture = gfx->newImage(TEXTURE_2D, pixelFormat, size.width, size.height, 1, settings); + Texture::Settings settings; + settings.format = pixelFormat; + settings.width = size.width; + settings.height = size.height; + texture = gfx->newImage(settings, nullptr); texture->setSamplerState(samplerState); { diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index c0a5a2f1f..c76c0afc3 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -820,7 +820,7 @@ Texture *Graphics::getTemporaryTexture(PixelFormat format, int w, int h, int sam if (texture == nullptr) { - Canvas::Settings settings; + Texture::Settings settings; settings.format = format; settings.width = w; settings.height = h; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 24a42bf29..f7bf99529 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -32,13 +32,11 @@ #include "StreamBuffer.h" #include "vertex.h" #include "Texture.h" -#include "Canvas.h" #include "Font.h" #include "ShaderStage.h" #include "Shader.h" #include "Quad.h" #include "Mesh.h" -#include "Image.h" #include "Deprecations.h" #include "renderstate.h" #include "math/Transform.h" @@ -428,8 +426,7 @@ public: // Implements Module. virtual ModuleType getModuleType() const { return M_GRAPHICS; } - virtual Texture *newImage(const Texture::Slices &data, const Image::Settings &settings) = 0; - virtual Texture *newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) = 0; + virtual Texture *newImage(const Texture::Settings &settings, const Texture::Slices *data) = 0; Quad *newQuad(Quad::Viewport v, double sw, double sh); Font *newFont(love::font::Rasterizer *data); @@ -439,7 +436,7 @@ public: SpriteBatch *newSpriteBatch(Texture *texture, int size, vertex::Usage usage); ParticleSystem *newParticleSystem(Texture *texture, int size); - virtual Texture *newCanvas(const Canvas::Settings &settings) = 0; + virtual Texture *newCanvas(const Texture::Settings &settings) = 0; ShaderStage *newShaderStage(ShaderStage::StageType stage, const std::string &source); Shader *newShader(const std::string &vertex, const std::string &pixel); diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp deleted file mode 100644 index 63d3694b7..000000000 --- a/src/modules/graphics/Image.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Copyright (c) 2006-2020 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "Image.h" -#include "Graphics.h" - -// C++ -#include - -namespace love -{ -namespace graphics -{ - -love::Type Image::type("Image", &Texture::type); - -Image::Image(TextureType textype, const Settings &settings) - : Texture(textype) - , settings(settings) -{ - renderTarget = false; - sRGB = isGammaCorrect() && !settings.linear; -} - -Image::Image(TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings) - : Image(textype, settings) -{ - if (isPixelFormatCompressed(format)) - throw love::Exception("This constructor is only supported for non-compressed pixel formats."); - - if (textype == TEXTURE_2D_ARRAY) - layers = slices; - else if (textype == TEXTURE_VOLUME) - depth = slices; - - init(format, width, height, 1, settings); -} - -Image::Image(const Slices &slices, const Settings &settings) - : Image(slices.getTextureType(), settings) -{ - int dataMipmaps = 1; - if (slices.validate() && slices.getMipmapCount() > 1) - dataMipmaps = slices.getMipmapCount(); - - if (texType == TEXTURE_2D_ARRAY) - this->layers = slices.getSliceCount(); - else if (texType == TEXTURE_VOLUME) - this->depth = slices.getSliceCount(); - - love::image::ImageDataBase *slice = slices.get(0, 0); - init(slice->getFormat(), slice->getWidth(), slice->getHeight(), dataMipmaps, settings); -} - -Image::~Image() -{ -} - -void Image::init(PixelFormat fmt, int w, int h, int dataMipmaps, const Settings &settings) -{ - Graphics *gfx = Module::getInstance(Module::M_GRAPHICS); - if (gfx != nullptr && !gfx->isPixelFormatSupported(fmt, renderTarget, readable, sRGB)) - { - const char *str; - if (love::getConstant(fmt, str)) - { - throw love::Exception("Cannot create image: " - "%s%s images are not supported on this system.", sRGB ? "sRGB " : "", str); - } - else - throw love::Exception("cannot create image: format is not supported on this system."); - } - - pixelWidth = w; - pixelHeight = h; - mipmapsMode = settings.mipmaps ? MIPMAPS_MANUAL : MIPMAPS_NONE; - - width = (int) (pixelWidth / settings.dpiScale + 0.5); - height = (int) (pixelHeight / settings.dpiScale + 0.5); - - format = fmt; - - if (mipmapsMode == MIPMAPS_NONE || (isCompressed() && dataMipmaps <= 1)) - mipmapCount = 1; - else - mipmapCount = getTotalMipmapCount(w, h, depth); - - initQuad(); -} - -bool Image::getConstant(const char *in, SettingType &out) -{ - return settingTypes.find(in, out); -} - -bool Image::getConstant(SettingType in, const char *&out) -{ - return settingTypes.find(in, out); -} - -const char *Image::getConstant(SettingType in) -{ - const char *name = nullptr; - getConstant(in, name); - return name; -} - -std::vector Image::getConstants(SettingType) -{ - return settingTypes.getNames(); -} - -StringMap::Entry Image::settingTypeEntries[] = -{ - { "mipmaps", SETTING_MIPMAPS }, - { "linear", SETTING_LINEAR }, - { "dpiscale", SETTING_DPI_SCALE }, -}; - -StringMap Image::settingTypes(Image::settingTypeEntries, sizeof(Image::settingTypeEntries)); - -} // graphics -} // love diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Image.h deleted file mode 100644 index 9893f7d8f..000000000 --- a/src/modules/graphics/Image.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2006-2020 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#pragma once - -// LOVE -#include "common/config.h" -#include "common/StringMap.h" -#include "common/math.h" -#include "Texture.h" - -namespace love -{ -namespace graphics -{ - -class Image : public Texture -{ -public: - - static love::Type type; - - enum SettingType - { - SETTING_MIPMAPS, - SETTING_LINEAR, - SETTING_DPI_SCALE, - SETTING_MAX_ENUM - }; - - struct Settings - { - bool mipmaps = false; - bool linear = false; - float dpiScale = 1.0f; - }; - - virtual ~Image(); - - static bool getConstant(const char *in, SettingType &out); - static bool getConstant(SettingType in, const char *&out); - static const char *getConstant(SettingType in); - static std::vector getConstants(SettingType); - -protected: - - Image(const Slices &data, const Settings &settings); - Image(TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings); - - // The settings used to initialize this Image. - Settings settings; - -private: - - Image(TextureType textype, const Settings &settings); - - void init(PixelFormat fmt, int w, int h, int dataMipmaps, const Settings &settings); - - static StringMap::Entry settingTypeEntries[]; - static StringMap settingTypes; - -}; // Image - -} // graphics -} // love diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 2f0131f00..3a7e73061 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -159,28 +159,122 @@ love::Type Texture::type("Texture", &Drawable::type); int Texture::textureCount = 0; int64 Texture::totalGraphicsMemory = 0; -Texture::Texture(TextureType texType) - : texType(texType) - , format(PIXELFORMAT_UNKNOWN) - , renderTarget(false) +Texture::Texture(const Settings &settings, const Slices *slices) + : texType(settings.type) + , format(settings.format) + , renderTarget(settings.renderTarget) , readable(true) - , mipmapsMode(MIPMAPS_NONE) - , sRGB(false) - , width(0) - , height(0) - , depth(1) - , layers(1) + , mipmapsMode(settings.mipmaps) + , sRGB(isGammaCorrect() && !settings.linear) + , width(settings.width) + , height(settings.height) + , depth(settings.type == TEXTURE_VOLUME ? settings.layers : 1) + , layers(settings.type == TEXTURE_2D_ARRAY ? settings.layers : 1) , mipmapCount(1) , pixelWidth(0) , pixelHeight(0) - , requestedMSAA(1) + , requestedMSAA(settings.msaa) , samplerState() , graphicsMemorySize(0) , usingDefaultTexture(false) { auto gfx = Module::getInstance(Module::M_GRAPHICS); - if (gfx != nullptr) - samplerState = gfx->getDefaultSamplerState(); + + if (slices != nullptr && slices->getMipmapCount() > 0 && slices->getSliceCount() > 0) + { + texType = slices->getTextureType(); + + int dataMipmaps = 1; + if (slices->validate() && slices->getMipmapCount() > 1) + dataMipmaps = slices->getMipmapCount(); + + love::image::ImageDataBase *slice = slices->get(0, 0); + + format = slice->getFormat(); + + pixelWidth = slice->getWidth(); + pixelHeight = slice->getHeight(); + + if (texType == TEXTURE_2D_ARRAY) + layers = slices->getSliceCount(); + else if (texType == TEXTURE_VOLUME) + depth = slices->getSliceCount(); + + width = (int) (pixelWidth / settings.dpiScale + 0.5); + height = (int) (pixelHeight / settings.dpiScale + 0.5); + + if (isCompressed() && dataMipmaps <= 1) + mipmapsMode = MIPMAPS_NONE; + } + else + { + if (isCompressed()) + throw love::Exception("Compressed textures must be created with initial data."); + + pixelWidth = (int) ((width * settings.dpiScale) + 0.5); + pixelHeight = (int) ((height * settings.dpiScale) + 0.5); + } + + if (settings.readable.hasValue) + readable = settings.readable.value; + else + readable = !isPixelFormatDepthStencil(format); + + format = gfx->getSizedFormat(format, renderTarget, readable, sRGB); + + if (mipmapsMode == MIPMAPS_AUTO && isCompressed()) + mipmapsMode = MIPMAPS_MANUAL; + + if (mipmapsMode != MIPMAPS_NONE) + mipmapCount = getTotalMipmapCount(pixelWidth, pixelHeight, depth); + + if (pixelWidth <= 0 || pixelHeight <= 0 || layers <= 0 || depth <= 0) + throw love::Exception("Texture dimensions must be greater than 0."); + + if (texType != TEXTURE_2D && requestedMSAA > 1) + throw love::Exception("MSAA is only supported for textures with the 2D texture type."); + + if (readable && isPixelFormatDepthStencil(format) && settings.msaa > 1) + throw love::Exception("Readable depth/stencil textures with MSAA are not currently supported."); + + if ((!readable || settings.msaa > 1) && mipmapsMode != MIPMAPS_NONE) + throw love::Exception("Non-readable and MSAA textures cannot have mipmaps."); + + if (!readable && texType != TEXTURE_2D) + throw love::Exception("Non-readable pixel formats are only supported for 2D texture types."); + + if (isCompressed() && renderTarget) + throw love::Exception("Compressed textures cannot be render targets."); + + if (!gfx->isPixelFormatSupported(format, renderTarget, readable, sRGB)) + { + const char *fstr = "unknown"; + love::getConstant(format, fstr); + + const char *readablestr = ""; + if (readable != !isPixelFormatDepthStencil(format)) + readablestr = readable ? " readable" : " non-readable"; + + const char *rtstr = ""; + if (renderTarget) + rtstr = " as a render target"; + + throw love::Exception("The %s%s pixel format is not supported%s on this system.", fstr, readablestr, rtstr); + } + + if (!gfx->getCapabilities().textureTypes[texType]) + { + const char *textypestr = "unknown"; + Texture::getConstant(texType, textypestr); + throw love::Exception("%s textures are not supported on this system.", textypestr); + } + + validateDimensions(!renderTarget); + + samplerState = gfx->getDefaultSamplerState(); + + initQuad(); + ++textureCount; } @@ -780,6 +874,42 @@ bool Texture::Slices::validate() const return true; } +static StringMap::Entry texTypeEntries[] = +{ + { "2d", TEXTURE_2D }, + { "volume", TEXTURE_VOLUME }, + { "array", TEXTURE_2D_ARRAY }, + { "cube", TEXTURE_CUBE }, +}; + +static StringMap texTypes(texTypeEntries, sizeof(texTypeEntries)); + +static StringMap::Entry mipmapEntries[] = +{ + { "none", Texture::MIPMAPS_NONE }, + { "manual", Texture::MIPMAPS_MANUAL }, + { "auto", Texture::MIPMAPS_AUTO }, +}; + +static StringMap mipmapModes(mipmapEntries, sizeof(mipmapEntries)); + +static StringMap::Entry settingTypeEntries[] = +{ + { "width", Texture::SETTING_WIDTH }, + { "height", Texture::SETTING_HEIGHT }, + { "layers", Texture::SETTING_LAYERS }, + { "mipmaps", Texture::SETTING_MIPMAPS }, + { "format", Texture::SETTING_FORMAT }, + { "linear", Texture::SETTING_LINEAR }, + { "type", Texture::SETTING_TYPE }, + { "dpiscale", Texture::SETTING_DPI_SCALE }, + { "msaa", Texture::SETTING_MSAA }, + { "rendertarget", Texture::SETTING_RENDER_TARGET }, + { "readable", Texture::SETTING_READABLE }, +}; + +static StringMap settingTypes(settingTypeEntries, sizeof(settingTypeEntries)); + bool Texture::getConstant(const char *in, TextureType &out) { return texTypes.find(in, out); @@ -795,25 +925,6 @@ std::vector Texture::getConstants(TextureType) return texTypes.getNames(); } -StringMap::Entry Texture::texTypeEntries[] = -{ - { "2d", TEXTURE_2D }, - { "volume", TEXTURE_VOLUME }, - { "array", TEXTURE_2D_ARRAY }, - { "cube", TEXTURE_CUBE }, -}; - -StringMap Texture::texTypes(Texture::texTypeEntries, sizeof(Texture::texTypeEntries)); - -static StringMap::Entry mipmapEntries[] = -{ - { "none", Texture::MIPMAPS_NONE }, - { "manual", Texture::MIPMAPS_MANUAL }, - { "auto", Texture::MIPMAPS_AUTO }, -}; - -static StringMap mipmapModes(mipmapEntries, sizeof(mipmapEntries)); - bool Texture::getConstant(const char *in, MipmapsMode &out) { return mipmapModes.find(in, out); @@ -829,5 +940,27 @@ std::vector Texture::getConstants(MipmapsMode) return mipmapModes.getNames(); } +bool Texture::getConstant(const char *in, SettingType &out) +{ + return settingTypes.find(in, out); +} + +bool Texture::getConstant(SettingType in, const char *&out) +{ + return settingTypes.find(in, out); +} + +const char *Texture::getConstant(SettingType in) +{ + const char *name = nullptr; + getConstant(in, name); + return name; +} + +std::vector Texture::getConstants(SettingType) +{ + return settingTypes.getNames(); +} + } // graphics } // love diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 57172898a..1b583be8d 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -137,6 +137,38 @@ public: MIPMAPS_MAX_ENUM }; + enum SettingType + { + SETTING_WIDTH, + SETTING_HEIGHT, + SETTING_LAYERS, + SETTING_MIPMAPS, + SETTING_FORMAT, + SETTING_LINEAR, + SETTING_TYPE, + SETTING_DPI_SCALE, + SETTING_MSAA, + SETTING_RENDER_TARGET, + SETTING_READABLE, + SETTING_MAX_ENUM + }; + + // Size and format will be overridden by ImageData when supplied. + struct Settings + { + int width = 1; + int height = 1; + int layers = 1; // depth for 3D textures + TextureType type = TEXTURE_2D; + MipmapsMode mipmaps = MIPMAPS_NONE; + PixelFormat format = PIXELFORMAT_NORMAL; + bool linear = false; + float dpiScale = 1.0f; + int msaa = 0; + bool renderTarget = false; + OptionalBool readable; + }; + struct Slices { public: @@ -169,7 +201,7 @@ public: static int64 totalGraphicsMemory; - Texture(TextureType texType); + Texture(const Settings &settings, const Slices *slices); virtual ~Texture(); // Drawable. @@ -234,6 +266,11 @@ public: static bool getConstant(MipmapsMode in, const char *&out); static std::vector getConstants(MipmapsMode); + static bool getConstant(const char *in, SettingType &out); + static bool getConstant(SettingType in, const char *&out); + static const char *getConstant(SettingType in); + static std::vector getConstants(SettingType); + protected: void initQuad(); @@ -276,11 +313,6 @@ protected: // back to a default texture. bool usingDefaultTexture; -private: - - static StringMap::Entry texTypeEntries[]; - static StringMap texTypes; - }; // Texture } // graphics diff --git a/src/modules/graphics/Video.cpp b/src/modules/graphics/Video.cpp index fe5207961..92d387cd3 100644 --- a/src/modules/graphics/Video.cpp +++ b/src/modules/graphics/Video.cpp @@ -79,11 +79,14 @@ Video::Video(Graphics *gfx, love::video::VideoStream *stream, float dpiscale) const unsigned char *data[3] = {frame->yplane, frame->cbplane, frame->crplane}; - Image::Settings settings; + Texture::Settings settings; for (int i = 0; i < 3; i++) { - Texture *tex = gfx->newImage(TEXTURE_2D, PIXELFORMAT_R8_UNORM, widths[i], heights[i], 1, settings); + settings.width = widths[i]; + settings.height = heights[i]; + settings.format = PIXELFORMAT_R8_UNORM; + Texture *tex = gfx->newImage(settings, nullptr); tex->setSamplerState(samplerState); diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 56de9ca81..6f5b46881 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -183,7 +183,7 @@ static bool createRenderbuffer(int width, int height, int &samples, PixelFormat } Canvas::Canvas(const Settings &settings) - : love::graphics::Canvas(settings) + : love::graphics::Texture(settings, nullptr) , fbo(0) , texture(0) , renderbuffer(0) @@ -346,7 +346,7 @@ ptrdiff_t Canvas::getHandle() const love::image::ImageData *Canvas::newImageData(love::image::Image *module, int slice, int mipmap, const Rect &r) { - love::image::ImageData *data = love::graphics::Canvas::newImageData(module, slice, mipmap, r); + love::image::ImageData *data = love::graphics::Texture::newImageData(module, slice, mipmap, r); bool isSRGB = false; OpenGL::TextureFormat fmt = gl.convertPixelFormat(data->getFormat(), false, isSRGB); diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index d1bc3cb1c..158f134b0 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -24,7 +24,7 @@ #include "common/config.h" #include "common/Color.h" #include "common/int.h" -#include "graphics/Canvas.h" +#include "graphics/Texture.h" #include "graphics/Volatile.h" #include "OpenGL.h" @@ -35,7 +35,7 @@ namespace graphics namespace opengl { -class Canvas final : public love::graphics::Canvas, public Volatile +class Canvas final : public love::graphics::Texture, public Volatile { public: diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index d61f7f57e..4cc54eb22 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -130,17 +130,12 @@ love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t return CreateStreamBuffer(type, size); } -love::graphics::Texture *Graphics::newImage(const Texture::Slices &data, const Image::Settings &settings) +love::graphics::Texture *Graphics::newImage(const Texture::Settings &settings, const Texture::Slices *data) { - return new Image(data, settings); + return new Image(settings, data); } -love::graphics::Texture *Graphics::newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) -{ - return new Image(textype, format, width, height, slices, settings); -} - -love::graphics::Texture *Graphics::newCanvas(const Canvas::Settings &settings) +love::graphics::Texture *Graphics::newCanvas(const Texture::Settings &settings) { return new Canvas(settings); } diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 5745f8e99..1375feca9 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -60,9 +60,8 @@ public: // Implements Module. const char *getName() const override; - love::graphics::Texture *newImage(const Texture::Slices &data, const Image::Settings &settings) override; - love::graphics::Texture *newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) override; - love::graphics::Texture *newCanvas(const Canvas::Settings &settings) override; + love::graphics::Texture *newImage(const Texture::Settings &settings, const Texture::Slices *data) override; + love::graphics::Texture *newCanvas(const Texture::Settings &settings) override; love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override; void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override; diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 95750aad5..233e7a291 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -33,19 +33,13 @@ namespace graphics namespace opengl { -Image::Image(TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings) - : love::graphics::Image(textype, format, width, height, slices, settings) - , slices(textype) - , texture(0) -{ - loadVolatile(); -} - -Image::Image(const Slices &slices, const Settings &settings) - : love::graphics::Image(slices, settings) - , slices(slices) +Image::Image(const Settings &settings, const Slices *data) + : love::graphics::Texture(settings, data) + , slices(settings.type) , texture(0) { + if (data != nullptr) + slices = *data; loadVolatile(); } diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index c660903c2..f2811e827 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -21,7 +21,7 @@ #pragma once // LOVE -#include "graphics/Image.h" +#include "graphics/Texture.h" #include "graphics/Volatile.h" // OpenGL @@ -34,12 +34,11 @@ namespace graphics namespace opengl { -class Image final : public love::graphics::Image, public Volatile +class Image final : public love::graphics::Texture, public Volatile { public: - Image(const Slices &data, const Settings &settings); - Image(TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings); + Image(const Settings &settings, const Slices *data); virtual ~Image(); diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index da1d1fdea..2989d5f0f 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -700,19 +700,19 @@ static void parseDPIScale(Data *d, float *dpiscale) } } -static Image::Settings w__optImageSettings(lua_State *L, int idx, bool &setdpiscale) +static Texture::Settings w__optImageSettings(lua_State *L, int idx, bool &setdpiscale) { - Image::Settings s; + Texture::Settings s; setdpiscale = false; if (!lua_isnoneornil(L, idx)) { - luax_checktablefields(L, idx, "image setting name", Image::getConstant); + luax_checktablefields(L, idx, "image setting name", Texture::getConstant); - s.mipmaps = luax_boolflag(L, idx, Image::getConstant(Image::SETTING_MIPMAPS), s.mipmaps); - s.linear = luax_boolflag(L, idx, Image::getConstant(Image::SETTING_LINEAR), s.linear); + s.mipmaps = luax_boolflag(L, idx, "mipmaps", false) ? Texture::MIPMAPS_MANUAL : Texture::MIPMAPS_NONE; + s.linear = luax_boolflag(L, idx, Texture::getConstant(Texture::SETTING_LINEAR), s.linear); - lua_getfield(L, idx, Image::getConstant(Image::SETTING_DPI_SCALE)); + lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_DPI_SCALE)); if (lua_isnumber(L, -1)) { s.dpiScale = (float) lua_tonumber(L, -1); @@ -757,11 +757,11 @@ getImageData(lua_State *L, int idx, bool allowcompressed, float *dpiscale) return std::make_pair(idata, cdata); } -static int w__pushNewImage(lua_State *L, Texture::Slices &slices, const Image::Settings &settings) +static int w__pushNewImage(lua_State *L, Texture::Slices &slices, const Texture::Settings &settings) { StrongRef i; luax_catchexcept(L, - [&]() { i.set(instance()->newImage(slices, settings), Acquire::NORETAIN); }, + [&]() { i.set(instance()->newImage(settings, &slices), Acquire::NORETAIN); }, [&](bool) { slices.clear(); } ); @@ -776,7 +776,7 @@ int w_newCubeImage(lua_State *L) Texture::Slices slices(TEXTURE_CUBE); bool dpiscaleset = false; - Image::Settings settings = w__optImageSettings(L, 2, dpiscaleset); + Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset); float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; auto imagemodule = Module::getInstance(Module::M_IMAGE); @@ -870,7 +870,7 @@ int w_newArrayImage(lua_State *L) Texture::Slices slices(TEXTURE_2D_ARRAY); bool dpiscaleset = false; - Image::Settings settings = w__optImageSettings(L, 2, dpiscaleset); + Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset); float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; if (lua_istable(L, 1)) @@ -936,7 +936,7 @@ int w_newVolumeImage(lua_State *L) Texture::Slices slices(TEXTURE_VOLUME); bool dpiscaleset = false; - Image::Settings settings = w__optImageSettings(L, 2, dpiscaleset); + Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset); float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; if (lua_istable(L, 1)) @@ -1007,7 +1007,7 @@ int w_newImage(lua_State *L) Texture::Slices slices(TEXTURE_2D); bool dpiscaleset = false; - Image::Settings settings = w__optImageSettings(L, 2, dpiscaleset); + Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset); float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; if (lua_istable(L, 1)) @@ -1185,7 +1185,8 @@ int w_newCanvas(lua_State *L) { luax_checkgraphicscreated(L); - Canvas::Settings settings; + Texture::Settings settings; + settings.renderTarget = true; // check if width and height are given. else default to screen dimensions. settings.width = (int) luaL_optinteger(L, 1, instance()->getWidth()); @@ -1205,12 +1206,12 @@ int w_newCanvas(lua_State *L) if (!lua_isnoneornil(L, startidx)) { - luax_checktablefields(L, startidx, "canvas setting name", Canvas::getConstant); + luax_checktablefields(L, startidx, "texture setting name", Texture::getConstant); - settings.dpiScale = (float) luax_numberflag(L, startidx, Canvas::getConstant(Canvas::SETTING_DPI_SCALE), settings.dpiScale); - settings.msaa = luax_intflag(L, startidx, Canvas::getConstant(Canvas::SETTING_MSAA), settings.msaa); + settings.dpiScale = (float) luax_numberflag(L, startidx, Texture::getConstant(Texture::SETTING_DPI_SCALE), settings.dpiScale); + settings.msaa = luax_intflag(L, startidx, Texture::getConstant(Texture::SETTING_MSAA), settings.msaa); - lua_getfield(L, startidx, Canvas::getConstant(Canvas::SETTING_FORMAT)); + lua_getfield(L, startidx, Texture::getConstant(Texture::SETTING_FORMAT)); if (!lua_isnoneornil(L, -1)) { const char *str = luaL_checkstring(L, -1); @@ -1219,7 +1220,7 @@ int w_newCanvas(lua_State *L) } lua_pop(L, 1); - lua_getfield(L, startidx, Canvas::getConstant(Canvas::SETTING_TYPE)); + lua_getfield(L, startidx, Texture::getConstant(Texture::SETTING_TYPE)); if (!lua_isnoneornil(L, -1)) { const char *str = luaL_checkstring(L, -1); @@ -1228,7 +1229,7 @@ int w_newCanvas(lua_State *L) } lua_pop(L, 1); - lua_getfield(L, startidx, Canvas::getConstant(Canvas::SETTING_READABLE)); + lua_getfield(L, startidx, Texture::getConstant(Texture::SETTING_READABLE)); if (!lua_isnoneornil(L, -1)) { settings.readable.hasValue = true; @@ -1236,7 +1237,7 @@ int w_newCanvas(lua_State *L) } lua_pop(L, 1); - lua_getfield(L, startidx, Canvas::getConstant(Canvas::SETTING_MIPMAPS)); + lua_getfield(L, startidx, Texture::getConstant(Texture::SETTING_MIPMAPS)); if (!lua_isnoneornil(L, -1)) { const char *str = luaL_checkstring(L, -1); From 0017f9c77dce9371b7fa7f5e7275054084ec1b9e Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Feb 2020 22:15:18 -0400 Subject: [PATCH 16/31] Remove a redundant internal Texture method --- src/modules/graphics/Texture.cpp | 113 ++++++++++++------------- src/modules/graphics/Texture.h | 1 - src/modules/graphics/opengl/Canvas.cpp | 1 - 3 files changed, 54 insertions(+), 61 deletions(-) diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 3a7e73061..8d8f21121 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -273,7 +273,8 @@ Texture::Texture(const Settings &settings, const Slices *slices) samplerState = gfx->getDefaultSamplerState(); - initQuad(); + Quad::Viewport v = {0, 0, (double) width, (double) height}; + quad.set(new Quad(v, width, height), Acquire::NORETAIN); ++textureCount; } @@ -284,12 +285,6 @@ Texture::~Texture() setGraphicsMemorySize(0); } -void Texture::initQuad() -{ - Quad::Viewport v = {0, 0, (double) width, (double) height}; - quad.set(new Quad(v, width, height), Acquire::NORETAIN); -} - void Texture::setGraphicsMemorySize(int64 bytes) { totalGraphicsMemory = std::max(totalGraphicsMemory - graphicsMemorySize, (int64) 0); @@ -299,58 +294,6 @@ void Texture::setGraphicsMemorySize(int64 bytes) totalGraphicsMemory += bytes; } -TextureType Texture::getTextureType() const -{ - return texType; -} - -PixelFormat Texture::getPixelFormat() const -{ - return format; -} - -Texture::MipmapsMode Texture::getMipmapsMode() const -{ - return mipmapsMode; -} - -bool Texture::isRenderTarget() const -{ - return renderTarget; -} - -bool Texture::isReadable() const -{ - return readable; -} - -bool Texture::isCompressed() const -{ - return isPixelFormatCompressed(format); -} - -bool Texture::isFormatLinear() const -{ - return isGammaCorrect() && !sRGB && format != PIXELFORMAT_sRGBA8_UNORM; -} - -bool Texture::isValidSlice(int slice) const -{ - if (slice < 0) - return false; - - if (texType == TEXTURE_CUBE) - return slice < 6; - else if (texType == TEXTURE_VOLUME) - return slice < depth; - else if (texType == TEXTURE_2D_ARRAY) - return slice < layers; - else if (slice > 0) - return false; - - return true; -} - void Texture::draw(Graphics *gfx, const Matrix4 &m) { draw(gfx, quad, m); @@ -577,6 +520,58 @@ love::image::ImageData *Texture::newImageData(love::image::Image *module, int sl return module->newImageData(r.w, r.h, dataformat); } +TextureType Texture::getTextureType() const +{ + return texType; +} + +PixelFormat Texture::getPixelFormat() const +{ + return format; +} + +Texture::MipmapsMode Texture::getMipmapsMode() const +{ + return mipmapsMode; +} + +bool Texture::isRenderTarget() const +{ + return renderTarget; +} + +bool Texture::isReadable() const +{ + return readable; +} + +bool Texture::isCompressed() const +{ + return isPixelFormatCompressed(format); +} + +bool Texture::isFormatLinear() const +{ + return isGammaCorrect() && !sRGB && format != PIXELFORMAT_sRGBA8_UNORM; +} + +bool Texture::isValidSlice(int slice) const +{ + if (slice < 0) + return false; + + if (texType == TEXTURE_CUBE) + return slice < 6; + else if (texType == TEXTURE_VOLUME) + return slice < depth; + else if (texType == TEXTURE_2D_ARRAY) + return slice < layers; + else if (slice > 0) + return false; + + return true; +} + int Texture::getWidth(int mip) const { return std::max(width >> mip, 1); diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 1b583be8d..ec2d7cc68 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -273,7 +273,6 @@ public: protected: - void initQuad(); void setGraphicsMemorySize(int64 size); void uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y); diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 6f5b46881..4b77c06f4 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -193,7 +193,6 @@ Canvas::Canvas(const Settings &settings) if (gfx != nullptr) format = gfx->getSizedFormat(format, renderTarget, readable, sRGB); - initQuad(); loadVolatile(); if (status != GL_FRAMEBUFFER_COMPLETE) From ca84b6db488237f2b3ccaa6528eaa35388c79a56 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 5 Feb 2020 07:49:38 -0400 Subject: [PATCH 17/31] More robust error handling for AMD Pinned Memory buffers (issue #1540) Also print out any errors that are produced from that (for now). --- src/modules/graphics/opengl/StreamBuffer.cpp | 31 ++++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/modules/graphics/opengl/StreamBuffer.cpp b/src/modules/graphics/opengl/StreamBuffer.cpp index 605bcd31b..7e2590417 100644 --- a/src/modules/graphics/opengl/StreamBuffer.cpp +++ b/src/modules/graphics/opengl/StreamBuffer.cpp @@ -406,7 +406,12 @@ public: if (!alignedMalloc((void **) &data, alignedSize, alignment)) throw love::Exception("Out of memory."); - loadVolatile(); + if (!loadVolatile()) + { + ptrdiff_t pointer = (ptrdiff_t) data; + alignedFree(data); + throw love::Exception("AMD Pinned Memory StreamBuffer implementation failed to create buffer (address: %p, alignment: %ld, aiigned size: %ld)", pointer, alignment, alignedSize); + } } ~StreamBufferPinnedMemory() @@ -441,9 +446,19 @@ public: glGenBuffers(1, &vbo); + while (glGetError() != GL_NO_ERROR) + /* Clear errors. */; + glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, vbo); glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, alignedSize, data, GL_STREAM_DRAW); + if (glGetError() != GL_NO_ERROR) + { + gl.deleteBuffer(vbo); + vbo = 0; + return false; + } + frameGPUReadOffset = 0; frameIndex = 0; @@ -485,8 +500,18 @@ love::graphics::StreamBuffer *CreateStreamBuffer(BufferType mode, size_t size) // AMD's pinned memory seems to be faster than persistent mapping, // on AMD GPUs. if (GLAD_AMD_pinned_memory) - return new StreamBufferPinnedMemory(mode, size); - else if (GLAD_VERSION_4_4 || GLAD_ARB_buffer_storage) + { + try + { + return new StreamBufferPinnedMemory(mode, size); + } + catch (love::Exception &e) + { + printf("Failed creating Pinned Memory StreamBuffer: %s\n", e.what()); + } + } + + if (GLAD_VERSION_4_4 || GLAD_ARB_buffer_storage) return new StreamBufferPersistentMapSync(mode, size); // Most modern drivers have a separate internal thread which queues From 813b1e0e69852e7744e3a9e6e4855be22f085c31 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 5 Feb 2020 18:03:34 -0400 Subject: [PATCH 18/31] Remove debug print --- src/modules/graphics/opengl/StreamBuffer.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/graphics/opengl/StreamBuffer.cpp b/src/modules/graphics/opengl/StreamBuffer.cpp index 7e2590417..8ea3a39a8 100644 --- a/src/modules/graphics/opengl/StreamBuffer.cpp +++ b/src/modules/graphics/opengl/StreamBuffer.cpp @@ -507,7 +507,11 @@ love::graphics::StreamBuffer *CreateStreamBuffer(BufferType mode, size_t size) } catch (love::Exception &e) { - printf("Failed creating Pinned Memory StreamBuffer: %s\n", e.what()); + // According to the spec, oinned memory can fail if the RAM + // allocation can't be mapped to the GPU's address space. + // This seems to happen in practice on Mesa + amdgpu: + // https://bitbucket.org/rude/love/issues/1540 + // Fall through to other implementations when that happens. } } From 17f77407bb83c1cf4cc28dc85d67bb236c6367b6 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 5 Feb 2020 20:39:55 -0400 Subject: [PATCH 19/31] Replace internal C++ newImage and newCanvas methods with newTexture --- src/modules/graphics/Font.cpp | 2 +- src/modules/graphics/Graphics.cpp | 3 ++- src/modules/graphics/Graphics.h | 4 +--- src/modules/graphics/Video.cpp | 2 +- src/modules/graphics/opengl/Graphics.cpp | 12 +++++------- src/modules/graphics/opengl/Graphics.h | 3 +-- src/modules/graphics/wrap_Graphics.cpp | 4 ++-- 7 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index 97f82572a..3d71b84fd 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -154,7 +154,7 @@ void Font::createTexture() settings.format = pixelFormat; settings.width = size.width; settings.height = size.height; - texture = gfx->newImage(settings, nullptr); + texture = gfx->newTexture(settings, nullptr); texture->setSamplerState(samplerState); { diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index c76c0afc3..9620a579e 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -821,12 +821,13 @@ Texture *Graphics::getTemporaryTexture(PixelFormat format, int w, int h, int sam if (texture == nullptr) { Texture::Settings settings; + settings.renderTarget = true; settings.format = format; settings.width = w; settings.height = h; settings.msaa = samples; - texture = newCanvas(settings); + texture = newTexture(settings); temporaryTextures.emplace_back(texture); } diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index f7bf99529..09a34bf00 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -426,7 +426,7 @@ public: // Implements Module. virtual ModuleType getModuleType() const { return M_GRAPHICS; } - virtual Texture *newImage(const Texture::Settings &settings, const Texture::Slices *data) = 0; + virtual Texture *newTexture(const Texture::Settings &settings, const Texture::Slices *data = nullptr) = 0; Quad *newQuad(Quad::Viewport v, double sw, double sh); Font *newFont(love::font::Rasterizer *data); @@ -436,8 +436,6 @@ public: SpriteBatch *newSpriteBatch(Texture *texture, int size, vertex::Usage usage); ParticleSystem *newParticleSystem(Texture *texture, int size); - virtual Texture *newCanvas(const Texture::Settings &settings) = 0; - ShaderStage *newShaderStage(ShaderStage::StageType stage, const std::string &source); Shader *newShader(const std::string &vertex, const std::string &pixel); diff --git a/src/modules/graphics/Video.cpp b/src/modules/graphics/Video.cpp index 92d387cd3..8854e64c7 100644 --- a/src/modules/graphics/Video.cpp +++ b/src/modules/graphics/Video.cpp @@ -86,7 +86,7 @@ Video::Video(Graphics *gfx, love::video::VideoStream *stream, float dpiscale) settings.width = widths[i]; settings.height = heights[i]; settings.format = PIXELFORMAT_R8_UNORM; - Texture *tex = gfx->newImage(settings, nullptr); + Texture *tex = gfx->newTexture(settings, nullptr); tex->setSamplerState(samplerState); diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 4cc54eb22..ef7c46622 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -130,14 +130,12 @@ love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t return CreateStreamBuffer(type, size); } -love::graphics::Texture *Graphics::newImage(const Texture::Settings &settings, const Texture::Slices *data) +love::graphics::Texture *Graphics::newTexture(const Texture::Settings &settings, const Texture::Slices *data) { - return new Image(settings, data); -} - -love::graphics::Texture *Graphics::newCanvas(const Texture::Settings &settings) -{ - return new Canvas(settings); + if (settings.renderTarget) + return new Canvas(settings); + else + return new Image(settings, data); } love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 1375feca9..b2ba4d186 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -60,8 +60,7 @@ public: // Implements Module. const char *getName() const override; - love::graphics::Texture *newImage(const Texture::Settings &settings, const Texture::Slices *data) override; - love::graphics::Texture *newCanvas(const Texture::Settings &settings) override; + love::graphics::Texture *newTexture(const Texture::Settings &settings, const Texture::Slices *data = nullptr) override; love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override; void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override; diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 2989d5f0f..dac60e959 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -761,7 +761,7 @@ static int w__pushNewImage(lua_State *L, Texture::Slices &slices, const Texture: { StrongRef i; luax_catchexcept(L, - [&]() { i.set(instance()->newImage(settings, &slices), Acquire::NORETAIN); }, + [&]() { i.set(instance()->newTexture(settings, &slices), Acquire::NORETAIN); }, [&](bool) { slices.clear(); } ); @@ -1248,7 +1248,7 @@ int w_newCanvas(lua_State *L) } Texture *texture = nullptr; - luax_catchexcept(L, [&](){ texture = instance()->newCanvas(settings); }); + luax_catchexcept(L, [&](){ texture = instance()->newTexture(settings); }); luax_pushtype(L, texture); texture->release(); From 12c90b3dca3e8c5291b0630f6ae1fd3b70188b0e Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 7 Feb 2020 20:29:21 -0400 Subject: [PATCH 20/31] Merge Image and Canvas GL backend classes into new common Texture class. --- CMakeLists.txt | 6 +- .../xcode/liblove.xcodeproj/project.pbxproj | 30 +- src/common/pixelformat.cpp | 196 +++++--- src/common/pixelformat.h | 46 +- src/modules/font/GlyphData.cpp | 2 +- src/modules/graphics/Font.cpp | 2 +- src/modules/graphics/Texture.cpp | 17 +- src/modules/graphics/Texture.h | 2 +- src/modules/graphics/Video.cpp | 4 +- src/modules/graphics/opengl/Graphics.cpp | 23 +- src/modules/graphics/opengl/Graphics.h | 7 +- src/modules/graphics/opengl/Image.cpp | 296 ------------- src/modules/graphics/opengl/Image.h | 72 --- src/modules/graphics/opengl/OpenGL.cpp | 1 - src/modules/graphics/opengl/Shader.cpp | 12 +- src/modules/graphics/opengl/Shader.h | 6 +- .../opengl/{Canvas.cpp => Texture.cpp} | 417 ++++++++++++------ .../graphics/opengl/{Canvas.h => Texture.h} | 51 +-- src/modules/image/ImageData.cpp | 6 +- src/modules/image/magpie/EXRHandler.cpp | 2 +- src/modules/window/sdl/Window.cpp | 2 +- 21 files changed, 521 insertions(+), 679 deletions(-) delete mode 100644 src/modules/graphics/opengl/Image.cpp delete mode 100644 src/modules/graphics/opengl/Image.h rename src/modules/graphics/opengl/{Canvas.cpp => Texture.cpp} (57%) rename src/modules/graphics/opengl/{Canvas.h => Texture.h} (74%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1413f57ac..726e778db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -580,14 +580,10 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT set(LOVE_SRC_MODULE_GRAPHICS_OPENGL src/modules/graphics/opengl/Buffer.cpp src/modules/graphics/opengl/Buffer.h - src/modules/graphics/opengl/Canvas.cpp - src/modules/graphics/opengl/Canvas.h src/modules/graphics/opengl/FenceSync.cpp src/modules/graphics/opengl/FenceSync.h src/modules/graphics/opengl/Graphics.cpp src/modules/graphics/opengl/Graphics.h - src/modules/graphics/opengl/Image.cpp - src/modules/graphics/opengl/Image.h src/modules/graphics/opengl/OpenGL.cpp src/modules/graphics/opengl/OpenGL.h src/modules/graphics/opengl/Shader.cpp @@ -596,6 +592,8 @@ set(LOVE_SRC_MODULE_GRAPHICS_OPENGL src/modules/graphics/opengl/ShaderStage.h src/modules/graphics/opengl/StreamBuffer.cpp src/modules/graphics/opengl/StreamBuffer.h + src/modules/graphics/opengl/Texture.cpp + src/modules/graphics/opengl/Texture.h ) set(LOVE_SRC_MODULE_GRAPHICS diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 73496ae8a..0a692bf79 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -403,15 +403,12 @@ FA0B7D301A95902C000E1D17 /* Graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B8A1A95902C000E1D17 /* Graphics.cpp */; }; FA0B7D311A95902C000E1D17 /* Graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B8A1A95902C000E1D17 /* Graphics.cpp */; }; FA0B7D321A95902C000E1D17 /* Graphics.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7B8B1A95902C000E1D17 /* Graphics.h */; }; - FA0B7D331A95902C000E1D17 /* Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B8D1A95902C000E1D17 /* Canvas.cpp */; }; - FA0B7D341A95902C000E1D17 /* Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B8D1A95902C000E1D17 /* Canvas.cpp */; }; - FA0B7D351A95902C000E1D17 /* Canvas.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7B8E1A95902C000E1D17 /* Canvas.h */; }; FA0B7D391A95902C000E1D17 /* Graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B911A95902C000E1D17 /* Graphics.cpp */; }; FA0B7D3A1A95902C000E1D17 /* Graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B911A95902C000E1D17 /* Graphics.cpp */; }; FA0B7D3B1A95902C000E1D17 /* Graphics.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7B921A95902C000E1D17 /* Graphics.h */; }; - FA0B7D3C1A95902C000E1D17 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B931A95902C000E1D17 /* Image.cpp */; }; - FA0B7D3D1A95902C000E1D17 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B931A95902C000E1D17 /* Image.cpp */; }; - FA0B7D3E1A95902C000E1D17 /* Image.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7B941A95902C000E1D17 /* Image.h */; }; + FA0B7D3C1A95902C000E1D17 /* Texture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B931A95902C000E1D17 /* Texture.cpp */; }; + FA0B7D3D1A95902C000E1D17 /* Texture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B931A95902C000E1D17 /* Texture.cpp */; }; + FA0B7D3E1A95902C000E1D17 /* Texture.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7B941A95902C000E1D17 /* Texture.h */; }; FA0B7D421A95902C000E1D17 /* OpenGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B971A95902C000E1D17 /* OpenGL.cpp */; }; FA0B7D431A95902C000E1D17 /* OpenGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B971A95902C000E1D17 /* OpenGL.cpp */; }; FA0B7D441A95902C000E1D17 /* OpenGL.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7B981A95902C000E1D17 /* OpenGL.h */; }; @@ -1536,12 +1533,10 @@ FA0B7B891A95902C000E1D17 /* Drawable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Drawable.h; sourceTree = ""; }; FA0B7B8A1A95902C000E1D17 /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Graphics.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; FA0B7B8B1A95902C000E1D17 /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Graphics.h; sourceTree = ""; }; - FA0B7B8D1A95902C000E1D17 /* Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Canvas.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - FA0B7B8E1A95902C000E1D17 /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Canvas.h; sourceTree = ""; }; FA0B7B911A95902C000E1D17 /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Graphics.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; FA0B7B921A95902C000E1D17 /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Graphics.h; sourceTree = ""; }; - FA0B7B931A95902C000E1D17 /* Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Image.cpp; sourceTree = ""; }; - FA0B7B941A95902C000E1D17 /* Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = ""; }; + FA0B7B931A95902C000E1D17 /* Texture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Texture.cpp; sourceTree = ""; }; + FA0B7B941A95902C000E1D17 /* Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Texture.h; sourceTree = ""; }; FA0B7B971A95902C000E1D17 /* OpenGL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpenGL.cpp; sourceTree = ""; }; FA0B7B981A95902C000E1D17 /* OpenGL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenGL.h; sourceTree = ""; }; FA0B7B9B1A95902C000E1D17 /* Polyline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Polyline.cpp; sourceTree = ""; }; @@ -2887,14 +2882,10 @@ children = ( FA0B7BA41A95902C000E1D17 /* Buffer.cpp */, FA0B7BA51A95902C000E1D17 /* Buffer.h */, - FA0B7B8D1A95902C000E1D17 /* Canvas.cpp */, - FA0B7B8E1A95902C000E1D17 /* Canvas.h */, FA28EBD31E352DB5003446F4 /* FenceSync.cpp */, FA28EBD41E352DB5003446F4 /* FenceSync.h */, FA0B7B911A95902C000E1D17 /* Graphics.cpp */, FA0B7B921A95902C000E1D17 /* Graphics.h */, - FA0B7B931A95902C000E1D17 /* Image.cpp */, - FA0B7B941A95902C000E1D17 /* Image.h */, FA0B7B971A95902C000E1D17 /* OpenGL.cpp */, FA0B7B981A95902C000E1D17 /* OpenGL.h */, FA0B7B9D1A95902C000E1D17 /* Shader.cpp */, @@ -2903,6 +2894,8 @@ FA3C5E461F8D80CA0003C579 /* ShaderStage.h */, FA7634481E28722A0066EF9E /* StreamBuffer.cpp */, FA7634491E28722A0066EF9E /* StreamBuffer.h */, + FA0B7B931A95902C000E1D17 /* Texture.cpp */, + FA0B7B941A95902C000E1D17 /* Texture.h */, ); path = opengl; sourceTree = ""; @@ -3820,9 +3813,8 @@ FA0B7CFC1A95902C000E1D17 /* Filesystem.h in Headers */, FA0B7AD81A958EA3000E1D17 /* lua-enet.h in Headers */, FA0B7A3A1A958EA3000E1D17 /* b2DynamicTree.h in Headers */, - FA0B7D351A95902C000E1D17 /* Canvas.h in Headers */, FA0B7EBA1A95902C000E1D17 /* Channel.h in Headers */, - FA0B7D3E1A95902C000E1D17 /* Image.h in Headers */, + FA0B7D3E1A95902C000E1D17 /* Texture.h in Headers */, FA0B7ECA1A95902C000E1D17 /* threads.h in Headers */, FADF54361E3DAE6E00012CC0 /* wrap_SpriteBatch.h in Headers */, FA0B7DB01A95902C000E1D17 /* wrap_CompressedImageData.h in Headers */, @@ -4381,7 +4373,7 @@ FA0B7D191A95902C000E1D17 /* TrueTypeRasterizer.cpp in Sources */, FAC271E723B5B5B400C200D3 /* renderstate.cpp in Sources */, FA0B7CFB1A95902C000E1D17 /* Filesystem.cpp in Sources */, - FA0B7D3D1A95902C000E1D17 /* Image.cpp in Sources */, + FA0B7D3D1A95902C000E1D17 /* Texture.cpp in Sources */, FA0B7B351A958EA3000E1D17 /* wuff_convert.c in Sources */, FAF140941E20934C00F898D2 /* PpScanner.cpp in Sources */, FA9D53AD1F5307E900125C6B /* Deprecations.cpp in Sources */, @@ -4545,7 +4537,6 @@ FA0B79411A958E3B000E1D17 /* utf8.cpp in Sources */, FAE64A862071363100BC7981 /* physfs_archiver_qpak.c in Sources */, FA0B7ADF1A958EA3000E1D17 /* lodepng.cpp in Sources */, - FA0B7D341A95902C000E1D17 /* Canvas.cpp in Sources */, FAF140761E20934C00F898D2 /* IntermTraverse.cpp in Sources */, FA0B7E8C1A95902C000E1D17 /* FLACDecoder.cpp in Sources */, FA0B7A421A958EA3000E1D17 /* b2CircleShape.cpp in Sources */, @@ -4778,7 +4769,7 @@ FA0B7CFA1A95902C000E1D17 /* Filesystem.cpp in Sources */, FA1BA0A21E16D97500AA2803 /* wrap_Font.cpp in Sources */, FAC7CD781FE35E95006A60C7 /* physfs_platform_qnx.c in Sources */, - FA0B7D3C1A95902C000E1D17 /* Image.cpp in Sources */, + FA0B7D3C1A95902C000E1D17 /* Texture.cpp in Sources */, FA0B7A8C1A958EA3000E1D17 /* b2DistanceJoint.cpp in Sources */, FADF53FD1E3D74F200012CC0 /* Text.cpp in Sources */, FA6A2B741F60B6710074C308 /* ByteData.cpp in Sources */, @@ -4939,7 +4930,6 @@ FA0B7AD41A958EA3000E1D17 /* unix.c in Sources */, FA0B7A771A958EA3000E1D17 /* b2CircleContact.cpp in Sources */, FADF543B1E3DAFF700012CC0 /* wrap_Graphics.cpp in Sources */, - FA0B7D331A95902C000E1D17 /* Canvas.cpp in Sources */, FA0B7E941A95902C000E1D17 /* Mpg123Decoder.cpp in Sources */, FA0B7E8B1A95902C000E1D17 /* FLACDecoder.cpp in Sources */, FA0B7B3A1A958EA3000E1D17 /* wuff_memory.c in Sources */, diff --git a/src/common/pixelformat.cpp b/src/common/pixelformat.cpp index 0048236b4..6ded27517 100644 --- a/src/common/pixelformat.cpp +++ b/src/common/pixelformat.cpp @@ -24,6 +24,87 @@ namespace love { +static PixelFormatInfo formatInfo[] = +{ + // components, blockW, blockH, blockSize, color, depth, stencil, compressed + { 0, 1, 1, 0, false, false, false, false }, // PIXELFORMAT_UNKNOWN + + { 0, 1, 1, 0, true, false, false, false }, // PIXELFORMAT_NORMAL + { 0, 1, 1, 0, true, false, false, false }, // PIXELFORMAT_HDR + + { 1, 1, 1, 1, true, false, false, false }, // PIXELFORMAT_R8_UNORM + { 1, 1, 1, 2, true, false, false, false }, // PIXELFORMAT_R16_UNORM + { 1, 1, 1, 2, true, false, false, false }, // PIXELFORMAT_R16_FLOAT + { 1, 1, 1, 4, true, false, false, false }, // PIXELFORMAT_R32_FLOAT + + { 2, 1, 1, 2, true, false, false, false }, // PIXELFORMAT_RG8_UNORM + { 2, 1, 1, 2, true, false, false, false }, // PIXELFORMAT_LA8_UNORM + { 2, 1, 1, 4, true, false, false, false }, // PIXELFORMAT_RG16_UNORM + { 2, 1, 1, 4, true, false, false, false }, // PIXELFORMAT_RG16_FLOAT + { 2, 1, 1, 8, true, false, false, false }, // PIXELFORMAT_RG32_FLOAT + + { 4, 1, 1, 4, true, false, false, false }, // PIXELFORMAT_RGBA8_UNORM + { 4, 1, 1, 4, true, false, false, false }, // PIXELFORMAT_sRGBA8_UNORM + { 4, 1, 1, 8, true, false, false, false }, // PIXELFORMAT_RGBA16_UNORM + { 4, 1, 1, 8, true, false, false, false }, // PIXELFORMAT_RGBA16_FLOAT + { 4, 1, 1, 16, true, false, false, false }, // PIXELFORMAT_RGBA32_FLOAT + + { 4, 1, 1, 2, true, false, false, false }, // PIXELFORMAT_RGBA4_UNORM + { 4, 1, 1, 2, true, false, false, false }, // PIXELFORMAT_RGB5A1_UNORM + { 3, 1, 1, 2, true, false, false, false }, // PIXELFORMAT_RGB565_UNORM + { 4, 1, 1, 4, true, false, false, false }, // PIXELFORMAT_RGB10A2_UNORM + { 3, 1, 1, 4, true, false, false, false }, // PIXELFORMAT_RG11B10_FLOAT + + { 1, 1, 1, 1, false, false, true , false }, // PIXELFORMAT_STENCIL8 + { 1, 1, 1, 2, false, true, false, false }, // PIXELFORMAT_DEPTH16_UNORM + { 1, 1, 1, 3, false, true, false, false }, // PIXELFORMAT_DEPTH24_UNORM + { 1, 1, 1, 4, false, true, false, false }, // PIXELFORMAT_DEPTH32_FLOAT + { 2, 1, 1, 4, false, true, true , false }, // PIXELFORMAT_DEPTH24_UNORM_STENCIL8 + { 2, 1, 1, 5, false, true, true , false }, // PIXELFORMAT_DEPTH32_FLOAT_STENCIL8 + + { 3, 4, 4, 8, true, false, false, true }, // PIXELFORMAT_DXT1_UNORM + { 4, 4, 4, 16, true, false, false, true }, // PIXELFORMAT_DXT3_UNORM + { 4, 4, 4, 16, true, false, false, true }, // PIXELFORMAT_DXT5_UNORM + { 1, 4, 4, 8, true, false, false, true }, // PIXELFORMAT_BC4_UNORM + { 1, 4, 4, 8, true, false, false, true }, // PIXELFORMAT_BC4_SNORM + { 2, 4, 4, 16, true, false, false, true }, // PIXELFORMAT_BC5_UNORM + { 2, 4, 4, 16, true, false, false, true }, // PIXELFORMAT_BC5_SNORM + { 3, 4, 4, 16, true, false, false, true }, // PIXELFORMAT_BC6H_UFLOAT + { 3, 4, 4, 16, true, false, false, true }, // PIXELFORMAT_BC6H_FLOAT + { 4, 4, 4, 16, true, false, false, true }, // PIXELFORMAT_BC7_UNORM + + { 3, 16, 8, 32, true, false, false, true }, // PIXELFORMAT_PVR1_RGB2_UNORM + { 3, 8, 8, 32, true, false, false, true }, // PIXELFORMAT_PVR1_RGB4_UNORM + { 4, 16, 8, 32, true, false, false, true }, // PIXELFORMAT_PVR1_RGBA2_UNORM + { 4, 8, 8, 32, true, false, false, true }, // PIXELFORMAT_PVR1_RGBA4_UNORM + + { 3, 4, 4, 8, true, false, false, true }, // PIXELFORMAT_ETC1_UNORM + { 3, 4, 4, 8, true, false, false, true }, // PIXELFORMAT_ETC2_RGB_UNORM + { 4, 4, 4, 16, true, false, false, true }, // PIXELFORMAT_ETC2_RGBA_UNORM + { 4, 4, 4, 8, true, false, false, true }, // PIXELFORMAT_ETC2_RGBA1_UNORM + { 1, 4, 4, 8, true, false, false, true }, // PIXELFORMAT_EAC_R_UNORM + { 1, 4, 4, 8, true, false, false, true }, // PIXELFORMAT_EAC_R_SNORM + { 2, 4, 4, 16, true, false, false, true }, // PIXELFORMAT_EAC_RG_UNORM + { 2, 4, 4, 16, true, false, false, true }, // PIXELFORMAT_EAC_RG_SNORM + + { 4, 4, 4, 1, true, false, false, true }, // PIXELFORMAT_ASTC_4x4 + { 4, 5, 4, 1, true, false, false, true }, // PIXELFORMAT_ASTC_5x4 + { 4, 5, 5, 1, true, false, false, true }, // PIXELFORMAT_ASTC_5x5 + { 4, 6, 5, 1, true, false, false, true }, // PIXELFORMAT_ASTC_6x5 + { 4, 6, 6, 1, true, false, false, true }, // PIXELFORMAT_ASTC_6x6 + { 4, 8, 5, 1, true, false, false, true }, // PIXELFORMAT_ASTC_8x5 + { 4, 8, 6, 1, true, false, false, true }, // PIXELFORMAT_ASTC_8x6 + { 4, 8, 8, 1, true, false, false, true }, // PIXELFORMAT_ASTC_8x8 + { 4, 8, 5, 1, true, false, false, true }, // PIXELFORMAT_ASTC_10x5 + { 4, 10, 6, 1, true, false, false, true }, // PIXELFORMAT_ASTC_10x6 + { 4, 10, 8, 1, true, false, false, true }, // PIXELFORMAT_ASTC_10x8 + { 4, 10, 10, 1, true, false, false, true }, // PIXELFORMAT_ASTC_10x10 + { 4, 12, 10, 1, true, false, false, true }, // PIXELFORMAT_ASTC_12x10 + { 4, 12, 12, 1, true, false, false, true }, // PIXELFORMAT_ASTC_12x12 +}; + +static_assert(sizeof(formatInfo) / sizeof(PixelFormatInfo) == PIXELFORMAT_MAX_ENUM, "Update the formatInfo array when adding or removing a PixelFormat"); + static StringMap::Entry formatEntries[] = { { "unknown", PIXELFORMAT_UNKNOWN }, @@ -113,28 +194,30 @@ bool getConstant(PixelFormat in, const char *&out) return formats.find(in, out); } +const PixelFormatInfo &getPixelFormatInfo(PixelFormat format) +{ + return formatInfo[format]; +} + bool isPixelFormatCompressed(PixelFormat format) { - // I'm lazy - int iformat = (int) format; - return iformat >= (int) PIXELFORMAT_DXT1_UNORM && iformat < (int) PIXELFORMAT_MAX_ENUM; + return formatInfo[format].compressed; } bool isPixelFormatDepthStencil(PixelFormat format) { - int iformat = (int) format; - return iformat >= (int) PIXELFORMAT_STENCIL8 && iformat <= (int) PIXELFORMAT_DEPTH32_FLOAT_STENCIL8; + const PixelFormatInfo &info = formatInfo[format]; + return info.depth || info.stencil; } bool isPixelFormatDepth(PixelFormat format) { - int iformat = (int) format; - return iformat >= (int) PIXELFORMAT_DEPTH16_UNORM && iformat <= (int) PIXELFORMAT_DEPTH32_FLOAT_STENCIL8; + return formatInfo[format].depth; } bool isPixelFormatStencil(PixelFormat format) { - return format == PIXELFORMAT_STENCIL8 || format == PIXELFORMAT_DEPTH24_UNORM_STENCIL8 || format == PIXELFORMAT_DEPTH32_FLOAT_STENCIL8; + return formatInfo[format].stencil; } PixelFormat getSRGBPixelFormat(PixelFormat format) @@ -151,76 +234,43 @@ PixelFormat getLinearPixelFormat(PixelFormat format) return format; } -size_t getPixelFormatSize(PixelFormat format) +size_t getPixelFormatBlockSize(PixelFormat format) { - switch (format) - { - case PIXELFORMAT_R8_UNORM: - case PIXELFORMAT_STENCIL8: - return 1; - case PIXELFORMAT_RG8_UNORM: - case PIXELFORMAT_R16_UNORM: - case PIXELFORMAT_R16_FLOAT: - case PIXELFORMAT_LA8_UNORM: - case PIXELFORMAT_RGBA4_UNORM: - case PIXELFORMAT_RGB5A1_UNORM: - case PIXELFORMAT_RGB565_UNORM: - case PIXELFORMAT_DEPTH16_UNORM: - return 2; - case PIXELFORMAT_RGBA8_UNORM: - case PIXELFORMAT_sRGBA8_UNORM: - case PIXELFORMAT_RG16_UNORM: - case PIXELFORMAT_RG16_FLOAT: - case PIXELFORMAT_R32_FLOAT: - case PIXELFORMAT_RGB10A2_UNORM: - case PIXELFORMAT_RG11B10_FLOAT: - case PIXELFORMAT_DEPTH24_UNORM: - case PIXELFORMAT_DEPTH32_FLOAT: - case PIXELFORMAT_DEPTH24_UNORM_STENCIL8: - return 4; - case PIXELFORMAT_RGBA16_UNORM: - case PIXELFORMAT_RGBA16_FLOAT: - case PIXELFORMAT_RG32_FLOAT: - case PIXELFORMAT_DEPTH32_FLOAT_STENCIL8: - return 8; - case PIXELFORMAT_RGBA32_FLOAT: - return 16; - default: - // TODO: compressed formats - return 0; - } + return formatInfo[format].blockSize; +} + +size_t getPixelFormatUncompressedRowSize(PixelFormat format, int width) +{ + const PixelFormatInfo &info = formatInfo[format]; + if (info.compressed) return 0; + return info.blockSize * width / info.blockWidth; +} + +size_t getPixelFormatCompressedBlockRowSize(PixelFormat format, int width) +{ + const PixelFormatInfo &info = formatInfo[format]; + if (!info.compressed) return 0; + return info.blockSize * ((width + info.blockWidth - 1) / info.blockWidth); +} + +size_t getPixelFormatCompressedBlockRowCount(PixelFormat format, int height) +{ + const PixelFormatInfo &info = formatInfo[format]; + if (!info.compressed) return 0; + return (height + info.blockHeight - 1) / info.blockHeight; +} + +size_t getPixelFormatSliceSize(PixelFormat format, int width, int height) +{ + const PixelFormatInfo &info = formatInfo[format]; + size_t blockW = (width + info.blockWidth - 1) / info.blockWidth; + size_t blockH = (height + info.blockHeight - 1) / info.blockHeight; + return info.blockSize * blockW * blockH; } int getPixelFormatColorComponents(PixelFormat format) { - switch (format) - { - case PIXELFORMAT_R8_UNORM: - case PIXELFORMAT_R16_UNORM: - case PIXELFORMAT_R16_FLOAT: - case PIXELFORMAT_R32_FLOAT: - return 1; - case PIXELFORMAT_RG8_UNORM: - case PIXELFORMAT_RG16_UNORM: - case PIXELFORMAT_RG16_FLOAT: - case PIXELFORMAT_RG32_FLOAT: - case PIXELFORMAT_LA8_UNORM: - return 2; - case PIXELFORMAT_RGB565_UNORM: - case PIXELFORMAT_RG11B10_FLOAT: - return 3; - case PIXELFORMAT_RGBA8_UNORM: - case PIXELFORMAT_sRGBA8_UNORM: - case PIXELFORMAT_RGBA16_UNORM: - case PIXELFORMAT_RGBA16_FLOAT: - case PIXELFORMAT_RGBA32_FLOAT: - case PIXELFORMAT_RGBA4_UNORM: - case PIXELFORMAT_RGB5A1_UNORM: - case PIXELFORMAT_RGB10A2_UNORM: - return 4; - default: - return 0; - } + return formatInfo[format].components; } } // love diff --git a/src/common/pixelformat.h b/src/common/pixelformat.h index 40f1be664..a1a4b1ddb 100644 --- a/src/common/pixelformat.h +++ b/src/common/pixelformat.h @@ -109,9 +109,23 @@ enum PixelFormat PIXELFORMAT_MAX_ENUM }; +struct PixelFormatInfo +{ + int components; + size_t blockWidth; + size_t blockHeight; + size_t blockSize; + bool color; + bool depth; + bool stencil; + bool compressed; +}; + bool getConstant(PixelFormat in, const char *&out); bool getConstant(const char *in, PixelFormat &out); +const PixelFormatInfo &getPixelFormatInfo(PixelFormat format); + /** * Gets whether the specified pixel format is a compressed type. **/ @@ -143,10 +157,36 @@ PixelFormat getSRGBPixelFormat(PixelFormat format); PixelFormat getLinearPixelFormat(PixelFormat format); /** - * Gets the size in bytes of the specified pixel format. - * NOTE: Currently returns 0 for compressed formats. + * Gets the block size in bytes of the specified pixel format. + * This is the size in bytes of a pixel for uncompressed formats, but *not* + * for compressed formats! **/ -size_t getPixelFormatSize(PixelFormat format); +size_t getPixelFormatBlockSize(PixelFormat format); + +/** + * Gets the size in bytes of a row of an uncompressed pixel format. + **/ +size_t getPixelFormatUncompressedRowSize(PixelFormat format, int width); + +/** + * Gets the size in bytes of a row of a compressed pixel format. This is the + * number of blocks used by the given width, multiplied by the block size. The + * number of rows of blocks for a given height can be computed by + * getPixelFormatCompressedBlockRowCount. + **/ +size_t getPixelFormatCompressedBlockRowSize(PixelFormat format, int width); + +/** + * Gets the number of rows of blocks the given compressed pixel format will use, + * for the given height in pixels. + **/ +size_t getPixelFormatCompressedBlockRowCount(PixelFormat format, int height); + +/** + * Gets the size in bytes of a slice (width x height 2D plane) which uses the + * given pixel format. + **/ +size_t getPixelFormatSliceSize(PixelFormat format, int width, int height); /** * Gets the number of color components in the given pixel format. diff --git a/src/modules/font/GlyphData.cpp b/src/modules/font/GlyphData.cpp index 640888322..69ec25ca8 100644 --- a/src/modules/font/GlyphData.cpp +++ b/src/modules/font/GlyphData.cpp @@ -78,7 +78,7 @@ void *GlyphData::getData() const size_t GlyphData::getPixelSize() const { - return getPixelFormatSize(format); + return getPixelFormatBlockSize(format); } void *GlyphData::getData(int x, int y) const diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index 3d71b84fd..928d96f7d 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -158,7 +158,7 @@ void Font::createTexture() texture->setSamplerState(samplerState); { - size_t bpp = getPixelFormatSize(pixelFormat); + size_t bpp = getPixelFormatBlockSize(pixelFormat); size_t pixelcount = size.width * size.height; // Initialize the texture with transparent white for Luminance-Alpha diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 8d8f21121..7ebd427c5 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -184,6 +184,9 @@ Texture::Texture(const Settings &settings, const Slices *slices) { texType = slices->getTextureType(); + if (requestedMSAA > 1) + throw love::Exception("MSAA textures cannot be created from image data."); + int dataMipmaps = 1; if (slices->validate() && slices->getMipmapCount() > 1) dataMipmaps = slices->getMipmapCount(); @@ -218,7 +221,7 @@ Texture::Texture(const Settings &settings, const Slices *slices) if (settings.readable.hasValue) readable = settings.readable.value; else - readable = !isPixelFormatDepthStencil(format); + readable = !renderTarget || !isPixelFormatDepthStencil(format); format = gfx->getSizedFormat(format, renderTarget, readable, sRGB); @@ -234,6 +237,9 @@ Texture::Texture(const Settings &settings, const Slices *slices) if (texType != TEXTURE_2D && requestedMSAA > 1) throw love::Exception("MSAA is only supported for textures with the 2D texture type."); + if (!renderTarget && requestedMSAA > 1) + throw love::Exception("MSAA is only supported with render target textures."); + if (readable && isPixelFormatDepthStencil(format) && settings.msaa > 1) throw love::Exception("Readable depth/stencil textures with MSAA are not currently supported."); @@ -269,7 +275,7 @@ Texture::Texture(const Settings &settings, const Slices *slices) throw love::Exception("%s textures are not supported on this system.", textypestr); } - validateDimensions(!renderTarget); + validateDimensions(renderTarget || !readable); samplerState = gfx->getDefaultSamplerState(); @@ -619,8 +625,11 @@ int Texture::getRequestedMSAA() const void Texture::setSamplerState(const SamplerState &s) { - if (s.depthSampleMode.hasValue && (!readable || !isPixelFormatDepthStencil(format))) - throw love::Exception("Only readable depth textures can have a depth sample compare mode."); + if (!readable) + return; + + if (s.depthSampleMode.hasValue && !isPixelFormatDepth(format)) + throw love::Exception("Only depth textures can have a depth sample compare mode."); Graphics::flushStreamDrawsGlobal(); diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index ec2d7cc68..8b82e583e 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -164,7 +164,7 @@ public: PixelFormat format = PIXELFORMAT_NORMAL; bool linear = false; float dpiScale = 1.0f; - int msaa = 0; + int msaa = 1; bool renderTarget = false; OptionalBool readable; }; diff --git a/src/modules/graphics/Video.cpp b/src/modules/graphics/Video.cpp index 8854e64c7..9f2df9c5b 100644 --- a/src/modules/graphics/Video.cpp +++ b/src/modules/graphics/Video.cpp @@ -90,7 +90,7 @@ Video::Video(Graphics *gfx, love::video::VideoStream *stream, float dpiscale) tex->setSamplerState(samplerState); - size_t bpp = getPixelFormatSize(PIXELFORMAT_R8_UNORM); + size_t bpp = getPixelFormatBlockSize(PIXELFORMAT_R8_UNORM); size_t size = bpp * widths[i] * heights[i]; Rect rect = {0, 0, widths[i], heights[i]}; @@ -167,7 +167,7 @@ void Video::update() for (int i = 0; i < 3; i++) { - size_t bpp = getPixelFormatSize(PIXELFORMAT_R8_UNORM); + size_t bpp = getPixelFormatBlockSize(PIXELFORMAT_R8_UNORM); size_t size = bpp * widths[i] * heights[i]; Rect rect = {0, 0, widths[i], heights[i]}; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index ef7c46622..9f2bf702c 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -132,10 +132,7 @@ love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t love::graphics::Texture *Graphics::newTexture(const Texture::Settings &settings, const Texture::Slices *data) { - if (settings.renderTarget) - return new Canvas(settings); - else - return new Image(settings, data); + return new Texture(settings, data); } love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) @@ -569,8 +566,7 @@ void Graphics::endPass() for (int i = 0; i < (int) rts.colors.size(); i++) { - // FIXME - Canvas *c = (Canvas *) rts.colors[i].texture.get(); + Texture *c = (Texture *) rts.colors[i].texture.get(); if (!c->isReadable()) continue; @@ -588,7 +584,7 @@ void Graphics::endPass() if (depthstencil != nullptr && depthstencil->getMSAA() > 1 && depthstencil->isReadable()) { - gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, ((Canvas *) depthstencil)->getFBO()); + gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, ((Texture *) depthstencil)->getFBO()); if (GLAD_APPLE_framebuffer_multisample) glResolveMultisampleFramebufferAPPLE(); @@ -613,14 +609,13 @@ void Graphics::endPass() for (const auto &rt : rts.colors) { - // TODO -// if (rt.texture->getMipmapMode() == Canvas::MIPMAPS_AUTO && rt.mipmap == 0) -// rt.texture->generateMipmaps(); + if (rt.texture->getMipmapsMode() == Texture::MIPMAPS_AUTO && rt.mipmap == 0) + rt.texture->generateMipmaps(); } -// int dsmipmap = rts.depthStencil.mipmap; -// if (depthstencil != nullptr && depthstencil->getMipmapMode() == Canvas::MIPMAPS_AUTO && dsmipmap == 0) -// depthstencil->generateMipmaps(); + int dsmipmap = rts.depthStencil.mipmap; + if (depthstencil != nullptr && depthstencil->getMipmapsMode() == Texture::MIPMAPS_AUTO && dsmipmap == 0) + depthstencil->generateMipmaps(); } void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth) @@ -813,7 +808,7 @@ void Graphics::discard(OpenGL::FramebufferTarget target, const std::vector glDiscardFramebufferEXT(gltarget, (GLint) attachments.size(), &attachments[0]); } -void Graphics::cleanupRenderTexture(Texture *texture) +void Graphics::cleanupRenderTexture(love::graphics::Texture *texture) { if (!texture->isRenderTarget()) return; diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index b2ba4d186..b6df9b629 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -36,8 +36,7 @@ #include "image/Image.h" #include "image/ImageData.h" -#include "Image.h" -#include "Canvas.h" +#include "Texture.h" #include "Shader.h" #include "libraries/xxHash/xxhash.h" @@ -71,7 +70,7 @@ public: void draw(const DrawCommand &cmd) override; void draw(const DrawIndexedCommand &cmd) override; - void drawQuads(int start, int count, const vertex::Attributes &attributes, const vertex::BufferBindings &buffers, Texture *texture) override; + void drawQuads(int start, int count, const vertex::Attributes &attributes, const vertex::BufferBindings &buffers, love::graphics::Texture *texture) override; void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) override; void clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) override; @@ -110,7 +109,7 @@ public: Shader::Language getShaderLanguageTarget() const override; // Internal use. - void cleanupRenderTexture(Texture *texture); + void cleanupRenderTexture(love::graphics::Texture *texture); private: diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp deleted file mode 100644 index 233e7a291..000000000 --- a/src/modules/graphics/opengl/Image.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/** - * Copyright (c) 2006-2020 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "Image.h" - -#include "graphics/Graphics.h" -#include "common/int.h" - -// STD -#include // for min/max - -namespace love -{ -namespace graphics -{ -namespace opengl -{ - -Image::Image(const Settings &settings, const Slices *data) - : love::graphics::Texture(settings, data) - , slices(settings.type) - , texture(0) -{ - if (data != nullptr) - slices = *data; - loadVolatile(); -} - -Image::~Image() -{ - unloadVolatile(); -} - -void Image::generateMipmaps() -{ - if (getMipmapCount() > 1 && !isCompressed() && - (GLAD_ES_VERSION_2_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object || GLAD_EXT_framebuffer_object)) - { - gl.bindTextureToUnit(this, 0, false); - - GLenum gltextype = OpenGL::getGLTextureType(texType); - - if (gl.bugs.generateMipmapsRequiresTexture2DEnable) - glEnable(gltextype); - - glGenerateMipmap(gltextype); - } -} - -void Image::loadDefaultTexture() -{ - usingDefaultTexture = true; - - gl.bindTextureToUnit(this, 0, false); - setSamplerState(samplerState); - - bool isSRGB = false; - gl.rawTexStorage(texType, 1, PIXELFORMAT_RGBA8_UNORM, isSRGB, 2, 2, 1); - - // A nice friendly checkerboard to signify invalid textures... - GLubyte px[] = {0xFF,0xFF,0xFF,0xFF, 0xFF,0xA0,0xA0,0xFF, - 0xFF,0xA0,0xA0,0xFF, 0xFF,0xFF,0xFF,0xFF}; - - int slices = texType == TEXTURE_CUBE ? 6 : 1; - Rect rect = {0, 0, 2, 2}; - for (int slice = 0; slice < slices; slice++) - uploadByteData(PIXELFORMAT_RGBA8_UNORM, px, sizeof(px), 0, slice, rect, nullptr); -} - -void Image::loadData() -{ - int mipcount = getMipmapCount(); - int slicecount = 1; - - if (texType == TEXTURE_VOLUME) - slicecount = getDepth(); - else if (texType == TEXTURE_2D_ARRAY) - slicecount = getLayerCount(); - else if (texType == TEXTURE_CUBE) - slicecount = 6; - - if (!isCompressed()) - gl.rawTexStorage(texType, mipcount, format, sRGB, pixelWidth, pixelHeight, texType == TEXTURE_VOLUME ? depth : layers); - - int w = pixelWidth; - int h = pixelHeight; - int d = depth; - - OpenGL::TextureFormat fmt = gl.convertPixelFormat(format, false, sRGB); - - for (int mip = 0; mip < mipcount; mip++) - { - if (isCompressed() && (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME)) - { - size_t mipsize = 0; - - if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) - { - for (int slice = 0; slice < slices.getSliceCount(mip); slice++) - { - auto id = slices.get(slice, mip); - if (id != nullptr) - mipsize += id->getSize(); - } - } - - if (mipsize > 0) - { - GLenum gltarget = OpenGL::getGLTextureType(texType); - glCompressedTexImage3D(gltarget, mip, fmt.internalformat, w, h, d, 0, mipsize, nullptr); - } - } - - for (int slice = 0; slice < slicecount; slice++) - { - love::image::ImageDataBase *id = slices.get(slice, mip); - if (id != nullptr) - uploadImageData(id, mip, slice, 0, 0); - } - - w = std::max(w / 2, 1); - h = std::max(h / 2, 1); - - if (texType == TEXTURE_VOLUME) - d = std::max(d / 2, 1); - } - - if (getMipmapCount() > 1 && slices.getMipmapCount() <= 1) - generateMipmaps(); -} - -void Image::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd) -{ - love::image::ImageDataBase *oldd = slices.get(slice, level); - - // We can only replace the internal Data (used when reloading due to setMode) - // if the dimensions match. - if (imgd != nullptr && oldd != nullptr && oldd->getWidth() == imgd->getWidth() - && oldd->getHeight() == imgd->getHeight()) - { - slices.set(slice, level, imgd); - } - - OpenGL::TempDebugGroup debuggroup("Image data upload"); - - gl.bindTextureToUnit(this, 0, false); - - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, false, sRGB); - GLenum gltarget = OpenGL::getGLTextureType(texType); - - if (texType == TEXTURE_CUBE) - gltarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice; - - if (isPixelFormatCompressed(pixelformat)) - { - if (r.x != 0 || r.y != 0) - throw love::Exception("x and y parameters must be 0 for compressed images."); - - if (texType == TEXTURE_2D || texType == TEXTURE_CUBE) - glCompressedTexImage2D(gltarget, level, fmt.internalformat, r.w, r.h, 0, size, data); - else if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) - glCompressedTexSubImage3D(gltarget, level, 0, 0, slice, r.w, r.h, 1, fmt.internalformat, size, data); - } - else - { - if (texType == TEXTURE_2D || texType == TEXTURE_CUBE) - glTexSubImage2D(gltarget, level, r.x, r.y, r.w, r.h, fmt.externalformat, fmt.type, data); - else if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) - glTexSubImage3D(gltarget, level, r.x, r.y, slice, r.w, r.h, 1, fmt.externalformat, fmt.type, data); - } -} - -bool Image::loadVolatile() -{ - if (texture != 0) - return true; - - OpenGL::TempDebugGroup debuggroup("Image load"); - - // NPOT textures don't support mipmapping without full NPOT support. - if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) - && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight))) - { - mipmapCount = 1; - samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; - } - - glGenTextures(1, &texture); - gl.bindTextureToUnit(this, 0, false); - - // Use a default texture if the size is too big for the system. - if (!validateDimensions(false)) - { - loadDefaultTexture(); - return true; - } - - setSamplerState(samplerState); - - while (glGetError() != GL_NO_ERROR); // Clear errors. - - try - { - loadData(); - - GLenum glerr = glGetError(); - if (glerr != GL_NO_ERROR) - throw love::Exception("Cannot create image (OpenGL error: %s)", OpenGL::errorString(glerr)); - } - catch (love::Exception &) - { - gl.deleteTexture(texture); - texture = 0; - throw; - } - - int64 memsize = 0; - - for (int slice = 0; slice < slices.getSliceCount(0); slice++) - memsize += slices.get(slice, 0)->getSize(); - - if (getMipmapCount() > 1) - memsize *= 1.33334; - - setGraphicsMemorySize(memsize); - - usingDefaultTexture = false; - return true; -} - -void Image::unloadVolatile() -{ - if (texture == 0) - return; - - gl.deleteTexture(texture); - texture = 0; - - setGraphicsMemorySize(0); -} - -ptrdiff_t Image::getHandle() const -{ - return texture; -} - -void Image::setSamplerState(const SamplerState &s) -{ - Texture::setSamplerState(s); - - if (!OpenGL::hasTextureFilteringSupport(getPixelFormat())) - { - samplerState.magFilter = samplerState.minFilter = SamplerState::FILTER_NEAREST; - - if (samplerState.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) - samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NEAREST; - } - - // We don't want filtering or (attempted) mipmaps on the default texture. - if (usingDefaultTexture) - { - samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; - samplerState.minFilter = samplerState.magFilter = SamplerState::FILTER_NEAREST; - } - - // If we only have limited NPOT support then the wrap mode must be CLAMP. - if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) - && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight) || depth != nextP2(depth))) - { - samplerState.wrapU = samplerState.wrapV = samplerState.wrapW = SamplerState::WRAP_CLAMP; - } - - gl.bindTextureToUnit(this, 0, false); - gl.setSamplerState(texType, samplerState); -} - -} // opengl -} // graphics -} // love diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h deleted file mode 100644 index f2811e827..000000000 --- a/src/modules/graphics/opengl/Image.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (c) 2006-2020 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#pragma once - -// LOVE -#include "graphics/Texture.h" -#include "graphics/Volatile.h" - -// OpenGL -#include "OpenGL.h" - -namespace love -{ -namespace graphics -{ -namespace opengl -{ - -class Image final : public love::graphics::Texture, public Volatile -{ -public: - - Image(const Settings &settings, const Slices *data); - - virtual ~Image(); - - // Implements Volatile. - bool loadVolatile() override; - void unloadVolatile() override; - - ptrdiff_t getHandle() const override; - ptrdiff_t getRenderTargetHandle() const override { return 0; } - - int getMSAA() const override { return 1; } - void setSamplerState(const SamplerState &s) override; - void generateMipmaps() override; - -private: - - void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override; - - void loadDefaultTexture(); - void loadData(); - - Slices slices; - - // OpenGL texture identifier. - GLuint texture; - -}; // Image - -} // opengl -} // graphics -} // love diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 984140633..2b4c15454 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -23,7 +23,6 @@ #include "OpenGL.h" #include "Shader.h" -#include "Canvas.h" #include "common/Exception.h" #include "graphics/Graphics.h" diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index cb175e082..519cba618 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -195,7 +195,7 @@ void Shader::mapActiveUniforms() glUniform1iv(u.location, u.count, u.ints); - u.textures = new Texture*[u.count]; + u.textures = new love::graphics::Texture*[u.count]; memset(u.textures, 0, sizeof(Texture *) * u.count); } } @@ -564,12 +564,12 @@ void Shader::updateUniform(const UniformInfo *info, int count, bool internalupda } } -void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count) +void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) { Shader::sendTextures(info, textures, count, false); } -void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate) +void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count, bool internalUpdate) { if (info->baseType != UNIFORM_SAMPLER) return; @@ -584,7 +584,7 @@ void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count // Bind the textures to the texture units. for (int i = 0; i < count; i++) { - Texture *tex = textures[i]; + love::graphics::Texture *tex = textures[i]; if (tex != nullptr) { @@ -671,7 +671,7 @@ int Shader::getVertexAttributeIndex(const std::string &name) return location; } -void Shader::setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture) +void Shader::setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) { const BuiltinUniform builtins[3] = { BUILTIN_TEXTURE_VIDEO_Y, @@ -679,7 +679,7 @@ void Shader::setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *cr BUILTIN_TEXTURE_VIDEO_CR, }; - Texture *textures[3] = {ytexture, cbtexture, crtexture}; + love::graphics::Texture *textures[3] = {ytexture, cbtexture, crtexture}; for (int i = 0; i < 3; i++) { diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 8522716bd..23397ac57 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -61,10 +61,10 @@ public: const UniformInfo *getUniformInfo(const std::string &name) const override; const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override; void updateUniform(const UniformInfo *info, int count) override; - void sendTextures(const UniformInfo *info, Texture **textures, int count) override; + void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override; bool hasUniform(const std::string &name) const override; ptrdiff_t getHandle() const override; - void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture) override; + void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override; void updatePointSize(float size); void updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, int viewportH); @@ -82,7 +82,7 @@ private: void mapActiveUniforms(); void updateUniform(const UniformInfo *info, int count, bool internalupdate); - void sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalupdate); + void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count, bool internalupdate); int getUniformTypeComponents(GLenum type) const; MatrixSize getMatrixSize(GLenum type) const; diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Texture.cpp similarity index 57% rename from src/modules/graphics/opengl/Canvas.cpp rename to src/modules/graphics/opengl/Texture.cpp index 4b77c06f4..a9675ff67 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -18,11 +18,14 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#include "Canvas.h" +#include "Texture.h" + #include "graphics/Graphics.h" #include "Graphics.h" +#include "common/int.h" -#include // For min/max +// STD +#include // for min/max namespace love { @@ -31,7 +34,7 @@ namespace graphics namespace opengl { -static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat format, GLuint texture, int layers) +static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat format, GLuint texture, int layers, bool clear) { // get currently bound fbo to reset to it later GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL); @@ -100,7 +103,7 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo return status; } -static bool createRenderbuffer(int width, int height, int &samples, PixelFormat pixelformat, GLuint &buffer) +static bool newRenderbuffer(int width, int height, int &samples, PixelFormat pixelformat, GLuint &buffer) { int reqsamples = samples; bool unusedSRGB = false; @@ -140,8 +143,6 @@ static bool createRenderbuffer(int width, int height, int &samples, PixelFormat if (samples > 1) glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples); - else - samples = 0; glBindRenderbuffer(GL_RENDERBUFFER, 0); @@ -173,7 +174,7 @@ static bool createRenderbuffer(int width, int height, int &samples, PixelFormat { glDeleteRenderbuffers(1, &buffer); buffer = 0; - samples = 0; + samples = 1; } gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo); @@ -182,110 +183,221 @@ static bool createRenderbuffer(int width, int height, int &samples, PixelFormat return status == GL_FRAMEBUFFER_COMPLETE; } -Canvas::Canvas(const Settings &settings) - : love::graphics::Texture(settings, nullptr) +Texture::Texture(const Settings &settings, const Slices *data) + : love::graphics::Texture(settings, data) + , slices(settings.type) , fbo(0) , texture(0) - , renderbuffer(0) - , actualSamples(0) + , renderbuffer(0) + , framebufferStatus(GL_FRAMEBUFFER_COMPLETE) + , actualSamples(1) { - auto gfx = Module::getInstance(Module::M_GRAPHICS); - if (gfx != nullptr) - format = gfx->getSizedFormat(format, renderTarget, readable, sRGB); - + if (data != nullptr) + slices = *data; loadVolatile(); - - if (status != GL_FRAMEBUFFER_COMPLETE) - throw love::Exception("Cannot create Canvas: %s", OpenGL::framebufferStatusString(status)); } -Canvas::~Canvas() +Texture::~Texture() { unloadVolatile(); } -bool Canvas::loadVolatile() +bool Texture::createTexture() { - if (texture != 0) - return true; + // 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 + // a compressed format, etc. - OpenGL::TempDebugGroup debuggroup("Canvas load"); + glGenTextures(1, &texture); + gl.bindTextureToUnit(this, 0, false); - fbo = texture = 0; - renderbuffer = 0; - status = GL_FRAMEBUFFER_COMPLETE; - - // getMaxRenderbufferSamples will be 0 on systems that don't support - // multisampled renderbuffers / don't export FBO multisample extensions. - actualSamples = std::min(getRequestedMSAA(), gl.getMaxRenderbufferSamples()); - actualSamples = std::max(actualSamples, 0); - actualSamples = actualSamples == 1 ? 0 : actualSamples; - - if (isReadable()) + // Use a default texture if the size is too big for the system. + // validateDimensions is also called in the base class for RTs and + // non-readable textures. + if (!renderTarget && !validateDimensions(false)) { - glGenTextures(1, &texture); - gl.bindTextureToUnit(this, 0, false); - - GLenum gltype = OpenGL::getGLTextureType(texType); - - if (GLAD_ANGLE_texture_usage) - glTexParameteri(gltype, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + usingDefaultTexture = true; setSamplerState(samplerState); - while (glGetError() != GL_NO_ERROR) - /* Clear the error buffer. */; + bool isSRGB = false; + gl.rawTexStorage(texType, 1, PIXELFORMAT_RGBA8_UNORM, isSRGB, 2, 2, 1); - bool isSRGB = format == PIXELFORMAT_sRGBA8_UNORM; - if (!gl.rawTexStorage(texType, mipmapCount, format, isSRGB, pixelWidth, pixelHeight, texType == TEXTURE_VOLUME ? depth : layers)) - { - status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - return false; - } + // A nice friendly checkerboard to signify invalid textures... + GLubyte px[] = {0xFF,0xFF,0xFF,0xFF, 0xFF,0xA0,0xA0,0xFF, + 0xFF,0xA0,0xA0,0xFF, 0xFF,0xFF,0xFF,0xFF}; - if (glGetError() != GL_NO_ERROR) - { - gl.deleteTexture(texture); - texture = 0; - status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - return false; - } + int slices = texType == TEXTURE_CUBE ? 6 : 1; + Rect rect = {0, 0, 2, 2}; + for (int slice = 0; slice < slices; slice++) + uploadByteData(PIXELFORMAT_RGBA8_UNORM, px, sizeof(px), 0, slice, rect, nullptr); - // Create a local FBO used for glReadPixels as well as MSAA blitting. - status = createFBO(fbo, texType, format, texture, texType == TEXTURE_VOLUME ? depth : layers); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - if (fbo != 0) - { - gl.deleteFramebuffer(fbo); - fbo = 0; - } - return false; - } + return true; } - if (!isReadable() || actualSamples > 0) - createRenderbuffer(pixelWidth, pixelHeight, actualSamples, format, renderbuffer); + GLenum gltype = OpenGL::getGLTextureType(texType); + if (renderTarget && GLAD_ANGLE_texture_usage) + glTexParameteri(gltype, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE); - int64 memsize = getPixelFormatSize(format) * pixelWidth * pixelHeight; - if (getMipmapCount() > 1) - memsize *= 1.33334; + setSamplerState(samplerState); - if (actualSamples > 1 && isReadable()) - memsize += getPixelFormatSize(format) * pixelWidth * pixelHeight * actualSamples; - else if (actualSamples > 1) - memsize *= actualSamples; + int mipcount = getMipmapCount(); + int slicecount = 1; - setGraphicsMemorySize(memsize); + if (texType == TEXTURE_VOLUME) + slicecount = getDepth(); + else if (texType == TEXTURE_2D_ARRAY) + slicecount = getLayerCount(); + else if (texType == TEXTURE_CUBE) + slicecount = 6; - if (getMipmapCount() > 1) + if (!isCompressed()) + gl.rawTexStorage(texType, mipcount, format, sRGB, pixelWidth, pixelHeight, texType == TEXTURE_VOLUME ? depth : layers); + + int w = pixelWidth; + int h = pixelHeight; + int d = depth; + + OpenGL::TextureFormat fmt = gl.convertPixelFormat(format, false, sRGB); + + for (int mip = 0; mip < mipcount; mip++) + { + if (isCompressed() && (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME)) + { + size_t mipsize = 0; + + if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) + { + for (int slice = 0; slice < slices.getSliceCount(mip); slice++) + { + auto id = slices.get(slice, mip); + if (id != nullptr) + mipsize += id->getSize(); + } + } + + if (mipsize > 0) + { + GLenum gltarget = OpenGL::getGLTextureType(texType); + glCompressedTexImage3D(gltarget, mip, fmt.internalformat, w, h, d, 0, mipsize, nullptr); + } + } + + for (int slice = 0; slice < slicecount; slice++) + { + love::image::ImageDataBase *id = slices.get(slice, mip); + if (id != nullptr) + uploadImageData(id, mip, slice, 0, 0); + } + + w = std::max(w / 2, 1); + h = std::max(h / 2, 1); + + if (texType == TEXTURE_VOLUME) + d = std::max(d / 2, 1); + } + + bool hasdata = slices.get(0, 0) != nullptr; + + // Create a local FBO used for glReadPixels as well as MSAA blitting. + if (isRenderTarget()) + { + bool clear = !hasdata; + int slices = texType == TEXTURE_VOLUME ? depth : layers; + framebufferStatus = createFBO(fbo, texType, format, texture, slices, clear); + } + else if (!hasdata) + { + // Initialize all slices to transparent black. + std::vector emptydata(getPixelFormatSliceSize(format, w, h)); + + Rect r = {0, 0, w, h}; + int slices = texType == TEXTURE_VOLUME ? depth : layers; + slices = texType == TEXTURE_CUBE ? 6 : slices; + for (int i = 0; i < slices; i++) + uploadByteData(format, emptydata.data(), emptydata.size(), 0, i, r); + } + + // Non-readable textures can't have mipmaps (enforced in the base class), + // so generateMipmaps here is fine - when they aren't already initialized. + if (getMipmapCount() > 1 && slices.getMipmapCount() <= 1) generateMipmaps(); return true; } -void Canvas::unloadVolatile() +bool Texture::createRenderbuffer() +{ + if (isReadable() && actualSamples <= 1) + return true; + + return newRenderbuffer(pixelWidth, pixelHeight, actualSamples, format, renderbuffer); +} + +bool Texture::loadVolatile() +{ + if (texture != 0 || renderbuffer != 0) + return true; + + OpenGL::TempDebugGroup debuggroup("Texture load"); + + // NPOT textures don't support mipmapping without full NPOT support. + if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) + && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight))) + { + mipmapCount = 1; + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; + } + + // getMaxRenderbufferSamples will be 0 on systems that don't support + // multisampled renderbuffers / don't export FBO multisample extensions. + actualSamples = std::min(getRequestedMSAA(), gl.getMaxRenderbufferSamples()); + actualSamples = std::max(actualSamples, 1); + + while (glGetError() != GL_NO_ERROR); // Clear errors. + + try + { + 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)); + } + catch (love::Exception &) + { + unloadVolatile(); + throw; + } + + int64 memsize = 0; + + for (int mip = 0; mip < getMipmapCount(); mip++) + { + int w = getPixelWidth(mip); + int h = getPixelHeight(mip); + int slices = getDepth(mip) * layers * (texType == TEXTURE_CUBE ? 6 : 1); + memsize += getPixelFormatSliceSize(format, w, h) * slices; + } + + if (actualSamples > 1 && isReadable()) + { + int slices = depth * layers * (texType == TEXTURE_CUBE ? 6 : 1); + memsize += getPixelFormatSliceSize(format, pixelWidth, pixelHeight) * slices * actualSamples; + } + else if (actualSamples > 1) + memsize *= actualSamples; + + setGraphicsMemorySize(memsize); + + usingDefaultTexture = false; + return true; +} + +void Texture::unloadVolatile() { if (isRenderTarget() && (fbo != 0 || renderbuffer != 0 || texture != 0)) { @@ -312,41 +424,73 @@ void Canvas::unloadVolatile() setGraphicsMemorySize(0); } -void Canvas::setSamplerState(const SamplerState &s) +void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd) { - Texture::setSamplerState(s); + love::image::ImageDataBase *oldd = slices.get(slice, level); - if (samplerState.depthSampleMode.hasValue && !gl.isDepthCompareSampleSupported()) - throw love::Exception("Depth comparison sampling in shaders is not supported on this system."); - - if (!OpenGL::hasTextureFilteringSupport(getPixelFormat())) + // We can only replace the internal Data (used when reloading due to setMode) + // if the dimensions match. + if (imgd != nullptr && oldd != nullptr && oldd->getWidth() == imgd->getWidth() + && oldd->getHeight() == imgd->getHeight()) { - samplerState.magFilter = samplerState.minFilter = SamplerState::FILTER_NEAREST; - - if (samplerState.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) - samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NEAREST; + slices.set(slice, level, imgd); } - // If we only have limited NPOT support then the wrap mode must be CLAMP. - if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) - && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight) || depth != nextP2(depth))) - { - samplerState.wrapU = samplerState.wrapV = samplerState.wrapW = SamplerState::WRAP_CLAMP; - } + OpenGL::TempDebugGroup debuggroup("Texture data upload"); gl.bindTextureToUnit(this, 0, false); - gl.setSamplerState(texType, samplerState); + + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, false, sRGB); + GLenum gltarget = OpenGL::getGLTextureType(texType); + + if (texType == TEXTURE_CUBE) + gltarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice; + + if (isPixelFormatCompressed(pixelformat)) + { + if (r.x != 0 || r.y != 0) + throw love::Exception("x and y parameters must be 0 for compressed textures."); + + if (texType == TEXTURE_2D || texType == TEXTURE_CUBE) + glCompressedTexImage2D(gltarget, level, fmt.internalformat, r.w, r.h, 0, size, data); + else if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) + glCompressedTexSubImage3D(gltarget, level, 0, 0, slice, r.w, r.h, 1, fmt.internalformat, size, data); + } + else + { + if (texType == TEXTURE_2D || texType == TEXTURE_CUBE) + glTexSubImage2D(gltarget, level, r.x, r.y, r.w, r.h, fmt.externalformat, fmt.type, data); + else if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) + glTexSubImage3D(gltarget, level, r.x, r.y, slice, r.w, r.h, 1, fmt.externalformat, fmt.type, data); + } } -ptrdiff_t Canvas::getHandle() const +void Texture::generateMipmaps() { - return texture; + if (getMipmapCount() == 1 || getMipmapsMode() == MIPMAPS_NONE) + throw love::Exception("generateMipmaps can only be called on a Texture which was created with mipmaps enabled."); + + if (isPixelFormatCompressed(format)) + throw love::Exception("generateMipmaps cannot be called on a compressed Texture."); + + gl.bindTextureToUnit(this, 0, false); + + GLenum gltextype = OpenGL::getGLTextureType(texType); + + if (gl.bugs.generateMipmapsRequiresTexture2DEnable) + glEnable(gltextype); + + glGenerateMipmap(gltextype); } -love::image::ImageData *Canvas::newImageData(love::image::Image *module, int slice, int mipmap, const Rect &r) +love::image::ImageData *Texture::newImageData(love::image::Image *module, int slice, int mipmap, const Rect &r) { + // Base class does validation (only RTs allowed, etc) and creates ImageData. love::image::ImageData *data = love::graphics::Texture::newImageData(module, slice, mipmap, r); + if (fbo == 0) // Should never be reached. + return data; + bool isSRGB = false; OpenGL::TextureFormat fmt = gl.convertPixelFormat(data->getFormat(), false, isSRGB); @@ -370,53 +514,48 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *module, int sli return data; } -void Canvas::generateMipmaps() +void Texture::setSamplerState(const SamplerState &s) { - if (getMipmapCount() == 1 || getMipmapsMode() == MIPMAPS_NONE) - throw love::Exception("generateMipmaps can only be called on a Texture which was created with mipmaps enabled."); + if (samplerState.depthSampleMode.hasValue && !gl.isDepthCompareSampleSupported()) + throw love::Exception("Depth comparison sampling in shaders is not supported on this system."); - if (isPixelFormatCompressed(format)) - throw love::Exception("generateMipmaps cannot be called on a compressed Texture."); + // Base class does common validation and assigns samplerState. + love::graphics::Texture::setSamplerState(s); + + if (!OpenGL::hasTextureFilteringSupport(getPixelFormat())) + { + samplerState.magFilter = samplerState.minFilter = SamplerState::FILTER_NEAREST; + + if (samplerState.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NEAREST; + } + + // We don't want filtering or (attempted) mipmaps on the default texture. + if (usingDefaultTexture) + { + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; + samplerState.minFilter = samplerState.magFilter = SamplerState::FILTER_NEAREST; + } + + // If we only have limited NPOT support then the wrap mode must be CLAMP. + if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) + && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight) || depth != nextP2(depth))) + { + samplerState.wrapU = samplerState.wrapV = samplerState.wrapW = SamplerState::WRAP_CLAMP; + } gl.bindTextureToUnit(this, 0, false); - - GLenum gltextype = OpenGL::getGLTextureType(texType); - - if (gl.bugs.generateMipmapsRequiresTexture2DEnable) - glEnable(gltextype); - - glGenerateMipmap(gltextype); + gl.setSamplerState(texType, samplerState); } -void Canvas::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase */*imgd*/) +ptrdiff_t Texture::getHandle() const { - OpenGL::TempDebugGroup debuggroup("Texture data upload"); + return texture; +} - gl.bindTextureToUnit(this, 0, false); - - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, false, sRGB); - GLenum gltarget = OpenGL::getGLTextureType(texType); - - if (texType == TEXTURE_CUBE) - gltarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice; - - if (isPixelFormatCompressed(pixelformat)) - { - if (r.x != 0 || r.y != 0) - throw love::Exception("x and y parameters must be 0 for compressed images."); - - if (texType == TEXTURE_2D || texType == TEXTURE_CUBE) - glCompressedTexImage2D(gltarget, level, fmt.internalformat, r.w, r.h, 0, size, data); - else if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) - glCompressedTexSubImage3D(gltarget, level, 0, 0, slice, r.w, r.h, 1, fmt.internalformat, size, data); - } - else - { - if (texType == TEXTURE_2D || texType == TEXTURE_CUBE) - glTexSubImage2D(gltarget, level, r.x, r.y, r.w, r.h, fmt.externalformat, fmt.type, data); - else if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) - glTexSubImage3D(gltarget, level, r.x, r.y, slice, r.w, r.h, 1, fmt.externalformat, fmt.type, data); - } +ptrdiff_t Texture::getRenderTargetHandle() const +{ + return renderTarget ? (renderbuffer != 0 ? renderbuffer : texture) : 0; } } // opengl diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Texture.h similarity index 74% rename from src/modules/graphics/opengl/Canvas.h rename to src/modules/graphics/opengl/Texture.h index 158f134b0..6699a586d 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Texture.h @@ -18,14 +18,13 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_GRAPHICS_OPENGL_CANVAS_H -#define LOVE_GRAPHICS_OPENGL_CANVAS_H +#pragma once -#include "common/config.h" -#include "common/Color.h" -#include "common/int.h" +// LOVE #include "graphics/Texture.h" #include "graphics/Volatile.h" + +// OpenGL #include "OpenGL.h" namespace love @@ -35,56 +34,48 @@ namespace graphics namespace opengl { -class Canvas final : public love::graphics::Texture, public Volatile +class Texture final : public love::graphics::Texture, public Volatile { public: - Canvas(const Settings &settings); - virtual ~Canvas(); + Texture(const Settings &settings, const Slices *data); + + virtual ~Texture(); // Implements Volatile. bool loadVolatile() override; void unloadVolatile() override; - // Implements Texture. - void setSamplerState(const SamplerState &s) override; - ptrdiff_t getHandle() const override; - - love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect) override; void generateMipmaps() override; + love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect) override; + void setSamplerState(const SamplerState &s) override; - int getMSAA() const override - { - return actualSamples; - } + ptrdiff_t getHandle() const override; + ptrdiff_t getRenderTargetHandle() const override; + int getMSAA() const override { return actualSamples; } - ptrdiff_t getRenderTargetHandle() const override - { - return renderbuffer != 0 ? renderbuffer : texture; - } - - inline GLuint getFBO() const - { - return fbo; - } + inline GLuint getFBO() const { return fbo; } private: + bool createTexture(); + bool createRenderbuffer(); + void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override; + Slices slices; + GLuint fbo; GLuint texture; GLuint renderbuffer; - GLenum status; + GLenum framebufferStatus; int actualSamples; -}; // Canvas +}; // Texture } // opengl } // graphics } // love - -#endif // LOVE_GRAPHICS_OPENGL_CANVAS_H diff --git a/src/modules/image/ImageData.cpp b/src/modules/image/ImageData.cpp index d9238ba7c..41c89299c 100644 --- a/src/modules/image/ImageData.cpp +++ b/src/modules/image/ImageData.cpp @@ -84,7 +84,7 @@ love::image::ImageData *ImageData::clone() const void ImageData::create(int width, int height, PixelFormat format, void *data) { - size_t datasize = width * height * getPixelFormatSize(format); + size_t datasize = getPixelFormatSliceSize(format, width, height); try { @@ -140,7 +140,7 @@ void ImageData::decode(Data *data) throw love::Exception("Could not decode data to ImageData: unsupported encoded format"); } - if (decodedimage.size != decodedimage.width * decodedimage.height * getPixelFormatSize(decodedimage.format)) + if (decodedimage.size != getPixelFormatSliceSize(decodedimage.format, decodedimage.width, decodedimage.height)) { decoder->freeRawPixels(decodedimage.data); throw love::Exception("Could not convert image!"); @@ -782,7 +782,7 @@ love::thread::Mutex *ImageData::getMutex() const size_t ImageData::getPixelSize() const { - return getPixelFormatSize(format); + return getPixelFormatBlockSize(format); } bool ImageData::validPixelFormat(PixelFormat format) diff --git a/src/modules/image/magpie/EXRHandler.cpp b/src/modules/image/magpie/EXRHandler.cpp index 85cfde0fa..b37f692b1 100644 --- a/src/modules/image/magpie/EXRHandler.cpp +++ b/src/modules/image/magpie/EXRHandler.cpp @@ -193,7 +193,7 @@ FormatHandler::DecodedImage EXRHandler::decode(Data *data) throw love::Exception("Could not decode EXR image: unknown pixel format."); } - img.size = img.width * img.height * getPixelFormatSize(img.format); + img.size = getPixelFormatSliceSize(img.format, img.width, img.height); FreeEXRImage(&exrImage); diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 5e9d2d505..43d8ec238 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -933,7 +933,7 @@ bool Window::setIcon(love::image::ImageData *imgd) int w = imgd->getWidth(); int h = imgd->getHeight(); - int bytesperpixel = (int) getPixelFormatSize(imgd->getFormat()); + int bytesperpixel = (int) getPixelFormatBlockSize(imgd->getFormat()); int pitch = w * bytesperpixel; SDL_Surface *sdlicon = nullptr; From 453322678c56afc9311735ae3431d461f850372f Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 8 Feb 2020 20:40:10 -0400 Subject: [PATCH 21/31] Rename internal uses of canvas to texture/render target --- src/modules/event/sdl/Event.cpp | 6 +- src/modules/graphics/Graphics.cpp | 82 ++++++++++++------------ src/modules/graphics/Graphics.h | 14 ++-- src/modules/graphics/opengl/Graphics.cpp | 50 +++++++-------- src/modules/graphics/opengl/Graphics.h | 2 +- src/modules/graphics/opengl/OpenGL.cpp | 8 +-- src/modules/graphics/opengl/OpenGL.h | 2 +- src/modules/graphics/opengl/Shader.cpp | 4 +- src/modules/graphics/opengl/Texture.cpp | 2 +- src/modules/graphics/wrap_Graphics.cpp | 14 ++-- src/modules/graphics/wrap_Texture.cpp | 6 +- src/modules/window/sdl/Window.cpp | 12 ++-- 12 files changed, 101 insertions(+), 101 deletions(-) diff --git a/src/modules/event/sdl/Event.cpp b/src/modules/event/sdl/Event.cpp index 8f4b891df..59b779863 100644 --- a/src/modules/event/sdl/Event.cpp +++ b/src/modules/event/sdl/Event.cpp @@ -161,11 +161,11 @@ void Event::exceptionIfInRenderPass(const char *name) { // Some core OS graphics functionality (e.g. swap buffers on some platforms) // happens inside SDL_PumpEvents - which is called by SDL_PollEvent and - // friends. It's probably a bad idea to call those functions while a Canvas + // friends. It's probably a bad idea to call those functions while a RT // is active. auto gfx = Module::getInstance(Module::M_GRAPHICS); - if (gfx != nullptr && gfx->isCanvasActive()) - throw love::Exception("%s cannot be called while a Canvas is active in love.graphics.", name); + if (gfx != nullptr && gfx->isRenderTargetActive()) + throw love::Exception("%s cannot be called while a render target is active in love.graphics.", name); } Message *Event::convert(const SDL_Event &e) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 9620a579e..f2fc3b11f 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -397,7 +397,7 @@ void Graphics::restoreState(const DisplayState &s) setFont(s.font.get()); setShader(s.shader.get()); - setCanvas(s.renderTargets); + setRenderTargets(s.renderTargets); setColorMask(s.colorMask); setWireframe(s.wireframe); @@ -450,27 +450,27 @@ void Graphics::restoreStateChecked(const DisplayState &s) const auto &sRTs = s.renderTargets; const auto &curRTs = cur.renderTargets; - bool canvaseschanged = sRTs.colors.size() != curRTs.colors.size(); - if (!canvaseschanged) + bool rtschanged = sRTs.colors.size() != curRTs.colors.size(); + if (!rtschanged) { for (size_t i = 0; i < sRTs.colors.size() && i < curRTs.colors.size(); i++) { if (sRTs.colors[i] != curRTs.colors[i]) { - canvaseschanged = true; + rtschanged = true; break; } } - if (!canvaseschanged && sRTs.depthStencil != curRTs.depthStencil) - canvaseschanged = true; + if (!rtschanged && sRTs.depthStencil != curRTs.depthStencil) + rtschanged = true; if (sRTs.temporaryRTFlags != curRTs.temporaryRTFlags) - canvaseschanged = true; + rtschanged = true; } - if (canvaseschanged) - setCanvas(s.renderTargets); + if (rtschanged) + setRenderTargets(s.renderTargets); if (s.colorMask != cur.colorMask) setColorMask(s.colorMask); @@ -543,19 +543,19 @@ love::graphics::Shader *Graphics::getShader() const return states.back().shader.get(); } -void Graphics::setCanvas(RenderTarget rt, uint32 temporaryRTFlags) +void Graphics::setRenderTarget(RenderTarget rt, uint32 temporaryRTFlags) { if (rt.texture == nullptr) - return setCanvas(); + return setRenderTarget(); RenderTargets rts; rts.colors.push_back(rt); rts.temporaryRTFlags = temporaryRTFlags; - setCanvas(rts); + setRenderTargets(rts); } -void Graphics::setCanvas(const RenderTargetsStrongRef &rts) +void Graphics::setRenderTargets(const RenderTargetsStrongRef &rts) { RenderTargets targets; targets.colors.reserve(rts.colors.size()); @@ -566,27 +566,27 @@ void Graphics::setCanvas(const RenderTargetsStrongRef &rts) targets.depthStencil = RenderTarget(rts.depthStencil.texture, rts.depthStencil.slice, rts.depthStencil.mipmap); targets.temporaryRTFlags = rts.temporaryRTFlags; - return setCanvas(targets); + return setRenderTargets(targets); } -void Graphics::setCanvas(const RenderTargets &rts) +void Graphics::setRenderTargets(const RenderTargets &rts) { DisplayState &state = states.back(); - int ncanvases = (int) rts.colors.size(); + int rtcount = (int) rts.colors.size(); RenderTarget firsttarget = rts.getFirstTarget(); Texture *firsttex = firsttarget.texture; if (firsttex == nullptr) - return setCanvas(); + return setRenderTarget(); const auto &prevRTs = state.renderTargets; - if (ncanvases == (int) prevRTs.colors.size()) + if (rtcount == (int) prevRTs.colors.size()) { bool modified = false; - for (int i = 0; i < ncanvases; i++) + for (int i = 0; i < rtcount; i++) { if (rts.colors[i] != prevRTs.colors[i]) { @@ -605,8 +605,8 @@ void Graphics::setCanvas(const RenderTargets &rts) return; } - if (ncanvases > capabilities.limits[LIMIT_MULTI_CANVAS]) - throw love::Exception("This system can't simultaneously render to %d canvases.", ncanvases); + if (rtcount > capabilities.limits[LIMIT_MULTI_CANVAS]) + throw love::Exception("This system can't simultaneously render to %d textures.", rtcount); bool multiformatsupported = capabilities.features[FEATURE_MULTI_CANVAS_FORMATS]; @@ -615,10 +615,10 @@ void Graphics::setCanvas(const RenderTargets &rts) firstcolorformat = rts.colors[0].texture->getPixelFormat(); if (!firsttex->isRenderTarget()) - throw love::Exception("Texture must be created as a render target to be used in setCanvas."); + throw love::Exception("Texture must be created as a render target to be used in setRenderTargets."); if (isPixelFormatDepthStencil(firstcolorformat)) - throw love::Exception("Depth/stencil format Canvases must be used with the 'depthstencil' field of the table passed into setCanvas."); + throw love::Exception("Depth/stencil format textures must be used with the 'depthstencil' field of the table passed into setRenderTargets."); if (firsttarget.mipmap < 0 || firsttarget.mipmap >= firsttex->getMipmapCount()) throw love::Exception("Invalid mipmap level %d.", firsttarget.mipmap + 1); @@ -626,12 +626,12 @@ void Graphics::setCanvas(const RenderTargets &rts) if (!firsttex->isValidSlice(firsttarget.slice)) throw love::Exception("Invalid slice index: %d.", firsttarget.slice + 1); - bool hasSRGBcanvas = firstcolorformat == PIXELFORMAT_sRGBA8_UNORM; + bool hasSRGBtexture = firstcolorformat == PIXELFORMAT_sRGBA8_UNORM; int pixelw = firsttex->getPixelWidth(firsttarget.mipmap); int pixelh = firsttex->getPixelHeight(firsttarget.mipmap); int reqmsaa = firsttex->getRequestedMSAA(); - for (int i = 1; i < ncanvases; i++) + for (int i = 1; i < rtcount; i++) { Texture *c = rts.colors[i].texture; PixelFormat format = c->getPixelFormat(); @@ -639,7 +639,7 @@ void Graphics::setCanvas(const RenderTargets &rts) int slice = rts.colors[i].slice; if (!c->isRenderTarget()) - throw love::Exception("Texture must be created as a render target to be used in setCanvas."); + throw love::Exception("Texture must be created as a render target to be used in setRenderTargets."); if (mip < 0 || mip >= c->getMipmapCount()) throw love::Exception("Invalid mipmap level %d.", mip + 1); @@ -648,19 +648,19 @@ void Graphics::setCanvas(const RenderTargets &rts) throw love::Exception("Invalid slice index: %d.", slice + 1); if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh) - throw love::Exception("All canvases must have the same pixel dimensions."); + throw love::Exception("All textures must have the same pixel dimensions."); if (!multiformatsupported && format != firstcolorformat) - throw love::Exception("This system doesn't support multi-canvas rendering with different canvas formats."); + throw love::Exception("This system doesn't support multi-render-target rendering with different texture formats."); if (c->getRequestedMSAA() != reqmsaa) - throw love::Exception("All Canvases must have the same MSAA value."); + throw love::Exception("All textures must have the same MSAA value."); if (isPixelFormatDepthStencil(format)) - throw love::Exception("Depth/stencil format Canvases must be used with the 'depthstencil' field of the table passed into setCanvas."); + throw love::Exception("Depth/stencil format textures must be used with the 'depthstencil' field of the table passed into setRenderTargets."); if (format == PIXELFORMAT_sRGBA8_UNORM) - hasSRGBcanvas = true; + hasSRGBtexture = true; } if (rts.depthStencil.texture != nullptr) @@ -670,10 +670,10 @@ void Graphics::setCanvas(const RenderTargets &rts) int slice = rts.depthStencil.slice; if (!c->isRenderTarget()) - throw love::Exception("Texture must be created as a render target to be used in setCanvas."); + throw love::Exception("Texture must be created as a render target to be used in setRenderTargets."); if (!isPixelFormatDepthStencil(c->getPixelFormat())) - throw love::Exception("Only depth/stencil format Texture can be used with the 'depthstencil' field of the table passed into setCanvas."); + throw love::Exception("Only depth/stencil format textures can be used with the 'depthstencil' field of the table passed into setRenderTargets."); if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh) throw love::Exception("All Textures must have the same pixel dimensions."); @@ -708,17 +708,17 @@ void Graphics::setCanvas(const RenderTargets &rts) else if (wantsstencil) dsformat = PIXELFORMAT_STENCIL8; - // We want setCanvasInternal to have a pointer to the temporary RT, but - // we don't want to directly store it in the main graphics state. + // We want setRenderTargetsInternal to have a pointer to the temporary RT, + // but we don't want to directly store it in the main graphics state. RenderTargets realRTs = rts; realRTs.depthStencil.texture = getTemporaryTexture(dsformat, pixelw, pixelh, reqmsaa); realRTs.depthStencil.slice = 0; - setCanvasInternal(realRTs, w, h, pixelw, pixelh, hasSRGBcanvas); + setRenderTargetsInternal(realRTs, w, h, pixelw, pixelh, hasSRGBtexture); } else - setCanvasInternal(rts, w, h, pixelw, pixelh, hasSRGBcanvas); + setRenderTargetsInternal(rts, w, h, pixelw, pixelh, hasSRGBtexture); RenderTargetsStrongRef refs; refs.colors.reserve(rts.colors.size()); @@ -734,7 +734,7 @@ void Graphics::setCanvas(const RenderTargets &rts) renderTargetSwitchCount++; } -void Graphics::setCanvas() +void Graphics::setRenderTarget() { DisplayState &state = states.back(); @@ -742,13 +742,13 @@ void Graphics::setCanvas() return; flushStreamDraws(); - setCanvasInternal(RenderTargets(), width, height, pixelWidth, pixelHeight, isGammaCorrect()); + setRenderTargetsInternal(RenderTargets(), width, height, pixelWidth, pixelHeight, isGammaCorrect()); state.renderTargets = RenderTargetsStrongRef(); renderTargetSwitchCount++; } -Graphics::RenderTargets Graphics::getCanvas() const +Graphics::RenderTargets Graphics::getRenderTargets() const { const auto &curRTs = states.back().renderTargets; @@ -764,7 +764,7 @@ Graphics::RenderTargets Graphics::getCanvas() const return rts; } -bool Graphics::isCanvasActive() const +bool Graphics::isRenderTargetActive() const { const auto &rts = states.back().renderTargets; return !rts.colors.empty() || rts.depthStencil.texture != nullptr; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 09a34bf00..0b97a69ec 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -538,13 +538,13 @@ public: Shader *getShader() const; - void setCanvas(RenderTarget rt, uint32 temporaryRTFlags); - void setCanvas(const RenderTargets &rts); - void setCanvas(const RenderTargetsStrongRef &rts); - void setCanvas(); + void setRenderTarget(RenderTarget rt, uint32 temporaryRTFlags); + void setRenderTargets(const RenderTargets &rts); + void setRenderTargets(const RenderTargetsStrongRef &rts); + void setRenderTarget(); - RenderTargets getCanvas() const; - bool isCanvasActive() const; + RenderTargets getRenderTargets() const; + bool isRenderTargetActive() const; bool isRenderTargetActive(Texture *texture) const; bool isRenderTargetActive(Texture *texture, int slice) const; @@ -949,7 +949,7 @@ protected: virtual Shader *newShaderInternal(ShaderStage *vertex, ShaderStage *pixel) = 0; virtual StreamBuffer *newStreamBuffer(BufferType type, size_t size) = 0; - virtual void setCanvasInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) = 0; + virtual void setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBtexture) = 0; virtual void initCapabilities() = 0; virtual void getAPIStats(int &shaderswitches) const = 0; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 9f2bf702c..b0b9f25e6 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -157,7 +157,7 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh this->pixelWidth = pixelwidth; this->pixelHeight = pixelheight; - if (!isCanvasActive()) + if (!isRenderTargetActive()) { // Set the viewport to top-left corner. gl.setViewport({0, 0, pixelwidth, pixelheight}); @@ -499,11 +499,11 @@ void Graphics::setDebug(bool enable) ::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n"); } -void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) +void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBtexture) { const DisplayState &state = states.back(); - OpenGL::TempDebugGroup debuggroup("setCanvas"); + OpenGL::TempDebugGroup debuggroup("setRenderTargets"); flushStreamDraws(); endPass(); @@ -515,8 +515,8 @@ void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pix { gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, gl.getDefaultFBO()); - // The projection matrix is flipped compared to rendering to a canvas, due - // to OpenGL considering (0,0) bottom-left instead of top-left. + // The projection matrix is flipped compared to rendering to a texture, + // due to OpenGL considering (0,0) bottom-left instead of top-left. projectionMatrix = Matrix4::ortho(0.0, (float) w, (float) h, 0.0, -10.0f, 10.0f); } else @@ -525,7 +525,7 @@ void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pix projectionMatrix = Matrix4::ortho(0.0, (float) w, 0.0, (float) h, -10.0f, 10.0f); - // Flip front face winding when rendering to a canvas, since our + // Flip front face winding when rendering to a texture, since our // projection matrix is flipped. vertexwinding = vertexwinding == vertex::WINDING_CW ? vertex::WINDING_CCW : vertex::WINDING_CW; } @@ -539,11 +539,11 @@ void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pix if (state.scissor) setScissor(state.scissorRect); - // Make sure the correct sRGB setting is used when drawing to the canvases. + // Make sure the correct sRGB setting is used when drawing to the textures. if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control) { - if (hasSRGBcanvas != gl.isStateEnabled(OpenGL::ENABLE_FRAMEBUFFER_SRGB)) - gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, hasSRGBcanvas); + if (hasSRGBtexture != gl.isStateEnabled(OpenGL::ENABLE_FRAMEBUFFER_SRGB)) + gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, hasSRGBtexture); } } @@ -669,10 +669,10 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten if (colors.size() == 0 && !stencil.hasValue && !depth.hasValue) return; - int ncolorcanvases = (int) states.back().renderTargets.colors.size(); + int ncolorRTs = (int) states.back().renderTargets.colors.size(); int ncolors = (int) colors.size(); - if (ncolors <= 1 && ncolorcanvases <= 1) + if (ncolors <= 1 && ncolorRTs <= 1) { clear(ncolors > 0 ? colors[0] : OptionalColorf(), stencil, depth); return; @@ -681,7 +681,7 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten flushStreamDraws(); bool drawbuffersmodified = false; - ncolors = std::min(ncolors, ncolorcanvases); + ncolors = std::min(ncolors, ncolorRTs); for (int i = 0; i < ncolors; i++) { @@ -712,10 +712,10 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten { GLenum bufs[MAX_COLOR_RENDER_TARGETS]; - for (int i = 0; i < ncolorcanvases; i++) + for (int i = 0; i < ncolorRTs; i++) bufs[i] = GL_COLOR_ATTACHMENT0 + i; - glDrawBuffers(ncolorcanvases, bufs); + glDrawBuffers(ncolorRTs, bufs); } GLbitfield flags = 0; @@ -773,7 +773,7 @@ void Graphics::discard(OpenGL::FramebufferTarget target, const std::vector attachments.reserve(colorbuffers.size()); // glDiscardFramebuffer uses different attachment enums for the default FBO. - if (!isCanvasActive() && gl.getDefaultFBO() == 0) + if (!isRenderTargetActive() && gl.getDefaultFBO() == 0) { if (colorbuffers.size() > 0 && colorbuffers[0]) attachments.push_back(GL_COLOR); @@ -859,7 +859,7 @@ void Graphics::bindCachedFBO(const RenderTargets &targets) int ncolortargets = 0; GLenum drawbuffers[MAX_COLOR_RENDER_TARGETS]; - auto attachCanvas = [&](const RenderTarget &rt) + auto attachRT = [&](const RenderTarget &rt) { bool renderbuffer = msaa > 1 || !rt.texture->isReadable(); bool srgb = false; @@ -894,10 +894,10 @@ void Graphics::bindCachedFBO(const RenderTargets &targets) }; for (const auto &rt : targets.colors) - attachCanvas(rt); + attachRT(rt); if (hasDS) - attachCanvas(targets.depthStencil); + attachRT(targets.depthStencil); if (ncolortargets > 1) glDrawBuffers(ncolortargets, drawbuffers); @@ -930,8 +930,8 @@ void Graphics::present(void *screenshotCallbackData) if (!isActive()) return; - if (isCanvasActive()) - throw love::Exception("present cannot be called while a Canvas is active."); + if (isRenderTargetActive()) + throw love::Exception("present cannot be called while a render target is active."); deprecations.draw(this); @@ -1084,7 +1084,7 @@ void Graphics::setScissor(const Rect &rect) glrect.h = (int) (rect.h * dpiscale); // OpenGL's reversed y-coordinate is compensated for in OpenGL::setScissor. - gl.setScissor(glrect, isCanvasActive()); + gl.setScissor(glrect, isRenderTargetActive()); state.scissor = true; state.scissorRect = rect; @@ -1106,10 +1106,10 @@ void Graphics::drawToStencilBuffer(StencilAction action, int value) const auto &rts = states.back().renderTargets; love::graphics::Texture *dstexture = rts.depthStencil.texture.get(); - if (!isCanvasActive() && !windowHasStencil) + if (!isRenderTargetActive() && !windowHasStencil) throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer."); - else if (isCanvasActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat()))) - throw love::Exception("Drawing to the stencil buffer with a Canvas active requires either stencil=true or a custom stencil-type Canvas to be used, in setCanvas."); + else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat()))) + throw love::Exception("Drawing to the stencil buffer with a render target active requires either stencil=true or a custom stencil-type texture to be used, in setRenderTarget."); flushStreamDraws(); @@ -1237,7 +1237,7 @@ void Graphics::setFrontFaceWinding(vertex::Winding winding) state.winding = winding; - if (isCanvasActive()) + if (isRenderTargetActive()) winding = winding == vertex::WINDING_CW ? vertex::WINDING_CCW : vertex::WINDING_CW; glFrontFace(winding == vertex::WINDING_CW ? GL_CW : GL_CCW); diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index b6df9b629..e6b59c71a 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -135,7 +135,7 @@ private: love::graphics::ShaderStage *newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) override; love::graphics::Shader *newShaderInternal(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel) override; love::graphics::StreamBuffer *newStreamBuffer(BufferType type, size_t size) override; - void setCanvasInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) override; + void setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBtexture) override; void initCapabilities() override; void getAPIStats(int &shaderswitches) const override; diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 2b4c15454..b010202d4 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -804,13 +804,13 @@ Rect OpenGL::getViewport() const return state.viewport; } -void OpenGL::setScissor(const Rect &v, bool canvasActive) +void OpenGL::setScissor(const Rect &v, bool rtActive) { - if (canvasActive) + if (rtActive) glScissor(v.x, v.y, v.w, v.h); else { - // With no Canvas active, we need to compensate for glScissor starting + // With no RT active, we need to compensate for glScissor starting // from the lower left of the viewport instead of the top left. glScissor(v.x, state.viewport.h - (v.y + v.h), v.w, v.h); } @@ -1996,7 +1996,7 @@ const char *OpenGL::framebufferStatusString(GLenum status) case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: return "Error in graphics driver (incomplete read buffer)"; case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - return "Canvas with the specified MSAA count cannot be rendered to on this system."; + return "Texture with the specified MSAA count cannot be rendered to on this system."; case GL_FRAMEBUFFER_UNSUPPORTED: return "Renderable textures are unsupported"; default: diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 9e7b26f55..ba17b8431 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -261,7 +261,7 @@ public: * Sets the scissor box to the specified rectangle. * The y-coordinate starts at the top and is flipped internally. **/ - void setScissor(const Rect &v, bool canvasActive); + void setScissor(const Rect &v, bool rtActive); /** * Sets the global point size. diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 519cba618..e57f918f3 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -734,8 +734,8 @@ void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, // The shader does pixcoord.y = gl_FragCoord.y * params.z + params.w. // This lets us flip pixcoord.y when needed, to be consistent (drawing - // with no Canvas active makes the pixel coordinates y-flipped.) - if (gfx->isCanvasActive()) + // with no RT active makes the pixel coordinates y-flipped.) + if (gfx->isRenderTargetActive()) { // No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0. data.screenSizeParams.z = 1.0f; diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index a9675ff67..ec6da42a8 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -402,7 +402,7 @@ void Texture::unloadVolatile() if (isRenderTarget() && (fbo != 0 || renderbuffer != 0 || texture != 0)) { // This is a bit ugly, but we need some way to destroy the cached FBO - // when this Canvas' texture is destroyed. + // when this texture's texture is destroyed. auto gfx = Module::getInstance(Module::M_GRAPHICS); if (gfx != nullptr) gfx->cleanupRenderTexture(this); diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index dac60e959..647a7242d 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -169,7 +169,7 @@ int w_discard(lua_State *L) else { bool discardcolor = luax_optboolean(L, 1, true); - size_t numbuffers = std::max((size_t) 1, instance()->getCanvas().colors.size()); + size_t numbuffers = std::max((size_t) 1, instance()->getRenderTargets().colors.size()); colorbuffers = std::vector(numbuffers, discardcolor); } @@ -271,7 +271,7 @@ int w_setCanvas(lua_State *L) // called with none -> reset to default buffer if (lua_isnoneornil(L, 1)) { - instance()->setCanvas(); + instance()->setRenderTarget(); return 0; } @@ -295,7 +295,7 @@ int w_setCanvas(lua_State *L) targets.colors.emplace_back(luax_checktexture(L, -1), 0); if (targets.colors.back().texture->getTextureType() != TEXTURE_2D) - return luaL_error(L, "Non-2D canvases must use the table-of-tables variant of setCanvas."); + return luaL_error(L, "Non-2D textures must use the table-of-tables variant of setRenderTargets."); } lua_pop(L, 1); @@ -341,7 +341,7 @@ int w_setCanvas(lua_State *L) } if (i > 1 && type != TEXTURE_2D) - return luaL_error(L, "This variant of setCanvas only supports 2D texture types."); + return luaL_error(L, "This variant of setRenderTargets only supports 2D texture types."); targets.colors.push_back(target); } @@ -349,9 +349,9 @@ int w_setCanvas(lua_State *L) luax_catchexcept(L, [&]() { if (targets.getFirstTarget().texture != nullptr) - instance()->setCanvas(targets); + instance()->setRenderTargets(targets); else - instance()->setCanvas(); + instance()->setRenderTarget(); }); return 0; @@ -383,7 +383,7 @@ static void pushRenderTarget(lua_State *L, const Graphics::RenderTarget &rt) int w_getCanvas(lua_State *L) { - Graphics::RenderTargets targets = instance()->getCanvas(); + Graphics::RenderTargets targets = instance()->getRenderTargets(); int ntargets = (int) targets.colors.size(); if (ntargets == 0) diff --git a/src/modules/graphics/wrap_Texture.cpp b/src/modules/graphics/wrap_Texture.cpp index a27b55c54..28e1d6b5f 100644 --- a/src/modules/graphics/wrap_Texture.cpp +++ b/src/modules/graphics/wrap_Texture.cpp @@ -418,7 +418,7 @@ int w_Texture_renderTo(lua_State *L) if (graphics) { // Save the current render targets so we can restore them when we're done. - Graphics::RenderTargets oldtargets = graphics->getCanvas(); + Graphics::RenderTargets oldtargets = graphics->getRenderTargets(); for (auto c : oldtargets.colors) c.texture->retain(); @@ -427,7 +427,7 @@ int w_Texture_renderTo(lua_State *L) oldtargets.depthStencil.texture->retain(); luax_catchexcept(L, - [&]() { graphics->setCanvas(rt, 0); }, + [&]() { graphics->setRenderTarget(rt, 0); }, [&](bool err) { if (err) @@ -441,7 +441,7 @@ int w_Texture_renderTo(lua_State *L) lua_settop(L, 2); // make sure the function is on top of the stack int status = lua_pcall(L, 0, 0, 0); - graphics->setCanvas(oldtargets); + graphics->setRenderTargets(oldtargets); for (auto c : oldtargets.colors) c.texture->release(); diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 43d8ec238..1f77ff641 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -432,8 +432,8 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) if (!graphics.get()) graphics.set(Module::getInstance(Module::M_GRAPHICS)); - if (graphics.get() && graphics->isCanvasActive()) - throw love::Exception("love.window.setMode cannot be called while a Canvas is active in love.graphics."); + if (graphics.get() && graphics->isRenderTargetActive()) + throw love::Exception("love.window.setMode cannot be called while a render target is active in love.graphics."); WindowSettings f; @@ -664,8 +664,8 @@ void Window::close(bool allowExceptions) { if (graphics.get()) { - if (allowExceptions && graphics->isCanvasActive()) - throw love::Exception("love.window.close cannot be called while a Canvas is active in love.graphics."); + if (allowExceptions && graphics->isRenderTargetActive()) + throw love::Exception("love.window.close cannot be called while a render target is active in love.graphics."); graphics->unSetMode(); } @@ -694,8 +694,8 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) if (!window) return false; - if (graphics.get() && graphics->isCanvasActive()) - throw love::Exception("love.window.setFullscreen cannot be called while a Canvas is active in love.graphics."); + if (graphics.get() && graphics->isRenderTargetActive()) + throw love::Exception("love.window.setFullscreen cannot be called while a render target is active in love.graphics."); WindowSettings newsettings = settings; newsettings.fullscreen = fullscreen; From 694bc9c5b79bba2c4b894e9843c1f1035c0284bd Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 9 Feb 2020 12:11:19 -0400 Subject: [PATCH 22/31] rename love_Canvases to love_RenderTargets in shaders. More misc. renaming --- src/modules/graphics/Graphics.cpp | 28 +++++++++--------- src/modules/graphics/Graphics.h | 8 ++--- src/modules/graphics/Texture.cpp | 8 ++--- src/modules/graphics/Texture.h | 2 +- src/modules/graphics/opengl/Graphics.cpp | 12 ++++---- src/modules/graphics/opengl/OpenGL.cpp | 5 ++-- src/modules/graphics/opengl/Shader.h | 2 +- src/modules/graphics/opengl/Texture.cpp | 31 +++++++++++--------- src/modules/graphics/wrap_GraphicsShader.lua | 27 ++++++++++------- 9 files changed, 67 insertions(+), 56 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index f2fc3b11f..b54ff62c6 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -605,10 +605,10 @@ void Graphics::setRenderTargets(const RenderTargets &rts) return; } - if (rtcount > capabilities.limits[LIMIT_MULTI_CANVAS]) + if (rtcount > capabilities.limits[LIMIT_RENDER_TARGETS]) throw love::Exception("This system can't simultaneously render to %d textures.", rtcount); - bool multiformatsupported = capabilities.features[FEATURE_MULTI_CANVAS_FORMATS]; + bool multiformatsupported = capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS]; PixelFormat firstcolorformat = PIXELFORMAT_UNKNOWN; if (!rts.colors.empty()) @@ -1886,16 +1886,16 @@ StringMap Graphics::lineJoins( StringMap::Entry Graphics::featureEntries[] = { - { "multicanvasformats", FEATURE_MULTI_CANVAS_FORMATS }, - { "clampzero", FEATURE_CLAMP_ZERO }, - { "blendminmax", FEATURE_BLENDMINMAX }, - { "lighten", FEATURE_LIGHTEN }, - { "fullnpot", FEATURE_FULL_NPOT }, - { "pixelshaderhighp", FEATURE_PIXEL_SHADER_HIGHP }, - { "shaderderivatives", FEATURE_SHADER_DERIVATIVES }, - { "glsl3", FEATURE_GLSL3 }, - { "glsl4", FEATURE_GLSL4 }, - { "instancing", FEATURE_INSTANCING }, + { "multirendertargetformats", FEATURE_MULTI_RENDER_TARGET_FORMATS }, + { "clampzero", FEATURE_CLAMP_ZERO }, + { "blendminmax", FEATURE_BLEND_MINMAX }, + { "lighten", FEATURE_LIGHTEN }, + { "fullnpot", FEATURE_FULL_NPOT }, + { "pixelshaderhighp", FEATURE_PIXEL_SHADER_HIGHP }, + { "shaderderivatives", FEATURE_SHADER_DERIVATIVES }, + { "glsl3", FEATURE_GLSL3 }, + { "glsl4", FEATURE_GLSL4 }, + { "instancing", FEATURE_INSTANCING }, }; StringMap Graphics::features(Graphics::featureEntries, sizeof(Graphics::featureEntries)); @@ -1907,8 +1907,8 @@ StringMap::Entry Graphics::syst { "texturelayers", LIMIT_TEXTURE_LAYERS }, { "volumetexturesize", LIMIT_VOLUME_TEXTURE_SIZE }, { "cubetexturesize", LIMIT_CUBE_TEXTURE_SIZE }, - { "multicanvas", LIMIT_MULTI_CANVAS }, - { "canvasmsaa", LIMIT_CANVAS_MSAA }, + { "rendertargets", LIMIT_RENDER_TARGETS }, + { "texturemsaa", LIMIT_TEXTURE_MSAA }, { "anisotropy", LIMIT_ANISOTROPY }, }; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 0b97a69ec..119ef5ff8 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -133,9 +133,9 @@ public: enum Feature { - FEATURE_MULTI_CANVAS_FORMATS, + FEATURE_MULTI_RENDER_TARGET_FORMATS, FEATURE_CLAMP_ZERO, - FEATURE_BLENDMINMAX, + FEATURE_BLEND_MINMAX, FEATURE_LIGHTEN, // Deprecated FEATURE_FULL_NPOT, FEATURE_PIXEL_SHADER_HIGHP, @@ -160,8 +160,8 @@ public: LIMIT_VOLUME_TEXTURE_SIZE, LIMIT_CUBE_TEXTURE_SIZE, LIMIT_TEXTURE_LAYERS, - LIMIT_MULTI_CANVAS, - LIMIT_CANVAS_MSAA, + LIMIT_RENDER_TARGETS, + LIMIT_TEXTURE_MSAA, LIMIT_ANISOTROPY, LIMIT_MAX_ENUM }; diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 7ebd427c5..dcfa3b407 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -826,10 +826,10 @@ bool Texture::Slices::validate() const int expectedmips = Texture::getTotalMipmapCount(w, h, depth); if (mipcount != expectedmips && mipcount != 1) - throw love::Exception("Image does not have all required mipmap levels (expected %d, got %d)", expectedmips, mipcount); + throw love::Exception("Texture does not have all required mipmap levels (expected %d, got %d)", expectedmips, mipcount); if (textureType == TEXTURE_CUBE && w != h) - throw love::Exception("Cube images must have equal widths and heights for each cube face."); + throw love::Exception("Cube textures must have equal widths and heights for each cube face."); int mipw = w; int miph = h; @@ -856,7 +856,7 @@ bool Texture::Slices::validate() const int realh = slicedata->getHeight(); if (getMipmapCount(slice) != mipcount) - throw love::Exception("All Image layers must have the same mipmap count."); + throw love::Exception("All texture layers must have the same mipmap count."); if (mipw != realw) throw love::Exception("Width of image data (slice %d, mipmap level %d) is incorrect (expected %d, got %d)", slice+1, mip+1, mipw, realw); @@ -865,7 +865,7 @@ bool Texture::Slices::validate() const throw love::Exception("Height of image data (slice %d, mipmap level %d) is incorrect (expected %d, got %d)", slice+1, mip+1, miph, realh); if (format != slicedata->getFormat()) - throw love::Exception("All Image slices and mipmaps must have the same pixel format."); + throw love::Exception("All texture slices and mipmaps must have the same pixel format."); } mipw = std::max(mipw / 2, 1); diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 8b82e583e..1f4e52671 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -308,7 +308,7 @@ protected: int64 graphicsMemorySize; - // True if the image wasn't able to be properly created and it had to fall + // True if the texture wasn't able to be properly created and it had to fall // back to a default texture. bool usingDefaultTexture; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index b0b9f25e6..d5b6c0469 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1269,7 +1269,7 @@ void Graphics::setBlendState(const BlendState &blend) if (blend.operationRGB == BLENDOP_MAX || blend.operationA == BLENDOP_MAX || blend.operationRGB == BLENDOP_MIN || blend.operationA == BLENDOP_MIN) { - if (!capabilities.features[FEATURE_BLENDMINMAX]) + if (!capabilities.features[FEATURE_BLEND_MINMAX]) throw love::Exception("The 'min' and 'max' blend operations are not supported on this system."); } @@ -1355,10 +1355,10 @@ void Graphics::getAPIStats(int &shaderswitches) const void Graphics::initCapabilities() { - capabilities.features[FEATURE_MULTI_CANVAS_FORMATS] = gl.isMultiFormatMRTSupported(); + capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = gl.isMultiFormatMRTSupported(); capabilities.features[FEATURE_CLAMP_ZERO] = gl.isClampZeroOneTextureWrapSupported(); - capabilities.features[FEATURE_BLENDMINMAX] = GLAD_VERSION_1_4 || GLAD_ES_VERSION_3_0 || GLAD_EXT_blend_minmax; - capabilities.features[FEATURE_LIGHTEN] = capabilities.features[FEATURE_BLENDMINMAX]; + capabilities.features[FEATURE_BLEND_MINMAX] = GLAD_VERSION_1_4 || GLAD_ES_VERSION_3_0 || GLAD_EXT_blend_minmax; + capabilities.features[FEATURE_LIGHTEN] = capabilities.features[FEATURE_BLEND_MINMAX]; capabilities.features[FEATURE_FULL_NPOT] = GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot; capabilities.features[FEATURE_PIXEL_SHADER_HIGHP] = gl.isPixelShaderHighpSupported(); capabilities.features[FEATURE_SHADER_DERIVATIVES] = GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_standard_derivatives; @@ -1372,8 +1372,8 @@ void Graphics::initCapabilities() capabilities.limits[LIMIT_TEXTURE_LAYERS] = gl.getMaxTextureLayers(); capabilities.limits[LIMIT_VOLUME_TEXTURE_SIZE] = gl.getMax3DTextureSize(); capabilities.limits[LIMIT_CUBE_TEXTURE_SIZE] = gl.getMaxCubeTextureSize(); - capabilities.limits[LIMIT_MULTI_CANVAS] = gl.getMaxRenderTargets(); - capabilities.limits[LIMIT_CANVAS_MSAA] = gl.getMaxRenderbufferSamples(); + capabilities.limits[LIMIT_RENDER_TARGETS] = gl.getMaxRenderTargets(); + capabilities.limits[LIMIT_TEXTURE_MSAA] = gl.getMaxRenderbufferSamples(); capabilities.limits[LIMIT_ANISOTROPY] = gl.getMaxAnisotropy(); static_assert(LIMIT_MAX_ENUM == 8, "Graphics::initCapabilities must be updated when adding a new system limit!"); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index b010202d4..df8cae160 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -259,8 +259,9 @@ void OpenGL::setupContext() #ifdef LOVE_ANDROID // This can't be done in initContext with the rest of the bug checks because - // Canvas::isFormatSupported relies on state initialized here / after init. - if (GLAD_ES_VERSION_3_0 && !Canvas::isFormatSupported(PIXELFORMAT_R8)) + // isPixelFormatSupported relies on state initialized here / after init. + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (GLAD_ES_VERSION_3_0 && gfx != nullptr && !gfx->isPixelFormatSupported(PIXELFORMAT_R8_UNORM, true, true)) bugs.brokenR8PixelFormat = true; #endif } diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 23397ac57..8681ca5b1 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -110,7 +110,7 @@ private: // Uniform location buffer map std::map uniforms; - // Texture unit pool for setting images + // Texture unit pool for setting textures std::vector textureUnits; std::vector> pendingUniformUpdates; diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index ec6da42a8..5b9d82fe8 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -75,23 +75,26 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo gl.framebufferTexture(attachment, texType, texture, 0, layer, face); } - if (isPixelFormatDepthStencil(format)) + if (clear) { - bool hadDepthWrites = gl.hasDepthWrites(); - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); + if (isPixelFormatDepthStencil(format)) + { + bool hadDepthWrites = gl.hasDepthWrites(); + if (!hadDepthWrites) // glDepthMask also affects glClear. + gl.setDepthWrites(true); - gl.clearDepth(1.0); - glClearStencil(0); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.clearDepth(1.0); + glClearStencil(0); + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - if (!hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); - } - else - { - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); + if (!hadDepthWrites) + gl.setDepthWrites(hadDepthWrites); + } + else + { + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + } } } } diff --git a/src/modules/graphics/wrap_GraphicsShader.lua b/src/modules/graphics/wrap_GraphicsShader.lua index 14a1ba19d..f0631c6f6 100644 --- a/src/modules/graphics/wrap_GraphicsShader.lua +++ b/src/modules/graphics/wrap_GraphicsShader.lua @@ -271,7 +271,7 @@ GLSL.PIXEL = { precision mediump float; #endif -#define love_MaxCanvases gl_MaxDrawBuffers +#define love_MaxRenderTargets gl_MaxDrawBuffers #if __VERSION__ >= 130 #define varying in @@ -279,19 +279,26 @@ GLSL.PIXEL = { // pixel shader outputs are defined, even when only one is actually used. // TODO: We should use reflection or something instead of this, to determine // how many outputs are actually used in the shader code. - #ifdef LOVE_MULTI_CANVAS - layout(location = 0) out vec4 love_Canvases[love_MaxCanvases]; - #define love_PixelColor love_Canvases[0] + #ifdef LOVE_MULTI_RENDER_TARGETS + layout(location = 0) out vec4 love_RenderTargets[love_MaxRenderTargets]; + #define love_PixelColor love_RenderTargets[0] #else layout(location = 0) out vec4 love_PixelColor; #endif #else - #ifdef LOVE_MULTI_CANVAS - #define love_Canvases gl_FragData + #ifdef LOVE_MULTI_RENDER_TARGETS + #define love_RenderTargets gl_FragData #endif #define love_PixelColor gl_FragColor #endif +// Legacy +#define love_MaxCanvases love_MaxRenderTargets +#define love_Canvases love_RenderTargets +#ifdef LOVE_MULTI_RENDER_TARGETS +#define LOVE_MULTI_CANVASES 1 +#endif + // See Shader::updateScreenParams in Shader.cpp. #define love_PixelCoord (vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w))]], @@ -345,14 +352,14 @@ local function getLanguageTarget(code) return (code:match("^%s*#pragma language (%w+)")) or "glsl1" end -local function createShaderStageCode(stage, code, lang, gles, glsl1on3, gammacorrect, custom, multicanvas) +local function createShaderStageCode(stage, code, lang, gles, glsl1on3, gammacorrect, custom, multirendertarget) stage = stage:upper() local lines = { GLSL.VERSION[lang][gles], "#define " ..stage .. " " .. stage, glsl1on3 and "#define LOVE_GLSL1_ON_GLSL3 1" or "", gammacorrect and "#define LOVE_GAMMA_CORRECT 1" or "", - multicanvas and "#define LOVE_MULTI_CANVAS 1" or "", + multirendertarget and "#define LOVE_MULTI_RENDER_TARGETS 1" or "", GLSL.SYNTAX, GLSL[stage].HEADER, GLSL.UNIFORMS, @@ -373,8 +380,8 @@ local function isPixelCode(code) if code:match("vec4%s+effect%s*%(") then return true elseif code:match("void%s+effect%s*%(") then -- custom effect function - local multicanvas = code:match("love_Canvases") ~= nil - return true, true, multicanvas + local multirendertargets = (code:match("love_RenderTargets") ~= nil) or (code:match("love_Canvases") ~= nil) + return true, true, multirendertargets else return false end From aa636381d0b5aa317eaac4025b841c6368f5cae9 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 9 Feb 2020 12:46:52 -0400 Subject: [PATCH 23/31] Fix MSAA texture creation logic --- src/modules/graphics/opengl/Graphics.cpp | 2 +- src/modules/graphics/opengl/OpenGL.cpp | 10 +++++----- src/modules/graphics/opengl/OpenGL.h | 6 +++--- src/modules/graphics/opengl/Texture.cpp | 12 +++--------- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index d5b6c0469..7a700420a 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1373,7 +1373,7 @@ void Graphics::initCapabilities() capabilities.limits[LIMIT_VOLUME_TEXTURE_SIZE] = gl.getMax3DTextureSize(); capabilities.limits[LIMIT_CUBE_TEXTURE_SIZE] = gl.getMaxCubeTextureSize(); capabilities.limits[LIMIT_RENDER_TARGETS] = gl.getMaxRenderTargets(); - capabilities.limits[LIMIT_TEXTURE_MSAA] = gl.getMaxRenderbufferSamples(); + capabilities.limits[LIMIT_TEXTURE_MSAA] = gl.getMaxSamples(); capabilities.limits[LIMIT_ANISOTROPY] = gl.getMaxAnisotropy(); static_assert(LIMIT_MAX_ENUM == 8, "Graphics::initCapabilities must be updated when adding a new system limit!"); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index df8cae160..c098a67ae 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -102,7 +102,7 @@ OpenGL::OpenGL() , maxCubeTextureSize(0) , maxTextureArrayLayers(0) , maxRenderTargets(1) - , maxRenderbufferSamples(0) + , maxSamples(1) , maxTextureUnits(1) , maxPointSize(1) , coreProfile(false) @@ -474,10 +474,10 @@ void OpenGL::initMaxValues() || GLAD_EXT_framebuffer_multisample || GLAD_APPLE_framebuffer_multisample || GLAD_ANGLE_framebuffer_multisample) { - glGetIntegerv(GL_MAX_SAMPLES, &maxRenderbufferSamples); + glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); } else - maxRenderbufferSamples = 0; + maxSamples = 1; glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); @@ -1358,9 +1358,9 @@ int OpenGL::getMaxRenderTargets() const return std::min(maxRenderTargets, MAX_COLOR_RENDER_TARGETS); } -int OpenGL::getMaxRenderbufferSamples() const +int OpenGL::getMaxSamples() const { - return maxRenderbufferSamples; + return maxSamples; } int OpenGL::getMaxTextureUnits() const diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index ba17b8431..ad02098ff 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -363,9 +363,9 @@ public: int getMaxRenderTargets() const; /** - * Returns the maximum supported number of MSAA samples for renderbuffers. + * Returns the maximum supported number of MSAA sampless. **/ - int getMaxRenderbufferSamples() const; + int getMaxSamples() const; /** * Returns the maximum number of accessible texture units. @@ -436,7 +436,7 @@ private: int maxCubeTextureSize; int maxTextureArrayLayers; int maxRenderTargets; - int maxRenderbufferSamples; + int maxSamples; int maxTextureUnits; float maxPointSize; diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index 5b9d82fe8..0c5113b0d 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -280,10 +280,7 @@ bool Texture::createTexture() } if (mipsize > 0) - { - GLenum gltarget = OpenGL::getGLTextureType(texType); - glCompressedTexImage3D(gltarget, mip, fmt.internalformat, w, h, d, 0, mipsize, nullptr); - } + glCompressedTexImage3D(gltype, mip, fmt.internalformat, w, h, d, 0, mipsize, nullptr); } for (int slice = 0; slice < slicecount; slice++) @@ -352,10 +349,7 @@ bool Texture::loadVolatile() samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; } - // getMaxRenderbufferSamples will be 0 on systems that don't support - // multisampled renderbuffers / don't export FBO multisample extensions. - actualSamples = std::min(getRequestedMSAA(), gl.getMaxRenderbufferSamples()); - actualSamples = std::max(actualSamples, 1); + actualSamples = std::max(1, std::min(getRequestedMSAA(), gl.getMaxSamples())); while (glGetError() != GL_NO_ERROR); // Clear errors. @@ -363,7 +357,7 @@ bool Texture::loadVolatile() { if (isReadable()) createTexture(); - if (!isReadable() && actualSamples > 1) + if (!isReadable() || actualSamples > 1) createRenderbuffer(); GLenum glerr = glGetError(); From d24b9e9e6f28a4a90943a82d6b371c4baf31d7a5 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 11 Feb 2020 19:32:00 -0400 Subject: [PATCH 24/31] Rename love.graphics.newCanvas to newRenderTarget --- src/modules/graphics/SpriteBatch.cpp | 2 +- src/modules/graphics/opengl/Texture.cpp | 2 +- src/modules/graphics/wrap_Graphics.cpp | 204 +++++++++++++++--------- 3 files changed, 130 insertions(+), 78 deletions(-) diff --git a/src/modules/graphics/SpriteBatch.cpp b/src/modules/graphics/SpriteBatch.cpp index 2b7348aed..ce264b019 100644 --- a/src/modules/graphics/SpriteBatch.cpp +++ b/src/modules/graphics/SpriteBatch.cpp @@ -176,7 +176,7 @@ void SpriteBatch::flush() void SpriteBatch::setTexture(Texture *newtexture) { if (texture->getTextureType() != newtexture->getTextureType()) - throw love::Exception("Texture must have the same texture type as the SpriteBatch's previous texture."); + throw love::Exception("Texture must have the same type as the SpriteBatch's previous texture."); texture.set(newtexture); } diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index 0c5113b0d..632523d8b 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -399,7 +399,7 @@ void Texture::unloadVolatile() if (isRenderTarget() && (fbo != 0 || renderbuffer != 0 || texture != 0)) { // This is a bit ugly, but we need some way to destroy the cached FBO - // when this texture's texture is destroyed. + // when this texture's GL object is destroyed. auto gfx = Module::getInstance(Module::M_GRAPHICS); if (gfx != nullptr) gfx->cleanupRenderTexture(this); diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 647a7242d..793b765df 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -707,7 +707,7 @@ static Texture::Settings w__optImageSettings(lua_State *L, int idx, bool &setdpi setdpiscale = false; if (!lua_isnoneornil(L, idx)) { - luax_checktablefields(L, idx, "image setting name", Texture::getConstant); + luax_checktablefields(L, idx, "texture setting name", Texture::getConstant); s.mipmaps = luax_boolflag(L, idx, "mipmaps", false) ? Texture::MIPMAPS_MANUAL : Texture::MIPMAPS_NONE; s.linear = luax_boolflag(L, idx, Texture::getConstant(Texture::SETTING_LINEAR), s.linear); @@ -769,6 +769,129 @@ static int w__pushNewImage(lua_State *L, Texture::Slices &slices, const Texture: return 1; } +static void luax_checktexturesettings(lua_State *L, int idx, bool opt, bool checkType, bool checkDimensions, OptionalBool forceRenderTarget, Texture::Settings &s, bool &setdpiscale) +{ + setdpiscale = false; + + if (opt && lua_isnoneornil(L, idx)) + return; + + luax_checktablefields(L, idx, "texture setting name", Texture::getConstant); + + if (forceRenderTarget.hasValue) + s.renderTarget = forceRenderTarget.value; + else + s.renderTarget = luax_boolflag(L, idx, Texture::getConstant(Texture::SETTING_RENDER_TARGET), s.renderTarget); + + lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_FORMAT)); + if (!lua_isnoneornil(L, -1)) + { + const char *str = luaL_checkstring(L, -1); + if (!getConstant(str, s.format)) + luax_enumerror(L, "pixel format", str); + } + lua_pop(L, 1); + + if (checkType) + { + lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_TYPE)); + if (!lua_isnoneornil(L, -1)) + { + const char *str = luaL_checkstring(L, -1); + if (!Texture::getConstant(str, s.type)) + luax_enumerror(L, "texture type", Texture::getConstants(s.type), str); + } + lua_pop(L, 1); + } + + if (checkDimensions) + { + s.width = luax_checkintflag(L, idx, Texture::getConstant(Texture::SETTING_WIDTH)); + s.height = luax_checkintflag(L, idx, Texture::getConstant(Texture::SETTING_HEIGHT)); + if (s.type == TEXTURE_2D_ARRAY || s.type == TEXTURE_VOLUME) + s.layers = luax_checkintflag(L, idx, Texture::getConstant(Texture::SETTING_LAYERS)); + } + + lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_MIPMAPS)); + if (!lua_isnoneornil(L, -1)) + { + if (lua_type(L, -1) == LUA_TBOOLEAN) + s.mipmaps = luax_toboolean(L, -1) ? Texture::MIPMAPS_MANUAL : Texture::MIPMAPS_NONE; + else + { + const char *str = luaL_checkstring(L, -1); + if (!Texture::getConstant(str, s.mipmaps)) + luax_enumerror(L, "Texture mipmap mode", Texture::getConstants(s.mipmaps), str); + } + } + lua_pop(L, 1); + + s.linear = luax_boolflag(L, idx, Texture::getConstant(Texture::SETTING_LINEAR), s.linear); + s.msaa = luax_intflag(L, idx, Texture::getConstant(Texture::SETTING_MSAA), s.msaa); + + lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_READABLE)); + if (!lua_isnoneornil(L, -1)) + s.readable.set(luax_checkboolean(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_DPI_SCALE)); + if (lua_isnumber(L, -1)) + { + s.dpiScale = (float) lua_tonumber(L, -1); + setdpiscale = true; + } + lua_pop(L, 1); +} + +int w_newRenderTarget(lua_State *L) +{ + luax_checkgraphicscreated(L); + + Texture::Settings s; + s.renderTarget = true; + + bool setDPIScale = false; + + if (lua_istable(L, 1)) + { + luax_checktexturesettings(L, 1, false, true, true, OptionalBool(true), s, setDPIScale); + } + else + { + // check if width and height are given. else default to screen dimensions. + s.width = (int) luaL_optinteger(L, 1, instance()->getWidth()); + s.height = (int) luaL_optinteger(L, 2, instance()->getHeight()); + + int startidx = 3; + + if (lua_isnumber(L, 3)) + { + s.layers = (int) luaL_checkinteger(L, 3); + s.type = TEXTURE_2D_ARRAY; + startidx = 4; + } + + luax_checktexturesettings(L, startidx, true, true, false, OptionalBool(true), s, setDPIScale); + } + + // Default to the screen's current pixel density scale. + if (!setDPIScale) + s.dpiScale = instance()->getScreenDPIScale(); + + Texture *texture = nullptr; + luax_catchexcept(L, [&](){ texture = instance()->newTexture(s); }); + + luax_pushtype(L, texture); + texture->release(); + return 1; +} + +int w_newCanvas(lua_State *L) +{ + luax_markdeprecated(L, "newCanvas", API_FUNCTION, DEPRECATED_RENAMED, "newRenderTarget"); + return w_newRenderTarget(L); +} + int w_newCubeImage(lua_State *L) { luax_checkgraphicscreated(L); @@ -1181,80 +1304,6 @@ int w_newParticleSystem(lua_State *L) return 1; } -int w_newCanvas(lua_State *L) -{ - luax_checkgraphicscreated(L); - - Texture::Settings settings; - settings.renderTarget = true; - - // check if width and height are given. else default to screen dimensions. - settings.width = (int) luaL_optinteger(L, 1, instance()->getWidth()); - settings.height = (int) luaL_optinteger(L, 2, instance()->getHeight()); - - // Default to the screen's current pixel density scale. - settings.dpiScale = instance()->getScreenDPIScale(); - - int startidx = 3; - - if (lua_isnumber(L, 3)) - { - settings.layers = (int) luaL_checkinteger(L, 3); - settings.type = TEXTURE_2D_ARRAY; - startidx = 4; - } - - if (!lua_isnoneornil(L, startidx)) - { - luax_checktablefields(L, startidx, "texture setting name", Texture::getConstant); - - settings.dpiScale = (float) luax_numberflag(L, startidx, Texture::getConstant(Texture::SETTING_DPI_SCALE), settings.dpiScale); - settings.msaa = luax_intflag(L, startidx, Texture::getConstant(Texture::SETTING_MSAA), settings.msaa); - - lua_getfield(L, startidx, Texture::getConstant(Texture::SETTING_FORMAT)); - if (!lua_isnoneornil(L, -1)) - { - const char *str = luaL_checkstring(L, -1); - if (!getConstant(str, settings.format)) - return luax_enumerror(L, "pixel format", str); - } - lua_pop(L, 1); - - lua_getfield(L, startidx, Texture::getConstant(Texture::SETTING_TYPE)); - if (!lua_isnoneornil(L, -1)) - { - const char *str = luaL_checkstring(L, -1); - if (!Texture::getConstant(str, settings.type)) - return luax_enumerror(L, "texture type", Texture::getConstants(settings.type), str); - } - lua_pop(L, 1); - - lua_getfield(L, startidx, Texture::getConstant(Texture::SETTING_READABLE)); - if (!lua_isnoneornil(L, -1)) - { - settings.readable.hasValue = true; - settings.readable.value = luax_checkboolean(L, -1); - } - lua_pop(L, 1); - - lua_getfield(L, startidx, Texture::getConstant(Texture::SETTING_MIPMAPS)); - if (!lua_isnoneornil(L, -1)) - { - const char *str = luaL_checkstring(L, -1); - if (!Texture::getConstant(str, settings.mipmaps)) - return luax_enumerror(L, "Texture mipmap mode", Texture::getConstants(settings.mipmaps), str); - } - lua_pop(L, 1); - } - - Texture *texture = nullptr; - luax_catchexcept(L, [&](){ texture = instance()->newTexture(settings); }); - - luax_pushtype(L, texture); - texture->release(); - return 1; -} - static int w_getShaderSource(lua_State *L, int startidx, bool gles, std::string &vertexsource, std::string &pixelsource) { using namespace love::filesystem; @@ -3000,7 +3049,7 @@ static const luaL_Reg functions[] = { "newImageFont", w_newImageFont }, { "newSpriteBatch", w_newSpriteBatch }, { "newParticleSystem", w_newParticleSystem }, - { "newCanvas", w_newCanvas }, + { "newRenderTarget", w_newRenderTarget }, { "newShader", w_newShader }, { "newMesh", w_newMesh }, { "newText", w_newText }, @@ -3110,6 +3159,9 @@ static const luaL_Reg functions[] = { "transformPoint", w_transformPoint }, { "inverseTransformPoint", w_inverseTransformPoint }, + // Deprecated + { "newCanvas", w_newCanvas }, + { 0, 0 } }; From ceb854db5bf1caf662eb20867c73a5c69e047044 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 12 Feb 2020 18:56:55 -0400 Subject: [PATCH 25/31] rename new[Cube|Array|Volume]Image to new[Cube|Array|Volume]Texture --- src/modules/graphics/wrap_Graphics.cpp | 138 +++++++++++++++---------- 1 file changed, 83 insertions(+), 55 deletions(-) diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 793b765df..1d8024954 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -757,12 +757,12 @@ getImageData(lua_State *L, int idx, bool allowcompressed, float *dpiscale) return std::make_pair(idata, cdata); } -static int w__pushNewImage(lua_State *L, Texture::Slices &slices, const Texture::Settings &settings) +static int w__pushNewTexture(lua_State *L, Texture::Slices *slices, const Texture::Settings &settings) { StrongRef i; luax_catchexcept(L, - [&]() { i.set(instance()->newTexture(settings, &slices), Acquire::NORETAIN); }, - [&](bool) { slices.clear(); } + [&]() { i.set(instance()->newTexture(settings, slices), Acquire::NORETAIN); }, + [&](bool) { if (slices) slices->clear(); } ); luax_pushtype(L, i); @@ -848,13 +848,13 @@ int w_newRenderTarget(lua_State *L) luax_checkgraphicscreated(L); Texture::Settings s; - s.renderTarget = true; + OptionalBool forceRenderTarget(true); bool setDPIScale = false; if (lua_istable(L, 1)) { - luax_checktexturesettings(L, 1, false, true, true, OptionalBool(true), s, setDPIScale); + luax_checktexturesettings(L, 1, false, true, true, forceRenderTarget, s, setDPIScale); } else { @@ -871,7 +871,7 @@ int w_newRenderTarget(lua_State *L) startidx = 4; } - luax_checktexturesettings(L, startidx, true, true, false, OptionalBool(true), s, setDPIScale); + luax_checktexturesettings(L, startidx, true, true, false, forceRenderTarget, s, setDPIScale); } // Default to the screen's current pixel density scale. @@ -886,13 +886,43 @@ int w_newRenderTarget(lua_State *L) return 1; } -int w_newCanvas(lua_State *L) +int w_newTexture(lua_State *L) { - luax_markdeprecated(L, "newCanvas", API_FUNCTION, DEPRECATED_RENAMED, "newRenderTarget"); - return w_newRenderTarget(L); + luax_checkgraphicscreated(L); + + Texture::Slices slices(TEXTURE_2D); + + bool dpiscaleset = false; + Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset); + float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; + + if (lua_istable(L, 1)) + { + int n = std::max(1, (int) luax_objlen(L, 1)); + for (int i = 0; i < n; i++) + { + lua_rawgeti(L, 1, i + 1); + auto data = getImageData(L, -1, true, i == 0 ? autodpiscale : nullptr); + if (data.first.get()) + slices.set(0, i, data.first); + else + slices.set(0, i, data.second->getSlice(0, 0)); + } + lua_pop(L, n); + } + else + { + auto data = getImageData(L, 1, true, autodpiscale); + if (data.first.get()) + slices.set(0, 0, data.first); + else + slices.add(data.second, 0, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); + } + + return w__pushNewTexture(L, &slices, settings); } -int w_newCubeImage(lua_State *L) +int w_newCubeTexture(lua_State *L) { luax_checkgraphicscreated(L); @@ -918,7 +948,7 @@ int w_newCubeImage(lua_State *L) slices.set(i, 0, faces[i]); } else - slices.add(data.second, 0, 0, true, settings.mipmaps); + slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE); } else { @@ -976,17 +1006,17 @@ int w_newCubeImage(lua_State *L) slices.set(i, 0, data.first); } else - slices.add(data.second, i, 0, false, settings.mipmaps); + slices.add(data.second, i, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); } } lua_pop(L, tlen); } - return w__pushNewImage(L, slices, settings); + return w__pushNewTexture(L, &slices, settings); } -int w_newArrayImage(lua_State *L) +int w_newArrayTexture(lua_State *L) { luax_checkgraphicscreated(L); @@ -1032,7 +1062,7 @@ int w_newArrayImage(lua_State *L) if (data.first.get()) slices.set(slice, 0, data.first); else - slices.add(data.second, slice, 0, false, settings.mipmaps); + slices.add(data.second, slice, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); } } @@ -1044,13 +1074,13 @@ int w_newArrayImage(lua_State *L) if (data.first.get()) slices.set(0, 0, data.first); else - slices.add(data.second, 0, 0, true, settings.mipmaps); + slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE); } - return w__pushNewImage(L, slices, settings); + return w__pushNewTexture(L, &slices, settings); } -int w_newVolumeImage(lua_State *L) +int w_newVolumeTexture(lua_State *L) { luax_checkgraphicscreated(L); @@ -1098,7 +1128,7 @@ int w_newVolumeImage(lua_State *L) if (data.first.get()) slices.set(layer, 0, data.first); else - slices.add(data.second, layer, 0, false, settings.mipmaps); + slices.add(data.second, layer, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); } } @@ -1117,46 +1147,40 @@ int w_newVolumeImage(lua_State *L) slices.set(i, 0, layers[i]); } else - slices.add(data.second, 0, 0, true, settings.mipmaps); + slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE); } - return w__pushNewImage(L, slices, settings); + return w__pushNewTexture(L, &slices, settings); +} + +int w_newCanvas(lua_State *L) +{ + luax_markdeprecated(L, "love.graphics.newCanvas", API_FUNCTION, DEPRECATED_RENAMED, "love.graphics.newRenderTarget"); + return w_newRenderTarget(L); } int w_newImage(lua_State *L) { - luax_checkgraphicscreated(L); + luax_markdeprecated(L, "love.graphics.newImage", API_FUNCTION, DEPRECATED_RENAMED, "love.graphics.newTexture"); + return w_newTexture(L); +} - Texture::Slices slices(TEXTURE_2D); +int w_newCubeImage(lua_State *L) +{ + luax_markdeprecated(L, "love.graphics.newCubeImage", API_FUNCTION, DEPRECATED_RENAMED, "love.graphics.newCubeTexture"); + return w_newCubeTexture(L); +} - bool dpiscaleset = false; - Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset); - float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; +int w_newArrayImage(lua_State *L) +{ + luax_markdeprecated(L, "love.graphics.newArrayImage", API_FUNCTION, DEPRECATED_RENAMED, "love.graphics.newArrayTexture"); + return w_newArrayTexture(L); +} - if (lua_istable(L, 1)) - { - int n = std::max(1, (int) luax_objlen(L, 1)); - for (int i = 0; i < n; i++) - { - lua_rawgeti(L, 1, i + 1); - auto data = getImageData(L, -1, true, i == 0 ? autodpiscale : nullptr); - if (data.first.get()) - slices.set(0, i, data.first); - else - slices.set(0, i, data.second->getSlice(0, 0)); - } - lua_pop(L, n); - } - else - { - auto data = getImageData(L, 1, true, autodpiscale); - if (data.first.get()) - slices.set(0, 0, data.first); - else - slices.add(data.second, 0, 0, false, settings.mipmaps); - } - - return w__pushNewImage(L, slices, settings); +int w_newVolumeImage(lua_State *L) +{ + luax_markdeprecated(L, "love.graphics.newVolumeImage", API_FUNCTION, DEPRECATED_RENAMED, "love.graphics.newVolumeTexture"); + return w_newVolumeTexture(L); } int w_newQuad(lua_State *L) @@ -3040,16 +3064,16 @@ static const luaL_Reg functions[] = { "discard", w_discard }, { "present", w_present }, - { "newImage", w_newImage }, - { "newArrayImage", w_newArrayImage }, - { "newVolumeImage", w_newVolumeImage }, - { "newCubeImage", w_newCubeImage }, + { "newRenderTarget", w_newRenderTarget }, + { "newTexture", w_newTexture }, + { "newCubeTexture", w_newCubeTexture }, + { "newArrayTexture", w_newArrayTexture }, + { "newVolumeTexture", w_newVolumeTexture }, { "newQuad", w_newQuad }, { "newFont", w_newFont }, { "newImageFont", w_newImageFont }, { "newSpriteBatch", w_newSpriteBatch }, { "newParticleSystem", w_newParticleSystem }, - { "newRenderTarget", w_newRenderTarget }, { "newShader", w_newShader }, { "newMesh", w_newMesh }, { "newText", w_newText }, @@ -3161,6 +3185,10 @@ static const luaL_Reg functions[] = // Deprecated { "newCanvas", w_newCanvas }, + { "newImage", w_newImage }, + { "newArrayImage", w_newArrayImage }, + { "newVolumeImage", w_newVolumeImage }, + { "newCubeImage", w_newCubeImage }, { 0, 0 } }; From 8478a870a918aabc54b4b5b420a8c5797d3b8537 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 12 Feb 2020 20:07:35 -0400 Subject: [PATCH 26/31] Add new*Texture variants which don't require image files. Update the no-game screen to avoid deprecated functions. --- src/modules/graphics/wrap_Graphics.cpp | 434 ++++++++++++++----------- src/scripts/nogame.lua | 26 +- src/scripts/nogame.lua.h | 72 ++-- 3 files changed, 291 insertions(+), 241 deletions(-) diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 1d8024954..06d0d8d14 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -700,30 +700,6 @@ static void parseDPIScale(Data *d, float *dpiscale) } } -static Texture::Settings w__optImageSettings(lua_State *L, int idx, bool &setdpiscale) -{ - Texture::Settings s; - - setdpiscale = false; - if (!lua_isnoneornil(L, idx)) - { - luax_checktablefields(L, idx, "texture setting name", Texture::getConstant); - - s.mipmaps = luax_boolflag(L, idx, "mipmaps", false) ? Texture::MIPMAPS_MANUAL : Texture::MIPMAPS_NONE; - s.linear = luax_boolflag(L, idx, Texture::getConstant(Texture::SETTING_LINEAR), s.linear); - - lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_DPI_SCALE)); - if (lua_isnumber(L, -1)) - { - s.dpiScale = (float) lua_tonumber(L, -1); - setdpiscale = true; - } - lua_pop(L, 1); - } - - return s; -} - static std::pair, StrongRef> getImageData(lua_State *L, int idx, bool allowcompressed, float *dpiscale) { @@ -891,35 +867,60 @@ int w_newTexture(lua_State *L) luax_checkgraphicscreated(L); Texture::Slices slices(TEXTURE_2D); + Texture::Slices *slicesref = &slices; + Texture::Settings settings; + settings.type = TEXTURE_2D; bool dpiscaleset = false; - Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset); - float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; - if (lua_istable(L, 1)) + if (lua_type(L, 1) == LUA_TNUMBER) { - int n = std::max(1, (int) luax_objlen(L, 1)); - for (int i = 0; i < n; i++) + slicesref = nullptr; + + settings.width = (int) luaL_checkinteger(L, 1); + settings.height = (int) luaL_checkinteger(L, 2); + + int startidx = 3; + + if (lua_type(L, 3) == LUA_TNUMBER) { - lua_rawgeti(L, 1, i + 1); - auto data = getImageData(L, -1, true, i == 0 ? autodpiscale : nullptr); - if (data.first.get()) - slices.set(0, i, data.first); - else - slices.set(0, i, data.second->getSlice(0, 0)); + settings.layers = (int) luaL_checkinteger(L, 3); + settings.type = TEXTURE_2D_ARRAY; + startidx = 4; } - lua_pop(L, n); + + luax_checktexturesettings(L, startidx, true, true, false, OptionalBool(), settings, dpiscaleset); } else { - auto data = getImageData(L, 1, true, autodpiscale); - if (data.first.get()) - slices.set(0, 0, data.first); + luax_checktexturesettings(L, 2, true, false, false, OptionalBool(), settings, dpiscaleset); + float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; + + if (lua_istable(L, 1)) + { + int n = std::max(1, (int) luax_objlen(L, 1)); + for (int i = 0; i < n; i++) + { + lua_rawgeti(L, 1, i + 1); + auto data = getImageData(L, -1, true, i == 0 ? autodpiscale : nullptr); + if (data.first.get()) + slices.set(0, i, data.first); + else + slices.set(0, i, data.second->getSlice(0, 0)); + } + lua_pop(L, n); + } else - slices.add(data.second, 0, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); + { + auto data = getImageData(L, 1, true, autodpiscale); + if (data.first.get()) + slices.set(0, 0, data.first); + else + slices.add(data.second, 0, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); + } } - return w__pushNewTexture(L, &slices, settings); + return w__pushNewTexture(L, slicesref, settings); } int w_newCubeTexture(lua_State *L) @@ -927,93 +928,106 @@ int w_newCubeTexture(lua_State *L) luax_checkgraphicscreated(L); Texture::Slices slices(TEXTURE_CUBE); + Texture::Slices *slicesref = &slices; + Texture::Settings settings; + settings.type = TEXTURE_CUBE; bool dpiscaleset = false; - Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset); - float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; - auto imagemodule = Module::getInstance(Module::M_IMAGE); - - if (!lua_istable(L, 1)) + if (lua_type(L, 1) == LUA_TNUMBER) { - auto data = getImageData(L, 1, true, autodpiscale); - - std::vector> faces; - - if (data.first.get()) - { - luax_catchexcept(L, [&](){ faces = imagemodule->newCubeFaces(data.first); }); - - for (int i = 0; i < (int) faces.size(); i++) - slices.set(i, 0, faces[i]); - } - else - slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE); + slicesref = nullptr; + settings.width = settings.height = (int) luaL_checkinteger(L, 1); + luax_checktexturesettings(L, 2, true, false, false, OptionalBool(), settings, dpiscaleset); } else { - int tlen = (int) luax_objlen(L, 1); + luax_checktexturesettings(L, 2, true, false, false, OptionalBool(), settings, dpiscaleset); + float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; - if (luax_isarrayoftables(L, 1)) + auto imagemodule = Module::getInstance(Module::M_IMAGE); + + if (!lua_istable(L, 1)) { - if (tlen != 6) - return luaL_error(L, "Cubemap images must have 6 faces."); + auto data = getImageData(L, 1, true, autodpiscale); - for (int face = 0; face < tlen; face++) + std::vector> faces; + + if (data.first.get()) { - lua_rawgeti(L, 1, face + 1); - luaL_checktype(L, -1, LUA_TTABLE); + luax_catchexcept(L, [&](){ faces = imagemodule->newCubeFaces(data.first); }); - int miplen = std::max(1, (int) luax_objlen(L, -1)); - - for (int mip = 0; mip < miplen; mip++) - { - lua_rawgeti(L, -1, mip + 1); - - auto data = getImageData(L, -1, true, face == 0 && mip == 0 ? autodpiscale : nullptr); - if (data.first.get()) - slices.set(face, mip, data.first); - else - slices.set(face, mip, data.second->getSlice(0, 0)); - - lua_pop(L, 1); - } + for (int i = 0; i < (int) faces.size(); i++) + slices.set(i, 0, faces[i]); } + else + slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE); } else { - bool usemipmaps = false; + int tlen = (int) luax_objlen(L, 1); - for (int i = 0; i < tlen; i++) + if (luax_isarrayoftables(L, 1)) { - lua_rawgeti(L, 1, i + 1); + if (tlen != 6) + return luaL_error(L, "Cubemap images must have 6 faces."); - auto data = getImageData(L, -1, true, i == 0 ? autodpiscale : nullptr); - - if (data.first.get()) + for (int face = 0; face < tlen; face++) { - if (usemipmaps || data.first->getWidth() != data.first->getHeight()) + lua_rawgeti(L, 1, face + 1); + luaL_checktype(L, -1, LUA_TTABLE); + + int miplen = std::max(1, (int) luax_objlen(L, -1)); + + for (int mip = 0; mip < miplen; mip++) { - usemipmaps = true; + lua_rawgeti(L, -1, mip + 1); - std::vector> faces; - luax_catchexcept(L, [&](){ faces = imagemodule->newCubeFaces(data.first); }); + auto data = getImageData(L, -1, true, face == 0 && mip == 0 ? autodpiscale : nullptr); + if (data.first.get()) + slices.set(face, mip, data.first); + else + slices.set(face, mip, data.second->getSlice(0, 0)); - for (int face = 0; face < (int) faces.size(); face++) - slices.set(face, i, faces[i]); + lua_pop(L, 1); + } + } + } + else + { + bool usemipmaps = false; + + for (int i = 0; i < tlen; i++) + { + lua_rawgeti(L, 1, i + 1); + + auto data = getImageData(L, -1, true, i == 0 ? autodpiscale : nullptr); + + if (data.first.get()) + { + if (usemipmaps || data.first->getWidth() != data.first->getHeight()) + { + usemipmaps = true; + + std::vector> faces; + luax_catchexcept(L, [&](){ faces = imagemodule->newCubeFaces(data.first); }); + + for (int face = 0; face < (int) faces.size(); face++) + slices.set(face, i, faces[i]); + } + else + slices.set(i, 0, data.first); } else - slices.set(i, 0, data.first); + slices.add(data.second, i, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); } - else - slices.add(data.second, i, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); } - } - lua_pop(L, tlen); + lua_pop(L, tlen); + } } - return w__pushNewTexture(L, &slices, settings); + return w__pushNewTexture(L, slicesref, settings); } int w_newArrayTexture(lua_State *L) @@ -1021,63 +1035,78 @@ int w_newArrayTexture(lua_State *L) luax_checkgraphicscreated(L); Texture::Slices slices(TEXTURE_2D_ARRAY); + Texture::Slices *slicesref = &slices; + Texture::Settings settings; + settings.type = TEXTURE_2D_ARRAY; bool dpiscaleset = false; - Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset); - float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; - if (lua_istable(L, 1)) + if (lua_type(L, 1) == LUA_TNUMBER) { - int tlen = std::max(1, (int) luax_objlen(L, 1)); - - if (luax_isarrayoftables(L, 1)) - { - for (int slice = 0; slice < tlen; slice++) - { - lua_rawgeti(L, 1, slice + 1); - luaL_checktype(L, -1, LUA_TTABLE); - - int miplen = std::max(1, (int) luax_objlen(L, -1)); - - for (int mip = 0; mip < miplen; mip++) - { - lua_rawgeti(L, -1, mip + 1); - - auto data = getImageData(L, -1, true, slice == 0 && mip == 0 ? autodpiscale : nullptr); - if (data.first.get()) - slices.set(slice, mip, data.first); - else - slices.set(slice, mip, data.second->getSlice(0, 0)); - - lua_pop(L, 1); - } - } - } - else - { - for (int slice = 0; slice < tlen; slice++) - { - lua_rawgeti(L, 1, slice + 1); - auto data = getImageData(L, -1, true, slice == 0 ? autodpiscale : nullptr); - if (data.first.get()) - slices.set(slice, 0, data.first); - else - slices.add(data.second, slice, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); - } - } - - lua_pop(L, tlen); + slicesref = nullptr; + settings.width = (int) luaL_checkinteger(L, 1); + settings.height = (int) luaL_checkinteger(L, 2); + settings.layers = (int) luaL_checkinteger(L, 3); + luax_checktexturesettings(L, 4, true, false, false, OptionalBool(), settings, dpiscaleset); } else { - auto data = getImageData(L, 1, true, autodpiscale); - if (data.first.get()) - slices.set(0, 0, data.first); + luax_checktexturesettings(L, 2, true, false, false, OptionalBool(), settings, dpiscaleset); + float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; + + if (lua_istable(L, 1)) + { + int tlen = std::max(1, (int) luax_objlen(L, 1)); + + if (luax_isarrayoftables(L, 1)) + { + for (int slice = 0; slice < tlen; slice++) + { + lua_rawgeti(L, 1, slice + 1); + luaL_checktype(L, -1, LUA_TTABLE); + + int miplen = std::max(1, (int) luax_objlen(L, -1)); + + for (int mip = 0; mip < miplen; mip++) + { + lua_rawgeti(L, -1, mip + 1); + + auto data = getImageData(L, -1, true, slice == 0 && mip == 0 ? autodpiscale : nullptr); + if (data.first.get()) + slices.set(slice, mip, data.first); + else + slices.set(slice, mip, data.second->getSlice(0, 0)); + + lua_pop(L, 1); + } + } + } + else + { + for (int slice = 0; slice < tlen; slice++) + { + lua_rawgeti(L, 1, slice + 1); + auto data = getImageData(L, -1, true, slice == 0 ? autodpiscale : nullptr); + if (data.first.get()) + slices.set(slice, 0, data.first); + else + slices.add(data.second, slice, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); + } + } + + lua_pop(L, tlen); + } else - slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE); + { + auto data = getImageData(L, 1, true, autodpiscale); + if (data.first.get()) + slices.set(0, 0, data.first); + else + slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE); + } } - return w__pushNewTexture(L, &slices, settings); + return w__pushNewTexture(L, slicesref, settings); } int w_newVolumeTexture(lua_State *L) @@ -1087,70 +1116,85 @@ int w_newVolumeTexture(lua_State *L) auto imagemodule = Module::getInstance(Module::M_IMAGE); Texture::Slices slices(TEXTURE_VOLUME); + Texture::Slices *slicesref = &slices; + Texture::Settings settings; + settings.type = TEXTURE_VOLUME; bool dpiscaleset = false; - Texture::Settings settings = w__optImageSettings(L, 2, dpiscaleset); - float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; - if (lua_istable(L, 1)) + if (lua_type(L, 1) == LUA_TNUMBER) { - int tlen = std::max(1, (int) luax_objlen(L, 1)); - - if (luax_isarrayoftables(L, 1)) - { - for (int mip = 0; mip < tlen; mip++) - { - lua_rawgeti(L, 1, mip + 1); - luaL_checktype(L, -1, LUA_TTABLE); - - int slicelen = std::max(1, (int) luax_objlen(L, -1)); - - for (int slice = 0; slice < slicelen; slice++) - { - lua_rawgeti(L, -1, mip + 1); - - auto data = getImageData(L, -1, true, slice == 0 && mip == 0 ? autodpiscale : nullptr); - if (data.first.get()) - slices.set(slice, mip, data.first); - else - slices.set(slice, mip, data.second->getSlice(0, 0)); - - lua_pop(L, 1); - } - } - } - else - { - for (int layer = 0; layer < tlen; layer++) - { - lua_rawgeti(L, 1, layer + 1); - auto data = getImageData(L, -1, true, layer == 0 ? autodpiscale : nullptr); - if (data.first.get()) - slices.set(layer, 0, data.first); - else - slices.add(data.second, layer, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); - } - } - - lua_pop(L, tlen); + slicesref = nullptr; + settings.width = (int) luaL_checkinteger(L, 1); + settings.height = (int) luaL_checkinteger(L, 2); + settings.layers = (int) luaL_checkinteger(L, 3); + luax_checktexturesettings(L, 4, true, false, false, OptionalBool(), settings, dpiscaleset); } else { - auto data = getImageData(L, 1, true, autodpiscale); + luax_checktexturesettings(L, 2, true, false, false, OptionalBool(), settings, dpiscaleset); + float *autodpiscale = dpiscaleset ? nullptr : &settings.dpiScale; - if (data.first.get()) + if (lua_istable(L, 1)) { - std::vector> layers; - luax_catchexcept(L, [&](){ layers = imagemodule->newVolumeLayers(data.first); }); + int tlen = std::max(1, (int) luax_objlen(L, 1)); - for (int i = 0; i < (int) layers.size(); i++) - slices.set(i, 0, layers[i]); + if (luax_isarrayoftables(L, 1)) + { + for (int mip = 0; mip < tlen; mip++) + { + lua_rawgeti(L, 1, mip + 1); + luaL_checktype(L, -1, LUA_TTABLE); + + int slicelen = std::max(1, (int) luax_objlen(L, -1)); + + for (int slice = 0; slice < slicelen; slice++) + { + lua_rawgeti(L, -1, mip + 1); + + auto data = getImageData(L, -1, true, slice == 0 && mip == 0 ? autodpiscale : nullptr); + if (data.first.get()) + slices.set(slice, mip, data.first); + else + slices.set(slice, mip, data.second->getSlice(0, 0)); + + lua_pop(L, 1); + } + } + } + else + { + for (int layer = 0; layer < tlen; layer++) + { + lua_rawgeti(L, 1, layer + 1); + auto data = getImageData(L, -1, true, layer == 0 ? autodpiscale : nullptr); + if (data.first.get()) + slices.set(layer, 0, data.first); + else + slices.add(data.second, layer, 0, false, settings.mipmaps != Texture::MIPMAPS_NONE); + } + } + + lua_pop(L, tlen); } else - slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE); + { + auto data = getImageData(L, 1, true, autodpiscale); + + if (data.first.get()) + { + std::vector> layers; + luax_catchexcept(L, [&](){ layers = imagemodule->newVolumeLayers(data.first); }); + + for (int i = 0; i < (int) layers.size(); i++) + slices.set(i, 0, layers[i]); + } + else + slices.add(data.second, 0, 0, true, settings.mipmaps != Texture::MIPMAPS_NONE); + } } - return w__pushNewTexture(L, &slices, settings); + return w__pushNewTexture(L, slicesref, settings); } int w_newCanvas(lua_State *L) diff --git a/src/scripts/nogame.lua b/src/scripts/nogame.lua index 6f721b2dc..f9603b9eb 100644 --- a/src/scripts/nogame.lua +++ b/src/scripts/nogame.lua @@ -3186,21 +3186,21 @@ function love.nogame() R.bg.cloud_3 = R.bg[dpiscale].cloud_3_png R.bg.cloud_4 = R.bg[dpiscale].cloud_4_png - img_duckloon_normal = love.graphics.newImage(R.duckloon.normal, settings) - img_duckloon_blink = love.graphics.newImage(R.duckloon.blink, settings) + img_duckloon_normal = love.graphics.newTexture(R.duckloon.normal, settings) + img_duckloon_blink = love.graphics.newTexture(R.duckloon.blink, settings) - img_n = love.graphics.newImage(R.chain.n, settings) - img_o = love.graphics.newImage(R.chain.o, settings) - img_g = love.graphics.newImage(R.chain.g, settings) - img_a = love.graphics.newImage(R.chain.a, settings) - img_m = love.graphics.newImage(R.chain.m, settings) - img_e = love.graphics.newImage(R.chain.e, settings) - img_square = love.graphics.newImage(R.chain.square, settings) + img_n = love.graphics.newTexture(R.chain.n, settings) + img_o = love.graphics.newTexture(R.chain.o, settings) + img_g = love.graphics.newTexture(R.chain.g, settings) + img_a = love.graphics.newTexture(R.chain.a, settings) + img_m = love.graphics.newTexture(R.chain.m, settings) + img_e = love.graphics.newTexture(R.chain.e, settings) + img_square = love.graphics.newTexture(R.chain.square, settings) - img_cloud_1 = love.graphics.newImage(R.bg.cloud_1, settings) - img_cloud_2 = love.graphics.newImage(R.bg.cloud_2, settings) - img_cloud_3 = love.graphics.newImage(R.bg.cloud_3, settings) - img_cloud_4 = love.graphics.newImage(R.bg.cloud_4, settings) + img_cloud_1 = love.graphics.newTexture(R.bg.cloud_1, settings) + img_cloud_2 = love.graphics.newTexture(R.bg.cloud_2, settings) + img_cloud_3 = love.graphics.newTexture(R.bg.cloud_3, settings) + img_cloud_4 = love.graphics.newTexture(R.bg.cloud_4, settings) cloud_images = { img_cloud_1, diff --git a/src/scripts/nogame.lua.h b/src/scripts/nogame.lua.h index be9da60e1..d3e51767f 100644 --- a/src/scripts/nogame.lua.h +++ b/src/scripts/nogame.lua.h @@ -11936,54 +11936,60 @@ const unsigned char nogame_lua[] = 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x64, 0x75, 0x63, 0x6b, 0x6c, 0x6f, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, - 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x64, 0x75, 0x63, 0x6b, 0x6c, - 0x6f, 0x6f, 0x6e, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x29, 0x0a, + 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x64, 0x75, 0x63, + 0x6b, 0x6c, 0x6f, 0x6f, 0x6e, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x64, 0x75, 0x63, 0x6b, 0x6c, 0x6f, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, - 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x64, 0x75, 0x63, 0x6b, 0x6c, 0x6f, - 0x6f, 0x6e, 0x2e, 0x62, 0x6c, 0x69, 0x6e, 0x6b, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x29, 0x0a, + 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x64, 0x75, 0x63, 0x6b, + 0x6c, 0x6f, 0x6f, 0x6e, 0x2e, 0x62, 0x6c, 0x69, 0x6e, 0x6b, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x29, 0x0a, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x6e, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6e, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, + 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, + 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6e, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x29, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x6f, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6f, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, + 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, + 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6f, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x29, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x67, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x67, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, + 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, + 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x67, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x29, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x61, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x61, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, + 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, + 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x61, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x29, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x6d, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6d, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, + 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, + 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x6d, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x29, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x28, 0x52, 0x2e, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, + 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, + 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x29, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, - 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, - 0x65, 0x28, 0x52, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x2c, 0x20, - 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, + 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, 0x74, + 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, + 0x2c, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x31, 0x20, 0x3d, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, - 0x67, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x31, 0x2c, 0x20, 0x73, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, + 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, + 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x31, 0x2c, + 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x32, 0x20, 0x3d, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, - 0x67, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x32, 0x2c, 0x20, 0x73, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, + 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, + 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x32, 0x2c, + 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x33, 0x20, 0x3d, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, - 0x67, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x33, 0x2c, 0x20, 0x73, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, + 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, + 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x33, 0x2c, + 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x34, 0x20, 0x3d, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, - 0x67, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x34, 0x2c, 0x20, 0x73, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, + 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x54, 0x65, 0x78, + 0x74, 0x75, 0x72, 0x65, 0x28, 0x52, 0x2e, 0x62, 0x67, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x34, 0x2c, + 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x29, 0x0a, 0x0a, 0x09, 0x09, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x6d, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x31, 0x2c, 0x0a, From f5f7e908a9813a8a775dff671b4304555054c878 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 12 Feb 2020 21:50:23 -0400 Subject: [PATCH 27/31] Rename love.graphics.get/setCanvas to get/setRenderTarget Rename 'canvasswitches' field in love.graphics.getStats to 'rendertargetswitches'. --- src/modules/graphics/wrap_Graphics.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 06d0d8d14..4a1c04b99 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -263,7 +263,7 @@ static Graphics::RenderTarget checkRenderTarget(lua_State *L, int idx) return target; } -int w_setCanvas(lua_State *L) +int w_setRenderTarget(lua_State *L) { // Disable stencil writes. luax_catchexcept(L, [](){ instance()->stopDrawToStencilBuffer(); }); @@ -341,7 +341,7 @@ int w_setCanvas(lua_State *L) } if (i > 1 && type != TEXTURE_2D) - return luaL_error(L, "This variant of setRenderTargets only supports 2D texture types."); + return luaL_error(L, "This variant of setRenderTarget only supports 2D texture types."); targets.colors.push_back(target); } @@ -357,6 +357,12 @@ int w_setCanvas(lua_State *L) return 0; } +int w_setCanvas(lua_State *L) +{ + luax_markdeprecated(L, "love.graphics.setCanvas", API_FUNCTION, DEPRECATED_RENAMED, "love.graphics.setRenderTarget"); + return w_setRenderTarget(L); +} + static void pushRenderTarget(lua_State *L, const Graphics::RenderTarget &rt) { lua_createtable(L, 1, 2); @@ -381,7 +387,7 @@ static void pushRenderTarget(lua_State *L, const Graphics::RenderTarget &rt) lua_setfield(L, -2, "mipmap"); } -int w_getCanvas(lua_State *L) +int w_getRenderTarget(lua_State *L) { Graphics::RenderTargets targets = instance()->getRenderTargets(); int ntargets = (int) targets.colors.size(); @@ -433,6 +439,12 @@ int w_getCanvas(lua_State *L) } } +int w_getCanvas(lua_State *L) +{ + luax_markdeprecated(L, "love.graphics.getCanvas", API_FUNCTION, DEPRECATED_RENAMED, "love.graphics.getRenderTarget"); + return w_getRenderTarget(L); +} + static void screenshotFunctionCallback(const Graphics::ScreenshotInfo *info, love::image::ImageData *i, void *gd) { if (info == nullptr) @@ -2507,7 +2519,7 @@ int w_getStats(lua_State *L) lua_setfield(L, -2, "drawcallsbatched"); lua_pushinteger(L, stats.renderTargetSwitches); - lua_setfield(L, -2, "canvasswitches"); + lua_setfield(L, -2, "rendertargetswitches"); lua_pushinteger(L, stats.shaderSwitches); lua_setfield(L, -2, "shaderswitches"); @@ -3125,8 +3137,8 @@ static const luaL_Reg functions[] = { "validateShader", w_validateShader }, - { "setCanvas", w_setCanvas }, - { "getCanvas", w_getCanvas }, + { "setRenderTarget", w_setRenderTarget }, + { "getRenderTarget", w_getRenderTarget }, { "setColor", w_setColor }, { "getColor", w_getColor }, @@ -3233,6 +3245,8 @@ static const luaL_Reg functions[] = { "newArrayImage", w_newArrayImage }, { "newVolumeImage", w_newVolumeImage }, { "newCubeImage", w_newCubeImage }, + { "setCanvas", w_setCanvas }, + { "getCanvas", w_getCanvas }, { 0, 0 } }; From 5c06b2a860e085c47e1f8483817560a838956035 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 12 Feb 2020 22:25:04 -0400 Subject: [PATCH 28/31] Replace getCanvas/ImageFormats with getTextureFormats --- src/common/Optional.h | 10 ++++++ src/common/runtime.cpp | 19 +++++++++- src/common/runtime.h | 1 + src/modules/graphics/wrap_Graphics.cpp | 48 ++++++++++++++++++++++++-- 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/common/Optional.h b/src/common/Optional.h index 0bb762643..c0cfbb8a6 100644 --- a/src/common/Optional.h +++ b/src/common/Optional.h @@ -45,6 +45,16 @@ struct Optional value = val; hasValue = true; } + + T get(T defaultVal) + { + return hasValue ? value : defaultVal; + } + + void clear() + { + hasValue = false; + } }; typedef Optional OptionalBool; diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index d76bded00..befeb4bb8 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -300,6 +300,23 @@ double luax_numberflag(lua_State *L, int table_index, const char *key, double de return retval; } +bool luax_checkboolflag(lua_State *L, int table_index, const char *key) +{ + lua_getfield(L, table_index, key); + + bool retval = false; + if (lua_type(L, -1) != LUA_TBOOLEAN) + { + std::string err = "expected boolean field '" + std::string(key) + "' in table"; + return luaL_argerror(L, table_index, err.c_str()); + } + else + retval = luax_toboolean(L, -1); + lua_pop(L, 1); + + return retval; +} + int luax_checkintflag(lua_State *L, int table_index, const char *key) { lua_getfield(L, table_index, key); @@ -307,7 +324,7 @@ int luax_checkintflag(lua_State *L, int table_index, const char *key) int retval; if (!lua_isnumber(L, -1)) { - std::string err = "expected integer field " + std::string(key) + " in table"; + std::string err = "expected integer field '" + std::string(key) + "' in table"; return luaL_argerror(L, table_index, err.c_str()); } else diff --git a/src/common/runtime.h b/src/common/runtime.h index 5c884ebcd..c3e4574e5 100644 --- a/src/common/runtime.h +++ b/src/common/runtime.h @@ -190,6 +190,7 @@ bool luax_boolflag(lua_State *L, int table_index, const char *key, bool defaultV int luax_intflag(lua_State *L, int table_index, const char *key, int defaultValue); double luax_numberflag(lua_State *L, int table_index, const char *key, double defaultValue); +bool luax_checkboolflag(lua_State *L, int table_index, const char *key); int luax_checkintflag(lua_State *L, int table_index, const char *key); /** diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 4a1c04b99..388a209f4 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -2371,6 +2371,45 @@ int w_getSupported(lua_State *L) return 1; } +int w_getTextureFormats(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + + bool rt = luax_checkboolflag(L, 1, Texture::getConstant(Texture::SETTING_RENDER_TARGET)); + bool linear = luax_boolflag(L, 1, Texture::getConstant(Texture::SETTING_LINEAR), false); + + OptionalBool readable; + lua_getfield(L, 1, Texture::getConstant(Texture::SETTING_READABLE)); + if (!lua_isnoneornil(L, -1)) + readable.set(luax_checkboolean(L, -1)); + lua_pop(L, 1); + + if (lua_istable(L, 2)) + lua_pushvalue(L, 2); + else + lua_createtable(L, 0, (int) PIXELFORMAT_MAX_ENUM); + + for (int i = 0; i < (int) PIXELFORMAT_MAX_ENUM; i++) + { + PixelFormat format = (PixelFormat) i; + const char *name = nullptr; + + if (format == PIXELFORMAT_UNKNOWN || !love::getConstant(format, name)) + continue; + + if (rt && isPixelFormatDepth(format)) + continue; + + bool formatReadable = readable.get(!isPixelFormatDepthStencil(format)); + bool sRGB = isGammaCorrect() && !linear; + + luax_pushboolean(L, instance()->isPixelFormatSupported(format, rt, formatReadable, sRGB)); + lua_setfield(L, -2, name); + } + + return 1; +} + static int w__getFormats(lua_State *L, int idx, bool (*isFormatSupported)(PixelFormat), bool (*ignore)(PixelFormat)) { if (lua_istable(L, idx)) @@ -2395,6 +2434,8 @@ static int w__getFormats(lua_State *L, int idx, bool (*isFormatSupported)(PixelF int w_getCanvasFormats(lua_State *L) { + luax_markdeprecated(L, "love.graphics.getCanvasFormats", API_FUNCTION, DEPRECATED_REPLACED, "love.graphics.getTextureFormats"); + bool (*supported)(PixelFormat); int idx = 1; @@ -2430,6 +2471,8 @@ int w_getCanvasFormats(lua_State *L) int w_getImageFormats(lua_State *L) { + luax_markdeprecated(L, "love.graphics.getImageFormats", API_FUNCTION, DEPRECATED_REPLACED, "love.graphics.getTextureFormats"); + const auto supported = [](PixelFormat format) -> bool { return instance()->isPixelFormatSupported(format, false, true, false); @@ -3181,8 +3224,7 @@ static const luaL_Reg functions[] = { "_setDefaultShaderCode", w_setDefaultShaderCode }, { "getSupported", w_getSupported }, - { "getCanvasFormats", w_getCanvasFormats }, - { "getImageFormats", w_getImageFormats }, + { "getTextureFormats", w_getTextureFormats }, { "getRendererInfo", w_getRendererInfo }, { "getSystemLimits", w_getSystemLimits }, { "getTextureTypes", w_getTextureTypes }, @@ -3247,6 +3289,8 @@ static const luaL_Reg functions[] = { "newCubeImage", w_newCubeImage }, { "setCanvas", w_setCanvas }, { "getCanvas", w_getCanvas }, + { "getCanvasFormats", w_getCanvasFormats }, + { "getImageFormats", w_getImageFormats }, { 0, 0 } }; From 4ec9cafdea594ce50eebe05adb352055f7297c31 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 12 Feb 2020 22:57:13 -0400 Subject: [PATCH 29/31] Better error checking in the GL texture backend --- src/modules/graphics/Texture.cpp | 4 +- src/modules/graphics/opengl/Texture.cpp | 64 ++++++++++++++----------- src/modules/graphics/opengl/Texture.h | 4 +- 3 files changed, 40 insertions(+), 32 deletions(-) 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; From 185498ba6d203d80ca681aa46b2d430191d5136e Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 15 Feb 2020 13:49:04 -0400 Subject: [PATCH 30/31] Fix depth sample mode validation checking the wrong state. --- src/modules/graphics/opengl/Texture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index 4d80bc5d4..b54b42eb0 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -521,7 +521,7 @@ love::image::ImageData *Texture::newImageData(love::image::Image *module, int sl void Texture::setSamplerState(const SamplerState &s) { - if (samplerState.depthSampleMode.hasValue && !gl.isDepthCompareSampleSupported()) + if (s.depthSampleMode.hasValue && !gl.isDepthCompareSampleSupported()) throw love::Exception("Depth comparison sampling in shaders is not supported on this system."); // Base class does common validation and assigns samplerState. From 15f0e4109b3375a35dfe1cbf4723554483c93d62 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 15 Feb 2020 13:50:47 -0400 Subject: [PATCH 31/31] Fix a typo in a comment --- src/modules/graphics/opengl/StreamBuffer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/graphics/opengl/StreamBuffer.cpp b/src/modules/graphics/opengl/StreamBuffer.cpp index 8ea3a39a8..10eed951e 100644 --- a/src/modules/graphics/opengl/StreamBuffer.cpp +++ b/src/modules/graphics/opengl/StreamBuffer.cpp @@ -505,9 +505,9 @@ love::graphics::StreamBuffer *CreateStreamBuffer(BufferType mode, size_t size) { return new StreamBufferPinnedMemory(mode, size); } - catch (love::Exception &e) + catch (love::Exception &) { - // According to the spec, oinned memory can fail if the RAM + // According to the spec, pinned memory can fail if the RAM // allocation can't be mapped to the GPU's address space. // This seems to happen in practice on Mesa + amdgpu: // https://bitbucket.org/rude/love/issues/1540