From ada0645f3476301fe3a0da4602e999dec31392bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 16 Oct 2023 18:26:21 +0200 Subject: [PATCH] TextureTools: make DistanceField working with subrectangles. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just cannot use gl_FragCoord in here. That's it, that's the fix. What's however COMPLETELY unexpected is that this simple change made the process significantly faster on my Intel GPU, from ~815 µs to 670! I can't even pretend I understand what's going on here, but maybe doing less math in the fragment shader when calculating the texture coordinates (and thus possibly the driver having a better idea how to prefetch or schedule?) is what made this faster? Or maybe it's due to one uniform input less, and two interpolated values instead of four on the way from the vertex shader? --- .../Test/DistanceFieldGlyphCacheGLTest.cpp | 10 ----- src/Magnum/TextureTools/DistanceField.cpp | 39 +++---------------- .../TextureTools/DistanceFieldShader.frag | 13 +++---- .../TextureTools/DistanceFieldShader.vert | 19 +++++++++ .../TextureTools/Test/DistanceFieldGLTest.cpp | 2 - 5 files changed, 30 insertions(+), 53 deletions(-) diff --git a/src/Magnum/Text/Test/DistanceFieldGlyphCacheGLTest.cpp b/src/Magnum/Text/Test/DistanceFieldGlyphCacheGLTest.cpp index 2b56dd78a..77e6e275e 100644 --- a/src/Magnum/Text/Test/DistanceFieldGlyphCacheGLTest.cpp +++ b/src/Magnum/Text/Test/DistanceFieldGlyphCacheGLTest.cpp @@ -192,16 +192,6 @@ void DistanceFieldGlyphCacheGLTest::setImage() { !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); - /* On GLES2 if EXT_unpack_subimage isn't supported or on WebGL 1, the whole - texture gets uploaded and processed every time. Which circumvents this - problem. */ - #if defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - CORRADE_EXPECT_FAIL_IF(GL::Context::current().isExtensionSupported() && !data.sourceOffset.isZero(), - "The distance field tool is currently broken if a non-zero offset is used."); - #elif !defined(MAGNUM_TARGET_GLES2) - CORRADE_EXPECT_FAIL_IF(!data.sourceOffset.isZero(), - "The distance field tool is currently broken if a non-zero offset is used."); - #endif /* The format may be three-component, consider just the first channel */ Containers::StridedArrayView3D pixels = actual.pixels(); CORRADE_COMPARE_WITH((Containers::arrayCast<2, const UnsignedByte>(pixels.prefix({pixels.size()[0], pixels.size()[1], 1})).exceptPrefix(data.offset)), diff --git a/src/Magnum/TextureTools/DistanceField.cpp b/src/Magnum/TextureTools/DistanceField.cpp index 30eb88e7d..8b342dafa 100644 --- a/src/Magnum/TextureTools/DistanceField.cpp +++ b/src/Magnum/TextureTools/DistanceField.cpp @@ -58,11 +58,6 @@ class DistanceFieldShader: public GL::AbstractShaderProgram { explicit DistanceFieldShader(UnsignedInt radius); - DistanceFieldShader& setScaling(const Vector2& scaling) { - setUniform(_scalingUniform, scaling); - return *this; - } - DistanceFieldShader& setImageSizeInverted(const Vector2& size) { setUniform(_imageSizeInvertedUniform, size); return *this; @@ -80,8 +75,7 @@ class DistanceFieldShader: public GL::AbstractShaderProgram { Unit 6 is used by Shaders::Vector and Shaders::DistanceFieldVector. */ enum: Int { TextureUnit = 7 }; - Int _scalingUniform{0}, - _imageSizeInvertedUniform; + Int _imageSizeInvertedUniform{0}; }; DistanceFieldShader::DistanceFieldShader(const UnsignedInt radius) { @@ -131,16 +125,7 @@ DistanceFieldShader::DistanceFieldShader(const UnsignedInt radius) { if(v < GL::Version::GLES310) #endif { - _scalingUniform = uniformLocation("scaling"_s); - - #ifndef MAGNUM_TARGET_GLES - if(!GL::Context::current().isVersionSupported(GL::Version::GL320)) - #else - if(!GL::Context::current().isVersionSupported(GL::Version::GLES300)) - #endif - { - _imageSizeInvertedUniform = uniformLocation("imageSizeInverted"_s); - } + _imageSizeInvertedUniform = uniformLocation("imageSizeInverted"_s); } #ifndef MAGNUM_TARGET_GLES @@ -211,9 +196,8 @@ void DistanceField::operator()(GL::Texture2D& input, GL::Framebuffer& output, co /* The shader assumes that the ratio between the output and input is a multiple of 2, causing output pixel *centers* to be aligned with input pixel *edges* */ - const Vector2i scaling = imageSize/rectangle.size(); CORRADE_ASSERT(imageSize % rectangle.size() == Vector2i{0} && - scaling % 2 == Vector2i{0}, + (imageSize/rectangle.size()) % 2 == Vector2i{0}, "TextureTools::DistanceField: expected input and output size ratio to be a multiple of 2, got" << Debug::packed << imageSize << "and" << Debug::packed << rectangle.size(), ); output @@ -221,20 +205,9 @@ void DistanceField::operator()(GL::Texture2D& input, GL::Framebuffer& output, co .bind(); _state->shader - .setScaling(Vector2{scaling}) - .bindTexture(input); - - #ifndef MAGNUM_TARGET_GLES - if(!GL::Context::current().isVersionSupported(GL::Version::GL320)) - #else - if(!GL::Context::current().isVersionSupported(GL::Version::GLES300)) - #endif - { - _state->shader.setImageSizeInverted(1.0f/Vector2(imageSize)); - } - - /* Draw the mesh */ - _state->shader.draw(_state->mesh); + .bindTexture(input) + .setImageSizeInverted(1.0f/Vector2(imageSize)) + .draw(_state->mesh); } void DistanceField::operator()(GL::Texture2D& input, GL::Texture2D& output, const Range2Di& rectangle, const Vector2i& diff --git a/src/Magnum/TextureTools/DistanceFieldShader.frag b/src/Magnum/TextureTools/DistanceFieldShader.frag index db06c2969..1f01a65a8 100644 --- a/src/Magnum/TextureTools/DistanceFieldShader.frag +++ b/src/Magnum/TextureTools/DistanceFieldShader.frag @@ -37,11 +37,6 @@ #define TEXELFETCH_USABLE #endif -#ifdef EXPLICIT_UNIFORM_LOCATION -layout(location = 0) -#endif -uniform mediump vec2 scaling; - #ifdef EXPLICIT_BINDING layout(binding = 7) #endif @@ -49,11 +44,13 @@ uniform lowp sampler2D textureData; #ifndef TEXELFETCH_USABLE #ifdef EXPLICIT_UNIFORM_LOCATION -layout(location = 1) +layout(location = 0) #endif uniform mediump vec2 imageSizeInverted; #endif +in mediump vec2 inputTextureCoordinates; + #ifdef NEW_GLSL out lowp float value; #endif @@ -169,9 +166,9 @@ void main() { /* The -0.5 is to make the position aligned with the center of the input pixel, and in the integer case to make the conversion not round up */ #ifdef TEXELFETCH_USABLE - const mediump ivec2 position = ivec2(gl_FragCoord.xy*scaling - vec2(0.5)); + const mediump ivec2 position = ivec2(inputTextureCoordinates - vec2(0.5)); #else - const mediump vec2 position = (gl_FragCoord.xy*scaling - vec2(0.5))*imageSizeInverted; + const mediump vec2 position = inputTextureCoordinates - vec2(0.5)*imageSizeInverted; #endif /* +=======+===== diff --git a/src/Magnum/TextureTools/DistanceFieldShader.vert b/src/Magnum/TextureTools/DistanceFieldShader.vert index 64d0d74af..8773b376d 100644 --- a/src/Magnum/TextureTools/DistanceFieldShader.vert +++ b/src/Magnum/TextureTools/DistanceFieldShader.vert @@ -23,6 +23,25 @@ DEALINGS IN THE SOFTWARE. */ +#if (defined(GL_ES) && __VERSION__ >= 300) || (!defined(GL_ES) && __VERSION__ >= 150) +#define TEXELFETCH_USABLE +#endif + +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 0) +#endif +uniform mediump vec2 imageSizeInverted; + +#ifndef NEW_GLSL +#define out varying +#endif +out mediump vec2 inputTextureCoordinates; + void main() { fullScreenTriangle(); + #ifdef TEXELFETCH_USABLE + inputTextureCoordinates = (gl_Position.xy*0.5 + 0.5)/imageSizeInverted; + #else + inputTextureCoordinates = gl_Position.xy*0.5 + 0.5; + #endif } diff --git a/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp b/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp index ef7764629..05f418acd 100644 --- a/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp +++ b/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp @@ -266,8 +266,6 @@ void DistanceFieldGLTest::run() { else pixels = Containers::arrayCast<2, UnsignedByte>(pixels3); - CORRADE_EXPECT_FAIL_IF(!data.offset.isZero(), - "Currently broken if a non-zero offset is used."); CORRADE_COMPARE_WITH( pixels, Utility::Path::join(_testDir, "output.tga"),