summaryrefslogtreecommitdiff
path: root/vcl/opengl/gdiimpl.cxx
diff options
context:
space:
mode:
authorMarco Cecchetti <marco.cecchetti@collabora.com>2016-04-06 13:59:50 +0200
committerTomaž Vajngerl <quikee@gmail.com>2016-04-07 00:25:46 +0000
commit641840dc0f63d23acceb7edd833f4a31f216009d (patch)
tree2980d018cd9d3c4b775131f05a711a847c2153c8 /vcl/opengl/gdiimpl.cxx
parent157469896ef56720f33676222b95e81c04ab5c72 (diff)
tdf#98960 - DrawTransformedTexture adapted to the new area scale shader
Change-Id: I7c911f2aaccbffacfa5673b120b6177b8bea0672 Reviewed-on: https://gerrit.libreoffice.org/23864 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'vcl/opengl/gdiimpl.cxx')
-rw-r--r--vcl/opengl/gdiimpl.cxx162
1 files changed, 130 insertions, 32 deletions
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 5773676b8afc..29ef7ca80d2b 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -1363,6 +1363,47 @@ void OpenGLSalGraphicsImpl::DrawTexture( OpenGLTexture& rTexture, const SalTwoRe
mpProgram->Clean();
}
+namespace {
+
+bool scaleTexture(const rtl::Reference< OpenGLContext > &xContext,
+ OpenGLTexture& rOutTexture, const double& ixscale, const double& iyscale, OpenGLTexture& rTexture)
+{
+ int nWidth = rTexture.GetWidth();
+ int nHeight = rTexture.GetHeight();
+ int nNewWidth = nWidth / ixscale;
+ int nNewHeight = nHeight / iyscale;
+
+ OpenGLProgram* pProgram = xContext->UseProgram("textureVertexShader", OUString("areaScaleFragmentShader"));
+ if (pProgram == nullptr)
+ return false;
+
+ OpenGLTexture aScratchTex(nNewWidth, nNewHeight);
+ OpenGLFramebuffer* pFramebuffer = xContext->AcquireFramebuffer(aScratchTex);
+
+ pProgram->SetUniform1f("xscale", ixscale);
+ pProgram->SetUniform1f("yscale", iyscale);
+ pProgram->SetUniform1i("swidth", nWidth);
+ pProgram->SetUniform1i("sheight", nHeight);
+ // For converting between <0,nWidth-1> and <0.0,1.0> coordinate systems.
+ pProgram->SetUniform1f("xsrcconvert", 1.0 / (nWidth - 1));
+ pProgram->SetUniform1f("ysrcconvert", 1.0 / (nHeight - 1));
+ pProgram->SetUniform1f("xdestconvert", 1.0 * (nNewWidth - 1));
+ pProgram->SetUniform1f("ydestconvert", 1.0 * (nNewHeight - 1));
+
+ pProgram->SetTexture("sampler", rTexture);
+ pProgram->DrawTexture(rTexture);
+ pProgram->Clean();
+
+ OpenGLContext::ReleaseFramebuffer(pFramebuffer);
+
+ CHECK_GL_ERROR();
+
+ rOutTexture = aScratchTex;
+ return true;
+}
+
+}
+
void OpenGLSalGraphicsImpl::DrawTransformedTexture(
OpenGLTexture& rTexture,
OpenGLTexture& rMask,
@@ -1377,10 +1418,6 @@ 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().
-
const long nDestWidth = basegfx::fround(basegfx::B2DVector(rX - rNull).getLength());
const long nDestHeight = basegfx::fround(basegfx::B2DVector(rY - rNull).getLength());
@@ -1388,19 +1425,24 @@ void OpenGLSalGraphicsImpl::DrawTransformedTexture(
if( nDestHeight == 0 || nDestWidth == 0 )
return;
- const double ixscale = rTexture.GetWidth() / double(nDestWidth);
- const double iyscale = rTexture.GetHeight() / double(nDestHeight);
+ // inverted scale ratios
+ double ixscale = rTexture.GetWidth() / double(nDestWidth);
+ double iyscale = rTexture.GetHeight() / double(nDestHeight);
+ // If downscaling at a higher scale ratio, use the area scaling algorithm rather
+ // than plain OpenGL's scaling (texture mapping), for better results.
+ // See OpenGLSalBitmap::ImplScaleArea().
bool areaScaling = false;
bool fastAreaScaling = false;
OUString textureFragmentShader;
- if( ixscale >= 2 && iyscale >= 2 ) // Downscaling to 50% or less? (inverted scale ratios)
+ if( ixscale >= 2 && iyscale >= 2 ) // scale ratio less than 50%
{
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).
+ // The generic case has arrays only up to 16 ratio downscaling and is performed in 2 passes,
+ // when the ratio is in the 16-100 range, 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 )
@@ -1409,17 +1451,69 @@ void OpenGLSalGraphicsImpl::DrawTransformedTexture(
textureFragmentShader = "areaScaleFragmentShader";
}
- if( rMask )
+ OpenGLTexture aInTexture = rTexture;
+ OpenGLTexture aInMask = rMask;
+
+ // When using the area scaling algorithm we need to reduce the texture size in 2 passes
+ // in order to not use a big array inside the fragment shader.
+ if (areaScaling && !fastAreaScaling)
+ {
+ // Perform a first texture downscaling by an inverted scale ratio equal to
+ // the square root of the whole inverted scale ratio.
+ if (ixscale > 16 || iyscale > 16)
+ {
+ // The scissor area is set to the current window size in PreDraw,
+ // so if we do not disable the scissor test, the texture produced
+ // by the first downscaling is clipped to the current window size.
+ glDisable(GL_SCISSOR_TEST);
+ CHECK_GL_ERROR();
+
+ // Maybe it can give problems too.
+ glDisable(GL_STENCIL_TEST);
+ CHECK_GL_ERROR();
+
+ // the square root of the whole inverted scale ratio
+ double ixscalesqrt = std::floor(std::sqrt(ixscale));
+ double iyscalesqrt = std::floor(std::sqrt(iyscale));
+ ixscale /= ixscalesqrt; // second pass inverted x-scale factor
+ iyscale /= iyscalesqrt; // second pass inverted y-scale factor
+
+ scaleTexture(mpContext, aInTexture, ixscalesqrt, iyscalesqrt, rTexture);
+
+ if (rMask) // we need to downscale the mask too
+ {
+ scaleTexture(mpContext, aInMask, ixscalesqrt, iyscalesqrt, rMask);
+ }
+
+ // We need to re-acquire the off-screen texture.
+ CheckOffscreenTexture();
+ CHECK_GL_ERROR();
+
+ // Re-enable scissor and stencil tests if needed.
+ if (mbUseScissor)
+ {
+ glEnable(GL_SCISSOR_TEST);
+ CHECK_GL_ERROR();
+ }
+ if (mbUseStencil)
+ {
+ glEnable(GL_STENCIL_TEST);
+ CHECK_GL_ERROR();
+ }
+ }
+ }
+
+ if( aInMask )
{
if( !UseProgram( "transformedTextureVertexShader",
textureFragmentShader.isEmpty() ? "maskedTextureFragmentShader" : textureFragmentShader,
"#define MASKED" ) )
return;
- mpProgram->SetTexture( "mask", rMask );
+ mpProgram->SetTexture( "mask", aInMask );
GLfloat aMaskCoord[8];
- rMask.GetWholeCoord(aMaskCoord);
+ aInMask.GetWholeCoord(aMaskCoord);
mpProgram->SetMaskCoord(aMaskCoord);
- rMask.SetFilter( GL_LINEAR );
+ aInMask.SetFilter( GL_LINEAR );
mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
else
@@ -1429,42 +1523,46 @@ void OpenGLSalGraphicsImpl::DrawTransformedTexture(
return;
}
- int mnWidth = rTexture.GetWidth();
- int mnHeight = rTexture.GetHeight();
- if(areaScaling )
+ if(areaScaling)
{
+ int nWidth = aInTexture.GetWidth();
+ int nHeight = aInTexture.GetHeight();
+
// From OpenGLSalBitmap::ImplScaleArea().
- if (fastAreaScaling && mnWidth && mnHeight)
+ if (fastAreaScaling && nWidth && nHeight)
{
mpProgram->SetUniform1i( "xscale", ixscale );
mpProgram->SetUniform1i( "yscale", iyscale );
- mpProgram->SetUniform1f( "xstep", 1.0 / mnWidth );
- mpProgram->SetUniform1f( "ystep", 1.0 / mnHeight );
+ mpProgram->SetUniform1f( "xstep", 1.0 / nWidth );
+ mpProgram->SetUniform1f( "ystep", 1.0 / nHeight );
mpProgram->SetUniform1f( "ratio", 1.0 / ( ixscale * iyscale ));
}
- else if (mnHeight > 1 && mnWidth > 1)
+ else if (nHeight > 1 && nWidth > 1)
{
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->SetUniform1i( "swidth", nWidth );
+ mpProgram->SetUniform1i( "sheight", nHeight );
+ // For converting between <0,nWidth-1> and <0.0,1.0> coordinate systems.
+ mpProgram->SetUniform1f( "xsrcconvert", 1.0 / ( nWidth - 1 ));
+ mpProgram->SetUniform1f( "ysrcconvert", 1.0 / ( nHeight - 1 ));
+ mpProgram->SetUniform1f( "xdestconvert", 1.0 * (( nWidth / ixscale ) - 1 ));
+ mpProgram->SetUniform1f( "ydestconvert", 1.0 * (( nHeight / iyscale ) - 1 ));
}
}
ApplyProgramMatrices();
mpProgram->SetUniform2f( "viewport", GetWidth(), GetHeight() );
+ // Here, in order to get the correct transformation we need to pass the original texture,
+ // since it has been used for initializing the rectangle vertices.
mpProgram->SetTransform( "transform", rTexture, rNull, rX, rY );
- rTexture.GetWholeCoord( aTexCoord );
- mpProgram->SetTexture( "sampler", rTexture );
- rTexture.SetFilter( GL_LINEAR );
+ aInTexture.GetWholeCoord(aTexCoord);
+ mpProgram->SetTexture("sampler", aInTexture);
+ aInTexture.SetFilter(GL_LINEAR);
mpProgram->SetTextureCoord( aTexCoord );
- mpProgram->SetVertices( &aVertices[0] );
+ mpProgram->SetVertices( aVertices );
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
+
CHECK_GL_ERROR();
mpProgram->Clean();
}