diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2015-01-20 15:41:51 +0100 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2015-01-27 18:42:48 +0100 |
commit | c44ee2beb3d8bbe932dd8799f818a2c61a078810 (patch) | |
tree | ce2b870621b0d4e7b77a567029f05875c70036bb /vcl | |
parent | df290c63451723ae05833cf5f13342d4c93f94cc (diff) |
when drawing a transformed bitmap in opengl backend, scale it better
The plain scaling is rather rough, and in fact drawing a scaled bitmap
the normal way gives much better results (because OutputDevice pre-scales
the bitmap before it's drawn). This one may be a bit slow perhaps,
but hopefully nobody there's no code that'd extensively use bitmap
drawing with custom transformations (wishful thinking).
Change-Id: I83e05307adfaeac0ed0757f1a0b2603f64caf8f8
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/opengl/areaScaleFastFragmentShader.glsl | 13 | ||||
-rw-r--r-- | vcl/opengl/areaScaleFragmentShader.glsl | 13 | ||||
-rw-r--r-- | vcl/opengl/gdiimpl.cxx | 59 | ||||
-rw-r--r-- | vcl/opengl/scale.cxx | 1 |
4 files changed, 84 insertions, 2 deletions
diff --git a/vcl/opengl/areaScaleFastFragmentShader.glsl b/vcl/opengl/areaScaleFastFragmentShader.glsl index b8874d1a3994..10ce9f583eeb 100644 --- a/vcl/opengl/areaScaleFastFragmentShader.glsl +++ b/vcl/opengl/areaScaleFastFragmentShader.glsl @@ -18,6 +18,12 @@ uniform float ratio; // = 1.0/(xscale*yscale) varying vec2 tex_coord; +// This mode makes the scaling work like maskedTextureFragmentShader.glsl +// (instead of like plain textureVertexShader.glsl). +#ifdef MASKED +uniform sampler2D mask; +#endif + /* Just make the resulting color the average of all the source pixels (which is an area (xscale)x(yscale) ). @@ -30,7 +36,14 @@ void main(void) { for( int x = 0; x < xscale; ++x ) { +#ifndef MASKED sum += texture2D( sampler, tex_coord.st + offset ); +#else + vec4 texel; + texel = texture2D( sampler, tex_coord.st + offset ); + texel.a = 1.0 - texture2D( mask, tex_coord.st + offset ).r; + sum += texel; +#endif offset.x += xstep; } offset.y += ystep; diff --git a/vcl/opengl/areaScaleFragmentShader.glsl b/vcl/opengl/areaScaleFragmentShader.glsl index 498b0b53ec4b..d72184cc2911 100644 --- a/vcl/opengl/areaScaleFragmentShader.glsl +++ b/vcl/opengl/areaScaleFragmentShader.glsl @@ -27,6 +27,12 @@ uniform float ydestconvert; varying vec2 tex_coord; +// This mode makes the scaling work like maskedTextureFragmentShader.glsl +// (instead of like plain textureVertexShader.glsl). +#ifdef MASKED +uniform sampler2D mask; +#endif + void main(void) { // Convert to pixel coordinates again. @@ -126,7 +132,14 @@ void main(void) for( int x = xstart; x <= xend; ++x, ++xpos ) { vec2 offset = vec2( x * xsrcconvert, y * ysrcconvert ); +#ifndef MASKED tmp += texture2D( sampler, offset ) * xratio[ xpos ]; +#else + vec4 texel; + texel = texture2D( sampler, offset ); + texel.a = 1.0 - texture2D( mask, offset ).r; + tmp += texel * xratio[ xpos ]; +#endif } sum += tmp * yratio[ ypos ]; } diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx index a120d819e641..854c09035ca3 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -894,9 +894,34 @@ void OpenGLSalGraphicsImpl::DrawTransformedTexture( (float) rTexture.GetWidth(), 0, (float) rTexture.GetWidth(), (float) rTexture.GetHeight() }; GLfloat aTexCoord[8]; + // If downscaling at a higher scale ratio, use the area scaling algorithm rather + // than plain OpenGL's scaling, for better results. + // See OpenGLSalBitmap::ImplScaleArea(). + double ixscale = rTexture.GetWidth() / fabs( rX.getX() - rNull.getX()); + double iyscale = rTexture.GetHeight() / fabs( rY.getY() - rNull.getY()); + bool areaScaling = false; + bool fastAreaScaling = false; + OUString textureFragmentShader; + if( ixscale >= 2 && iyscale >= 2 ) // Downscaling to 50% or less? (inverted scale ratios) + { + areaScaling = true; + fastAreaScaling = ( ixscale == int( ixscale ) && iyscale == int( iyscale )); + // The generic case has arrays only up to 100 ratio downscaling, which is hopefully enough + // in practice, but protect against buffer overflows in case such an extreme case happens + // (and in such case the precision of the generic algorithm probably doesn't matter anyway). + if( ixscale > 100 || iyscale > 100 ) + fastAreaScaling = true; + if( fastAreaScaling ) + textureFragmentShader = "areaScaleFastFragmentShader"; + else + textureFragmentShader = "areaScaleFragmentShader"; + } + if( rMask ) { - if( !UseProgram( "transformedTextureVertexShader", "maskedTextureFragmentShader" ) ) + if( !UseProgram( "transformedTextureVertexShader", + textureFragmentShader.isEmpty() ? "maskedTextureFragmentShader" : textureFragmentShader, + "#define MASKED" ) ) return; mpProgram->SetTexture( "mask", rMask ); rMask.SetFilter( GL_LINEAR ); @@ -904,10 +929,40 @@ void OpenGLSalGraphicsImpl::DrawTransformedTexture( } else { - if( !UseProgram( "transformedTextureVertexShader", "textureFragmentShader" ) ) + if( !UseProgram( "transformedTextureVertexShader", + textureFragmentShader.isEmpty() ? "textureFragmentShader" : textureFragmentShader ) ) return; } + if( areaScaling ) + { + // From OpenGLSalBitmap::ImplScaleArea(). + if( fastAreaScaling ) + { + int mnWidth = rTexture.GetWidth(); + int mnHeight = rTexture.GetHeight(); + mpProgram->SetUniform1i( "xscale", ixscale ); + mpProgram->SetUniform1i( "yscale", iyscale ); + mpProgram->SetUniform1f( "xstep", 1.0 / mnWidth ); + mpProgram->SetUniform1f( "ystep", 1.0 / mnHeight ); + mpProgram->SetUniform1f( "ratio", 1.0 / ( ixscale * iyscale )); + } + else + { + int mnWidth = rTexture.GetWidth(); + int mnHeight = rTexture.GetHeight(); + mpProgram->SetUniform1f( "xscale", ixscale ); + mpProgram->SetUniform1f( "yscale", iyscale ); + mpProgram->SetUniform1i( "swidth", mnWidth ); + mpProgram->SetUniform1i( "sheight", mnHeight ); + // For converting between <0,mnWidth-1> and <0.0,1.0> coordinate systems. + mpProgram->SetUniform1f( "xsrcconvert", 1.0 / ( mnWidth - 1 )); + mpProgram->SetUniform1f( "ysrcconvert", 1.0 / ( mnHeight - 1 )); + mpProgram->SetUniform1f( "xdestconvert", 1.0 * (( mnWidth / ixscale ) - 1 )); + mpProgram->SetUniform1f( "ydestconvert", 1.0 * (( mnHeight / iyscale ) - 1 )); + } + } + mpProgram->SetUniform2f( "viewport", GetWidth(), GetHeight() ); mpProgram->SetTransform( "transform", rTexture, rNull, rX, rY ); rTexture.GetWholeCoord( aTexCoord ); diff --git a/vcl/opengl/scale.cxx b/vcl/opengl/scale.cxx index 84cf96716671..a7a05a43986f 100644 --- a/vcl/opengl/scale.cxx +++ b/vcl/opengl/scale.cxx @@ -225,6 +225,7 @@ bool OpenGLSalBitmap::ImplScaleArea( double rScaleX, double rScaleY ) OpenGLTexture aScratchTex = OpenGLTexture( nNewWidth, nNewHeight ); OpenGLFramebuffer* pFramebuffer = mpContext->AcquireFramebuffer( aScratchTex ); + // NOTE: This setup is also done in OpenGLSalGraphicsImpl::DrawTransformedTexture(). if( fast ) { pProgram->SetUniform1i( "xscale", ixscale ); |