summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2015-01-20 15:41:51 +0100
committerLuboš Luňák <l.lunak@collabora.com>2015-01-27 18:42:48 +0100
commitc44ee2beb3d8bbe932dd8799f818a2c61a078810 (patch)
treece2b870621b0d4e7b77a567029f05875c70036bb
parentdf290c63451723ae05833cf5f13342d4c93f94cc (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
-rw-r--r--vcl/opengl/areaScaleFastFragmentShader.glsl13
-rw-r--r--vcl/opengl/areaScaleFragmentShader.glsl13
-rw-r--r--vcl/opengl/gdiimpl.cxx59
-rw-r--r--vcl/opengl/scale.cxx1
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 );