diff options
author | Tomaz Vajngerl <tomaz.vajngerl@collabora.com> | 2016-03-14 11:20:19 +0100 |
---|---|---|
committer | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2016-04-08 19:10:11 +0900 |
commit | 96a098c0e8a009b77a26061dac3318da71d34ee4 (patch) | |
tree | f675129ff246ad644f73717a118cbbdb55b72431 | |
parent | f781997ee1dcb61b01b04cc050001e2f46b12dfe (diff) |
opengl: deferred and optimized (text) texture drawing
Switching between textures is not cheap, so minimizing the amount
of switching performs better. So instead of immediate drawing we
can accumulate texture draw actions and defer drawing as long as
possible. After that switch all accumulated textures and draw
everything needed with one GL draw call.
This is beneficial for text drawing as we cache many glyphs in
per textue.
Change-Id: I1b94b9ac6a5f2c1a3dbbd75f4df76436a5d40f31
-rw-r--r-- | vcl/inc/opengl/AccumulatedTextures.hxx | 112 | ||||
-rw-r--r-- | vcl/inc/opengl/texture.hxx | 4 | ||||
-rw-r--r-- | vcl/inc/openglgdiimpl.hxx | 5 | ||||
-rw-r--r-- | vcl/opengl/gdiimpl.cxx | 96 | ||||
-rw-r--r-- | vcl/opengl/texture.cxx | 46 | ||||
-rw-r--r-- | vcl/win/gdi/winlayout.cxx | 16 |
6 files changed, 268 insertions, 11 deletions
diff --git a/vcl/inc/opengl/AccumulatedTextures.hxx b/vcl/inc/opengl/AccumulatedTextures.hxx new file mode 100644 index 000000000000..9ce170c2a0af --- /dev/null +++ b/vcl/inc/opengl/AccumulatedTextures.hxx @@ -0,0 +1,112 @@ +/* -*- 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 TextureDrawParameters +{ + std::vector<GLfloat> maVertices; + std::vector<GLfloat> maTextureCoords; + GLint getNumberOfVertices() + { + return maVertices.size() / 2; + } +}; + +struct AccumulatedTexturesEntry +{ + OpenGLTexture maTexture; + std::unordered_map<SalColor, TextureDrawParameters> maColorTextureDrawParametersMap; + + AccumulatedTexturesEntry(const OpenGLTexture& rTexture) + : maTexture(rTexture) + {} + + void insert(const SalColor& aColor, const SalTwoRect& r2Rect) + { + TextureDrawParameters& aDrawParameters = maColorTextureDrawParametersMap[aColor]; + maTexture.FillCoords<GL_TRIANGLES>(aDrawParameters.maTextureCoords, r2Rect, false); + + GLfloat nX1 = r2Rect.mnDestX; + GLfloat nY1 = r2Rect.mnDestY; + GLfloat nX2 = r2Rect.mnDestX + r2Rect.mnDestWidth; + GLfloat nY2 = r2Rect.mnDestY + r2Rect.mnDestHeight; + + auto& rVertices = aDrawParameters.maVertices; + rVertices.push_back(nX1); + rVertices.push_back(nY1); + + rVertices.push_back(nX2); + rVertices.push_back(nY1); + + rVertices.push_back(nX1); + rVertices.push_back(nY2); + + rVertices.push_back(nX1); + rVertices.push_back(nY2); + + rVertices.push_back(nX2); + rVertices.push_back(nY1); + + rVertices.push_back(nX2); + rVertices.push_back(nY2); + } +}; + +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/opengl/texture.hxx b/vcl/inc/opengl/texture.hxx index 113c65b79e34..f48a1a166b03 100644 --- a/vcl/inc/opengl/texture.hxx +++ b/vcl/inc/opengl/texture.hxx @@ -110,6 +110,7 @@ public: GLuint Id() const; int GetWidth() const; int GetHeight() const; + void GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted=false ) const; void GetWholeCoord( GLfloat* pCoord ) const; @@ -128,6 +129,9 @@ public: OpenGLTexture& operator=( const OpenGLTexture& rTexture ); bool operator==( const OpenGLTexture& rTexture ) const; bool operator!=( const OpenGLTexture& rTexture ) const; + + template<GLenum type> + void FillCoords(std::vector<GLfloat>& aCoordVector, const SalTwoRect& rPosAry, bool bInverted) const; }; #endif // INCLUDED_VCL_INC_OPENGL_TEXTURE_H diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx index 8dd063902075..0fb2941ace9c 100644 --- a/vcl/inc/openglgdiimpl.hxx +++ b/vcl/inc/openglgdiimpl.hxx @@ -29,6 +29,7 @@ #include "opengl/framebuffer.hxx" #include "opengl/program.hxx" #include "opengl/texture.hxx" +#include "opengl/AccumulatedTextures.hxx" #include <memory> @@ -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 355fe21fc6ea..bfa48b48402a 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -82,6 +82,7 @@ OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryPr , mnDrawCountAtFlush(0) , mProgramSolidColor(SALCOLOR_NONE) , mProgramSolidTransparency(0.0) + , mpAccumulatedTextures(new AccumulatedTextures) { } @@ -205,6 +206,8 @@ void OpenGLSalGraphicsImpl::PreDraw(XOROption eOpt) glViewport( 0, 0, GetWidth(), GetHeight() ); CHECK_GL_ERROR(); + FlushDeferredDrawing(true); + ImplInitClipRegion(); CHECK_GL_ERROR(); @@ -355,6 +358,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; @@ -371,6 +379,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; @@ -1656,6 +1669,81 @@ 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->maColorTextureDrawParametersMap) + { + TextureDrawParameters& rParameters = rColorTwoRectPair.second; + ApplyProgramMatrices(); + mpProgram->SetTextureCoord(rParameters.maTextureCoords.data()); + mpProgram->SetVertices(rParameters.maVertices.data()); + glDrawArrays(GL_TRIANGLES, 0, rParameters.getNumberOfVertices()); + } + } +#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->maColorTextureDrawParametersMap) + { + mpProgram->SetColor("color", rColorTwoRectPair.first, 0); + TextureDrawParameters& rParameters = rColorTwoRectPair.second; + ApplyProgramMatrices(); + mpProgram->SetTextureCoord(rParameters.maTextureCoords.data()); + mpProgram->SetVertices(rParameters.maVertices.data()); + glDrawArrays(GL_TRIANGLES, 0, rParameters.getNumberOfVertices()); + } + } + mpProgram->Clean(); + mpAccumulatedTextures->clear(); + if (!bIsInDraw) + PostDraw(); +} + void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect ) { OpenGLZone aZone; @@ -2019,6 +2107,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 " @@ -2120,6 +2210,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 ); @@ -2388,6 +2480,8 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly, void OpenGLSalGraphicsImpl::flush() { + FlushDeferredDrawing(); + if( IsOffscreen() ) return; @@ -2402,6 +2496,8 @@ void OpenGLSalGraphicsImpl::flush() void OpenGLSalGraphicsImpl::doFlush() { + FlushDeferredDrawing(); + if( IsOffscreen() ) return; diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx index 1b2e5a7caec6..fd6d11f04a5a 100644 --- a/vcl/opengl/texture.cxx +++ b/vcl/opengl/texture.cxx @@ -369,6 +369,52 @@ 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 +{ + VCL_GL_INFO("Add coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() ); + + GLfloat x1 = 0.0f; + GLfloat x2 = 0.0f; + GLfloat y1 = 0.0f; + GLfloat y2 = 0.0f; + + if (mpImpl) + { + x1 = (maRect.Left() + rPosAry.mnSrcX) / (double) mpImpl->mnWidth; + x2 = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / (double) mpImpl->mnWidth; + + if (bInverted) + { + y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight; + y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight; + } + else + { + y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight; + y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight; + } + } + + aCoord.push_back(x1); + aCoord.push_back(y1); + + aCoord.push_back(x2); + aCoord.push_back(y1); + + aCoord.push_back(x1); + aCoord.push_back(y2); + + aCoord.push_back(x1); + aCoord.push_back(y2); + + aCoord.push_back(x2); + aCoord.push_back(y1); + + aCoord.push_back(x2); + aCoord.push_back(y2); +} + void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const { if( GetWidth() != mpImpl->mnWidth || GetHeight() != mpImpl->mnHeight ) diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index 1ee9d0246235..293bfa247fb8 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -364,7 +364,7 @@ bool WinFontInstance::GlyphIsCached(int nGlyphIndex) const bool WinFontInstance::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; @@ -1556,8 +1556,6 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const if (!pImpl) return false; - pImpl->PreDraw(); - HFONT hOrigFont = DisableFontScaling(); Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) ); @@ -1589,7 +1587,8 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const nAdvance + aPos.X() - rChunk.getExtraOffset() + rChunk.maLeftOverhangs[n], aPos.Y() - rChunk.mnBaselineOffset - 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]; } @@ -1597,8 +1596,6 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const if( hOrigFont ) DeleteFont(SelectFont(hDC, hOrigFont)); - pImpl->PostDraw(); - return true; } @@ -3049,8 +3046,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; @@ -3109,7 +3104,7 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(), aPos.X() + rChunk.maLeftOverhangs[n], nAdvance + aPos.Y(), rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ??? - pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects); + pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects); } else { @@ -3118,12 +3113,11 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons nAdvance + aPos.X() + mpGlyphOffsets[i].du - rChunk.getExtraOffset() + rChunk.maLeftOverhangs[n], aPos.Y() + mpGlyphOffsets[i].dv - rChunk.mnBaselineOffset - 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; } |