summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorTomaz Vajngerl <tomaz.vajngerl@collabora.com>2016-03-14 11:20:19 +0100
committerTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2016-04-08 19:10:11 +0900
commit96a098c0e8a009b77a26061dac3318da71d34ee4 (patch)
treef675129ff246ad644f73717a118cbbdb55b72431 /vcl
parentf781997ee1dcb61b01b04cc050001e2f46b12dfe (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
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/opengl/AccumulatedTextures.hxx112
-rw-r--r--vcl/inc/opengl/texture.hxx4
-rw-r--r--vcl/inc/openglgdiimpl.hxx5
-rw-r--r--vcl/opengl/gdiimpl.cxx96
-rw-r--r--vcl/opengl/texture.cxx46
-rw-r--r--vcl/win/gdi/winlayout.cxx16
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;
}