[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