From 5f55f9e756018f3f00281f2dd8f4ddc37f76dc24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 13 Apr 2023 11:56:31 +0200 Subject: [PATCH] TextureTools: add a DistanceField overload taking a framebuffer. So one can directly read it back on GLES without having to wrap the texture in a framebuffer again. This change also puts the framebuffer completeness check *before* the clear() and bind() which makes it no longer emit a GL error. The error is still silent though, which isn't nice. Gotta fix that eventually as well. --- doc/changelog.dox | 3 ++ src/Magnum/TextureTools/DistanceField.cpp | 30 +++++++++++----- src/Magnum/TextureTools/DistanceField.h | 21 ++++++++++- .../TextureTools/Test/DistanceFieldGLTest.cpp | 36 +++++++++++-------- 4 files changed, 66 insertions(+), 24 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index f5ec66820..5676f2c1f 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -329,6 +329,9 @@ See also: - New @ref TextureTools::atlasArrayPowerOfTwo() utility for optimal packing of power-of-two textures into a texture atlas array +- Added a @ref TextureTools::DistanceField::operator()() overload taking a + @ref GL::Framebuffer instead of a @ref GL::Texture as an output for an + easier ability to download the resulting image on OpenGL ES platforms @subsubsection changelog-latest-new-trade Trade library diff --git a/src/Magnum/TextureTools/DistanceField.cpp b/src/Magnum/TextureTools/DistanceField.cpp index f2e1b56d5..6eb96f9e2 100644 --- a/src/Magnum/TextureTools/DistanceField.cpp +++ b/src/Magnum/TextureTools/DistanceField.cpp @@ -189,7 +189,7 @@ DistanceField::~DistanceField() = default; UnsignedInt DistanceField::radius() const { return _state->radius; } -void DistanceField::operator()(GL::Texture2D& input, GL::Texture2D& output, const Range2Di& rectangle, const Vector2i& +void DistanceField::operator()(GL::Texture2D& input, GL::Framebuffer& output, const Range2Di& rectangle, const Vector2i& #ifdef MAGNUM_TARGET_GLES imageSize #endif @@ -200,20 +200,17 @@ void DistanceField::operator()(GL::Texture2D& input, GL::Texture2D& output, cons Vector2i imageSize = input.imageSize(0); #endif - /* Framebuffer is instantiated here so it gets correctly unbound at the end - (and bound framebuffer reset back to the default) */ - GL::Framebuffer framebuffer{rectangle}; - framebuffer.attachTexture(GL::Framebuffer::ColorAttachment(0), output, 0) - .clear(GL::FramebufferClear::Color) - .bind(); - - const GL::Framebuffer::Status status = framebuffer.checkStatus(GL::FramebufferTarget::Draw); + const GL::Framebuffer::Status status = output.checkStatus(GL::FramebufferTarget::Draw); if(status != GL::Framebuffer::Status::Complete) { Error() << "TextureTools::DistanceField: cannot render to given output texture, unexpected framebuffer status" << status; return; } + output + .clear(GL::FramebufferClear::Color) + .bind(); + _state->shader.setScaling(Vector2(imageSize)/Vector2(rectangle.size())) .bindTexture(input); @@ -230,4 +227,19 @@ void DistanceField::operator()(GL::Texture2D& input, GL::Texture2D& output, cons _state->shader.draw(_state->mesh); } +void DistanceField::operator()(GL::Texture2D& input, GL::Texture2D& output, const Range2Di& rectangle, const Vector2i& + #ifdef MAGNUM_TARGET_GLES + imageSize + #endif +) { + GL::Framebuffer framebuffer{rectangle}; + framebuffer.attachTexture(GL::Framebuffer::ColorAttachment(0), output, 0); + + operator()(input, framebuffer, rectangle + #ifdef MAGNUM_TARGET_GLES + , imageSize + #endif + ); +} + }} diff --git a/src/Magnum/TextureTools/DistanceField.h b/src/Magnum/TextureTools/DistanceField.h index 4bb326b51..d897656e7 100644 --- a/src/Magnum/TextureTools/DistanceField.h +++ b/src/Magnum/TextureTools/DistanceField.h @@ -110,13 +110,32 @@ class MAGNUM_TEXTURETOOLS_EXPORT DistanceField { UnsignedInt radius() const; /** - * @brief Calculate the distance field + * @brief Calculate the distance field to a framebuffer + * @param input Input texture + * @param output Output framebuffer + * @param rectangle Rectangle in output texture where to render + * @param imageSize Input texture size. Needed only for OpenGL ES, + * on desktop GL the information is gathered automatically using + * @ref GL::Texture2D::imageSize(). + * @m_since_latest + */ + void operator()(GL::Texture2D& input, GL::Framebuffer& output, const Range2Di& rectangle, const Vector2i& imageSize + #ifndef MAGNUM_TARGET_GLES + = {} + #endif + ); + + /** + * @brief Calculate the distance field to a texture * @param input Input texture * @param output Output texture * @param rectangle Rectangle in output texture where to render * @param imageSize Input texture size. Needed only for OpenGL ES, * on desktop GL the information is gathered automatically using * @ref GL::Texture2D::imageSize(). + * + * Creates a framebuffer with @p output attached and calls + * @ref operator()(GL::Texture2D&, GL::Framebuffer&, const Range2Di&, const Vector2i&). */ void operator()(GL::Texture2D& input, GL::Texture2D& output, const Range2Di& rectangle, const Vector2i& imageSize #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp b/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp index 2015e43ba..e0909d6a8 100644 --- a/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp +++ b/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp @@ -23,9 +23,11 @@ DEALINGS IN THE SOFTWARE. */ +#include #include #include #include +#include #ifdef CORRADE_TARGET_APPLE #include @@ -64,6 +66,8 @@ namespace Magnum { namespace TextureTools { namespace Test { namespace { struct DistanceFieldGLTest: GL::OpenGLTester { explicit DistanceFieldGLTest(); + /* This tests the GL::Texture overload, which itself calls into the + GL::Framebuffer overload so both are covered */ void test(); #ifndef MAGNUM_TARGET_WEBGL void benchmark(); @@ -170,24 +174,28 @@ void DistanceFieldGLTest::test() { MAGNUM_VERIFY_NO_GL_ERROR(); - distanceField(input, output, {{}, Vector2i{64}} - #ifdef MAGNUM_TARGET_GLES - , inputImage->size() - #endif - ); + std::ostringstream out; + { + Error redirectError{&out}; + distanceField(input, output, {{}, Vector2i{64}} + #ifdef MAGNUM_TARGET_GLES + , inputImage->size() + #endif + ); + } #ifdef MAGNUM_TARGET_GLES + /* Probably due to the luminance target pixel format? Works with 4.1, + didn't find any commit in between that would clearly affect + this. */ + if(GL::Context::current().versionString().contains("SwiftShader 4.0.0"_s)) { + CORRADE_COMPARE(out.str(), "TextureTools::DistanceField: cannot render to given output texture, unexpected framebuffer status GL::Framebuffer::Status::IncompleteAttachment\n"); + CORRADE_SKIP("SwiftShader 4.0.0 has a bug where the framebuffer is considered incomplete."); + } else + #endif { - /* Probably due to the luminance target pixel format? Works with 4.1, - didn't find any commit in between that would clearly affect - this. */ - CORRADE_EXPECT_FAIL_IF(GL::Context::current().versionString().contains("SwiftShader 4.0.0"_s), - "SwiftShader 4.0.0 has a bug where the framebuffer is considered incomplete."); - MAGNUM_VERIFY_NO_GL_ERROR(); - if(GL::Context::current().versionString().contains("SwiftShader 4.0.0"_s)) - CORRADE_SKIP("Skipping the rest of the test."); + CORRADE_COMPARE(out.str(), ""); } - #endif Containers::Optional actualOutputImage; #ifndef MAGNUM_TARGET_GLES2