diff --git a/src/modules/graphics/Canvas.h b/src/modules/graphics/Canvas.h index 3088805f1..c6347927a 100644 --- a/src/modules/graphics/Canvas.h +++ b/src/modules/graphics/Canvas.h @@ -39,6 +39,13 @@ public: struct Settings { + // Defaults to true for color pixel formats, and false for depth/stencil. + struct Readable + { + bool set = false; + bool value = false; + }; + int width = 1; int height = 1; int layers = 1; // depth for 3D textures @@ -46,6 +53,7 @@ public: TextureType type = TEXTURE_2D; float pixeldensity = 1.0f; int msaa = 0; + Readable readable; }; Canvas(TextureType textype); diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index a55e8872a..8f56ddb64 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -723,6 +723,7 @@ public: * Images. **/ virtual bool isCanvasFormatSupported(PixelFormat format) const = 0; + virtual bool isCanvasFormatSupported(PixelFormat format, bool readable) const = 0; virtual bool isImageFormatSupported(PixelFormat format) const = 0; /** diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 887aef371..1af0fa968 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -165,7 +165,11 @@ Canvas::Canvas(const Settings &settings) throw love::Exception("MSAA is only supported for Canvases with the 2D texture type."); format = getSizedFormat(settings.format); - readable = !isPixelFormatDepthStencil(format); + + if (settings.readable.set) + readable = settings.readable.value; + else + readable = !isPixelFormatDepthStencil(format); initQuad(); loadVolatile(); @@ -187,7 +191,7 @@ bool Canvas::loadVolatile() if (!Canvas::isSupported()) throw love::Exception("Canvases are not supported by your OpenGL drivers!"); - if (!Canvas::isFormatSupported(format)) + if (!Canvas::isFormatSupported(format, readable)) { const char *fstr = "rgba8"; love::getConstant(Canvas::getSizedFormat(format), fstr); @@ -488,6 +492,11 @@ 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; @@ -498,9 +507,6 @@ bool Canvas::isFormatSupported(PixelFormat format) bool supported = true; format = getSizedFormat(format); - bool depthstencil = isPixelFormatDepthStencil(format); - bool readable = !depthstencil; - if (!OpenGL::isPixelFormatSupported(format, true, readable, false)) return false; @@ -525,7 +531,7 @@ bool Canvas::isFormatSupported(PixelFormat format) // Make sure at least something is bound to a color attachment. I believe // this is required on ES2 but I'm not positive. - if (depthstencil) + if (isPixelFormatDepthStencil(format)) gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, gl.getDefaultTexture(TEXTURE_2D), 0, 0, 0); if (readable) diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 7936fd20f..3faea6230 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -82,6 +82,7 @@ public: static PixelFormat getSizedFormat(PixelFormat format); static bool isSupported(); static bool isMultiFormatMultiCanvasSupported(); + static bool isFormatSupported(PixelFormat format, bool readable); static bool isFormatSupported(PixelFormat format); private: diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index ee7165a95..ce4ab75a9 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1487,6 +1487,11 @@ bool Graphics::isCanvasFormatSupported(PixelFormat format) const return Canvas::isFormatSupported(format); } +bool Graphics::isCanvasFormatSupported(PixelFormat format, bool readable) const +{ + return Canvas::isFormatSupported(format, readable); +} + bool Graphics::isImageFormatSupported(PixelFormat format) const { return Image::isFormatSupported(format); diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index ff7a81935..3e19148e0 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -122,6 +122,7 @@ public: bool isSupported(Feature feature) const override; double getSystemLimit(SystemLimit limittype) const override; bool isCanvasFormatSupported(PixelFormat format) const override; + bool isCanvasFormatSupported(PixelFormat format, bool readable) const override; bool isImageFormatSupported(PixelFormat format) const override; Renderer getRenderer() const override; RendererInfo getRendererInfo() const override; diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index e04a0c5d9..3ae813a53 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -1635,17 +1635,32 @@ bool OpenGL::isPixelFormatSupported(PixelFormat pixelformat, bool rendertarget, return rendertarget && !readable; case PIXELFORMAT_DEPTH16: - return rendertarget && !readable; + if (!rendertarget) + return false; + else if (readable) + return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_depth_texture; + else + return true; case PIXELFORMAT_DEPTH24: - return rendertarget && !readable && (GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_depth24 || GLAD_OES_packed_depth_stencil); + if (!rendertarget) + return false; + else if (readable) + return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || (GLAD_OES_depth_texture && (GLAD_OES_depth24 || GLAD_OES_depth_texture)); + else + return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_depth24 || GLAD_OES_depth_texture; case PIXELFORMAT_DEPTH24_STENCIL8: - return rendertarget && !readable && (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_packed_depth_stencil || GLAD_OES_packed_depth_stencil); + if (!rendertarget) + return false; + else if (readable) + return GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_packed_depth_stencil || (GLAD_OES_depth_texture && GLAD_OES_packed_depth_stencil); + else + return GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_packed_depth_stencil || GLAD_OES_packed_depth_stencil; case PIXELFORMAT_DEPTH32F: case PIXELFORMAT_DEPTH32F_STENCIL8: - return rendertarget && !readable && (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_ARB_depth_buffer_float); + return rendertarget && (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_ARB_depth_buffer_float); case PIXELFORMAT_DXT1: return GLAD_EXT_texture_compression_s3tc || GLAD_EXT_texture_compression_dxt1; diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 830793cf3..36118985c 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -1039,6 +1039,15 @@ int w_newCanvas(lua_State *L) return luaL_error(L, "Invalid texture type: %s", str); } lua_pop(L, 1); + + lua_getfield(L, startidx, "readable"); + if (!lua_isnoneornil(L, -1)) + { + luaL_checktype(L, -1, LUA_TBOOLEAN); + settings.readable.set = true; + settings.readable.value = luax_toboolean(L, -1); + } + lua_pop(L, 1); } Canvas *canvas = nullptr; @@ -1873,10 +1882,34 @@ static int w__getFormats(lua_State *L, bool (*isFormatSupported)(PixelFormat), b int w_getCanvasFormats(lua_State *L) { - const auto supported = [](PixelFormat format) -> bool + bool (*supported)(PixelFormat); + + if (!lua_isnoneornil(L, 1)) { - return instance()->isCanvasFormatSupported(format); - }; + luaL_checktype(L, 1, LUA_TBOOLEAN); + + if (luax_toboolean(L, 1)) + { + supported = [](PixelFormat format) -> bool + { + return instance()->isCanvasFormatSupported(format, true); + }; + } + else + { + supported = [](PixelFormat format) -> bool + { + return instance()->isCanvasFormatSupported(format, false); + }; + } + } + else + { + supported = [](PixelFormat format) -> bool + { + return instance()->isCanvasFormatSupported(format); + }; + } return w__getFormats(L, supported, isPixelFormatCompressed); }