[Libreoffice-commits] core.git: 2 commits - include/vcl vcl/inc vcl/opengl vcl/source

Luboš Luňák l.lunak at collabora.com
Tue Jan 27 09:43:22 PST 2015


 include/vcl/opengl/OpenGLContext.hxx        |   14 ++++--
 include/vcl/opengl/OpenGLHelper.hxx         |    2 
 vcl/inc/opengl/program.hxx                  |    2 
 vcl/inc/openglgdiimpl.hxx                   |    2 
 vcl/opengl/areaScaleFastFragmentShader.glsl |   13 +++++
 vcl/opengl/areaScaleFragmentShader.glsl     |   13 +++++
 vcl/opengl/gdiimpl.cxx                      |   63 ++++++++++++++++++++++++++--
 vcl/opengl/program.cxx                      |    4 -
 vcl/opengl/scale.cxx                        |    1 
 vcl/source/opengl/OpenGLContext.cxx         |   26 +++++++++--
 vcl/source/opengl/OpenGLHelper.cxx          |    6 ++
 11 files changed, 127 insertions(+), 19 deletions(-)

New commits:
commit c44ee2beb3d8bbe932dd8799f818a2c61a078810
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Tue Jan 20 15:41:51 2015 +0100

    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

diff --git a/vcl/opengl/areaScaleFastFragmentShader.glsl b/vcl/opengl/areaScaleFastFragmentShader.glsl
index b8874d1..10ce9f5 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 498b0b5..d72184c 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 a120d81..854c090 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 84cf967..a7a05a4 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 );
commit df290c63451723ae05833cf5f13342d4c93f94cc
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Tue Jan 20 14:48:48 2015 +0100

    make it possible to easily have variants of glsl programs
    
    Now it's possible to add a preamble to the compiled program, so there can
    be just one program with #ifdef's inside and the small variants can be
    selected using #define in the preamble instead of having several almost
    identical programs.
    
    Change-Id: I6c5112313b91b6269ebdecdfc896e0f96209ea2b

diff --git a/include/vcl/opengl/OpenGLContext.hxx b/include/vcl/opengl/OpenGLContext.hxx
index 0178e21..6f66587 100644
--- a/include/vcl/opengl/OpenGLContext.hxx
+++ b/include/vcl/opengl/OpenGLContext.hxx
@@ -161,8 +161,6 @@ struct GLWindow
     ~GLWindow();
 };
 
-typedef std::pair<OUString, OUString> ProgramKey;
-
 class VCLOPENGL_DLLPUBLIC OpenGLContext
 {
 public:
@@ -203,8 +201,8 @@ public:
     void               ReleaseFramebuffers();
 
     // retrieve a program from the cache or compile/link it
-    OpenGLProgram*      GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader );
-    OpenGLProgram*      UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader );
+    OpenGLProgram*      GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble = "" );
+    OpenGLProgram*      UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble = "" );
 
     bool isCurrent();
     static void clearCurrent();
@@ -266,6 +264,14 @@ private:
     OpenGLFramebuffer* mpFirstFramebuffer;
     OpenGLFramebuffer* mpLastFramebuffer;
 
+    struct ProgramKey
+    {
+        ProgramKey( const OUString& vertexShader, const OUString& fragmentShader, const OString& preamble );
+        bool operator< ( const ProgramKey& other ) const;
+        OUString vertexShader;
+        OUString fragmentShader;
+        OString preamble;
+    };
     boost::ptr_map<ProgramKey, OpenGLProgram> maPrograms;
     OpenGLProgram* mpCurrentProgram;
 #ifdef DBG_UTIL
diff --git a/include/vcl/opengl/OpenGLHelper.hxx b/include/vcl/opengl/OpenGLHelper.hxx
index 2430515..4e11bf8 100644
--- a/include/vcl/opengl/OpenGLHelper.hxx
+++ b/include/vcl/opengl/OpenGLHelper.hxx
@@ -25,7 +25,7 @@
 class VCLOPENGL_DLLPUBLIC OpenGLHelper
 {
 public:
-    static GLint LoadShaders(const OUString& rVertexShaderName, const OUString& rFragmentShaderName);
+    static GLint LoadShaders(const OUString& rVertexShaderName, const OUString& rFragmentShaderName, const OString& preamble = "" );
 
     /**
      * The caller is responsible for allocate the memory for the RGBA buffer, before call
diff --git a/vcl/inc/opengl/program.hxx b/vcl/inc/opengl/program.hxx
index f904984..8b42dd4 100644
--- a/vcl/inc/opengl/program.hxx
+++ b/vcl/inc/opengl/program.hxx
@@ -43,7 +43,7 @@ public:
     OpenGLProgram();
     ~OpenGLProgram();
 
-    bool Load( const OUString& rVertexShader, const OUString& rFragmentShader );
+    bool Load( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble = "" );
     bool Use();
     bool Clean();
 
diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index 5ae6ab8..77b148d 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -73,7 +73,7 @@ protected:
     bool CheckOffscreenTexture();
 
 public:
-    bool UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader );
+    bool UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble = "" );
     bool UseSolid( SalColor nColor, sal_uInt8 nTransparency );
     bool UseSolid( SalColor nColor, double fTransparency );
     bool UseSolid( SalColor nColor );
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index da2ace3..a120d81 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -373,11 +373,11 @@ bool OpenGLSalGraphicsImpl::CheckOffscreenTexture()
     return true;
 }
 
-bool OpenGLSalGraphicsImpl::UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader )
+bool OpenGLSalGraphicsImpl::UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble )
 {
     if( mpProgram != NULL )
         mpProgram->Clean();
-    mpProgram = mpContext->UseProgram( rVertexShader, rFragmentShader );
+    mpProgram = mpContext->UseProgram( rVertexShader, rFragmentShader, preamble );
 #ifdef DBG_UTIL
     mProgramIsSolidColor = false; // UseSolid() will set to true if needed
 #endif
diff --git a/vcl/opengl/program.cxx b/vcl/opengl/program.cxx
index cdf8131..3504b06 100644
--- a/vcl/opengl/program.cxx
+++ b/vcl/opengl/program.cxx
@@ -31,9 +31,9 @@ OpenGLProgram::~OpenGLProgram()
         glDeleteProgram( mnId );
 }
 
-bool OpenGLProgram::Load( const OUString& rVertexShader, const OUString& rFragmentShader )
+bool OpenGLProgram::Load( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble )
 {
-    mnId = OpenGLHelper::LoadShaders( rVertexShader, rFragmentShader );
+    mnId = OpenGLHelper::LoadShaders( rVertexShader, rFragmentShader, preamble );
     return ( mnId != 0 );
 }
 
diff --git a/vcl/source/opengl/OpenGLContext.cxx b/vcl/source/opengl/OpenGLContext.cxx
index 848296c..04aa5da 100644
--- a/vcl/source/opengl/OpenGLContext.cxx
+++ b/vcl/source/opengl/OpenGLContext.cxx
@@ -1582,9 +1582,9 @@ void OpenGLContext::ReleaseFramebuffers()
     }
 }
 
-OpenGLProgram* OpenGLContext::GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader )
+OpenGLProgram* OpenGLContext::GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble )
 {
-    ProgramKey aKey( rVertexShader, rFragmentShader );
+    ProgramKey aKey( rVertexShader, rFragmentShader, preamble );
 
     boost::ptr_map<ProgramKey, OpenGLProgram>::iterator
         it = maPrograms.find( aKey );
@@ -1592,7 +1592,7 @@ OpenGLProgram* OpenGLContext::GetProgram( const OUString& rVertexShader, const O
         return it->second;
 
     OpenGLProgram* pProgram = new OpenGLProgram;
-    if( !pProgram->Load( rVertexShader, rFragmentShader ) )
+    if( !pProgram->Load( rVertexShader, rFragmentShader, preamble ) )
     {
         delete pProgram;
         return NULL;
@@ -1602,9 +1602,9 @@ OpenGLProgram* OpenGLContext::GetProgram( const OUString& rVertexShader, const O
     return pProgram;
 }
 
-OpenGLProgram* OpenGLContext::UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader )
+OpenGLProgram* OpenGLContext::UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble )
 {
-    OpenGLProgram* pProgram = GetProgram( rVertexShader, rFragmentShader );
+    OpenGLProgram* pProgram = GetProgram( rVertexShader, rFragmentShader, preamble );
 
     if( pProgram == mpCurrentProgram )
         return pProgram;
@@ -1615,4 +1615,20 @@ OpenGLProgram* OpenGLContext::UseProgram( const OUString& rVertexShader, const O
     return mpCurrentProgram;
 }
 
+inline
+OpenGLContext::ProgramKey::ProgramKey( const OUString& v, const OUString& f, const OString& p )
+: vertexShader( v ), fragmentShader( f ), preamble( p )
+{
+}
+
+inline
+bool OpenGLContext::ProgramKey::operator< ( const ProgramKey& other ) const
+{
+    if( vertexShader != other.vertexShader )
+        return vertexShader < other.vertexShader;
+    if( fragmentShader != other.fragmentShader )
+        return fragmentShader < other.fragmentShader;
+    return preamble < other.preamble;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/opengl/OpenGLHelper.cxx b/vcl/source/opengl/OpenGLHelper.cxx
index 372f0bd..3523ae2 100644
--- a/vcl/source/opengl/OpenGLHelper.cxx
+++ b/vcl/source/opengl/OpenGLHelper.cxx
@@ -97,7 +97,7 @@ namespace {
     }
 }
 
-GLint OpenGLHelper::LoadShaders(const OUString& rVertexShaderName,const OUString& rFragmentShaderName)
+GLint OpenGLHelper::LoadShaders(const OUString& rVertexShaderName,const OUString& rFragmentShaderName, const OString& preamble)
 {
     // Create the shaders
     GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
@@ -107,6 +107,8 @@ GLint OpenGLHelper::LoadShaders(const OUString& rVertexShaderName,const OUString
 
     // Compile Vertex Shader
     OString aVertexShaderSource = loadShader(rVertexShaderName);
+    if( !preamble.isEmpty())
+        aVertexShaderSource = preamble + "\n" + aVertexShaderSource;
     char const * VertexSourcePointer = aVertexShaderSource.getStr();
     glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
     glCompileShader(VertexShaderID);
@@ -119,6 +121,8 @@ GLint OpenGLHelper::LoadShaders(const OUString& rVertexShaderName,const OUString
 
     // Compile Fragment Shader
     OString aFragmentShaderSource = loadShader(rFragmentShaderName);
+    if( !preamble.isEmpty())
+        aFragmentShaderSource = preamble + "\n" + aFragmentShaderSource;
     char const * FragmentSourcePointer = aFragmentShaderSource.getStr();
     glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
     glCompileShader(FragmentShaderID);


More information about the Libreoffice-commits mailing list