[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