opengl: batch drawing of pixel, line, rect draw calls

Change-Id: Ib1619fa476f488c5315411b1ad4d1b7464c70c69
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 83383ff..06e3153 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -621,6 +621,7 @@ else
	vcl/opengl/texture \
	vcl/opengl/FixedTextureAtlas \
	vcl/opengl/PackedTextureAtlas \
	vcl/opengl/RenderList \
    vcl/source/opengl/OpenGLContext \
    vcl/source/opengl/OpenGLHelper \
    vcl/source/window/openglwin \
diff --git a/vcl/inc/opengl/RenderList.hxx b/vcl/inc/opengl/RenderList.hxx
new file mode 100644
index 0000000..0ba977a
--- /dev/null
+++ b/vcl/inc/opengl/RenderList.hxx
@@ -0,0 +1,98 @@
/* -*- 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_RENDERLIST_H
#define INCLUDED_VCL_INC_OPENGL_RENDERLIST_H

#include <glm/glm.hpp>

#include <vcl/opengl/OpenGLHelper.hxx>
#include <vcl/salgtype.hxx>
#include <basegfx/range/b2drange.hxx>

struct RenderParameters
{
    std::vector<GLfloat>   maVertices;
    std::vector<GLfloat>   maExtrusionVectors;
    std::vector<glm::vec4> maColors;
};

struct RenderEntry
{
    RenderParameters maTriangleParameters;
    RenderParameters maLineParameters;
    RenderParameters maLineAAParameters;

    bool hasTriangles()
    {
        return !maTriangleParameters.maVertices.empty();
    }

    bool hasLines()
    {
        return !maLineParameters.maVertices.empty();
    }

    bool hasLinesAA()
    {
        return !maLineAAParameters.maVertices.empty();
    }
};

class RenderList
{
private:
    basegfx::B2DRange maOverlapTrackingRectangle;
    std::vector<RenderEntry> maRenderEntries;

    void checkOverlapping(const basegfx::B2DRange& rDrawRectangle)
    {
        if (maRenderEntries.empty() || maOverlapTrackingRectangle.overlaps(rDrawRectangle))
        {
            maRenderEntries.resize(maRenderEntries.size() + 1);
            maOverlapTrackingRectangle = rDrawRectangle;
        }
        else
        {
            maOverlapTrackingRectangle.expand(rDrawRectangle);
        }
    }

public:

    RenderList() = default;

    bool empty()
    {
        return maRenderEntries.empty();
    }

    void clear()
    {
        maRenderEntries.clear();
        maOverlapTrackingRectangle.reset();
    }

    std::vector<RenderEntry>& getEntries()
    {
        return maRenderEntries;
    }

    void addDrawPixel(long nX, long nY, const SalColor& rColor);

    void addDrawRectangle(long nX, long nY, long nWidth, long nHeight,
                          const SalColor& rLineColor, const SalColor& rFillColor);

    void addDrawLine(long nX1, long nY1, long nX2, long nY2, const SalColor& rLineColor, bool bUseAA);
};

#endif // INCLUDED_VCL_INC_OPENGL_RENDERLIST_H

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/opengl/VertexUtils.hxx b/vcl/inc/opengl/VertexUtils.hxx
index becc62b..c64340b 100644
--- a/vcl/inc/opengl/VertexUtils.hxx
+++ b/vcl/inc/opengl/VertexUtils.hxx
@@ -39,6 +39,44 @@ inline void addRectangle<GL_TRIANGLE_FAN>(std::vector<GLfloat>& rVertices, GLflo
    });
}

inline glm::vec4 createGLColor(const SalColor& rColor, GLfloat rTransparency)
{
    return glm::vec4(SALCOLOR_RED(rColor)   / 255.0f,
                     SALCOLOR_GREEN(rColor) / 255.0f,
                     SALCOLOR_BLUE(rColor)  / 255.0f,
                     1.0f - rTransparency);
}

template<GLenum TYPE>
inline void addQuadColors(std::vector<glm::vec4>& rColors, const SalColor& rColor, GLfloat rTransparency);

template<>
inline void addQuadColors<GL_TRIANGLES>(std::vector<glm::vec4>& rColors, const SalColor& rColor, GLfloat rTransparency)
{
    glm::vec4 color = createGLColor(rColor, rTransparency);

    rColors.insert(rColors.end(), {
        color, color, color,
        color, color, color
    });
}

template<GLenum TYPE>
inline void addQuadEmptyExtrusionVectors(std::vector<GLfloat>& rExtrusions);

template<>
inline void addQuadEmptyExtrusionVectors<GL_TRIANGLES>(std::vector<GLfloat>& rExtrusions)
{
    rExtrusions.insert(rExtrusions.end(), {
        0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f,
    });
}

inline void addLineVertex(std::vector<GLfloat>& rVertices, std::vector<GLfloat>& rExtrusionVectors, glm::vec2 point, glm::vec2 extrusionVector, float length)
{
    rVertices.push_back(point.x);
diff --git a/vcl/inc/opengl/program.hxx b/vcl/inc/opengl/program.hxx
index 3c194d8..c737c12 100644
--- a/vcl/inc/opengl/program.hxx
+++ b/vcl/inc/opengl/program.hxx
@@ -22,6 +22,7 @@
#include <tools/color.hxx>
#include <opengl/texture.hxx>

#include <glm/glm.hpp>
#include <unordered_map>

typedef std::unordered_map< OString, GLuint, OStringHash > UniformCache;
@@ -52,7 +53,9 @@ private:
    GLuint          mnTexCoordAttrib;
    GLuint          mnAlphaCoordAttrib;
    GLuint          mnMaskCoordAttrib;
    GLuint          mnNormalAttrib;
    GLuint          mnExtrusionVectorsAttrib;
    GLuint          mnVertexColorsAttrib;

    TextureList     maTextures;
    bool            mbBlending;

@@ -79,6 +82,7 @@ public:
    void SetAlphaCoord( const GLvoid* pData );
    void SetMaskCoord(const GLvoid* pData);
    void SetExtrusionVectors(const GLvoid* pData);
    void SetVertexColors(std::vector<glm::vec4>& rColorVector);

    void SetUniform1f( const OString& rName, GLfloat v1 );
    void SetUniform2f( const OString& rName, GLfloat v1, GLfloat v2 );
diff --git a/vcl/inc/opengl/texture.hxx b/vcl/inc/opengl/texture.hxx
index 5b4ccff..e120c08 100644
--- a/vcl/inc/opengl/texture.hxx
+++ b/vcl/inc/opengl/texture.hxx
@@ -78,6 +78,8 @@ private:
    ImplOpenGLTexture* mpImpl;
    int mnSlotNumber;

    inline bool GetTextureRect(const SalTwoRect& rPosAry, bool bInverted, GLfloat& x1, GLfloat& x2, GLfloat& y1, GLfloat& y2) const;

public:
                    OpenGLTexture();
                    OpenGLTexture(ImplOpenGLTexture* pImpl, Rectangle aRectangle, int nSlotNumber);
@@ -124,6 +126,10 @@ template<> void OpenGLTexture::FillCoords<GL_TRIANGLES>(
    std::vector<GLfloat>& aCoord, const SalTwoRect& rPosAry, bool bInverted)
    const;

template<> void OpenGLTexture::FillCoords<GL_TRIANGLE_FAN>(
    std::vector<GLfloat>& aCoord, const SalTwoRect& rPosAry, bool bInverted)
    const;

#endif // INCLUDED_VCL_INC_OPENGL_TEXTURE_H

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index ee8c7e2..09343c8 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -30,6 +30,7 @@
#include "opengl/program.hxx"
#include "opengl/texture.hxx"
#include "opengl/AccumulatedTextures.hxx"
#include "opengl/RenderList.hxx"

#include <memory>

@@ -100,7 +101,8 @@ protected:
    SalColor mProgramSolidColor;
    double mProgramSolidTransparency;

    std::unique_ptr<AccumulatedTextures> mpAccumulatedTextures;
    std::unique_ptr<AccumulatedTextures>  mpAccumulatedTextures;
    std::unique_ptr<RenderList> mpRenderList;

    void ImplInitClipRegion();
    void ImplSetClipBit( const vcl::Region& rClip, GLuint nMask );
@@ -114,12 +116,12 @@ public:
    bool UseSolid( SalColor nColor, sal_uInt8 nTransparency );
    bool UseSolid( SalColor nColor, double fTransparency );
    bool UseSolid( SalColor nColor );
    bool UseSolid();
    bool UseLine(SalColor nColor, double fTransparency, GLfloat fLineWidth, bool bUseAA);
    bool UseLine(GLfloat fLineWidth, bool bUseAA);
    bool UseInvert50();
    bool UseInvert(SalInvert nFlags);

    void DrawPoint( long nX, long nY );
    void DrawLine( double nX1, double nY1, double nX2, double nY2 );
    void DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry, bool blockAA = false );
    void DrawConvexPolygon( const tools::Polygon& rPolygon, bool blockAA = false );
    void DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid, bool blockAA = false );
diff --git a/vcl/opengl/RenderList.cxx b/vcl/opengl/RenderList.cxx
new file mode 100644
index 0000000..008be02
--- /dev/null
+++ b/vcl/opengl/RenderList.cxx
@@ -0,0 +1,122 @@
/* -*- 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/RenderList.hxx"
#include "opengl/VertexUtils.hxx"

namespace
{

inline void lclAddLineSegmentVertices(RenderParameters& rRenderParameter, GLfloat fX1, GLfloat fY1, GLfloat fX2, GLfloat fY2,
                                   const SalColor& rColor, double fTransparency)
{
    glm::vec2 aPoint1(fX1, fY1);
    glm::vec2 aPoint2(fX2, fY2);

    glm::vec2 aLineVector = vcl::vertex::normalize(aPoint2 - aPoint1);
    glm::vec2 aNormal = glm::vec2(-aLineVector.y, aLineVector.x);

    vcl::vertex::addLinePointFirst(rRenderParameter.maVertices, rRenderParameter.maExtrusionVectors,
                                   aPoint1, aNormal, 1.0f);
    vcl::vertex::addLinePointNext (rRenderParameter.maVertices, rRenderParameter.maExtrusionVectors,
                                   aPoint1, aNormal, 1.0f,
                                   aPoint2, aNormal, 1.0f);

    vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, rColor, fTransparency);
}

} // end anonymous namespace

void RenderList::addDrawPixel(long nX, long nY, const SalColor& rColor)
{
    if (rColor == SALCOLOR_NONE)
        return;

    checkOverlapping(basegfx::B2DRange(nX, nY, nX, nY));

    RenderParameters& rRenderParameter = maRenderEntries.back().maTriangleParameters;
    vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, nX - 0.5f, nY - 0.5f, nX + 0.5f, nY + 0.5f);
    vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, rColor, 0.0f);
    vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
}

void RenderList::addDrawRectangle(long nX, long nY, long nWidth, long nHeight, const SalColor& rLineColor, const SalColor& rFillColor)
{
    if (rLineColor == SALCOLOR_NONE && rFillColor == SALCOLOR_NONE)
        return;

    GLfloat fX1(nX);
    GLfloat fY1(nY);
    GLfloat fX2(nX + nWidth  - 1);
    GLfloat fY2(nY + nHeight - 1);

    checkOverlapping(basegfx::B2DRange(fX1, fY1, fX2, fY2));

    RenderParameters& rRenderParameter = maRenderEntries.back().maTriangleParameters;

    // Draw rectangle stroke with line color
    if (rLineColor != SALCOLOR_NONE)
    {
        vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY1 - 0.5f, fX1 + 0.5f, fY2 + 0.5f);
        vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY1 + 0.5f);
        vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX2 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY2 + 0.5f);
        vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY2 - 0.5f, fX2 + 0.5f, fY2 + 0.5f);

        vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, rLineColor, 0.0f);
        vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, rLineColor, 0.0f);
        vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, rLineColor, 0.0f);
        vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, rLineColor, 0.0f);

        vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
        vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
        vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
        vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
    }

    if (rFillColor != SALCOLOR_NONE)
    {
        if (rLineColor == SALCOLOR_NONE)
        {
            // Draw rectangle stroke with fill color
            vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY1 - 0.5f, fX1 + 0.5f, fY2 + 0.5f);
            vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY1 + 0.5f);
            vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX2 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY2 + 0.5f);
            vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY2 - 0.5f, fX2 + 0.5f, fY2 + 0.5f);

            vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, rFillColor, 0.0f);
            vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, rFillColor, 0.0f);
            vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, rFillColor, 0.0f);
            vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, rFillColor, 0.0f);

            vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
            vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
            vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
            vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
        }
        // Draw rectangle fill with fill color
        vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 + 0.5f, fY1 + 0.5f, fX2 - 0.5f, fY2 - 0.5f);
        vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, rFillColor, 0.0f);
        vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
    }
}

void RenderList::addDrawLine(long nX1, long nY1, long nX2, long nY2, const SalColor& rLineColor, bool bUseAA)
{
    if (rLineColor == SALCOLOR_NONE)
        return;

    checkOverlapping(basegfx::B2DRange(nX1, nY1, nX2, nY2));

    RenderParameters& rRenderParameter = bUseAA ? maRenderEntries.back().maLineAAParameters :
                                                  maRenderEntries.back().maLineParameters;
    lclAddLineSegmentVertices(rRenderParameter, nX1, nY1, nX2, nY2, rLineColor, 0.0f);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/combinedFragmentShader.glsl b/vcl/opengl/combinedFragmentShader.glsl
index 8d73d08..b200601 100644
--- a/vcl/opengl/combinedFragmentShader.glsl
+++ b/vcl/opengl/combinedFragmentShader.glsl
@@ -8,8 +8,12 @@
 */

varying float fade_factor; // 0->1 fade factor used for AA
uniform vec4 color;

#ifdef USE_VERTEX_COLORS
varying vec4 vertex_color;
#endif

uniform vec4 color;
uniform float line_width;
uniform float feather;

@@ -22,6 +26,12 @@ void main()
{
    float alpha = 1.0;

#ifdef USE_VERTEX_COLORS
    vec4 result = vertex_color;
#else
    vec4 result = color;
#endif

    if (type == TYPE_LINE)
    {
        float start = (line_width / 2.0) - feather; // where we start to apply alpha
@@ -36,10 +46,9 @@ void main()
        alpha = clamp(dist, 0.0, 1.0);
    }

    vec4 result_color = color;
    result_color.a = result_color.a * alpha;
    result.a = result.a * alpha;

    gl_FragColor = result_color;
    gl_FragColor = result;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/combinedVertexShader.glsl b/vcl/opengl/combinedVertexShader.glsl
index 9272544..8c6a856 100644
--- a/vcl/opengl/combinedVertexShader.glsl
+++ b/vcl/opengl/combinedVertexShader.glsl
@@ -9,8 +9,14 @@

attribute vec2 position;
attribute vec4 extrusion_vectors;
#ifdef USE_VERTEX_COLORS
attribute vec4 vertex_color_in;
#endif

varying float fade_factor; // fade factor for anti-aliasing
#ifdef USE_VERTEX_COLORS
varying vec4 vertex_color;
#endif

uniform float line_width;
uniform float feather; // width where we fade the line
@@ -42,6 +48,9 @@ void main()
   }

   gl_Position = mvp * final_position;
#ifdef USE_VERTEX_COLORS
   vertex_color = vertex_color_in;
#endif
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 7c8f65a..fe2151e 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -85,6 +85,7 @@ OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryPr
    , mProgramSolidColor(SALCOLOR_NONE)
    , mProgramSolidTransparency(0.0)
    , mpAccumulatedTextures(new AccumulatedTextures)
    , mpRenderList(new RenderList)
{
}

@@ -549,9 +550,7 @@ bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor, sal_uInt8 nTransparency )
{
    if( nColor == SALCOLOR_NONE )
        return false;
    if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
        return false;
    mpProgram->SetShaderType(DrawShaderType::Normal);
    UseSolid();
    mpProgram->SetColor( "color", nColor, nTransparency );
#ifdef DBG_UTIL
    mProgramIsSolidColor = true;
@@ -566,9 +565,7 @@ bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor, double fTransparency )
{
    if( nColor == SALCOLOR_NONE )
        return false;
    if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
        return false;
    mpProgram->SetShaderType(DrawShaderType::Normal);
    UseSolid();
    mpProgram->SetColorf( "color", nColor, fTransparency );
#ifdef DBG_UTIL
    mProgramIsSolidColor = true;
@@ -578,6 +575,14 @@ bool OpenGLSalGraphicsImpl::UseSolid( SalColor nColor, double fTransparency )
    return true;
}

bool OpenGLSalGraphicsImpl::UseSolid()
{
    if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
        return false;
    mpProgram->SetShaderType(DrawShaderType::Normal);
    return true;
}

bool OpenGLSalGraphicsImpl::UseInvert50()
{
    if( !UseProgram( "dumbVertexShader", "invert50FragmentShader" ) )
@@ -612,35 +617,6 @@ bool OpenGLSalGraphicsImpl::UseInvert( SalInvert nFlags )
    return true;
}

void OpenGLSalGraphicsImpl::DrawPoint( long nX, long nY )
{
    OpenGLZone aZone;

    std::vector<GLfloat> pPoint {
        GLfloat(nX), GLfloat(nY)
    };

    std::vector<GLfloat> aExtrusion(3, 0);
    mpProgram->SetExtrusionVectors(aExtrusion.data());
    ApplyProgramMatrices(0.5f);
    mpProgram->DrawArrays(GL_POINTS, pPoint);
    CHECK_GL_ERROR();
}

void OpenGLSalGraphicsImpl::DrawLine( double nX1, double nY1, double nX2, double nY2 )
{
    OpenGLZone aZone;

    std::vector<GLfloat> pPoint {
        GLfloat(nX1), GLfloat(nY1),
        GLfloat(nX2), GLfloat(nY2)
    };

    ApplyProgramMatrices(0.5f);
    mpProgram->DrawArrays(GL_LINES, pPoint);
    CHECK_GL_ERROR();
}

void OpenGLSalGraphicsImpl::DrawLineCap(float x1, float y1, float x2, float y2, css::drawing::LineCap eLineCap, float fLineWidth)
{
    if (eLineCap != css::drawing::LineCap_ROUND && eLineCap != css::drawing::LineCap_SQUARE)
@@ -906,16 +882,8 @@ bool OpenGLSalGraphicsImpl::UseLine(SalColor nColor, double fTransparency, GLflo
{
    if( nColor == SALCOLOR_NONE )
        return false;
    if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
        return false;
    mpProgram->SetShaderType(DrawShaderType::Line);
    UseLine(fLineWidth, bUseAA);
    mpProgram->SetColorf("color", nColor, fTransparency);
    mpProgram->SetUniform1f("line_width", fLineWidth);
    // The width of the feather - area we make lineary transparent in VS.
    // Good AA value is 0.5f, no AA if feather 0.0f
    mpProgram->SetUniform1f("feather", bUseAA ? 0.5f : 0.0f);
    // We need blending or AA won't work correctly
    mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
#ifdef DBG_UTIL
    mProgramIsSolidColor = true;
#endif
@@ -924,6 +892,20 @@ bool OpenGLSalGraphicsImpl::UseLine(SalColor nColor, double fTransparency, GLflo
    return true;
}

bool OpenGLSalGraphicsImpl::UseLine(GLfloat fLineWidth, bool bUseAA)
{
    if (!UseProgram("combinedVertexShader", "combinedFragmentShader"))
        return false;
    mpProgram->SetShaderType(DrawShaderType::Line);
    mpProgram->SetUniform1f("line_width", fLineWidth);
    // The width of the feather - area we make lineary transparent in VS.
    // Good AA value is 0.5f, no AA if feather 0.0f
    mpProgram->SetUniform1f("feather", bUseAA ? 0.5f : 0.0f);
    // We need blending or AA won't work correctly
    mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    return true;
}

void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry, bool blockAA )
{
    OpenGLZone aZone;
@@ -1524,76 +1506,101 @@ void OpenGLSalGraphicsImpl::DeferredTextDraw(OpenGLTexture& rTexture, SalColor a

void OpenGLSalGraphicsImpl::FlushDeferredDrawing()
{
    if (mpAccumulatedTextures->empty())
    if (mpAccumulatedTextures->empty() && mpRenderList->empty())
        return;

    InitializePreDrawState();
    VCL_GL_INFO("FlushDeferredDrawing: " << mpRenderList->getEntries().size());

    VCL_GL_INFO("FlushDeferredDrawing");

    OpenGLZone aZone;

#if 0 // Draw a background rect under text for debugging - same color shows text from the same texture
    static sal_uInt8 r = 0xBE;
    static sal_uInt8 g = 0xF0;
    static sal_uInt8 b = 0xFF;
    static std::unordered_map<GLuint, Color> aColorForTextureMap;


    for (auto& rPair : mpAccumulatedTextures->getAccumulatedTexturesMap())
    if (!mpAccumulatedTextures->empty())
    {
        OpenGLTexture& rTexture = rPair.second->maTexture;
        Color aUseColor;
        if (aColorForTextureMap.find(rTexture.Id()) == aColorForTextureMap.end())
        {
            Color aColor(r, g, b);
            sal_uInt16 h,s,br;
            aColor.RGBtoHSB(h, s, br);
            aColor = Color::HSBtoRGB((h + 40) % 360, s, br);
            r = aColor.GetRed();
            g = aColor.GetGreen();
            b = aColor.GetBlue();
            aColorForTextureMap[rTexture.Id()] = aColor;
        }
        aUseColor = aColorForTextureMap[rTexture.Id()];
        InitializePreDrawState();

        if (!UseSolid(MAKE_SALCOLOR(aUseColor.GetRed(), aUseColor.GetGreen(), aUseColor.GetBlue())))
        OpenGLZone aZone;

        if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
            return;
        for (auto rColorTwoRectPair: rPair.second->maColorTextureDrawParametersMap)
        mpProgram->SetShaderType(TextureShaderType::MaskedColor);
        mpProgram->SetIdentityTransform("transform");
        mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        for (auto& rPair : mpAccumulatedTextures->getAccumulatedTexturesMap())
        {
            TextureDrawParameters& rParameters = rColorTwoRectPair.second;
            ApplyProgramMatrices();
            mpProgram->SetTextureCoord(rParameters.maTextureCoords.data());
            mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices);
            OpenGLTexture& rTexture = rPair.second->maTexture;
            mpProgram->SetTexture("texture", rTexture);
            for (auto& rColorTwoRectPair: rPair.second->maColorTextureDrawParametersMap)
            {
                mpProgram->SetColor("color", rColorTwoRectPair.first, 0);
                TextureDrawParameters& rParameters = rColorTwoRectPair.second;
                ApplyProgramMatrices();
                mpProgram->SetTextureCoord(rParameters.maTextureCoords.data());
                mpProgram->SetMaskCoord(rParameters.maTextureCoords.data());
                mpProgram->SetAlphaCoord(rParameters.maTextureCoords.data());
                mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices);
            }
        }
        mpProgram->Clean();
        mpAccumulatedTextures->clear();

        PostDraw();
    }
#endif

    if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader"))
        return;
    mpProgram->SetShaderType(TextureShaderType::MaskedColor);
    mpProgram->SetIdentityTransform("transform");
    mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    for (auto& rPair : mpAccumulatedTextures->getAccumulatedTexturesMap())
    if (!mpRenderList->empty())
    {
        OpenGLTexture& rTexture = rPair.second->maTexture;
        mpProgram->SetTexture("texture", rTexture);
        for (auto& rColorTwoRectPair: rPair.second->maColorTextureDrawParametersMap)
        {
            mpProgram->SetColor("color", rColorTwoRectPair.first, 0);
            TextureDrawParameters& rParameters = rColorTwoRectPair.second;
            ApplyProgramMatrices();
            mpProgram->SetTextureCoord(rParameters.maTextureCoords.data());
            mpProgram->SetMaskCoord(rParameters.maTextureCoords.data());
            mpProgram->SetAlphaCoord(rParameters.maTextureCoords.data());
            mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices);
        }
    }
    mpProgram->Clean();
    mpAccumulatedTextures->clear();
        InitializePreDrawState(XOROption::IMPLEMENT_XOR);

    PostDraw();
        OpenGLZone aZone;
        for (RenderEntry& rRenderEntry : mpRenderList->getEntries())
        {
            if (rRenderEntry.hasTriangles() && UseProgram("combinedVertexShader", "combinedFragmentShader", "#define USE_VERTEX_COLORS"))
            {
                RenderParameters& rParameters = rRenderEntry.maTriangleParameters;
                VCL_GL_INFO("Flush Triangles: " << rParameters.maVertices.size());
                mpProgram->SetShaderType(DrawShaderType::Normal);
                ApplyProgramMatrices(0.5f);
                mpProgram->SetExtrusionVectors(rParameters.maExtrusionVectors.data());
                mpProgram->SetVertexColors(rParameters.maColors);
                mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices);
                CHECK_GL_ERROR();
                mpProgram->Clean();
            }
            if (rRenderEntry.hasLines() && UseProgram("combinedVertexShader", "combinedFragmentShader", "#define USE_VERTEX_COLORS"))
            {
                RenderParameters& rParameters = rRenderEntry.maLineParameters;
                VCL_GL_INFO("Flush Lines: " << rParameters.maVertices.size());
                mpProgram->SetShaderType(DrawShaderType::Line);
                mpProgram->SetUniform1f("line_width", 1.0f);
                mpProgram->SetUniform1f("feather", 0.0f); // Anti-Aliasing disabled
                mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                ApplyProgramMatrices(0.5f);
                mpProgram->SetExtrusionVectors(rParameters.maExtrusionVectors.data());
                mpProgram->SetVertexColors(rParameters.maColors);
                mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices);
                CHECK_GL_ERROR();
                mpProgram->Clean();
            }
            if (rRenderEntry.hasLinesAA() && UseProgram("combinedVertexShader", "combinedFragmentShader", "#define USE_VERTEX_COLORS"))
            {
                RenderParameters& rParameters = rRenderEntry.maLineAAParameters;
                VCL_GL_INFO("Flush Lines AA: " << rParameters.maVertices.size());
                mpProgram->SetShaderType(DrawShaderType::Line);
                mpProgram->SetUniform1f("line_width", 1.0f);
                mpProgram->SetUniform1f("feather", 0.5f); // Anti-Aliasing enabled
                mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                ApplyProgramMatrices(0.5f);
                mpProgram->SetExtrusionVectors(rParameters.maExtrusionVectors.data());
                mpProgram->SetVertexColors(rParameters.maColors);
                mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices);
                CHECK_GL_ERROR();
                mpProgram->Clean();
            }
        }

        mpRenderList->clear();
        PostDraw();
    }

    VCL_GL_INFO("End FlushDeferredDrawing");

}

void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect )
@@ -1702,72 +1709,28 @@ void OpenGLSalGraphicsImpl::DrawRadialGradient( const Gradient& rGradient, const
    DrawRect( rRect );
}


// draw --> LineColor and FillColor and RasterOp and ClipRegion
void OpenGLSalGraphicsImpl::drawPixel( long nX, long nY )
void OpenGLSalGraphicsImpl::drawPixel(long nX, long nY)
{
    VCL_GL_INFO( "::drawPixel" );
    if( mnLineColor != SALCOLOR_NONE )
    {
        PreDraw( XOROption::IMPLEMENT_XOR );
        if( UseSolid( mnLineColor ) )
            DrawPoint( nX, nY );
        PostDraw();
    }
    VCL_GL_INFO("::drawPixel: (" << nX << ", " << nY << ")");
    mpRenderList->addDrawPixel(nX, nY, mnLineColor);
}

void OpenGLSalGraphicsImpl::drawPixel( long nX, long nY, SalColor nSalColor )
void OpenGLSalGraphicsImpl::drawPixel(long nX, long nY, SalColor nSalColor)
{
    VCL_GL_INFO( "::drawPixel" );
    if( nSalColor != SALCOLOR_NONE )
    {
        PreDraw( XOROption::IMPLEMENT_XOR );
        if( UseSolid( nSalColor ) )
            DrawPoint( nX, nY );
        PostDraw();
    }
    VCL_GL_INFO("::drawPixel: (" << nX << ", " << nY << ")");
    mpRenderList->addDrawPixel(nX, nY, nSalColor);
}

void OpenGLSalGraphicsImpl::drawLine( long nX1, long nY1, long nX2, long nY2 )
void OpenGLSalGraphicsImpl::drawLine(long nX1, long nY1, long nX2, long nY2)
{
    VCL_GL_INFO( "::drawLine" );
    if( mnLineColor != SALCOLOR_NONE )
    {
        PreDraw( XOROption::IMPLEMENT_XOR );
        if (UseLine(mnLineColor, 0.0, 1.0f, mrParent.getAntiAliasB2DDraw()))
            DrawLineSegment(nX1, nY1, nX2, nY2);
        PostDraw();
    }
    VCL_GL_INFO("::drawLine (" << nX1 << ", " << nY1 << ") (" << nX2 << ", " << nY2 << ")");
    mpRenderList->addDrawLine(nX1, nY1, nX2, nY2, mnLineColor, mrParent.getAntiAliasB2DDraw());
}

void OpenGLSalGraphicsImpl::drawRect( long nX, long nY, long nWidth, long nHeight )
{
    VCL_GL_INFO( "::drawRect" );
    PreDraw( XOROption::IMPLEMENT_XOR );

    if( UseSolid( mnFillColor ) )
        DrawRect( nX, nY, nWidth, nHeight );

    if( UseSolid( mnLineColor ) )
    {
        GLfloat fX1(nX);
        GLfloat fY1(nY);
        GLfloat fX2(nX + nWidth - 1);
        GLfloat fY2(nY + nHeight - 1);

        std::vector<GLfloat> pPoints {
            fX1, fY1,
            fX2, fY1,
            fX2, fY2,
            fX1, fY2
        };

        ApplyProgramMatrices(0.5f);
        mpProgram->DrawArrays(GL_LINE_LOOP, pPoints);
        CHECK_GL_ERROR();
    }

    PostDraw();
    VCL_GL_INFO("::drawRect (" << nX << ", " << nY << ") [" << nWidth << ", " << nHeight << "]");
    mpRenderList->addDrawRectangle(nX, nY, nWidth, nHeight, mnLineColor, mnFillColor);
}

void OpenGLSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry )
diff --git a/vcl/opengl/program.cxx b/vcl/opengl/program.cxx
index de6cec7..8aadb9d 100644
--- a/vcl/opengl/program.cxx
+++ b/vcl/opengl/program.cxx
@@ -24,8 +24,9 @@ OpenGLProgram::OpenGLProgram() :
    mnTexCoordAttrib( SAL_MAX_UINT32 ),
    mnAlphaCoordAttrib( SAL_MAX_UINT32 ),
    mnMaskCoordAttrib( SAL_MAX_UINT32 ),
    mnNormalAttrib( SAL_MAX_UINT32 ),
    mbBlending( false ),
    mnExtrusionVectorsAttrib( SAL_MAX_UINT32 ),
    mnVertexColorsAttrib( SAL_MAX_UINT32 ),
    mbBlending(false),
    mfLastWidth(0.0),
    mfLastHeight(0.0),
    mfLastPixelOffset(0.0)
@@ -147,7 +148,12 @@ void OpenGLProgram::SetMaskCoord(const GLvoid* pData)

void OpenGLProgram::SetExtrusionVectors(const GLvoid* pData)
{
    SetVertexAttrib(mnNormalAttrib, "extrusion_vectors", pData, 3);
    SetVertexAttrib(mnExtrusionVectorsAttrib, "extrusion_vectors", pData, 3);
}

void OpenGLProgram::SetVertexColors(std::vector<glm::vec4>& rColorVector)
{
    SetVertexAttrib(mnVertexColorsAttrib, "vertex_color_in", glm::value_ptr(rColorVector[0]), 4);
}

void OpenGLProgram::SetShaderType(TextureShaderType eTextureShaderType)
diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx
index 0999484..3de7ac8 100644
--- a/vcl/opengl/texture.cxx
+++ b/vcl/opengl/texture.cxx
@@ -386,18 +386,8 @@ void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool b
    }
}

template <>
void OpenGLTexture::FillCoords<GL_TRIANGLES>(std::vector<GLfloat>& aCoord, const SalTwoRect& rPosAry, bool bInverted) const
bool OpenGLTexture::GetTextureRect(const SalTwoRect& rPosAry, bool bInverted, GLfloat& x1, GLfloat& x2, GLfloat& y1, GLfloat& y2) const
{
    VCL_GL_INFO("Add coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
    VCL_GL_INFO("   With 2Rect Src  [" << rPosAry.mnSrcX << ", " << rPosAry.mnSrcY << "] wh (" << rPosAry.mnSrcWidth << ", " << rPosAry.mnSrcHeight << ")");
    VCL_GL_INFO("   With 2Rect Dest [" << rPosAry.mnDestX << ", " << rPosAry.mnDestY << "] wh (" << rPosAry.mnDestWidth << ", " << rPosAry.mnDestHeight << ")");

    GLfloat x1 = 0.0f;
    GLfloat x2 = 0.0f;
    GLfloat y1 = 0.0f;
    GLfloat y2 = 0.0f;

    if (mpImpl)
    {
        double fTextureWidth(mpImpl->mnWidth);
@@ -416,25 +406,41 @@ void OpenGLTexture::FillCoords<GL_TRIANGLES>(std::vector<GLfloat>& aCoord, const
            y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / fTextureHeight;
            y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / fTextureHeight;
        }
        return true;
    }
    return false;
}

    aCoord.push_back(x1);
    aCoord.push_back(y1);
template <>
void OpenGLTexture::FillCoords<GL_TRIANGLE_FAN>(std::vector<GLfloat>& rCoords, const SalTwoRect& rPosAry, bool bInverted) const
{
    GLfloat x1 = 0.0f;
    GLfloat x2 = 0.0f;
    GLfloat y1 = 0.0f;
    GLfloat y2 = 0.0f;

    aCoord.push_back(x2);
    aCoord.push_back(y1);
    GetTextureRect(rPosAry, bInverted, x1, x2, y1, y2);

    aCoord.push_back(x1);
    aCoord.push_back(y2);
    rCoords.insert(rCoords.end(), {
        x1, y2, x1, y1,
        x2, y1, x2, y2
    });
}

    aCoord.push_back(x1);
    aCoord.push_back(y2);
template <>
void OpenGLTexture::FillCoords<GL_TRIANGLES>(std::vector<GLfloat>& rCoords, const SalTwoRect& rPosAry, bool bInverted) const
{
    GLfloat x1 = 0.0f;
    GLfloat x2 = 0.0f;
    GLfloat y1 = 0.0f;
    GLfloat y2 = 0.0f;

    aCoord.push_back(x2);
    aCoord.push_back(y1);
    GetTextureRect(rPosAry, bInverted, x1, x2, y1, y2);

    aCoord.push_back(x2);
    aCoord.push_back(y2);
    rCoords.insert(rCoords.end(), {
        x1, y1, x2, y1, x1, y2,
        x1, y2, x2, y1, x2, y2
    });
}

void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const