Browse Source

TextureTools: make DistanceField working with subrectangles.

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?
pull/168/head
Vladimír Vondruš 3 years ago
parent
commit
ada0645f34
  1. 10
      src/Magnum/Text/Test/DistanceFieldGlyphCacheGLTest.cpp
  2. 39
      src/Magnum/TextureTools/DistanceField.cpp
  3. 13
      src/Magnum/TextureTools/DistanceFieldShader.frag
  4. 19
      src/Magnum/TextureTools/DistanceFieldShader.vert
  5. 2
      src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp

10
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<GL::Extensions::EXT::unpack_subimage>() && !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<const char> pixels = actual.pixels();
CORRADE_COMPARE_WITH((Containers::arrayCast<2, const UnsignedByte>(pixels.prefix({pixels.size()[0], pixels.size()[1], 1})).exceptPrefix(data.offset)),

39
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&

13
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
/* +=======+=====

19
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
}

2
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"),

Loading…
Cancel
Save