[Libreoffice-commits] core.git: Branch 'feature/fixes18' - vcl/inc vcl/opengl vcl/win

Tomaž Vajngerl tomaz.vajngerl at collabora.com
Mon Mar 14 10:55:26 UTC 2016


 vcl/inc/opengl/AccumulatedTextures.hxx |   77 ++++++++++++++++++++++
 vcl/inc/openglgdiimpl.hxx              |    5 +
 vcl/opengl/gdiimpl.cxx                 |  114 +++++++++++++++++++++++++++++++++
 vcl/win/source/gdi/winlayout.cxx       |   16 +---
 4 files changed, 201 insertions(+), 11 deletions(-)

New commits:
commit edf30eb54e685ee6ffb85ab8faccc9e744504399
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Mon Mar 14 11:42:21 2016 +0100

    opengl: draw text with minimum texture switching
    
    In GL we need to draw characters into a bitmap and upload that to
    the GPU. This is expensive so we cache characters in texture
    atlases. Until now when we have drawn from a texture atlas we
    have always done this sequentially for every character and changed
    textures atlases quite extensively. This is quite bad for
    performance. This change deferrs drawing as long as possible and
    sorts drawing commands per texture so when we need to draw we
    draw with minimum texture rebinding.
    
    Change-Id: I237beaa9f3c3a4bcbd9750e107f017911c967704

diff --git a/vcl/inc/opengl/AccumulatedTextures.hxx b/vcl/inc/opengl/AccumulatedTextures.hxx
new file mode 100644
index 0000000..3fe327c
--- /dev/null
+++ b/vcl/inc/opengl/AccumulatedTextures.hxx
@@ -0,0 +1,77 @@
+/* -*- 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_ACCUMULATEDTEXTURES_H
+#define INCLUDED_VCL_INC_OPENGL_ACCUMULATEDTEXTURES_H
+
+#include <o3tl/make_unique.hxx>
+#include "opengl/texture.hxx"
+#include <memory>
+
+struct AccumulatedTexturesEntry
+{
+    OpenGLTexture maTexture;
+    std::unordered_map<SalColor, std::vector<SalTwoRect>> maColorTwoRectMap;
+
+    AccumulatedTexturesEntry(const OpenGLTexture& rTexture)
+        : maTexture(rTexture)
+    {}
+
+    void insert(const SalColor& aColor, const SalTwoRect& r2Rect)
+    {
+        maColorTwoRectMap[aColor].push_back(r2Rect);
+    }
+};
+
+class AccumulatedTextures
+{
+private:
+    typedef std::unordered_map<GLuint, std::unique_ptr<AccumulatedTexturesEntry>> AccumulatedTexturesMap;
+
+    AccumulatedTexturesMap maEntries;
+
+public:
+    AccumulatedTextures()
+    {}
+
+    bool empty()
+    {
+        return maEntries.empty();
+    }
+
+    void clear()
+    {
+        maEntries.clear();
+    }
+
+    void insert(const OpenGLTexture& rTexture, const SalColor& aColor, const SalTwoRect& r2Rect)
+    {
+        GLuint nTextureId = rTexture.Id();
+
+        auto iterator = maEntries.find(nTextureId);
+
+        if (iterator == maEntries.end())
+        {
+            maEntries[nTextureId] = o3tl::make_unique<AccumulatedTexturesEntry>(rTexture);
+        }
+
+        std::unique_ptr<AccumulatedTexturesEntry>& rEntry = maEntries[nTextureId];
+        rEntry->insert(aColor, r2Rect);
+    }
+
+    AccumulatedTexturesMap& getAccumulatedTexturesMap()
+    {
+        return maEntries;
+    }
+};
+
+#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 ca8232a..8d6eb1a 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -28,6 +28,7 @@
 #include "opengl/program.hxx"
 #include "opengl/texture.hxx"
 #include "regionband.hxx"
+#include "opengl/AccumulatedTextures.hxx"
 
 #include <vcl/opengl/OpenGLContext.hxx>
 
@@ -99,6 +100,8 @@ protected:
     SalColor mProgramSolidColor;
     double mProgramSolidTransparency;
 
+    std::unique_ptr<AccumulatedTextures> mpAccumulatedTextures;
+
     void ImplInitClipRegion();
     void ImplSetClipBit( const vcl::Region& rClip, GLuint nMask );
     void ImplDrawLineAA( double nX1, double nY1, double nX2, double nY2, bool edge = false );
@@ -144,6 +147,8 @@ public:
     void DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect );
     void DrawAxialGradient( const Gradient& rGradient, const Rectangle& rRect );
     void DrawRadialGradient( const Gradient& rGradient, const Rectangle& rRect );
+    void DeferredTextDraw(const OpenGLTexture& rTexture, const SalColor nMaskColor, const SalTwoRect& rPosAry);
+    void FlushDeferredDrawing(bool bInDraw = false);
 
 public:
     // get the width of the device
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 15cec83..567ecf2 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -83,6 +83,7 @@ OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryPr
     , mnDrawCountAtFlush(0)
     , mProgramSolidColor(SALCOLOR_NONE)
     , mProgramSolidTransparency(0.0)
+    , mpAccumulatedTextures(new AccumulatedTextures)
 {
 }
 
@@ -203,6 +204,8 @@ void OpenGLSalGraphicsImpl::PreDraw(XOROption eOpt)
     glViewport( 0, 0, GetWidth(), GetHeight() );
     CHECK_GL_ERROR();
 
+    FlushDeferredDrawing(true);
+
     ImplInitClipRegion();
     CHECK_GL_ERROR();
 
@@ -353,6 +356,11 @@ const vcl::Region& OpenGLSalGraphicsImpl::getClipRegion() const
 bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region& rClip )
 {
     VCL_GL_INFO( "::setClipRegion " << rClip );
+    if (maClipRegion == rClip)
+        return true;
+
+    FlushDeferredDrawing();
+
     maClipRegion = rClip;
 
     mbUseStencil = false;
@@ -369,6 +377,11 @@ bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region& rClip )
 void OpenGLSalGraphicsImpl::ResetClipRegion()
 {
     VCL_GL_INFO( "::ResetClipRegion" );
+    if (maClipRegion.IsEmpty())
+        return;
+
+    FlushDeferredDrawing();
+
     maClipRegion.SetEmpty();
     mbUseScissor = false;
     mbUseStencil = false;
@@ -1555,6 +1568,99 @@ void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture& rMask, SalColor nMaskColor,
     mpProgram->Clean();
 }
 
+void OpenGLSalGraphicsImpl::DeferredTextDraw(const OpenGLTexture& rTexture, SalColor aMaskColor, const SalTwoRect& rPosAry)
+{
+    mpAccumulatedTextures->insert(rTexture, aMaskColor, rPosAry);
+}
+
+void OpenGLSalGraphicsImpl::FlushDeferredDrawing(bool bIsInDraw)
+{
+    if (mpAccumulatedTextures->empty())
+        return;
+
+    if (!bIsInDraw)
+        PreDraw();
+
+    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())
+    {
+        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()];
+
+
+
+        if (!UseSolid(MAKE_SALCOLOR(aUseColor.GetRed(), aUseColor.GetGreen(), aUseColor.GetBlue())))
+            return;
+        for (auto rColorTwoRectPair: rPair.second->maColorTwoRectMap)
+        {
+            for (SalTwoRect& rPosAry : rColorTwoRectPair.second)
+            {
+                DrawRect(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
+            }
+        }
+    }
+#endif
+
+    if( !UseProgram( "textureVertexShader", "maskFragmentShader" ) )
+        return;
+    mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    for (auto& rPair : mpAccumulatedTextures->getAccumulatedTexturesMap())
+    {
+        OpenGLTexture& rTexture = rPair.second->maTexture;
+        mpProgram->SetTexture("sampler", rTexture);
+        for (auto& rColorTwoRectPair: rPair.second->maColorTwoRectMap)
+        {
+            mpProgram->SetColor("color", rColorTwoRectPair.first, 0);
+            for (SalTwoRect& rPosAry : rColorTwoRectPair.second)
+            {
+                GLfloat pTexCoord[8];
+                rTexture.GetCoord(pTexCoord, rPosAry, false);
+                mpProgram->SetTextureCoord(pTexCoord);
+
+                GLfloat nX1 = rPosAry.mnDestX;
+                GLfloat nY1 = rPosAry.mnDestY;
+                GLfloat nX2 = rPosAry.mnDestX + rPosAry.mnDestWidth;
+                GLfloat nY2 = rPosAry.mnDestY + rPosAry.mnDestHeight;
+
+                GLfloat pVertices[] =
+                {
+                    nX1, nY2,
+                    nX1, nY1,
+                    nX2, nY1,
+                    nX2, nY2
+                };
+                ApplyProgramMatrices();
+                mpProgram->SetVertices(pVertices);
+                glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+            }
+        }
+    }
+    mpProgram->Clean();
+    mpAccumulatedTextures->clear();
+    if (!bIsInDraw)
+        PostDraw();
+}
+
 void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect )
 {
     OpenGLZone aZone;
@@ -1918,6 +2024,8 @@ void OpenGLSalGraphicsImpl::DoCopyBits( const SalTwoRect& rPosAry, OpenGLSalGrap
 {
     VCL_GL_INFO( "::copyBits" );
 
+    rImpl.FlushDeferredDrawing();
+
     if( !rImpl.maOffscreenTex )
     {
         VCL_GL_INFO( "::copyBits - skipping copy of un-initialized framebuffer contents of size "
@@ -2014,6 +2122,8 @@ SalBitmap* OpenGLSalGraphicsImpl::getBitmap( long nX, long nY, long nWidth, long
 
 SalColor OpenGLSalGraphicsImpl::getPixel( long nX, long nY )
 {
+    FlushDeferredDrawing();
+
     char pixel[3] = { 0, 0, 0 };
 
     PreDraw( XOROption::IMPLEMENT_XOR );
@@ -2270,6 +2380,8 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly,
 
 void OpenGLSalGraphicsImpl::flush()
 {
+    FlushDeferredDrawing();
+
     if( IsOffscreen() )
         return;
 
@@ -2284,6 +2396,8 @@ void OpenGLSalGraphicsImpl::flush()
 
 void OpenGLSalGraphicsImpl::doFlush()
 {
+    FlushDeferredDrawing();
+
     if( IsOffscreen() )
         return;
 
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
index a37b198..715d5c6 100644
--- a/vcl/win/source/gdi/winlayout.cxx
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -236,7 +236,7 @@ bool ImplWinFontEntry::GlyphIsCached(int nGlyphIndex) const
 
 bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
 {
-    const int DEFAULT_CHUNK_SIZE = 20;
+    const int DEFAULT_CHUNK_SIZE = 40;
 
     if (nGlyphIndex == DROPPED_OUTGLYPH)
         return true;
@@ -1443,8 +1443,6 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
     if (!pImpl)
         return false;
 
-    pImpl->PreDraw();
-
     HFONT hOrigFont = DisableFontScaling();
     Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
 
@@ -1464,7 +1462,8 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
                            rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
                            nAdvance + aPos.X() - rChunk.getExtraOffset(), aPos.Y() - rChunk.mnAscent - rChunk.getExtraOffset(),
                            rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
-        pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects);
+
+        pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects);
 
         nAdvance += mpGlyphAdvances[i];
     }
@@ -1472,8 +1471,6 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
     if( hOrigFont )
         DeleteFont(SelectFont(hDC, hOrigFont));
 
-    pImpl->PostDraw();
-
     return true;
 }
 
@@ -2900,8 +2897,6 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons
     if (!pImpl)
         return false;
 
-    pImpl->PreDraw();
-
     // FIXME: This code snippet is mostly copied from the one in
     // UniscribeLayout::DrawTextImpl. Should be factored out.
     int nBaseClusterOffset = 0;
@@ -2960,7 +2955,7 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons
                                    rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
                                    aPos.X(), nAdvance + aPos.Y(),
                                    rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
-                pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects);
+                pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects);
             }
             else
             {
@@ -2968,12 +2963,11 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons
                                    rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
                                    nAdvance + aPos.X() + mpGlyphOffsets[i].du - rChunk.getExtraOffset(), aPos.Y() + mpGlyphOffsets[i].dv - rChunk.mnAscent - rChunk.getExtraOffset(),
                                    rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
-                pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects);
+                pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects);
             }
             nAdvance += pGlyphWidths[i];
         }
     }
-    pImpl->PostDraw();
 
     return true;
 }


More information about the Libreoffice-commits mailing list