[Libreoffice-commits] core.git: Branch 'feature/opengl-vcl2' - 2 commits - include/vcl vcl/inc vcl/Library_vcl.mk vcl/opengl vcl/Package_opengl.mk vcl/source

Louis-Francis Ratté-Boulianne lfrb at collabora.com
Mon Dec 1 13:42:06 PST 2014


 include/vcl/opengl/OpenGLContext.hxx      |   34 +
 vcl/Library_vcl.mk                        |    1 
 vcl/Package_opengl.mk                     |    4 
 vcl/inc/opengl/program.hxx                |   72 ++
 vcl/inc/opengl/salbmp.hxx                 |   11 
 vcl/inc/opengl/texture.hxx                |    1 
 vcl/inc/openglgdiimpl.hxx                 |   67 --
 vcl/opengl/dumbVertexShader.glsl          |   16 
 vcl/opengl/gdiimpl.cxx                    |  758 +++++-------------------------
 vcl/opengl/maskVertexShader.glsl          |   19 
 vcl/opengl/maskedTextureVertexShader.glsl |   19 
 vcl/opengl/program.cxx                    |  238 +++++++++
 vcl/opengl/salbmp.cxx                     |    7 
 vcl/opengl/scale.cxx                      |   96 ---
 vcl/opengl/solidVertexShader.glsl         |   16 
 vcl/opengl/texture.cxx                    |   32 -
 vcl/source/opengl/OpenGLContext.cxx       |   35 +
 17 files changed, 589 insertions(+), 837 deletions(-)

New commits:
commit b2e3367c3c7de2a4ff2ba825df561549b253e5bf
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Fri Nov 28 14:58:53 2014 -0500

    vcl: Fix a coordinate issue when getting a bitmap from a VirtualDevice
    
    Change-Id: I06fef2765f2dc9d64a991385a984a4c75a1fd424

diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 2f3b96b..7cd4e50 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -1128,8 +1128,8 @@ SalBitmap* OpenGLSalGraphicsImpl::getBitmap( long nX, long nY, long nWidth, long
     OpenGLSalBitmap* pBitmap = new OpenGLSalBitmap;
     SAL_INFO( "vcl.opengl", "::getBitmap " << nX << "," << nY <<
               " " << nWidth << "x" << nHeight );
+    //TODO really needed?
     PreDraw();
-    nY = GetHeight() - nHeight - nY;
     if( !pBitmap->Create( maOffscreenTex, nX, nY, nWidth, nHeight ) )
     {
         delete pBitmap;
@@ -1144,6 +1144,7 @@ SalColor OpenGLSalGraphicsImpl::getPixel( long nX, long nY )
     char pixel[3] = { 0, 0, 0 };
 
     PreDraw();
+    nY = GetHeight() - nY;
     glReadPixels( nX, nY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixel);
     PostDraw();
 
diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx
index 7618c04..0c45d77 100644
--- a/vcl/opengl/texture.cxx
+++ b/vcl/opengl/texture.cxx
@@ -52,6 +52,9 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight )
     mnHeight( nHeight ),
     mnFilter( GL_NEAREST )
 {
+    // FIXME We need the window height here
+    // nY = GetHeight() - nHeight - nY;
+
     glGenTextures( 1, &mnTexture );
     glBindTexture( GL_TEXTURE_2D, mnTexture );
     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
commit 766f1238d88cd980825e0613b194b0659fb93ba5
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Fri Nov 28 14:56:08 2014 -0500

    vcl: Only load OpenGL shaders once for each context
    
    Change-Id: Idbf9026c5e64ef41d4c913153dfddf36923ff7de

diff --git a/include/vcl/opengl/OpenGLContext.hxx b/include/vcl/opengl/OpenGLContext.hxx
index 1b21851..679de09 100644
--- a/include/vcl/opengl/OpenGLContext.hxx
+++ b/include/vcl/opengl/OpenGLContext.hxx
@@ -51,11 +51,13 @@ class NSOpenGLView;
 
 #include <vcl/vclopengl_dllapi.hxx>
 #include <boost/scoped_ptr.hpp>
+#include <boost/unordered_map.hpp>
 #include <vcl/window.hxx>
 #include <tools/gen.hxx>
 #include <vcl/syschild.hxx>
 
 class OpenGLFramebuffer;
+class OpenGLProgram;
 class OpenGLTexture;
 
 /// Holds the information of our new child window
@@ -155,6 +157,31 @@ struct GLWindow
     ~GLWindow();
 };
 
+struct ProgramKey
+{
+    OUString maVertexShader;
+    OUString maFragmentShader;
+
+    ProgramKey( const OUString& rVertexShader, const OUString& rFragmentShader )
+    {
+        maVertexShader = rVertexShader;
+        maFragmentShader = rFragmentShader;
+    }
+};
+
+inline bool operator==( ProgramKey const& k1, ProgramKey const& k2 )
+{
+    return k1.maVertexShader == k2.maVertexShader && k1.maFragmentShader == k2.maFragmentShader;
+}
+
+inline std::size_t hash_value( ProgramKey const& rKey )
+{
+    std::size_t nSeed = 0x9e3779b9;
+    nSeed = rKey.maVertexShader.hashCode();
+    nSeed = rKey.maFragmentShader.hashCode() + 0x9e3779b9 + (nSeed << 6) + (nSeed >> 2);
+    return nSeed;
+}
+
 class VCLOPENGL_DLLPUBLIC OpenGLContext
 {
 public:
@@ -187,6 +214,10 @@ public:
     OpenGLFramebuffer* AcquireFramebuffer( const OpenGLTexture& rTexture );
     void               ReleaseFramebuffer( OpenGLFramebuffer* pFramebuffer );
 
+    // 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 );
+
     void makeCurrent();
     void resetCurrent();
     void swapBuffers();
@@ -244,6 +275,9 @@ private:
     OpenGLFramebuffer* mpFirstFramebuffer;
     OpenGLFramebuffer* mpLastFramebuffer;
 
+    boost::unordered_map<ProgramKey, OpenGLProgram*> maPrograms;
+    OpenGLProgram* mpCurrentProgram;
+
 public:
     vcl::Region maClipRegion;
     int mnPainting;
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index a231dae..d5063627 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -126,6 +126,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
 	vcl/opengl/salbmp \
 	vcl/opengl/scale \
 	vcl/opengl/framebuffer \
+	vcl/opengl/program \
 	vcl/opengl/texture \
     vcl/source/opengl/OpenGLContext \
     vcl/source/opengl/OpenGLHelper \
diff --git a/vcl/Package_opengl.mk b/vcl/Package_opengl.mk
index d81c0ec..98ff78b 100644
--- a/vcl/Package_opengl.mk
+++ b/vcl/Package_opengl.mk
@@ -12,16 +12,14 @@ $(eval $(call gb_Package_Package,vcl_opengl_shader,$(SRCDIR)/vcl/opengl))
 $(eval $(call gb_Package_add_files,vcl_opengl_shader,$(LIBO_ETC_FOLDER)/opengl,\
 	blendedTextureFragmentShader.glsl \
 	blendedTextureVertexShader.glsl \
+	dumbVertexShader.glsl \
 	diffTextureFragmentShader.glsl \
 	convolutionFragmentShader.glsl \
 	linearGradientFragmentShader.glsl \
 	maskFragmentShader.glsl \
-	maskVertexShader.glsl \
 	maskedTextureFragmentShader.glsl \
-	maskedTextureVertexShader.glsl \
 	radialGradientFragmentShader.glsl \
 	solidFragmentShader.glsl \
-	solidVertexShader.glsl \
 	textureFragmentShader.glsl \
 	textureVertexShader.glsl \
 	transformedTextureVertexShader.glsl \
diff --git a/vcl/inc/opengl/program.hxx b/vcl/inc/opengl/program.hxx
new file mode 100644
index 0000000..4b2b26f
--- /dev/null
+++ b/vcl/inc/opengl/program.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_VCL_INC_OPENGL_PROGRAM_H
+#define INCLUDED_VCL_INC_OPENGL_PROGRAM_H
+
+#include <GL/glew.h>
+#include <vcl/dllapi.h>
+
+#include <basegfx/point/b2dpoint.hxx>
+#include <rtl/ustring.hxx>
+#include <tools/color.hxx>
+#include <opengl/texture.hxx>
+
+#include <boost/unordered_map.hpp>
+
+typedef boost::unordered_map< OString, GLuint, OStringHash > UniformCache;
+typedef std::list< OpenGLTexture > TextureList;
+
+class VCL_PLUGIN_PUBLIC OpenGLProgram
+{
+private:
+    GLuint          mnId;
+    UniformCache    maUniformLocations;
+    sal_uInt32      mnEnabledAttribs;
+    GLuint          mnAttribIndex;
+    GLuint          mnPositionAttrib;
+    GLuint          mnTexCoordAttrib;
+    GLuint          mnAlphaCoordAttrib;
+    TextureList     maTextures;
+    bool            mbBlending;
+
+public:
+    OpenGLProgram();
+    ~OpenGLProgram();
+
+    bool Load( const OUString& rVertexShader, const OUString& rFragmentShader );
+    bool Use();
+    bool Clean();
+
+    void SetVertices( const GLvoid* pData );
+    void SetTextureCoord( const GLvoid* pData );
+    void SetAlphaCoord( const GLvoid* pData );
+
+    void SetUniform2f( const OString& rName, GLfloat v1, GLfloat v2 );
+    void SetUniform1fv( const OString& rName, GLsizei nCount, GLfloat* aValues );
+    void SetUniform2fv( const OString& rName, GLsizei nCount, GLfloat* aValues );
+    void SetColor( const OString& rName, SalColor nColor, sal_uInt8 nTransparency );
+    void SetColorf( const OString& rName, SalColor nColor, double fTransparency );
+    void SetColorWithIntensity( const OString& rName, const Color& rColor, long nFactor );
+    void SetTexture( const OString& rName, OpenGLTexture& rTexture );
+    void SetTransform( const OString& rName, const OpenGLTexture& rTexture,
+                       const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX,
+                       const basegfx::B2DPoint& rY );
+    void SetBlendMode( GLenum nSFactor, GLenum nDFactor );
+
+    bool DrawTexture( OpenGLTexture& rTexture );
+
+protected:
+    void SetVertexAttrib( GLuint& rAttrib, const OString& rName, const GLvoid* pData );
+    GLuint GetUniformLocation( const OString& rName );
+};
+
+#endif // INCLUDED_VCL_INC_OPENGL_PROGRAM_H
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/opengl/salbmp.hxx b/vcl/inc/opengl/salbmp.hxx
index 6a812d0..c25dfa8 100644
--- a/vcl/inc/opengl/salbmp.hxx
+++ b/vcl/inc/opengl/salbmp.hxx
@@ -100,17 +100,6 @@ private:
 
 private:
 
-    GLuint          ImplGetTextureProgram();
-    GLuint          mnTexProgram;
-    GLuint          mnTexSamplerUniform;
-
-    GLuint          ImplGetConvolutionProgram();
-    GLuint          mnConvProgram;
-    GLuint          mnConvSamplerUniform;
-    GLuint          mnConvKernelUniform;
-    GLuint          mnConvKernelSizeUniform;
-    GLuint          mnConvOffsetsUniform;
-
     bool ImplScaleFilter( const double& rScaleX, const double& rScaleY, GLenum nFilter );
     void ImplCreateKernel( const double& fScale, const Kernel& rKernel, GLfloat*& pWeights, sal_uInt32& aKernelSize );
     bool ImplScaleConvolution( const double& rScaleX, const double& rScaleY, const Kernel& aKernel );
diff --git a/vcl/inc/opengl/texture.hxx b/vcl/inc/opengl/texture.hxx
index ad4738a..3d99526 100644
--- a/vcl/inc/opengl/texture.hxx
+++ b/vcl/inc/opengl/texture.hxx
@@ -65,6 +65,7 @@ public:
     int             GetWidth() const;
     int             GetHeight() const;
     void            GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted=false ) const;
+    void            GetWholeCoord( GLfloat* pCoord ) const;
 
     void            Bind();
     void            Unbind();
diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index ad13335..42c5520 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -25,6 +25,7 @@
 #include <vcl/dllapi.h>
 
 #include "opengl/framebuffer.hxx"
+#include "opengl/program.hxx"
 #include "opengl/texture.hxx"
 #include "regionband.hxx"
 
@@ -42,6 +43,7 @@ protected:
     /// Pointer to the SalFrame or SalVirtualDevice
     SalGeometryProvider* mpParent;
     OpenGLFramebuffer* mpFramebuffer;
+    OpenGLProgram* mpProgram;
 
     // clipping
     vcl::Region maClipRegion;
@@ -54,72 +56,17 @@ protected:
     SalColor mnLineColor;
     SalColor mnFillColor;
 
-    GLuint mnSolidProgram;
-    GLuint mnColorUniform;
-
-    GLuint mnTextureProgram;
-    GLuint mnSamplerUniform;
-
-    GLuint mnTransformedTextureProgram;
-    GLuint mnTransformedViewportUniform;
-    GLuint mnTransformedTransformUniform;
-    GLuint mnTransformedSamplerUniform;
-
-    GLuint mnTransformedMaskedTextureProgram;
-    GLuint mnTransformedMaskedViewportUniform;
-    GLuint mnTransformedMaskedTransformUniform;
-    GLuint mnTransformedMaskedSamplerUniform;
-    GLuint mnTransformedMaskedMaskUniform;
-
-    GLuint mnDiffTextureProgram;
-    GLuint mnDiffTextureUniform;
-    GLuint mnDiffMaskUniform;
-
-    GLuint mnMaskedTextureProgram;
-    GLuint mnMaskedSamplerUniform;
-    GLuint mnMaskSamplerUniform;
-
-    GLuint mnBlendedTextureProgram;
-    GLuint mnBlendedTextureUniform;
-    GLuint mnBlendedMaskUniform;
-    GLuint mnBlendedAlphaUniform;
-
-    GLuint mnMaskProgram;
-    GLuint mnMaskUniform;
-    GLuint mnMaskColorUniform;
-
-    GLuint mnLinearGradientProgram;
-    GLuint mnLinearGradientStartColorUniform;
-    GLuint mnLinearGradientEndColorUniform;
-
-    GLuint mnRadialGradientProgram;
-    GLuint mnRadialGradientStartColorUniform;
-    GLuint mnRadialGradientEndColorUniform;
-    GLuint mnRadialGradientCenterUniform;
-
     void ImplInitClipRegion();
     void ImplSetClipBit( const vcl::Region& rClip, GLuint nMask );
 
     bool CheckOffscreenTexture();
 
-    bool CreateSolidProgram( void );
-    bool CreateTextureProgram( void );
-    bool CreateTransformedTextureProgram( void );
-    bool CreateDiffTextureProgram( void );
-    bool CreateMaskedTextureProgram( void );
-    bool CreateBlendedTextureProgram( void );
-    bool CreateTransformedMaskedTextureProgram( void );
-    bool CreateMaskProgram( void );
-    bool CreateLinearGradientProgram( void );
-    bool CreateRadialGradientProgram( void );
-
 public:
-    void BeginSolid( SalColor nColor, sal_uInt8 nTransparency );
-    void BeginSolid( SalColor nColor, double fTransparency );
-    void BeginSolid( SalColor nColor );
-    void EndSolid( void );
-    void BeginInvert( void );
-    void EndInvert( void );
+    bool UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader );
+    bool UseSolid( SalColor nColor, sal_uInt8 nTransparency );
+    bool UseSolid( SalColor nColor, double fTransparency );
+    bool UseSolid( SalColor nColor );
+    bool UseInvert();
 
     void DrawPoint( long nX, long nY );
     void DrawLine( long nX1, long nY1, long nX2, long nY2 );
diff --git a/vcl/opengl/solidVertexShader.glsl b/vcl/opengl/dumbVertexShader.glsl
similarity index 100%
rename from vcl/opengl/solidVertexShader.glsl
rename to vcl/opengl/dumbVertexShader.glsl
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index f761ebf..2f3b96b 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -34,77 +34,18 @@
 #include "svdata.hxx"
 #include "opengl/salbmp.hxx"
 
-#include <glm/glm.hpp>
-#include <glm/gtc/type_ptr.hpp>
 #include <vector>
 
-#define GL_ATTRIB_POS  0
-#define GL_ATTRIB_TEX  1
-#define GL_ATTRIB_TEX2 2
-
-#define glUniformColor(nUniform, nColor, nTransparency)    \
-    glUniform4f( nUniform,                                 \
-                 ((float) SALCOLOR_RED( nColor )) / 255,   \
-                 ((float) SALCOLOR_GREEN( nColor )) / 255, \
-                 ((float) SALCOLOR_BLUE( nColor )) / 255,  \
-                 (100 - nTransparency) * (1.0 / 100) )
-
-#define glUniformColorf(nUniform, nColor, fTransparency)   \
-    glUniform4f( nUniform,                                 \
-                 ((float) SALCOLOR_RED( nColor )) / 255,   \
-                 ((float) SALCOLOR_GREEN( nColor )) / 255, \
-                 ((float) SALCOLOR_BLUE( nColor )) / 255,  \
-                 (1.0f - fTransparency) )
-
-#define glUniformColorIntensity(nUniform, aColor, nFactor)      \
-    glUniform4f( nUniform,                                      \
-                 ((float) aColor.GetRed()) * nFactor / 25500.0,   \
-                 ((float) aColor.GetGreen()) * nFactor / 25500.0, \
-                 ((float) aColor.GetBlue()) * nFactor / 25500.0,  \
-                 1.0f )
-
 OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGeometryProvider* pParent)
     : mpContext(0)
     , mpParent(pParent)
     , mpFramebuffer(NULL)
+    , mpProgram(NULL)
     , mbUseScissor(false)
     , mbUseStencil(false)
     , mbOffscreen(false)
     , mnLineColor(SALCOLOR_NONE)
     , mnFillColor(SALCOLOR_NONE)
-    , mnSolidProgram(0)
-    , mnColorUniform(0)
-    , mnTextureProgram(0)
-    , mnSamplerUniform(0)
-    , mnTransformedTextureProgram(0)
-    , mnTransformedViewportUniform(0)
-    , mnTransformedTransformUniform(0)
-    , mnTransformedSamplerUniform(0)
-    , mnTransformedMaskedTextureProgram(0)
-    , mnTransformedMaskedViewportUniform(0)
-    , mnTransformedMaskedTransformUniform(0)
-    , mnTransformedMaskedSamplerUniform(0)
-    , mnTransformedMaskedMaskUniform(0)
-    , mnDiffTextureProgram(0)
-    , mnDiffTextureUniform(0)
-    , mnDiffMaskUniform(0)
-    , mnMaskedTextureProgram(0)
-    , mnMaskedSamplerUniform(0)
-    , mnMaskSamplerUniform(0)
-    , mnBlendedTextureProgram(0)
-    , mnBlendedTextureUniform(0)
-    , mnBlendedMaskUniform(0)
-    , mnBlendedAlphaUniform(0)
-    , mnMaskProgram(0)
-    , mnMaskUniform(0)
-    , mnMaskColorUniform(0)
-    , mnLinearGradientProgram(0)
-    , mnLinearGradientStartColorUniform(0)
-    , mnLinearGradientEndColorUniform(0)
-    , mnRadialGradientProgram(0)
-    , mnRadialGradientStartColorUniform(0)
-    , mnRadialGradientEndColorUniform(0)
-    , mnRadialGradientCenterUniform(0)
 {
 }
 
@@ -204,6 +145,11 @@ void OpenGLSalGraphicsImpl::PostDraw()
         glDisable( GL_SCISSOR_TEST );
     if( mbUseStencil )
         glDisable( GL_STENCIL_TEST );
+    if( mpProgram )
+    {
+        mpProgram->Clean();
+        mpProgram = NULL;
+    }
 
     mpContext->ReleaseFramebuffer( mpFramebuffer );
     mpFramebuffer = NULL;
@@ -225,12 +171,13 @@ void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region& rClip, GLuint nMa
     glStencilOp( GL_REPLACE, GL_KEEP, GL_KEEP );
 
     glClear( GL_STENCIL_BUFFER_BIT );
-    BeginSolid( MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) );
-    if( rClip.getRegionBand() )
-        DrawRegionBand( *rClip.getRegionBand() );
-    else
-        DrawPolyPolygon( rClip.GetAsB2DPolyPolygon() );
-    EndSolid();
+    if( UseSolid( MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) ) )
+    {
+        if( rClip.getRegionBand() )
+            DrawRegionBand( *rClip.getRegionBand() );
+        else
+            DrawPolyPolygon( rClip.GetAsB2DPolyPolygon() );
+    }
 
     glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
     glStencilMask( 0x00 );
@@ -383,231 +330,45 @@ bool OpenGLSalGraphicsImpl::CheckOffscreenTexture()
     return true;
 }
 
-bool OpenGLSalGraphicsImpl::CreateSolidProgram( void )
-{
-    SAL_INFO( "vcl.opengl", "::CreateSolidProgram" );
-    mnSolidProgram = OpenGLHelper::LoadShaders( "solidVertexShader", "solidFragmentShader" );
-    if( mnSolidProgram == 0 )
-        return false;
-
-    SAL_INFO( "vcl.opengl", "Solid Program Created" );
-    glBindAttribLocation( mnSolidProgram, GL_ATTRIB_POS, "position" );
-    mnColorUniform = glGetUniformLocation( mnSolidProgram, "color" );
-
-    CHECK_GL_ERROR();
-    return true;
-}
-
-bool OpenGLSalGraphicsImpl::CreateTextureProgram( void )
-{
-    mnTextureProgram = OpenGLHelper::LoadShaders( "textureVertexShader", "textureFragmentShader" );
-    if( mnTextureProgram == 0 )
-        return false;
-
-    glBindAttribLocation( mnTextureProgram, GL_ATTRIB_POS, "position" );
-    glBindAttribLocation( mnTextureProgram, GL_ATTRIB_TEX, "tex_coord_in" );
-    mnSamplerUniform = glGetUniformLocation( mnTextureProgram, "sampler" );
-
-    CHECK_GL_ERROR();
-    return true;
-}
-
-bool OpenGLSalGraphicsImpl::CreateTransformedTextureProgram( void )
-{
-    mnTransformedTextureProgram = OpenGLHelper::LoadShaders( "transformedTextureVertexShader", "textureFragmentShader" );
-    if( mnTransformedTextureProgram == 0 )
-        return false;
-
-    glBindAttribLocation( mnTransformedTextureProgram, GL_ATTRIB_POS, "position" );
-    glBindAttribLocation( mnTransformedTextureProgram, GL_ATTRIB_TEX, "tex_coord_in" );
-    mnTransformedViewportUniform = glGetUniformLocation( mnTransformedTextureProgram, "viewport" );
-    mnTransformedTransformUniform = glGetUniformLocation( mnTransformedTextureProgram, "transform" );
-    mnTransformedSamplerUniform = glGetUniformLocation( mnTransformedTextureProgram, "sampler" );
-
-    CHECK_GL_ERROR();
-    return true;
-}
-
-bool OpenGLSalGraphicsImpl::CreateDiffTextureProgram( void )
+bool OpenGLSalGraphicsImpl::UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader )
 {
-    mnDiffTextureProgram = OpenGLHelper::LoadShaders( "textureVertexShader", "diffTextureFragmentShader" );
-    if( mnDiffTextureProgram == 0 )
-        return false;
-
-    glBindAttribLocation( mnDiffTextureProgram, GL_ATTRIB_POS, "position" );
-    glBindAttribLocation( mnDiffTextureProgram, GL_ATTRIB_TEX, "tex_coord_in" );
-    mnDiffTextureUniform = glGetUniformLocation( mnDiffTextureProgram, "texture" );
-    mnDiffMaskUniform = glGetUniformLocation( mnDiffTextureProgram, "mask" );
-
-    CHECK_GL_ERROR();
-    return true;
+    mpProgram = mpContext->UseProgram( rVertexShader, rFragmentShader );
+    return ( mpProgram != NULL );
 }
 
-bool OpenGLSalGraphicsImpl::CreateMaskedTextureProgram( void )
+bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor, sal_uInt8 nTransparency )
 {
-    mnMaskedTextureProgram = OpenGLHelper::LoadShaders( "maskedTextureVertexShader", "maskedTextureFragmentShader" );
-    if( mnMaskedTextureProgram == 0 )
+    if( nColor == SALCOLOR_NONE )
         return false;
-
-    glBindAttribLocation( mnMaskedTextureProgram, GL_ATTRIB_POS, "position" );
-    glBindAttribLocation( mnMaskedTextureProgram, GL_ATTRIB_TEX, "tex_coord_in" );
-    mnMaskedSamplerUniform = glGetUniformLocation( mnMaskedTextureProgram, "sampler" );
-    mnMaskSamplerUniform = glGetUniformLocation( mnMaskedTextureProgram, "mask" );
-
-    CHECK_GL_ERROR();
-    return true;
-}
-
-bool OpenGLSalGraphicsImpl::CreateTransformedMaskedTextureProgram( void )
-{
-    mnTransformedMaskedTextureProgram = OpenGLHelper::LoadShaders( "transformedTextureVertexShader", "maskedTextureFragmentShader" );
-    if( mnTransformedMaskedTextureProgram == 0 )
+    if( !UseProgram( "dumbVertexShader", "solidFragmentShader" ) )
         return false;
-
-    glBindAttribLocation( mnTransformedMaskedTextureProgram, GL_ATTRIB_POS, "position" );
-    glBindAttribLocation( mnTransformedMaskedTextureProgram, GL_ATTRIB_TEX, "tex_coord_in" );
-    mnTransformedMaskedViewportUniform = glGetUniformLocation( mnTransformedMaskedTextureProgram, "viewport" );
-    mnTransformedMaskedTransformUniform = glGetUniformLocation( mnTransformedMaskedTextureProgram, "transform" );
-    mnTransformedMaskedSamplerUniform = glGetUniformLocation( mnTransformedMaskedTextureProgram, "sampler" );
-    mnTransformedMaskedMaskUniform = glGetUniformLocation( mnTransformedMaskedTextureProgram, "mask" );
-
-    CHECK_GL_ERROR();
+    mpProgram->SetColor( "color", nColor, nTransparency );
     return true;
 }
 
-bool OpenGLSalGraphicsImpl::CreateBlendedTextureProgram( void )
+bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor, double fTransparency )
 {
-    mnBlendedTextureProgram = OpenGLHelper::LoadShaders( "blendedTextureVertexShader", "blendedTextureFragmentShader" );
-    if( mnBlendedTextureProgram == 0 )
+    if( nColor == SALCOLOR_NONE )
         return false;
-
-    glBindAttribLocation( mnBlendedTextureProgram, GL_ATTRIB_POS, "position" );
-    glBindAttribLocation( mnBlendedTextureProgram, GL_ATTRIB_TEX, "tex_coord_in" );
-    glBindAttribLocation( mnBlendedTextureProgram, GL_ATTRIB_TEX2, "alpha_coord_in" );
-    mnBlendedTextureUniform = glGetUniformLocation( mnBlendedTextureProgram, "sampler" );
-    mnBlendedMaskUniform = glGetUniformLocation( mnBlendedTextureProgram, "mask" );
-    mnBlendedAlphaUniform = glGetUniformLocation( mnBlendedTextureProgram, "alpha" );
-
-    CHECK_GL_ERROR();
-    return true;
-}
-
-bool OpenGLSalGraphicsImpl::CreateMaskProgram( void )
-{
-    mnMaskProgram = OpenGLHelper::LoadShaders( "maskVertexShader", "maskFragmentShader" );
-    if( mnMaskProgram == 0 )
+    if( !UseProgram( "dumbVertexShader", "solidFragmentShader" ) )
         return false;
-
-    glBindAttribLocation( mnMaskProgram, GL_ATTRIB_POS, "position" );
-    glBindAttribLocation( mnMaskProgram, GL_ATTRIB_TEX, "tex_coord_in" );
-    mnMaskUniform = glGetUniformLocation( mnMaskProgram, "sampler" );
-    mnMaskColorUniform = glGetUniformLocation( mnMaskProgram, "color" );
-
-    CHECK_GL_ERROR();
+    mpProgram->SetColorf( "color", nColor, fTransparency );
     return true;
 }
 
-bool OpenGLSalGraphicsImpl::CreateLinearGradientProgram( void )
+bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor )
 {
-    mnLinearGradientProgram = OpenGLHelper::LoadShaders( "textureVertexShader", "linearGradientFragmentShader" );
-    if( mnLinearGradientProgram == 0 )
-        return false;
-
-    glBindAttribLocation( mnLinearGradientProgram, GL_ATTRIB_POS, "position" );
-    glBindAttribLocation( mnLinearGradientProgram, GL_ATTRIB_TEX, "tex_coord_in" );
-    mnLinearGradientStartColorUniform = glGetUniformLocation( mnLinearGradientProgram, "start_color" );
-    mnLinearGradientEndColorUniform = glGetUniformLocation( mnLinearGradientProgram, "end_color" );
-
-    CHECK_GL_ERROR();
-    return true;
+    return UseSolid( nColor, 0.0f );
 }
 
-bool OpenGLSalGraphicsImpl::CreateRadialGradientProgram( void )
+bool OpenGLSalGraphicsImpl::UseInvert()
 {
-    mnRadialGradientProgram = OpenGLHelper::LoadShaders( "textureVertexShader", "radialGradientFragmentShader" );
-    if( mnRadialGradientProgram == 0 )
+    if( !UseSolid( MAKE_SALCOLOR( 255, 255, 255 ) ) )
         return false;
-
-    glBindAttribLocation( mnRadialGradientProgram, GL_ATTRIB_POS, "position" );
-    glBindAttribLocation( mnRadialGradientProgram, GL_ATTRIB_TEX, "tex_coord_in" );
-    mnRadialGradientStartColorUniform = glGetUniformLocation( mnRadialGradientProgram, "start_color" );
-    mnRadialGradientEndColorUniform = glGetUniformLocation( mnRadialGradientProgram, "end_color" );
-    mnRadialGradientCenterUniform = glGetUniformLocation( mnRadialGradientProgram, "center" );
-
-    CHECK_GL_ERROR();
+    mpProgram->SetBlendMode( GL_ONE_MINUS_DST_COLOR, GL_ZERO );
     return true;
 }
 
-void OpenGLSalGraphicsImpl::BeginSolid( SalColor nColor, sal_uInt8 nTransparency )
-{
-    if( mnSolidProgram == 0 )
-    {
-        glClearColor( 1, 1, 1, 1 );
-        glClear( GL_COLOR_BUFFER_BIT );
-        if( !CreateSolidProgram() )
-            return;
-    }
-
-    if( nTransparency > 0 )
-    {
-        glEnable( GL_BLEND );
-        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
-    }
-    glUseProgram( mnSolidProgram );
-    glUniformColor( mnColorUniform, nColor, nTransparency );
-
-    CHECK_GL_ERROR();
-}
-
-void OpenGLSalGraphicsImpl::BeginSolid( SalColor nColor, double fTransparency )
-{
-    if( mnSolidProgram == 0 )
-    {
-        if( !CreateSolidProgram() )
-            return;
-    }
-
-    if( fTransparency > 0.0f )
-    {
-        glEnable( GL_BLEND );
-        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
-    }
-    glUseProgram( mnSolidProgram );
-    glUniformColorf( mnColorUniform, nColor, fTransparency );
-
-    CHECK_GL_ERROR();
-}
-
-void OpenGLSalGraphicsImpl::BeginSolid( SalColor nColor )
-{
-    BeginSolid( nColor, 0.0f );
-}
-
-void OpenGLSalGraphicsImpl::EndSolid( void )
-{
-    glUseProgram( 0 );
-    glDisable( GL_BLEND );
-
-    CHECK_GL_ERROR();
-}
-
-void OpenGLSalGraphicsImpl::BeginInvert( void )
-{
-    glEnable( GL_BLEND );
-    glBlendFunc( GL_ONE_MINUS_DST_COLOR, GL_ZERO );
-    BeginSolid( MAKE_SALCOLOR( 255, 255, 255 ) );
-
-    CHECK_GL_ERROR();
-}
-
-void OpenGLSalGraphicsImpl::EndInvert( void )
-{
-    EndSolid();
-    glDisable( GL_BLEND );
-
-    CHECK_GL_ERROR();
-}
-
 void OpenGLSalGraphicsImpl::DrawPoint( long nX, long nY )
 {
     GLfloat pPoint[2];
@@ -615,12 +376,8 @@ void OpenGLSalGraphicsImpl::DrawPoint( long nX, long nY )
     pPoint[0] = 2 * nX / GetWidth() - 1.0f;
     pPoint[1] = 1.0f - 2 * nY / GetHeight();
 
-    glEnableVertexAttribArray( GL_ATTRIB_POS );
-    glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, pPoint );
+    mpProgram->SetVertices( pPoint );
     glDrawArrays( GL_POINTS, 0, 1 );
-    glDisableVertexAttribArray( GL_ATTRIB_POS );
-
-    CHECK_GL_ERROR();
 }
 
 void OpenGLSalGraphicsImpl::DrawLine( long nX1, long nY1, long nX2, long nY2 )
@@ -632,12 +389,8 @@ void OpenGLSalGraphicsImpl::DrawLine( long nX1, long nY1, long nX2, long nY2 )
     pPoints[2] = (2 * nX2) / GetWidth() - 1.0;;
     pPoints[3] = 1.0f - 2 * nY2 / GetHeight();
 
-    glEnableVertexAttribArray( GL_ATTRIB_POS );
-    glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, pPoints );
+    mpProgram->SetVertices( pPoints );
     glDrawArrays( GL_LINES, 0, 2 );
-    glDisableVertexAttribArray( GL_ATTRIB_POS );
-
-    CHECK_GL_ERROR();
 }
 
 void OpenGLSalGraphicsImpl::DrawLines( sal_uInt32 nPoints, const SalPoint* pPtAry, bool bClose )
@@ -651,15 +404,11 @@ void OpenGLSalGraphicsImpl::DrawLines( sal_uInt32 nPoints, const SalPoint* pPtAr
         aPoints[j++] = 1.0f - (2 * pPtAry[i].mnY) / GetHeight();
     }
 
-    glEnableVertexAttribArray( GL_ATTRIB_POS );
-    glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, &aPoints[0] );
+    mpProgram->SetVertices( &aPoints[0] );
     if( bClose )
         glDrawArrays( GL_LINE_LOOP, 0, nPoints );
     else
         glDrawArrays( GL_LINE_STRIP, 0, nPoints );
-    glDisableVertexAttribArray( GL_ATTRIB_POS );
-
-    CHECK_GL_ERROR();
 }
 
 void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
@@ -673,12 +422,8 @@ void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints, const SalPoin
         aVertices[j+1] = 1.0 - (2 * pPtAry[i].mnY / GetHeight());
     }
 
-    glEnableVertexAttribArray( GL_ATTRIB_POS );
-    glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, &aVertices[0] );
+    mpProgram->SetVertices( &aVertices[0] );
     glDrawArrays( GL_TRIANGLE_FAN, 0, nPoints );
-    glDisableVertexAttribArray( GL_ATTRIB_POS );
-
-    CHECK_GL_ERROR();
 }
 
 void OpenGLSalGraphicsImpl::DrawConvexPolygon( const Polygon& rPolygon )
@@ -694,12 +439,8 @@ void OpenGLSalGraphicsImpl::DrawConvexPolygon( const Polygon& rPolygon )
         aVertices[j+1] = 1.0 - (2 * rPt.Y() / GetHeight());
     }
 
-    glEnableVertexAttribArray( GL_ATTRIB_POS );
-    glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, &aVertices[0] );
+    mpProgram->SetVertices( &aVertices[0] );
     glDrawArrays( GL_TRIANGLE_FAN, 0, nPoints );
-    glDisableVertexAttribArray( GL_ATTRIB_POS );
-
-    CHECK_GL_ERROR();
 }
 
 void OpenGLSalGraphicsImpl::DrawRect( long nX, long nY, long nWidth, long nHeight )
@@ -768,12 +509,8 @@ void OpenGLSalGraphicsImpl::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPol
         }
     }
 
-    glEnableVertexAttribArray( GL_ATTRIB_POS );
-    glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, pVertices.data() );
+    mpProgram->SetVertices( pVertices.data() );
     glDrawArrays( GL_TRIANGLES, 0, pVertices.size() / 2 );
-    glDisableVertexAttribArray( GL_ATTRIB_POS );
-
-    CHECK_GL_ERROR();
 }
 
 void OpenGLSalGraphicsImpl::DrawRegionBand( const RegionBand& rRegion )
@@ -803,50 +540,25 @@ void OpenGLSalGraphicsImpl::DrawRegionBand( const RegionBand& rRegion )
 
 #undef ADD_VERTICE
 
-    glEnableVertexAttribArray( GL_ATTRIB_POS );
-    glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, &aVertices[0] );
+    mpProgram->SetVertices( &aVertices[0] );
     glDrawArrays( GL_TRIANGLES, 0, aVertices.size() / 2 );
-    glDisableVertexAttribArray( GL_ATTRIB_POS );
-
-    CHECK_GL_ERROR();
 }
 
 void OpenGLSalGraphicsImpl::DrawTextureRect( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted )
 {
     GLfloat aTexCoord[8];
-
     rTexture.GetCoord( aTexCoord, rPosAry, bInverted );
-    glEnableVertexAttribArray( GL_ATTRIB_TEX );
-    glVertexAttribPointer( GL_ATTRIB_TEX, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord );
-
+    mpProgram->SetTextureCoord( aTexCoord );
     DrawRect( rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight );
-
-    glDisableVertexAttribArray( GL_ATTRIB_TEX );
-
-    CHECK_GL_ERROR();
 }
 
 void OpenGLSalGraphicsImpl::DrawTexture( OpenGLTexture& rTexture, const SalTwoRect& pPosAry, bool bInverted )
 {
-    if( mnTextureProgram == 0 )
-    {
-        if( !CreateTextureProgram() )
-            return;
-    }
-
-    glUseProgram( mnTextureProgram );
-    glUniform1i( mnSamplerUniform, 0 );
-    glActiveTexture( GL_TEXTURE0 );
-    CHECK_GL_ERROR();
-
-    rTexture.Bind();
+    if( !UseProgram( "textureVertexShader", "textureFragmentShader" ) )
+        return;
+    mpProgram->SetTexture( "sampler", rTexture );
     DrawTextureRect( rTexture, pPosAry, bInverted );
-    rTexture.Unbind();
-    CHECK_GL_ERROR();
-
-    glUseProgram( 0 );
-
-    CHECK_GL_ERROR();
+    mpProgram->Clean();
 }
 
 void OpenGLSalGraphicsImpl::DrawTransformedTexture(
@@ -856,238 +568,105 @@ void OpenGLSalGraphicsImpl::DrawTransformedTexture(
     const basegfx::B2DPoint& rX,
     const basegfx::B2DPoint& rY )
 {
-    const basegfx::B2DVector aXRel = rX - rNull;
-    const basegfx::B2DVector aYRel = rY - rNull;
-    const float aValues[] = {
-        (float) aXRel.getX()/rTexture.GetWidth(),  (float) aXRel.getY()/rTexture.GetWidth(),  0, 0,
-        (float) aYRel.getX()/rTexture.GetHeight(), (float) aYRel.getY()/rTexture.GetHeight(), 0, 0,
-        0,                                         0,                                         1, 0,
-        (float) rNull.getX(),                      (float) rNull.getY(),                      0, 1 };
-    glm::mat4 mMatrix = glm::make_mat4( aValues );
     GLfloat aVertices[8] = {
         0, (float) rTexture.GetHeight(), 0, 0,
         (float) rTexture.GetWidth(), 0, (float) rTexture.GetWidth(), (float) rTexture.GetHeight() };
     GLfloat aTexCoord[8];
-    SalTwoRect aPosAry;
 
     if( rMask )
     {
-        if( mnTransformedMaskedTextureProgram == 0 )
-        {
-            if( !CreateTransformedMaskedTextureProgram() )
-                return;
-        }
-        glUseProgram( mnTransformedMaskedTextureProgram );
-        glUniform2f( mnTransformedMaskedViewportUniform, GetWidth(), GetHeight() );
-        glUniformMatrix4fv( mnTransformedMaskedTransformUniform, 1, GL_FALSE, glm::value_ptr( mMatrix ) );
-        glUniform1i( mnTransformedMaskedSamplerUniform, 0 );
-        glUniform1i( mnTransformedMaskedMaskUniform, 1 );
-        glActiveTexture( GL_TEXTURE1 );
-        rMask.Bind();
+        if( !UseProgram( "transformedTextureVertexShader", "maskedTextureFragmentShader" ) )
+            return;
+        mpProgram->SetTexture( "mask", rMask );
         rMask.SetFilter( GL_LINEAR );
-        glEnable( GL_BLEND );
-        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+        mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
     }
     else
     {
-        if( mnTransformedTextureProgram == 0 )
-        {
-            if( !CreateTransformedTextureProgram() )
-                return;
-        }
-        glUseProgram( mnTransformedTextureProgram );
-        glUniform2f( mnTransformedViewportUniform, GetWidth(), GetHeight() );
-        glUniformMatrix4fv( mnTransformedTransformUniform, 1, GL_FALSE, glm::value_ptr( mMatrix ) );
-        glUniform1i( mnTransformedSamplerUniform, 0 );
+        if( !UseProgram( "transformedTextureVertexShader", "textureFragmentShader" ) )
+            return;
     }
 
-    glActiveTexture( GL_TEXTURE0 );
-    rTexture.Bind();
+    mpProgram->SetUniform2f( "viewport", GetWidth(), GetHeight() );
+    mpProgram->SetTransform( "transform", rTexture, rNull, rX, rY );
+    rTexture.GetWholeCoord( aTexCoord );
+    mpProgram->SetTexture( "sampler", rTexture );
     rTexture.SetFilter( GL_LINEAR );
-    CHECK_GL_ERROR();
-
-    aPosAry.mnSrcX = aPosAry.mnSrcY = 0;
-    aPosAry.mnSrcWidth = rTexture.GetWidth();
-    aPosAry.mnSrcHeight = rTexture.GetHeight();
-    rTexture.GetCoord( aTexCoord, aPosAry );
-    glEnableVertexAttribArray( GL_ATTRIB_TEX );
-    glVertexAttribPointer( GL_ATTRIB_TEX, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord );
-    glEnableVertexAttribArray( GL_ATTRIB_POS );
-    glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, &aVertices[0] );
+    mpProgram->SetTextureCoord( aTexCoord );
+    mpProgram->SetVertices( &aVertices[0] );
     glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
-    glDisableVertexAttribArray( GL_ATTRIB_POS );
-    glDisableVertexAttribArray( GL_ATTRIB_TEX );
-
-    if( rMask )
-    {
-        glDisable( GL_BLEND );
-        glActiveTexture( GL_TEXTURE1 );
-        rMask.Unbind();
-    }
-
-    glActiveTexture( GL_TEXTURE0 );
-    rTexture.Unbind();
-    glUseProgram( 0 );
-    CHECK_GL_ERROR();
+    mpProgram->Clean();
 }
 
 void OpenGLSalGraphicsImpl::DrawAlphaTexture( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted, bool bPremultiplied )
 {
-    glEnable( GL_BLEND );
-    if( bPremultiplied )
-        glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
-    else
-        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
-    DrawTexture( rTexture, rPosAry, bInverted );
-    glDisable( GL_BLEND );
-    CHECK_GL_ERROR();
+    if( !UseProgram( "textureVertexShader", "textureFragmentShader" ) )
+        return;
+    mpProgram->SetTexture( "sampler", rTexture );
+    mpProgram->SetBlendMode( bPremultiplied ? GL_ONE : GL_SRC_ALPHA,
+                             GL_ONE_MINUS_SRC_ALPHA );
+    DrawTextureRect( rTexture, rPosAry, bInverted );
+    mpProgram->Clean();
 }
 
 void OpenGLSalGraphicsImpl::DrawTextureDiff( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& rPosAry, bool bInverted )
 {
-    if( mnDiffTextureProgram == 0 )
-    {
-        if( !CreateDiffTextureProgram() )
-            return;
-    }
-
-    glUseProgram( mnDiffTextureProgram );
-    glUniform1i( mnDiffTextureUniform, 0 );
-    glUniform1i( mnDiffMaskUniform, 1 );
-    glActiveTexture( GL_TEXTURE0 );
-    rTexture.Bind();
-    glActiveTexture( GL_TEXTURE1 );
-    rMask.Bind();
-
-    glEnable( GL_BLEND );
-    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+    if( !UseProgram( "textureVertexShader", "diffTextureFragmentShader" ) )
+        return;
+    mpProgram->SetTexture( "texture", rTexture );
+    mpProgram->SetTexture( "mask", rMask );
+    mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
     DrawTextureRect( rTexture, rPosAry, bInverted );
-    glDisable( GL_BLEND );
-
-    glActiveTexture( GL_TEXTURE1 );
-    rMask.Unbind();
-    glActiveTexture( GL_TEXTURE0 );
-    rTexture.Unbind();
-    glUseProgram( 0 );
-
-    CHECK_GL_ERROR();
+    mpProgram->Clean();
 }
 
 void OpenGLSalGraphicsImpl::DrawTextureWithMask( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& pPosAry )
 {
-    if( mnMaskedTextureProgram == 0 )
-    {
-        if( !CreateMaskedTextureProgram() )
-            return;
-    }
-
-    glUseProgram( mnMaskedTextureProgram );
-    glUniform1i( mnMaskedSamplerUniform, 0 );
-    glUniform1i( mnMaskSamplerUniform, 1 );
-    glActiveTexture( GL_TEXTURE0 );
-    rTexture.Bind();
-    glActiveTexture( GL_TEXTURE1 );
-    rMask.Bind();
-
-    glEnable( GL_BLEND );
-    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+    if( !UseProgram( "textureVertexShader", "maskedTextureFragmentShader" ) )
+        return;
+    mpProgram->SetTexture( "sampler", rTexture );
+    mpProgram->SetTexture( "mask", rMask );
+    mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
     DrawTextureRect( rTexture, pPosAry );
-    glDisable( GL_BLEND );
-
-    glActiveTexture( GL_TEXTURE1 );
-    rMask.Unbind();
-    glActiveTexture( GL_TEXTURE0 );
-    rTexture.Unbind();
-    glUseProgram( 0 );
-
-    CHECK_GL_ERROR();
+    mpProgram->Clean();
 }
 
 void OpenGLSalGraphicsImpl::DrawBlendedTexture( OpenGLTexture& rTexture, OpenGLTexture& rMask, OpenGLTexture& rAlpha, const SalTwoRect& rPosAry )
 {
     GLfloat aTexCoord[8];
-
-    if( mnBlendedTextureProgram == 0 )
-    {
-        if( !CreateBlendedTextureProgram() )
-            return;
-    }
-
-    glUseProgram( mnBlendedTextureProgram );
-    glUniform1i( mnBlendedTextureUniform, 0 );
-    glUniform1i( mnBlendedMaskUniform, 1 );
-    glUniform1i( mnBlendedAlphaUniform, 2 );
-    glActiveTexture( GL_TEXTURE0 );
-    rTexture.Bind();
-    glActiveTexture( GL_TEXTURE1 );
-    rMask.Bind();
-    glActiveTexture( GL_TEXTURE2 );
-    rAlpha.Bind();
-
+    if( !UseProgram( "blendedTextureVertexShader", "blendedTextureFragmentShader" ) )
+        return;
+    mpProgram->SetTexture( "sampler", rTexture );
+    mpProgram->SetTexture( "mask", rMask );
+    mpProgram->SetTexture( "alpha", rAlpha );
     rAlpha.GetCoord( aTexCoord, rPosAry );
-    glEnableVertexAttribArray( GL_ATTRIB_TEX2 );
-    glVertexAttribPointer( GL_ATTRIB_TEX2, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord );
-
-    glEnable( GL_BLEND );
-    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+    mpProgram->SetAlphaCoord( aTexCoord );
+    mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
     DrawTextureRect( rTexture, rPosAry );
-    glDisable( GL_BLEND );
-
-    glDisableVertexAttribArray( GL_ATTRIB_TEX2 );
-
-    glActiveTexture( GL_TEXTURE0 );
-    rTexture.Unbind();
-    glActiveTexture( GL_TEXTURE1 );
-    rMask.Unbind();
-    glActiveTexture( GL_TEXTURE2 );
-    rAlpha.Unbind();
-    glActiveTexture( GL_TEXTURE0 );
-    glUseProgram( 0 );
-
-    CHECK_GL_ERROR();
+    mpProgram->Clean();
 }
 
 void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture& rMask, SalColor nMaskColor, const SalTwoRect& pPosAry )
 {
-    if( mnMaskProgram == 0 )
-    {
-        if( !CreateMaskProgram() )
-            return;
-    }
-
-    glUseProgram( mnMaskProgram );
-    glUniformColor( mnMaskColorUniform, nMaskColor, 0 );
-    glUniform1i( mnMaskUniform, 0 );
-    glActiveTexture( GL_TEXTURE0 );
-    rMask.Bind();
-
-    glEnable( GL_BLEND );
-    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+    if( !UseProgram( "textureVertexShader", "maskFragmentShader" ) )
+        return;
+    mpProgram->SetColor( "color", nMaskColor, 0 );
+    mpProgram->SetTexture( "sampler", rMask );
+    mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
     DrawTextureRect( rMask, pPosAry );
-    glDisable( GL_BLEND );
-
-    rMask.Unbind();
-    glUseProgram( 0 );
-
-    CHECK_GL_ERROR();
+    mpProgram->Clean();
 }
 
 void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect )
 {
-    if( mnLinearGradientProgram == 0 )
-    {
-        if( !CreateLinearGradientProgram() )
-            return;
-    }
-
-    glUseProgram( mnLinearGradientProgram );
-
+    if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
+        return;
     Color aStartCol = rGradient.GetStartColor();
     Color aEndCol = rGradient.GetEndColor();
     long nFactor = rGradient.GetStartIntensity();
-    glUniformColorIntensity( mnLinearGradientStartColorUniform, aStartCol, nFactor );
+    mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor );
     nFactor = rGradient.GetEndIntensity();
-    glUniformColorIntensity( mnLinearGradientEndColorUniform, aEndCol, nFactor );
+    mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor );
 
     Rectangle aBoundRect;
     Point aCenter;
@@ -1098,35 +677,20 @@ void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const
     GLfloat aTexCoord[8] = { 0, 1, 1, 1, 1, 0, 0, 0 };
     GLfloat fMin = 1.0 - 100.0 / (100.0 - rGradient.GetBorder());
     aTexCoord[5] = aTexCoord[7] = fMin;
-    glEnableVertexAttribArray( GL_ATTRIB_TEX );
-    glVertexAttribPointer( GL_ATTRIB_TEX, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord );
-
+    mpProgram->SetTextureCoord( aTexCoord );
     DrawConvexPolygon( aPoly );
-
-    glDisableVertexAttribArray( GL_ATTRIB_TEX );
-    CHECK_GL_ERROR();
-
-    glUseProgram( 0 );
-
-    CHECK_GL_ERROR();
 }
 
 void OpenGLSalGraphicsImpl::DrawAxialGradient( const Gradient& rGradient, const Rectangle& rRect )
 {
-    if( mnLinearGradientProgram == 0 )
-    {
-        if( !CreateLinearGradientProgram() )
-            return;
-    }
-
-    glUseProgram( mnLinearGradientProgram );
-
+    if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) )
+        return;
     Color aStartCol = rGradient.GetStartColor();
     Color aEndCol = rGradient.GetEndColor();
     long nFactor = rGradient.GetStartIntensity();
-    glUniformColorIntensity( mnLinearGradientStartColorUniform, aStartCol, nFactor );
+    mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor );
     nFactor = rGradient.GetEndIntensity();
-    glUniformColorIntensity( mnLinearGradientEndColorUniform, aEndCol, nFactor );
+    mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor );
 
     /**
      * Draw two rectangles with linear gradient.
@@ -1163,33 +727,20 @@ void OpenGLSalGraphicsImpl::DrawAxialGradient( const Gradient& rGradient, const
     GLfloat aTexCoord[12] = { 0, 1, 1, 0, 2, 0, 3, 1, 4, 0, 5, 0 };
     GLfloat fMin = 1.0 - 100.0 / (100.0 - rGradient.GetBorder());
     aTexCoord[3] = aTexCoord[5] = aTexCoord[9] = aTexCoord[11] = fMin;
-    glEnableVertexAttribArray( GL_ATTRIB_TEX );
-    glVertexAttribPointer( GL_ATTRIB_TEX, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord );
-
+    mpProgram->SetTextureCoord( aTexCoord );
     DrawConvexPolygon( aPoly );
-
-    glDisableVertexAttribArray( GL_ATTRIB_TEX );
-    glUseProgram( 0 );
-
-    CHECK_GL_ERROR();
 }
 
 void OpenGLSalGraphicsImpl::DrawRadialGradient( const Gradient& rGradient, const Rectangle& rRect )
 {
-    if( mnRadialGradientProgram == 0 )
-    {
-        if( !CreateRadialGradientProgram() )
-            return;
-    }
-
-    glUseProgram( mnRadialGradientProgram );
-
+    if( !UseProgram( "textureVertexShader", "radialGradientFragmentShader" ) )
+        return;
     Color aStartCol = rGradient.GetStartColor();
     Color aEndCol = rGradient.GetEndColor();
     long nFactor = rGradient.GetStartIntensity();
-    glUniformColorIntensity( mnRadialGradientStartColorUniform, aStartCol, nFactor );
+    mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor );
     nFactor = rGradient.GetEndIntensity();
-    glUniformColorIntensity( mnRadialGradientEndColorUniform, aEndCol, nFactor );
+    mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor );
 
     Rectangle aRect;
     Point aCenter;
@@ -1199,18 +750,11 @@ void OpenGLSalGraphicsImpl::DrawRadialGradient( const Gradient& rGradient, const
     double fRadius = aRect.GetWidth() / 2.0f;
     GLfloat fWidth = rRect.GetWidth() / fRadius;
     GLfloat fHeight = rRect.GetHeight() / fRadius;
-    glUniform2f( mnRadialGradientCenterUniform, (aCenter.X() -rRect.Left()) / fRadius, (aCenter.Y() - rRect.Top()) / fRadius );
-
     GLfloat aTexCoord[8] = { 0, 0, 0, fHeight, fWidth, fHeight, fWidth, 0 };
-    glEnableVertexAttribArray( GL_ATTRIB_TEX );
-    glVertexAttribPointer( GL_ATTRIB_TEX, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord );
-
+    mpProgram->SetTextureCoord( aTexCoord );
+    mpProgram->SetUniform2f( "center", (aCenter.X() - rRect.Left()) / fRadius,
+                                       (aCenter.Y() - rRect.Top())  / fRadius );
     DrawRect( rRect );
-
-    glDisableVertexAttribArray( GL_ATTRIB_TEX );
-    glUseProgram( 0 );
-
-    CHECK_GL_ERROR();
 }
 
 
@@ -1221,9 +765,8 @@ void OpenGLSalGraphicsImpl::drawPixel( long nX, long nY )
     if( mnLineColor != SALCOLOR_NONE )
     {
         PreDraw();
-        BeginSolid( mnLineColor );
-        DrawPoint( nX, nY );
-        EndSolid();
+        if( UseSolid( mnLineColor ) )
+            DrawPoint( nX, nY );
         PostDraw();
     }
 }
@@ -1234,9 +777,8 @@ void OpenGLSalGraphicsImpl::drawPixel( long nX, long nY, SalColor nSalColor )
     if( nSalColor != SALCOLOR_NONE )
     {
         PreDraw();
-        BeginSolid( nSalColor );
-        DrawPoint( nX, nY );
-        EndSolid();
+        if( UseSolid( nSalColor ) )
+            DrawPoint( nX, nY );
         PostDraw();
     }
 }
@@ -1247,9 +789,8 @@ void OpenGLSalGraphicsImpl::drawLine( long nX1, long nY1, long nX2, long nY2 )
     if( mnLineColor != SALCOLOR_NONE )
     {
         PreDraw();
-        BeginSolid( mnLineColor );
-        DrawLine( nX1, nY1, nX2, nY2 );
-        EndSolid();
+        if( UseSolid( mnLineColor ) )
+            DrawLine( nX1, nY1, nX2, nY2 );
         PostDraw();
     }
 }
@@ -1259,14 +800,10 @@ void OpenGLSalGraphicsImpl::drawRect( long nX, long nY, long nWidth, long nHeigh
     SAL_INFO( "vcl.opengl", "::drawRect" );
     PreDraw();
 
-    if( mnFillColor != SALCOLOR_NONE )
-    {
-        BeginSolid( mnFillColor );
+    if( UseSolid( mnFillColor ) )
         DrawRect( nX, nY, nWidth, nHeight );
-        EndSolid();
-    }
 
-    if( mnLineColor != SALCOLOR_NONE )
+    if( UseSolid( mnLineColor ) )
     {
         const long nX1( nX );
         const long nY1( nY );
@@ -1274,10 +811,7 @@ void OpenGLSalGraphicsImpl::drawRect( long nX, long nY, long nWidth, long nHeigh
         const long nY2( nY + nHeight );
         const SalPoint aPoints[] = { { nX1, nY1 }, { nX2, nY1 },
                                      { nX2, nY2 }, { nX1, nY2 } };
-
-        BeginSolid( mnLineColor );
         DrawLines( 4, aPoints, true );
-        EndSolid();
     }
 
     PostDraw();
@@ -1290,9 +824,8 @@ void OpenGLSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pP
     if( mnLineColor != SALCOLOR_NONE && nPoints > 1 )
     {
         PreDraw();
-        BeginSolid( mnLineColor );
-        DrawLines( nPoints, pPtAry, false );
-        EndSolid();
+        if( UseSolid( mnLineColor ) )
+            DrawLines( nPoints, pPtAry, false );
         PostDraw();
     }
 }
@@ -1316,19 +849,11 @@ void OpenGLSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPt
 
     PreDraw();
 
-    if( mnFillColor != SALCOLOR_NONE )
-    {
-        BeginSolid( mnFillColor );
+    if( UseSolid( mnFillColor ) )
         DrawPolygon( nPoints, pPtAry );
-        EndSolid();
-    }
 
-    if( mnLineColor != SALCOLOR_NONE )
-    {
-        BeginSolid( mnLineColor );
+    if( UseSolid( mnLineColor ) )
         DrawLines( nPoints, pPtAry, true );
-        EndSolid();
-    }
 
     PostDraw();
 }
@@ -1341,21 +866,17 @@ void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32*
 
     PreDraw();
 
-    if( mnFillColor != SALCOLOR_NONE )
+    if( UseSolid( mnFillColor ) )
     {
-        BeginSolid( mnFillColor );
         for( sal_uInt32 i = 0; i < nPoly; i++ )
             DrawPolygon( pPoints[i], pPtAry[i] );
-        EndSolid();
     }
 
-    if( mnLineColor != SALCOLOR_NONE )
+    if( UseSolid( mnLineColor ) )
     {
         // TODO Use glMultiDrawElements or primitive restart
-        BeginSolid( mnLineColor );
         for( sal_uInt32 i = 0; i < nPoly; i++ )
             DrawLines( pPoints[i], pPtAry[i], true );
-        EndSolid();
     }
 
     PostDraw();
@@ -1369,15 +890,13 @@ bool OpenGLSalGraphicsImpl::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rP
 
     PreDraw();
 
-    if( mnFillColor != SALCOLOR_NONE )
+    if( UseSolid( mnFillColor, fTransparency ) )
     {
-        BeginSolid( mnFillColor, fTransparency );
         for( sal_uInt32 i = 0; i < rPolyPolygon.count(); i++ )
         {
             const ::basegfx::B2DPolyPolygon aOnePoly( rPolyPolygon.getB2DPolygon( i ) );
             DrawPolyPolygon( aOnePoly );
         }
-        EndSolid();
     }
 
     PostDraw();
@@ -1454,13 +973,14 @@ bool OpenGLSalGraphicsImpl::drawPolyLine(
     }
 
     PreDraw();
-    BeginSolid( mnLineColor, fTransparency );
-    for( sal_uInt32 i = 0; i < aAreaPolyPoly.count(); i++ )
+    if( UseSolid( mnLineColor, fTransparency ) )
     {
-        const ::basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( i ) );
-        DrawPolyPolygon( aOnePoly );
+        for( sal_uInt32 i = 0; i < aAreaPolyPoly.count(); i++ )
+        {
+            const ::basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( i ) );
+            DrawPolyPolygon( aOnePoly );
+        }
     }
-    EndSolid();
     PostDraw();
 
     return true;
@@ -1510,7 +1030,9 @@ void OpenGLSalGraphicsImpl::copyArea(
     aPosAry.mnSrcHeight = aPosAry.mnDestHeight = nSrcHeight;
 
     PreDraw();
-    aTexture = OpenGLTexture( nSrcX, GetHeight() - nSrcY - nSrcHeight, nSrcWidth, nSrcHeight );
+    // TODO offscreen case
+    aTexture = OpenGLTexture( nSrcX, GetHeight() - nSrcY - nSrcHeight,
+                              nSrcWidth, nSrcHeight );
     DrawTexture( aTexture, aPosAry );
     PostDraw();
 }
@@ -1651,9 +1173,8 @@ void OpenGLSalGraphicsImpl::invert(
     }
     else // just invert
     {
-        BeginInvert();
-        DrawRect( nX, nY, nWidth, nHeight );
-        EndInvert();
+        if( UseInvert() )
+            DrawRect( nX, nY, nWidth, nHeight );
     }
 
     PostDraw();
@@ -1673,9 +1194,8 @@ void OpenGLSalGraphicsImpl::invert( sal_uInt32 nPoints, const SalPoint* pPtAry,
     }
     else // just invert
     {
-        BeginInvert();
-        DrawPolygon( nPoints, pPtAry );
-        EndInvert();
+        if( UseInvert() )
+            DrawPolygon( nPoints, pPtAry );
     }
 
     PostDraw();
@@ -1811,9 +1331,8 @@ bool OpenGLSalGraphicsImpl::drawAlphaRect(
     if( mnFillColor != SALCOLOR_NONE && nTransparency < 100 )
     {
         PreDraw();
-        BeginSolid( mnFillColor, nTransparency );
+        UseSolid( mnFillColor, nTransparency );
         DrawRect( nX, nY, nWidth, nHeight );
-        EndSolid();
         PostDraw();
     }
 
@@ -1862,10 +1381,10 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly,
     {
         Color aCol = rGradient.GetStartColor();
         long nF = rGradient.GetStartIntensity();
-        BeginSolid( MAKE_SALCOLOR( aCol.GetRed() * nF / 100,
-                                   aCol.GetGreen() * nF / 100,
-                                   aCol.GetBlue() * nF / 100 ) );
-        DrawRect( aBoundRect );
+        if( UseSolid( MAKE_SALCOLOR( aCol.GetRed() * nF / 100,
+                                     aCol.GetGreen() * nF / 100,
+                                     aCol.GetBlue() * nF / 100 ) ) )
+            DrawRect( aBoundRect );
     }
     else if( rGradient.GetStyle() == GradientStyle_LINEAR )
     {
diff --git a/vcl/opengl/maskVertexShader.glsl b/vcl/opengl/maskVertexShader.glsl
deleted file mode 100644
index 99d7f37..0000000
--- a/vcl/opengl/maskVertexShader.glsl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-attribute vec4 position;
-attribute vec2 tex_coord_in;
-varying vec2 tex_coord;
-
-void main() {
-   gl_Position = position;
-   tex_coord = tex_coord_in;
-}
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/maskedTextureVertexShader.glsl b/vcl/opengl/maskedTextureVertexShader.glsl
deleted file mode 100644
index 99d7f37..0000000
--- a/vcl/opengl/maskedTextureVertexShader.glsl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-attribute vec4 position;
-attribute vec2 tex_coord_in;
-varying vec2 tex_coord;
-
-void main() {
-   gl_Position = position;
-   tex_coord = tex_coord_in;
-}
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/program.cxx b/vcl/opengl/program.cxx
new file mode 100644
index 0000000..c9542c7
--- /dev/null
+++ b/vcl/opengl/program.cxx
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <opengl/program.hxx>
+
+#include <vcl/opengl/OpenGLHelper.hxx>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
+
+OpenGLProgram::OpenGLProgram() :
+    mnId( 0 ),
+    mnEnabledAttribs( 0 ),
+    mnAttribIndex( 0 ),
+    mnPositionAttrib( SAL_MAX_UINT32 ),
+    mnTexCoordAttrib( SAL_MAX_UINT32 ),
+    mnAlphaCoordAttrib( SAL_MAX_UINT32 ),
+    mbBlending( false )
+{
+}
+
+OpenGLProgram::~OpenGLProgram()
+{
+    maUniformLocations.clear();
+    if( mnId != 0 )
+        glDeleteProgram( mnId );
+}
+
+bool OpenGLProgram::Load( const OUString& rVertexShader, const OUString& rFragmentShader )
+{
+    mnId = OpenGLHelper::LoadShaders( rVertexShader, rFragmentShader );
+    return ( mnId != 0 );
+}
+
+bool OpenGLProgram::Use()
+{
+    if( !mnId )
+        return false;
+
+    glUseProgram( mnId );
+    return true;
+}
+
+bool OpenGLProgram::Clean()
+{
+    // unbind all textures
+    if( !maTextures.empty() )
+    {
+        int nIndex( maTextures.size() - 1 );
+        TextureList::reverse_iterator it( maTextures.rbegin() );
+        while( it != maTextures.rend() )
+        {
+            glActiveTexture( GL_TEXTURE0 + nIndex-- );
+            it->Unbind();
+            it++;
+        }
+        maTextures.clear();
+    }
+
+    // disable any enabled vertex attrib array
+    if( mnEnabledAttribs )
+    {
+        for( int i = 0; i < 32; i++ )
+        {
+            if( mnEnabledAttribs & ( 1 << i ) )
+                glDisableVertexAttribArray( i );
+        }
+        mnEnabledAttribs = 0;
+    }
+
+    // disable blending if enabled
+    if( mbBlending )
+    {
+        mbBlending = false;
+        glDisable( GL_BLEND );
+    }
+
+    CHECK_GL_ERROR();
+    return true;
+}
+
+void OpenGLProgram::SetVertexAttrib( GLuint& rAttrib, const OString& rName, const GLvoid* pData )
+{
+    if( rAttrib == SAL_MAX_UINT32 )
+        rAttrib = glGetAttribLocation( mnId, (char*) rName.getStr() );
+    if( (mnEnabledAttribs & ( 1 << rAttrib )) == 0 )
+    {
+        glEnableVertexAttribArray( rAttrib );
+        mnEnabledAttribs |= ( 1 << rAttrib );
+    }
+    glVertexAttribPointer( rAttrib, 2, GL_FLOAT, GL_FALSE, 0, pData );
+}
+
+void OpenGLProgram::SetVertices( const GLvoid* pData )
+{
+    SetVertexAttrib( mnPositionAttrib, "position", pData );
+}
+
+void OpenGLProgram::SetTextureCoord( const GLvoid* pData )
+{
+    SetVertexAttrib( mnTexCoordAttrib, "tex_coord_in", pData );
+}
+
+void OpenGLProgram::SetAlphaCoord( const GLvoid* pData )
+{
+    SetVertexAttrib( mnAlphaCoordAttrib, "alpha_coord_in", pData );
+}
+
+GLuint OpenGLProgram::GetUniformLocation( const OString& rName )
+{
+    boost::unordered_map<OString, GLuint>::iterator it;
+
+    it = maUniformLocations.find( rName );
+    if( it == maUniformLocations.end() )
+    {
+        GLuint nLocation = glGetUniformLocation( mnId, (char*) rName.getStr() );
+        maUniformLocations[rName] = nLocation;
+        return nLocation;
+    }
+
+    return it->second;
+}
+
+void OpenGLProgram::SetUniform2f( const OString& rName, GLfloat v1, GLfloat v2 )
+{
+    GLuint nUniform = GetUniformLocation( rName );
+    glUniform2f( nUniform, v1, v2 );
+}
+
+void OpenGLProgram::SetUniform1fv( const OString& rName, GLsizei nCount, GLfloat* aValues )
+{
+    GLuint nUniform = GetUniformLocation( rName );
+    glUniform1fv( nUniform, nCount, aValues );
+}
+
+void OpenGLProgram::SetUniform2fv( const OString& rName, GLsizei nCount, GLfloat* aValues )
+{
+    GLuint nUniform = GetUniformLocation( rName );
+    glUniform2fv( nUniform, nCount, aValues );
+}
+
+void OpenGLProgram::SetColor( const OString& rName, SalColor nColor, sal_uInt8 nTransparency )
+{
+    GLuint nUniform = GetUniformLocation( rName );
+    glUniform4f( nUniform,
+                 ((float) SALCOLOR_RED( nColor )) / 255,
+                 ((float) SALCOLOR_GREEN( nColor )) / 255,
+                 ((float) SALCOLOR_BLUE( nColor )) / 255,
+                 (100 - nTransparency) * (1.0 / 100) );
+
+    if( nTransparency > 0 )
+        SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+}
+
+void OpenGLProgram::SetColorf( const OString& rName, SalColor nColor, double fTransparency )
+{
+    GLuint nUniform = GetUniformLocation( rName );
+    glUniform4f( nUniform,
+                 ((float) SALCOLOR_RED( nColor )) / 255,
+                 ((float) SALCOLOR_GREEN( nColor )) / 255,
+                 ((float) SALCOLOR_BLUE( nColor )) / 255,
+                 (1.0f - fTransparency) );
+
+    if( fTransparency > 0.0 )
+        SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+}
+
+void OpenGLProgram::SetColorWithIntensity( const OString& rName, const Color& rColor, long nFactor )
+{
+    GLuint nUniform = GetUniformLocation( rName );
+    glUniform4f( nUniform,
+                 ((float) rColor.GetRed()) * nFactor / 25500.0,
+                 ((float) rColor.GetGreen()) * nFactor / 25500.0,
+                 ((float) rColor.GetBlue()) * nFactor / 25500.0,
+                 1.0f );
+}
+
+void OpenGLProgram::SetTexture( const OString& rName, OpenGLTexture& rTexture )
+{
+    GLuint nUniform = GetUniformLocation( rName );
+    int nIndex = maTextures.size();
+
+    glUniform1i( nUniform, nIndex );
+    glActiveTexture( GL_TEXTURE0 + nIndex );
+    rTexture.Bind();
+    maTextures.push_back( rTexture );
+}
+
+void OpenGLProgram::SetTransform(
+    const OString& rName,
+    const OpenGLTexture& rTexture,
+    const basegfx::B2DPoint& rNull,
+    const basegfx::B2DPoint& rX,
+    const basegfx::B2DPoint& rY )
+{
+    GLuint nUniform = GetUniformLocation( rName );
+    const basegfx::B2DVector aXRel = rX - rNull;
+    const basegfx::B2DVector aYRel = rY - rNull;
+    const float aValues[] = {
+        (float) aXRel.getX()/rTexture.GetWidth(),  (float) aXRel.getY()/rTexture.GetWidth(),  0, 0,
+        (float) aYRel.getX()/rTexture.GetHeight(), (float) aYRel.getY()/rTexture.GetHeight(), 0, 0,
+        0,                                         0,                                         1, 0,
+        (float) rNull.getX(),                      (float) rNull.getY(),                      0, 1 };
+    glm::mat4 mMatrix = glm::make_mat4( aValues );
+    glUniformMatrix4fv( nUniform, 1, GL_FALSE, glm::value_ptr( mMatrix ) );
+}
+
+void OpenGLProgram::SetBlendMode( GLenum nSFactor, GLenum nDFactor )
+{
+    glEnable( GL_BLEND );
+    glBlendFunc( nSFactor, nDFactor );
+    mbBlending = true;
+}
+
+bool OpenGLProgram::DrawTexture( OpenGLTexture& rTexture )
+{
+    GLfloat aPosition[8] = { -1, -1, -1, 1, 1, 1, 1, -1 };
+    GLfloat aTexCoord[8];
+
+    if( !rTexture )
+        return false;
+
+    rTexture.GetWholeCoord( aTexCoord );
+    SetVertices( aPosition );
+    SetTextureCoord( aTexCoord );
+    glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
+    CHECK_GL_ERROR();
+
+    return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/salbmp.cxx b/vcl/opengl/salbmp.cxx
index ce566b0..9fde118 100644
--- a/vcl/opengl/salbmp.cxx
+++ b/vcl/opengl/salbmp.cxx
@@ -43,13 +43,6 @@ OpenGLSalBitmap::OpenGLSalBitmap()
 , mnHeight(0)
 , mnBufWidth(0)
 , mnBufHeight(0)
-, mnTexProgram(0)
-, mnTexSamplerUniform(0)
-, mnConvProgram(0)
-, mnConvSamplerUniform(0)
-, mnConvKernelUniform(0)
-, mnConvKernelSizeUniform(0)
-, mnConvOffsetsUniform(0)
 {
 }
 
diff --git a/vcl/opengl/scale.cxx b/vcl/opengl/scale.cxx
index d396652..7bcf7c0 100644
--- a/vcl/opengl/scale.cxx
+++ b/vcl/opengl/scale.cxx
@@ -25,6 +25,7 @@
 
 #include "opengl/bmpop.hxx"
 #include "opengl/salbmp.hxx"
+#include "opengl/program.hxx"
 #include "opengl/texture.hxx"
 
 class ScaleOp : public OpenGLSalBitmapOp
@@ -42,75 +43,32 @@ public:
     void GetSize( Size& rSize ) const SAL_OVERRIDE;
 };
 
-
-GLuint OpenGLSalBitmap::ImplGetTextureProgram()
-{
-    if( mnTexProgram == 0 )
-    {
-        mnTexProgram = OpenGLHelper::LoadShaders( "textureVertexShader",
-                                                  "textureFragmentShader" );
-        if( mnTexProgram == 0 )
-            return 0;
-
-        glBindAttribLocation( mnTexProgram, 0, "position" );
-        glBindAttribLocation( mnTexProgram, 1, "tex_coord_in" );
-        mnTexSamplerUniform = glGetUniformLocation( mnTexProgram, "sampler" );
-    }
-
-    CHECK_GL_ERROR();
-    return mnTexProgram;
-}
-
-GLuint OpenGLSalBitmap::ImplGetConvolutionProgram()
-{
-    if( mnConvProgram == 0 )
-    {
-        mnConvProgram = OpenGLHelper::LoadShaders( "textureVertexShader",
-                                                   "convolutionFragmentShader" );
-        if( mnConvProgram == 0 )
-            return 0;
-
-        glBindAttribLocation( mnConvProgram, 0, "position" );
-        glBindAttribLocation( mnConvProgram, 1, "tex_coord_in" );
-        mnConvSamplerUniform = glGetUniformLocation( mnConvProgram, "sampler" );
-        mnConvKernelUniform = glGetUniformLocation( mnConvProgram, "kernel" );
-        mnConvOffsetsUniform = glGetUniformLocation( mnConvProgram, "offsets" );
-    }
-
-    CHECK_GL_ERROR();
-    return mnConvProgram;
-}
-
 bool OpenGLSalBitmap::ImplScaleFilter(
     const double& rScaleX,
     const double& rScaleY,
     GLenum        nFilter )
 {
     OpenGLFramebuffer* pFramebuffer;
-    GLuint nProgram;
+    OpenGLProgram* pProgram;
     GLenum nOldFilter;
     int nNewWidth( mnWidth * rScaleX );
     int nNewHeight( mnHeight * rScaleY );
 
-    nProgram = ImplGetTextureProgram();
-    if( nProgram == 0 )
+    pProgram = mpContext->UseProgram( "textureVertexShader",
+                                      "textureFragmentShader" );
+    if( !pProgram )
         return false;
 
     OpenGLTexture aNewTex = OpenGLTexture( nNewWidth, nNewHeight );
     pFramebuffer = mpContext->AcquireFramebuffer( aNewTex );
 
-    glUseProgram( nProgram );
-    glUniform1i( mnTexSamplerUniform, 0 );
-    glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
-    glClear( GL_COLOR_BUFFER_BIT );
-    maTexture.Bind();
+    pProgram->SetTexture( "sampler", maTexture );
     nOldFilter = maTexture.GetFilter();
     maTexture.SetFilter( nFilter );
-    maTexture.Draw();
+    pProgram->DrawTexture( maTexture );
     maTexture.SetFilter( nOldFilter );
-    maTexture.Unbind();
+    pProgram->Clean();
 
-    glUseProgram( 0 );
     mpContext->ReleaseFramebuffer( pFramebuffer );
 
     mnWidth = nNewWidth;
@@ -165,8 +123,8 @@ bool OpenGLSalBitmap::ImplScaleConvolution(
     const Kernel& aKernel )
 {
     OpenGLFramebuffer* pFramebuffer;
+    OpenGLProgram* pProgram;
     GLfloat* pWeights( 0 );
-    GLuint nProgram;
     sal_uInt32 nKernelSize;
     GLfloat aOffsets[32];
     int nNewWidth( mnWidth * rScaleX );
@@ -174,14 +132,11 @@ bool OpenGLSalBitmap::ImplScaleConvolution(
 
     // TODO Make sure the framebuffer is alright
 
-    nProgram = ImplGetConvolutionProgram();
-    if( nProgram == 0 )
+    pProgram = mpContext->UseProgram( "textureVertexShader",
+                                      "convolutionFragmentShader" );
+    if( pProgram == 0 )
         return false;
 
-    glUseProgram( nProgram );
-    glUniform1i( mnConvSamplerUniform, 0 );
-    CHECK_GL_ERROR();
-
     // horizontal scaling in scratch texture
     if( mnWidth != nNewWidth )
     {
@@ -194,14 +149,11 @@ bool OpenGLSalBitmap::ImplScaleConvolution(
             aOffsets[i * 2 + 1] = 0;
         }
         ImplCreateKernel( rScaleX, aKernel, pWeights, nKernelSize );
-        glUniform1fv( mnConvKernelUniform, 16, pWeights );
-        CHECK_GL_ERROR();
-        glUniform2fv( mnConvOffsetsUniform, 16, aOffsets );
-        CHECK_GL_ERROR();
-
-        maTexture.Bind();
-        maTexture.Draw();
-        maTexture.Unbind();
+        pProgram->SetUniform1fv( "kernel", 16, pWeights );
+        pProgram->SetUniform2fv( "offsets", 16, aOffsets );
+        pProgram->SetTexture( "sampler", maTexture );
+        pProgram->DrawTexture( maTexture );
+        pProgram->Clean();
 
         maTexture = aScratchTex;
         mpContext->ReleaseFramebuffer( pFramebuffer );
@@ -219,20 +171,16 @@ bool OpenGLSalBitmap::ImplScaleConvolution(
             aOffsets[i * 2 + 1] = i / (double) mnHeight;
         }
         ImplCreateKernel( rScaleY, aKernel, pWeights, nKernelSize );
-        glUniform1fv( mnConvKernelUniform, 16, pWeights );
-        glUniform2fv( mnConvOffsetsUniform, 16, aOffsets );
-        CHECK_GL_ERROR();
-
-        maTexture.Bind();
-        maTexture.Draw();
-        maTexture.Unbind();
+        pProgram->SetUniform1fv( "kernel", 16, pWeights );
+        pProgram->SetUniform2fv( "offsets", 16, aOffsets );
+        pProgram->SetTexture( "sampler", maTexture );
+        pProgram->DrawTexture( maTexture );
+        pProgram->Clean();
 
         maTexture = aScratchTex;
         mpContext->ReleaseFramebuffer( pFramebuffer );
     }
 
-    glUseProgram( 0 );
-
     mnWidth = nNewWidth;
     mnHeight = nNewHeight;
 
diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx
index c8f4684..7618c04 100644
--- a/vcl/opengl/texture.cxx
+++ b/vcl/opengl/texture.cxx
@@ -188,6 +188,24 @@ void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool b
     }
 }
 
+void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const
+{
+    if( GetWidth() != mpImpl->mnWidth || GetHeight() != mpImpl->mnHeight )
+    {
+        pCoord[0] = pCoord[2] = maRect.Left() / (double) mpImpl->mnWidth;
+        pCoord[4] = pCoord[6] = maRect.Right() / (double) mpImpl->mnWidth;
+        pCoord[3] = pCoord[5] = 1.0f - maRect.Top() / (double) mpImpl->mnHeight;
+        pCoord[1] = pCoord[7] = 1.0f - maRect.Bottom() / (double) mpImpl->mnHeight;
+    }
+    else
+    {
+        pCoord[0] = pCoord[2] = 0;
+        pCoord[4] = pCoord[6] = 1;
+        pCoord[1] = pCoord[7] = 0;
+        pCoord[3] = pCoord[5] = 1;
+    }
+}
+
 GLenum OpenGLTexture::GetFilter() const
 {
     if( mpImpl )
@@ -226,7 +244,7 @@ void OpenGLTexture::Unbind()
 bool OpenGLTexture::Draw()
 {
     GLfloat aPosition[8] = { -1, -1, -1, 1, 1, 1, 1, -1 };
-    GLfloat aTexCoord[8] = {  0,  0,  0, 1, 1, 1, 1,  0 };
+    GLfloat aTexCoord[8];
 
     if( mpImpl == NULL )
     {
@@ -235,15 +253,8 @@ bool OpenGLTexture::Draw()
     }
 
     SAL_INFO( "vcl.opengl", "Drawing texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
-    if( GetWidth() != mpImpl->mnWidth || GetHeight() != mpImpl->mnHeight )
-    {
-        // FIXME: lfrb: check math
-        aTexCoord[0] = aTexCoord[2] = maRect.Left() / (double) mpImpl->mnWidth;
-        aTexCoord[4] = aTexCoord[6] = maRect.Right() / (double) mpImpl->mnWidth;
-        aTexCoord[1] = aTexCoord[7] = maRect.Top() / (double) mpImpl->mnHeight;
-        aTexCoord[3] = aTexCoord[5] = maRect.Bottom() / (double) mpImpl->mnHeight;
-    }
 
+    GetWholeCoord( aTexCoord );
     glActiveTexture( GL_TEXTURE0 );
     glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture );
     glEnableVertexAttribArray( 0 );
diff --git a/vcl/source/opengl/OpenGLContext.cxx b/vcl/source/opengl/OpenGLContext.cxx
index 424d2dc..1f82b59 100644
--- a/vcl/source/opengl/OpenGLContext.cxx
+++ b/vcl/source/opengl/OpenGLContext.cxx
@@ -30,6 +30,7 @@
 #include "svdata.hxx"
 
 #include <opengl/framebuffer.hxx>
+#include <opengl/program.hxx>
 #include <opengl/texture.hxx>
 
 using namespace com::sun::star;
@@ -59,6 +60,7 @@ OpenGLContext::OpenGLContext():
     mpCurrentFramebuffer(NULL),
     mpFirstFramebuffer(NULL),
     mpLastFramebuffer(NULL),
+    mpCurrentProgram(NULL),
     mnPainting(0),
     mpPrevContext(NULL),
     mpNextContext(NULL)
@@ -1382,4 +1384,37 @@ void OpenGLContext::ReleaseFramebuffer( OpenGLFramebuffer* pFramebuffer )
         pFramebuffer->DetachTexture();
 }
 
+OpenGLProgram* OpenGLContext::GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader )
+{
+    boost::unordered_map<ProgramKey, OpenGLProgram*>::iterator it;
+    ProgramKey aKey( rVertexShader, rFragmentShader );
+
+    it = maPrograms.find( aKey );
+    if( it != maPrograms.end() )
+        return it->second;
+
+    OpenGLProgram* pProgram = new OpenGLProgram;
+    if( !pProgram->Load( rVertexShader, rFragmentShader ) )
+    {
+        delete pProgram;
+        return NULL;
+    }
+
+    maPrograms[aKey] = pProgram;
+    return pProgram;
+}
+
+OpenGLProgram* OpenGLContext::UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader )
+{
+    OpenGLProgram* pProgram = GetProgram( rVertexShader, rFragmentShader );
+
+    if( pProgram == mpCurrentProgram )
+        return pProgram;
+
+    mpCurrentProgram = pProgram;
+    mpCurrentProgram->Use();
+
+    return mpCurrentProgram;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list