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 <[email protected]> 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; }
_______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
