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.lu...@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.lu...@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);
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits