[Libreoffice-commits] core.git: Branch 'libreoffice-5-1' - vcl/inc vcl/Library_vcl.mk vcl/opengl vcl/win
Tomaž Vajngerl
tomaz.vajngerl at collabora.co.uk
Fri Apr 8 14:47:32 UTC 2016
vcl/Library_vcl.mk | 1
vcl/inc/opengl/AccumulatedTextures.hxx | 113 +++++++++
vcl/inc/opengl/FixedTextureAtlas.hxx | 1
vcl/inc/opengl/PackedTextureAtlas.hxx | 46 +++
vcl/inc/opengl/texture.hxx | 36 ---
vcl/inc/openglgdiimpl.hxx | 8
vcl/inc/win/salgdi.h | 5
vcl/opengl/FixedTextureAtlas.cxx | 20 +
vcl/opengl/PackedTextureAtlas.cxx | 164 +++++++++++++
vcl/opengl/gdiimpl.cxx | 114 +++++++++
vcl/opengl/texture.cxx | 113 ++++++++-
vcl/win/source/gdi/salgdi.cxx | 8
vcl/win/source/gdi/winlayout.cxx | 394 +++++++++++----------------------
13 files changed, 729 insertions(+), 294 deletions(-)
New commits:
commit bd1bfeff238705fa89b4912865aa7cc6c4c1857f
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date: Fri Apr 8 19:17:41 2016 +0900
tdf#94682 optimize texture drawing on Win. (squashed multi commits)
Includes commits from master:
opengl: deferred and optimized (text) texture drawing
96a098c0e8a009b77a26061dac3318da71d34ee4
opengl: texture atlas impl. to efficiently packs textures
40e9ed91bd8bbfecfc3832d73a81741d0aa97d3a
opengl: use packed texture atlas for glyph cache in win. backend
80d0b2916db81a7f47bb1d368677016bbb870df6
opengl: fix wrong clipping when drawing text
094faaae6982472375420e57d6b9e34eefdbced8
opengl: cleanup texture, const internal format
f65e77c965bb47d53c994d90b7fd0bf5009b343b
Change-Id: I31ecd891d1d69e94973673930b0606e1ac884aab
Reviewed-on: https://gerrit.libreoffice.org/23914
Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
Tested-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 5b5c969..7f0b95d 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -135,6 +135,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/opengl/program \
vcl/opengl/texture \
vcl/opengl/FixedTextureAtlas \
+ vcl/opengl/PackedTextureAtlas \
vcl/source/opengl/OpenGLContext \
vcl/source/opengl/OpenGLHelper \
vcl/source/window/cairo_cairo \
diff --git a/vcl/inc/opengl/AccumulatedTextures.hxx b/vcl/inc/opengl/AccumulatedTextures.hxx
new file mode 100644
index 0000000..e74c065
--- /dev/null
+++ b/vcl/inc/opengl/AccumulatedTextures.hxx
@@ -0,0 +1,113 @@
+/* -*- 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 <vcl/opengl/OpenGLHelper.hxx>
+
+#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 OpenGLTexture& rTexture, const SalColor& aColor, const SalTwoRect& r2Rect)
+ {
+ TextureDrawParameters& aDrawParameters = maColorTextureDrawParametersMap[aColor];
+ rTexture.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(OpenGLTexture& rTexture, const SalColor& aColor, const SalTwoRect& r2Rect)
+ {
+ GLuint nTextureId = rTexture.Id();
+
+ if (maEntries.find(nTextureId) == maEntries.end())
+ {
+ OpenGLTexture aWholeTexture(rTexture.GetWholeTexture());
+ maEntries[nTextureId] = o3tl::make_unique<AccumulatedTexturesEntry>(aWholeTexture);
+ }
+
+ std::unique_ptr<AccumulatedTexturesEntry>& rEntry = maEntries[nTextureId];
+ rEntry->insert(rTexture, 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/FixedTextureAtlas.hxx b/vcl/inc/opengl/FixedTextureAtlas.hxx
index 5b22b619..8d104a7 100644
--- a/vcl/inc/opengl/FixedTextureAtlas.hxx
+++ b/vcl/inc/opengl/FixedTextureAtlas.hxx
@@ -28,6 +28,7 @@ public:
FixedTextureAtlasManager(int nWidthFactor, int nHeightFactor, int nTextureSize);
~FixedTextureAtlasManager();
OpenGLTexture InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData);
+ OpenGLTexture Reserve(int nWidth, int nHeight);
int GetSubtextureSize()
{
diff --git a/vcl/inc/opengl/PackedTextureAtlas.hxx b/vcl/inc/opengl/PackedTextureAtlas.hxx
new file mode 100644
index 0000000..17501f3
--- /dev/null
+++ b/vcl/inc/opengl/PackedTextureAtlas.hxx
@@ -0,0 +1,46 @@
+/* -*- 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_PACKEDTEXTUREATLAS_HXX
+#define INCLUDED_VCL_INC_OPENGL_PACKEDTEXTUREATLAS_HXX
+
+#include "opengl/texture.hxx"
+
+struct PackedTexture;
+
+/**
+ * Pack texutres into one texutre atlas.
+ *
+ * This is based on algorithm described in [1] and is an
+ * addaptation of "texture atlas generator" from [2].
+ *
+ * [1]: http://www.blackpawn.com/texts/lightmaps/
+ * [2]: https://github.com/lukaszdk/texture-atlas-generator
+ *
+ */
+class VCL_PLUGIN_PUBLIC PackedTextureAtlasManager
+{
+ std::vector<std::unique_ptr<PackedTexture>> maPackedTextures;
+
+ int mnTextureWidth;
+ int mnTextureHeight;
+
+ void CreateNewTexture();
+
+public:
+ PackedTextureAtlasManager(int nTextureWidth, int nTextureHeight);
+ ~PackedTextureAtlasManager();
+ OpenGLTexture InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData);
+ OpenGLTexture Reserve(int nWidth, int nHeight);
+};
+
+#endif // INCLUDED_VCL_INC_OPENGL_PACKEDTEXTUREATLAS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/opengl/texture.hxx b/vcl/inc/opengl/texture.hxx
index 9388918..6afc176 100644
--- a/vcl/inc/opengl/texture.hxx
+++ b/vcl/inc/opengl/texture.hxx
@@ -51,30 +51,8 @@ public:
bool InsertBuffer(int nX, int nY, int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData);
- void IncreaseRefCount(int nSlotNumber)
- {
- mnRefCount++;
- if (mpSlotReferences && nSlotNumber >= 0)
- {
- if (mpSlotReferences->at(nSlotNumber) == 0)
- mnFreeSlots--;
- mpSlotReferences->at(nSlotNumber)++;
- }
- }
-
- void DecreaseRefCount(int nSlotNumber)
- {
- mnRefCount--;
- if (mpSlotReferences && nSlotNumber >= 0)
- {
- mpSlotReferences->at(nSlotNumber)--;
- if (mpSlotReferences->at(nSlotNumber) == 0)
- mnFreeSlots++;
- }
-
- if (mnRefCount <= 0)
- delete this;
- }
+ void IncreaseRefCount(int nSlotNumber);
+ void DecreaseRefCount(int nSlotNumber);
bool IsUnique()
{
@@ -97,7 +75,7 @@ private:
public:
OpenGLTexture();
- OpenGLTexture(ImplOpenGLTexture* pImpl, Rectangle aRectangle, int nSlotNumber = 0);
+ OpenGLTexture(ImplOpenGLTexture* pImpl, Rectangle aRectangle, int nSlotNumber);
OpenGLTexture( int nWidth, int nHeight, bool bAllocate = true );
OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData );
@@ -111,9 +89,10 @@ 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;
-
+ OpenGLTexture GetWholeTexture();
void Bind();
void Unbind();
void Read( GLenum nFormat, GLenum nType, sal_uInt8* pData );
@@ -121,6 +100,8 @@ public:
bool HasStencil() const;
GLuint StencilId() const;
+ bool CopyData(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData);
+
void SaveToFile(const OUString& rFileName);
GLenum GetFilter() const;
@@ -130,6 +111,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 ca8232a..6dfa73c 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(OpenGLTexture& rTexture, const SalColor nMaskColor, const SalTwoRect& rPosAry);
+ void FlushDeferredDrawing();
public:
// get the width of the device
@@ -164,6 +169,9 @@ public:
// operations to do before painting
void PreDraw(XOROption eOpt = IGNORE_XOR);
+ // initialize pre-draw state
+ void InitializePreDrawState(XOROption eOpt = IGNORE_XOR);
+
// operations to do after painting
void PostDraw();
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index 085f77e..30b1438 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -173,11 +173,16 @@ public:
SalTwoRect getTwoRect() { return maRects; }
+ Size getBitmapSize() { return Size(maRects.mnSrcWidth, maRects.mnSrcHeight); }
+
/// Reset the DC with the defined color.
void fill(sal_uInt32 color);
/// Obtain the texture; the caller must delete it after use.
OpenGLTexture* getTexture();
+
+ /// Copy bitmap data to the texture. Texutre must be initialized and the correct size to hold the bitmap.
+ bool copyToTexture(OpenGLTexture& aTexture);
};
class WinSalGraphics : public SalGraphics
diff --git a/vcl/opengl/FixedTextureAtlas.cxx b/vcl/opengl/FixedTextureAtlas.cxx
index 80c1cfe..1ed8311 100644
--- a/vcl/opengl/FixedTextureAtlas.cxx
+++ b/vcl/opengl/FixedTextureAtlas.cxx
@@ -42,7 +42,7 @@ void FixedTextureAtlasManager::CreateNewTexture()
mpTextures.back()->InitializeSlots(mWidthFactor * mHeightFactor);
}
-OpenGLTexture FixedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
+OpenGLTexture FixedTextureAtlasManager::Reserve(int nWidth, int nHeight)
{
ImplOpenGLTexture* pTexture = nullptr;
@@ -71,14 +71,18 @@ OpenGLTexture FixedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, in
Rectangle aRectangle(Point(nX, nY), Size(nWidth, nHeight));
- // If available, copy the image data to the texture
- if (pData)
- {
- if (!pTexture->InsertBuffer(nX, nY, nWidth, nHeight, nFormat, nType, pData))
- return OpenGLTexture();
- }
-
return OpenGLTexture(pTexture, aRectangle, nSlot);
}
+OpenGLTexture FixedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
+{
+ OpenGLTexture aTexture = Reserve(nWidth, nHeight);
+ if (pData == nullptr)
+ return aTexture;
+
+ aTexture.CopyData(nWidth, nHeight, nFormat, nType, pData);
+
+ return aTexture;
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/PackedTextureAtlas.cxx b/vcl/opengl/PackedTextureAtlas.cxx
new file mode 100644
index 0000000..60fa1e9
--- /dev/null
+++ b/vcl/opengl/PackedTextureAtlas.cxx
@@ -0,0 +1,164 @@
+/* -*- 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/.
+ *
+ */
+
+#include <sal/config.h>
+#include <vcl/opengl/OpenGLContext.hxx>
+#include <vcl/opengl/OpenGLHelper.hxx>
+
+#include "opengl/framebuffer.hxx"
+#include "opengl/texture.hxx"
+
+#include "opengl/PackedTextureAtlas.hxx"
+
+struct Node
+{
+ Rectangle mRectangle;
+ std::unique_ptr<Node> mLeftNode;
+ std::unique_ptr<Node> mRightNode;
+ bool mOccupied;
+
+ Node(Rectangle& aRectangle);
+
+ bool isLeaf();
+ Node* insert(int nWidth, int nHeight, int nPadding);
+};
+
+Node::Node(Rectangle& aRectangle)
+ : mRectangle(aRectangle)
+ , mLeftNode()
+ , mRightNode()
+ , mOccupied(false)
+{}
+
+bool Node::isLeaf()
+{
+ return mLeftNode.get() == nullptr &&
+ mRightNode.get() == nullptr;
+}
+
+Node* Node::insert(int nWidth, int nHeight, int nPadding)
+{
+ if (!isLeaf())
+ {
+ Node* pNewNode = mLeftNode->insert(nWidth, nHeight, nPadding);
+
+ if (pNewNode != nullptr)
+ return pNewNode;
+
+ return mRightNode->insert(nWidth, nHeight, nPadding);
+ }
+ else
+ {
+ if (mOccupied)
+ {
+ return nullptr;
+ }
+
+ if (nWidth > mRectangle.GetWidth() || nHeight > mRectangle.GetHeight())
+ { // does not fit
+ return nullptr;
+ }
+
+ if (nWidth == mRectangle.GetWidth() && nHeight == mRectangle.GetHeight())
+ { // perfect fit
+ mOccupied = true;
+ return this;
+ }
+
+ int dw = mRectangle.GetWidth() - nWidth;
+ int dh = mRectangle.GetHeight() - nHeight;
+
+ Rectangle aLeftRect;
+ Rectangle aRightRect;
+ if (dw > dh)
+ {
+ aLeftRect = Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
+ Size(nWidth, mRectangle.GetHeight()));
+ aRightRect = Rectangle(Point(nPadding + mRectangle.Left() + nWidth, mRectangle.Top()),
+ Size(mRectangle.GetWidth() - nWidth - nPadding, mRectangle.GetHeight()));
+ }
+ else
+ {
+ aLeftRect = Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
+ Size(mRectangle.GetWidth(), nHeight));
+ aRightRect = Rectangle(Point(mRectangle.Left(), nPadding + mRectangle.Top() + nHeight),
+ Size(mRectangle.GetWidth(), mRectangle.GetHeight() - nHeight - nPadding));
+ }
+
+ mLeftNode.reset(new Node(aLeftRect));
+ mRightNode.reset(new Node(aRightRect));
+
+ return mLeftNode->insert(nWidth, nHeight, nPadding);
+ }
+}
+
+struct PackedTexture
+{
+ std::unique_ptr<Node> mpRootNode;
+ ImplOpenGLTexture* mpTexture;
+};
+
+PackedTextureAtlasManager::PackedTextureAtlasManager(int nTextureWidth, int nTextureHeight)
+ : mnTextureWidth(nTextureWidth)
+ , mnTextureHeight(nTextureHeight)
+{
+}
+
+PackedTextureAtlasManager::~PackedTextureAtlasManager()
+{
+ for (std::unique_ptr<PackedTexture>& pPackedTexture : maPackedTextures)
+ {
+ // Free texture early in VCL shutdown while we have a context.
+ pPackedTexture->mpTexture->Dispose();
+ pPackedTexture->mpTexture->DecreaseRefCount(0);
+ }
+}
+
+void PackedTextureAtlasManager::CreateNewTexture()
+{
+ std::unique_ptr<PackedTexture> pPackedTexture(new PackedTexture);
+ pPackedTexture->mpTexture = new ImplOpenGLTexture(mnTextureWidth, mnTextureHeight, true);
+ Rectangle aInitialRect(Point(0, 0), Size(mnTextureWidth, mnTextureHeight));
+ pPackedTexture->mpRootNode.reset(new Node(aInitialRect));
+ maPackedTextures.push_back(std::move(pPackedTexture));
+}
+
+OpenGLTexture PackedTextureAtlasManager::Reserve(int nWidth, int nHeight)
+{
+ for (std::unique_ptr<PackedTexture>& pPackedTexture : maPackedTextures)
+ {
+ Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1);
+ if (pNode != nullptr)
+ {
+ return OpenGLTexture(pPackedTexture->mpTexture, pNode->mRectangle, -1);
+ }
+ }
+ CreateNewTexture();
+ std::unique_ptr<PackedTexture>& pPackedTexture = maPackedTextures.back();
+ Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1);
+ if (pNode != nullptr)
+ {
+ return OpenGLTexture(pPackedTexture->mpTexture, pNode->mRectangle, -1);
+ }
+ return OpenGLTexture();
+}
+
+OpenGLTexture PackedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
+{
+ OpenGLTexture aTexture = Reserve(nWidth, nHeight);
+ if (aTexture && pData == nullptr)
+ return aTexture;
+
+ aTexture.CopyData(nWidth, nHeight, nFormat, nType, pData);
+
+ return aTexture;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index c9e59fd..d3d6392 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)
{
}
@@ -184,6 +185,13 @@ void OpenGLSalGraphicsImpl::DeInit()
void OpenGLSalGraphicsImpl::PreDraw(XOROption eOpt)
{
+ FlushDeferredDrawing();
+
+ InitializePreDrawState(eOpt);
+}
+
+void OpenGLSalGraphicsImpl::InitializePreDrawState(XOROption eOpt)
+{
OpenGLZone::enter();
mnDrawCount++;
@@ -263,6 +271,7 @@ void OpenGLSalGraphicsImpl::freeResources()
{
VCL_GL_INFO( "freeResources" );
mpContext->makeCurrent();
+ FlushDeferredDrawing();
mpContext->ReleaseFramebuffer( maOffscreenTex );
}
ReleaseContext();
@@ -352,7 +361,16 @@ const vcl::Region& OpenGLSalGraphicsImpl::getClipRegion() const
bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region& rClip )
{
+ if (maClipRegion == rClip)
+ {
+ VCL_GL_INFO("::setClipRegion (no change) " << rClip);
+ return true;
+ }
+
+ FlushDeferredDrawing();
+
VCL_GL_INFO( "::setClipRegion " << rClip );
+
maClipRegion = rClip;
mbUseStencil = false;
@@ -368,7 +386,16 @@ bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region& rClip )
// set the clip region to empty
void OpenGLSalGraphicsImpl::ResetClipRegion()
{
- VCL_GL_INFO( "::ResetClipRegion" );
+ if (maClipRegion.IsEmpty())
+ {
+ VCL_GL_INFO("::ResetClipRegion (no change) ");
+ return;
+ }
+
+ FlushDeferredDrawing();
+
+ VCL_GL_INFO("::ResetClipRegion");
+
maClipRegion.SetEmpty();
mbUseScissor = false;
mbUseStencil = false;
@@ -1654,6 +1681,83 @@ void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture& rMask, SalColor nMaskColor,
mpProgram->Clean();
}
+void OpenGLSalGraphicsImpl::DeferredTextDraw(OpenGLTexture& rTexture, SalColor aMaskColor, const SalTwoRect& rPosAry)
+{
+ mpAccumulatedTextures->insert(rTexture, aMaskColor, rPosAry);
+}
+
+void OpenGLSalGraphicsImpl::FlushDeferredDrawing()
+{
+ if (mpAccumulatedTextures->empty())
+ return;
+
+ InitializePreDrawState();
+
+ VCL_GL_INFO("FlushDeferredDrawing");
+
+ 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();
+
+ PostDraw();
+}
+
void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect )
{
OpenGLZone aZone;
@@ -2017,6 +2121,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 "
@@ -2113,6 +2219,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 );
@@ -2369,6 +2477,8 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly,
void OpenGLSalGraphicsImpl::flush()
{
+ FlushDeferredDrawing();
+
if( IsOffscreen() )
return;
@@ -2383,6 +2493,8 @@ void OpenGLSalGraphicsImpl::flush()
void OpenGLSalGraphicsImpl::doFlush()
{
+ FlushDeferredDrawing();
+
if( IsOffscreen() )
return;
diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx
index ffaaf09..61b6514 100644
--- a/vcl/opengl/texture.cxx
+++ b/vcl/opengl/texture.cxx
@@ -29,10 +29,17 @@
#include "opengl/framebuffer.hxx"
#include "opengl/texture.hxx"
#include "opengl/zone.hxx"
+namespace
+{
+
+SAL_CONSTEXPR GLenum constInternalFormat = GL_RGBA8;
+
+} // end anonymous namespace
// texture with allocated size
ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate ) :
mnRefCount( 1 ),
+ mnTexture( 0 ),
mnWidth( nWidth ),
mnHeight( nHeight ),
mnFilter( GL_NEAREST ),
@@ -55,7 +62,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate )
CHECK_GL_ERROR();
if( bAllocate )
{
- glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr );
+ glTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr );
CHECK_GL_ERROR();
}
glBindTexture( GL_TEXTURE_2D, 0 );
@@ -91,7 +98,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight )
CHECK_GL_ERROR();
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
CHECK_GL_ERROR();
- glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nX, nY, nWidth, nHeight, 0 );
+ glCopyTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, nX, nY, nWidth, nHeight, 0 );
CHECK_GL_ERROR();
glBindTexture( GL_TEXTURE_2D, 0 );
CHECK_GL_ERROR();
@@ -111,11 +118,8 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int
{
OpenGLVCLContextZone aContextZone;
- if( !mnTexture )
- {
- glGenTextures( 1, &mnTexture );
- CHECK_GL_ERROR();
- }
+ glGenTextures( 1, &mnTexture );
+ CHECK_GL_ERROR();
glBindTexture( GL_TEXTURE_2D, mnTexture );
CHECK_GL_ERROR();
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
@@ -128,7 +132,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int
CHECK_GL_ERROR();
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
CHECK_GL_ERROR();
- glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, mnWidth, mnHeight, 0, nFormat, nType, pData );
+ glTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, mnWidth, mnHeight, 0, nFormat, nType, pData );
CHECK_GL_ERROR();
glBindTexture( GL_TEXTURE_2D, 0 );
CHECK_GL_ERROR();
@@ -240,6 +244,32 @@ int ImplOpenGLTexture::FindFreeSlot()
return -1;
}
+void ImplOpenGLTexture::IncreaseRefCount(int nSlotNumber)
+{
+ mnRefCount++;
+ if (mpSlotReferences && nSlotNumber >= 0)
+ {
+ if (mpSlotReferences->at(nSlotNumber) == 0)
+ mnFreeSlots--;
+ mpSlotReferences->at(nSlotNumber)++;
+ }
+}
+
+void ImplOpenGLTexture::DecreaseRefCount(int nSlotNumber)
+{
+ mnRefCount--;
+ if (mpSlotReferences && nSlotNumber >= 0)
+ {
+ mpSlotReferences->at(nSlotNumber)--;
+ if (mpSlotReferences->at(nSlotNumber) == 0)
+ mnFreeSlots++;
+ }
+
+ if (mnRefCount <= 0)
+ delete this;
+}
+
+
OpenGLTexture::OpenGLTexture() :
maRect( 0, 0, 0, 0 ),
mpImpl(nullptr),
@@ -371,6 +401,57 @@ 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() );
+ VCL_GL_INFO(" With 2Rect Src [" << rPosAry.mnSrcX << ", " << rPosAry.mnSrcY << "] wh (" << rPosAry.mnSrcWidth << ", " << rPosAry.mnSrcHeight << ")");
+ VCL_GL_INFO(" With 2Rect Dest [" << rPosAry.mnDestX << ", " << rPosAry.mnDestY << "] wh (" << rPosAry.mnDestWidth << ", " << rPosAry.mnDestHeight << ")");
+
+ GLfloat x1 = 0.0f;
+ GLfloat x2 = 0.0f;
+ GLfloat y1 = 0.0f;
+ GLfloat y2 = 0.0f;
+
+ double fTextureWidth(mpImpl->mnWidth);
+ double fTextureHeight(mpImpl->mnHeight);
+
+ if (mpImpl)
+ {
+ x1 = (maRect.Left() + rPosAry.mnSrcX) / fTextureWidth;
+ x2 = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / fTextureWidth;
+
+ if (bInverted)
+ {
+ y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / fTextureHeight;
+ y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / fTextureHeight;
+ }
+ else
+ {
+ y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / fTextureHeight;
+ y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / fTextureHeight;
+ }
+ }
+
+ 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 )
@@ -389,6 +470,11 @@ void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const
}
}
+OpenGLTexture OpenGLTexture::GetWholeTexture()
+{
+ return OpenGLTexture(mpImpl, Rectangle(Point(0, 0), Size(mpImpl->mnWidth, mpImpl->mnHeight)), -1);
+}
+
GLenum OpenGLTexture::GetFilter() const
{
if( mpImpl )
@@ -396,6 +482,17 @@ GLenum OpenGLTexture::GetFilter() const
return GL_NEAREST;
}
+bool OpenGLTexture::CopyData(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
+{
+ if (!pData || mpImpl == nullptr)
+ return false;
+
+ int nX = maRect.Left();
+ int nY = maRect.Top();
+
+ return mpImpl->InsertBuffer(nX, nY, nWidth, nHeight, nFormat, nType, pData);
+}
+
void OpenGLTexture::SetFilter( GLenum nFilter )
{
if( mpImpl )
diff --git a/vcl/win/source/gdi/salgdi.cxx b/vcl/win/source/gdi/salgdi.cxx
index 42ab90e..85d54af 100644
--- a/vcl/win/source/gdi/salgdi.cxx
+++ b/vcl/win/source/gdi/salgdi.cxx
@@ -616,6 +616,14 @@ OpenGLTexture* OpenGLCompatibleDC::getTexture()
return new OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, reinterpret_cast<sal_uInt8*>(mpData));
}
+bool OpenGLCompatibleDC::copyToTexture(OpenGLTexture& aTexture)
+{
+ if (!mpImpl)
+ return false;
+
+ return aTexture.CopyData(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, reinterpret_cast<sal_uInt8*>(mpData));
+}
+
WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, SalGeometryProvider *pProvider):
mhLocalDC(0),
mbPrinter(eType == WinSalGraphics::PRINTER),
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
index d8073fd..49aa0c4 100644
--- a/vcl/win/source/gdi/winlayout.cxx
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -26,6 +26,8 @@
#include <opengl/texture.hxx>
#include <opengl/win/gdiimpl.hxx>
+#include "opengl/PackedTextureAtlas.hxx"
+
#include <vcl/opengl/OpenGLHelper.hxx>
#include <win/salgdi.h>
#include <win/saldata.hxx>
@@ -74,13 +76,11 @@ const int GLYPH_SPACE_RATIO = 8;
const int GLYPH_OFFSET_RATIO = GLYPH_SPACE_RATIO * 2;
}
-struct OpenGLGlyphCacheChunk
+struct OpenGLGlyphDrawElement
{
- int mnFirstGlyph; // Must be int to handle non-BMP code points when mbRealGlyphIndices is false
- int mnGlyphCount;
- std::vector<Rectangle> maLocation;
- std::vector<int> maLeftOverhangs;
- std::shared_ptr<OpenGLTexture> mpTexture;
+ Rectangle maLocation;
+ int maLeftOverhangs;
+ OpenGLTexture maTexture;
int mnBaselineOffset;
int mnHeight;
bool mbVertical;
@@ -97,6 +97,41 @@ struct OpenGLGlyphCacheChunk
}
};
+class GlyphCache
+{
+private:
+ static PackedTextureAtlasManager sPackedTextureAtlas;
+ std::unordered_map<int, OpenGLGlyphDrawElement> maOpenGLTextureCache;
+
+public:
+ GlyphCache()
+ {}
+
+ void ReserveTextureSpace(OpenGLGlyphDrawElement& rElement, int nWidth, int nHeight)
+ {
+ rElement.maTexture = sPackedTextureAtlas.Reserve(nWidth, nHeight);
+ }
+
+ void PutDrawElementInCache(const OpenGLGlyphDrawElement& rElement, int nGlyphIndex)
+ {
+ assert(!IsGlyphCached(nGlyphIndex));
+ maOpenGLTextureCache[nGlyphIndex] = OpenGLGlyphDrawElement(rElement);
+ }
+
+ OpenGLGlyphDrawElement& GetDrawElement(int nGlyphIndex)
+ {
+ assert(IsGlyphCached(nGlyphIndex));
+ return maOpenGLTextureCache[nGlyphIndex];
+ }
+
+ bool IsGlyphCached(int nGlyphIndex)
+ {
+ return maOpenGLTextureCache.find(nGlyphIndex) != maOpenGLTextureCache.end();
+ }
+};
+
+PackedTextureAtlasManager GlyphCache::sPackedTextureAtlas(2048, 2048);
+
// win32 specific physical font instance
class ImplWinFontEntry : public ImplFontEntry
{
@@ -122,7 +157,6 @@ public:
{ return maScriptCache; }
private:
mutable SCRIPT_CACHE maScriptCache;
- std::vector<OpenGLGlyphCacheChunk> maOpenGLGlyphCache;
public:
int GetCachedGlyphWidth( int nCharCode ) const;
@@ -136,9 +170,15 @@ public:
GLyphyDemo::demo_atlas_t* mpGLyphyAtlas;
GLyphyDemo::demo_font_t* mpGLyphyFont;
- bool GlyphIsCached(int nGlyphIndex) const;
- bool AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics);
- const OpenGLGlyphCacheChunk& GetCachedGlyphChunkFor(int nGlyphIndex) const;
+private:
+ GlyphCache maGlyphCache;
+public:
+ bool CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics);
+
+ GlyphCache& GetGlyphCache()
+ {
+ return maGlyphCache;
+ }
private:
IntMap maWidthMap;
@@ -246,146 +286,16 @@ private:
HDC mhDC;
};
-
-#ifdef SAL_LOG_INFO
-
-namespace {
-
-char ColorFor(COLORREF aColor)
-{
- if (aColor == RGB(0xFF, 0xFF, 0xFF))
- return ' ';
- else if (aColor == RGB(0x00, 0x00, 0x00))
- return 'X';
-
- return '0' + (10*(GetRValue(aColor) + GetGValue(aColor) + GetBValue(aColor))) / (0xFF*3);
-}
-
-void DumpGlyphBitmap(HDC hDC, const OpenGLGlyphCacheChunk& rChunk)
-{
- HBITMAP hBitmap = static_cast<HBITMAP>(GetCurrentObject(hDC, OBJ_BITMAP));
- if (hBitmap == NULL)
- {
- SAL_WARN("vcl.gdi", "GetCurrentObject failed: " << WindowsErrorString(GetLastError()));
- return;
- }
-
- BITMAP aBitmap;
- if (!GetObjectW(hBitmap, sizeof(aBitmap), &aBitmap))
- {
- SAL_WARN("vcl.gdi", "GetObjectW failed: " << WindowsErrorString(GetLastError()));
- return;
- }
-
- SAL_INFO("vcl.gdi.opengl", "Bitmap " << hBitmap << ": " << aBitmap.bmWidth << "x" << aBitmap.bmHeight << ":");
-
- std::ostringstream sLine("\n", std::ios_base::ate);
- for (long y = 0; y < aBitmap.bmHeight; y++)
- {
- if (y == rChunk.mnBaselineOffset + rChunk.getExtraOffset())
- sLine << "-";
- else
- sLine << ColorFor(GetPixel(hDC, 0, y));
- for (long x = 1; x < std::min(75l, aBitmap.bmWidth); x++)
- sLine << ColorFor(GetPixel(hDC, x, y));
- if (y < aBitmap.bmHeight - 1)
- sLine << "\n";
- }
- SAL_INFO("vcl.gdi.opengl", sLine.str());
-}
-
-} // anonymous namespace
-
-#endif // SAL_LOG_INFO
-
-template< typename charT, typename traits >
-inline std::basic_ostream<charT, traits> & operator <<(
- std::basic_ostream<charT, traits> & stream, const std::vector<OpenGLGlyphCacheChunk>& rCache )
-{
- stream << "{";
- for (auto i = rCache.cbegin(); i != rCache.cend(); ++i)
- {
- stream << "[" << i->mnFirstGlyph;
- if (i->mnGlyphCount > 1)
- stream << ".." << (i->mnFirstGlyph + i->mnGlyphCount - 1);
- stream << "]";
- if (i+1 != rCache.cend())
- {
- stream << ",";
- assert(i->mnFirstGlyph + i->mnGlyphCount <= (i+1)->mnFirstGlyph);
- }
- }
-
- return stream << "}";
-}
-
-inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth )
-{
- maWidthMap[ nCharCode ] = nCharWidth;
-}
-
-inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const
-{
- IntMap::const_iterator it = maWidthMap.find( nCharCode );
- if( it == maWidthMap.end() )
- return -1;
- return it->second;
-}
-
-bool ImplWinFontEntry::GlyphIsCached(int nGlyphIndex) const
+bool ImplWinFontEntry::CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
{
if (nGlyphIndex == DROPPED_OUTGLYPH)
return true;
- for (size_t i = 0; i < maOpenGLGlyphCache.size(); i++)
- if (nGlyphIndex >= maOpenGLGlyphCache[i].mnFirstGlyph &&
- nGlyphIndex < maOpenGLGlyphCache[i].mnFirstGlyph + maOpenGLGlyphCache[i].mnGlyphCount)
- return true;
-
- return false;
-}
-
-bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
-{
- const int DEFAULT_CHUNK_SIZE = 20;
-
- if (nGlyphIndex == DROPPED_OUTGLYPH)
- return true;
-
- SAL_INFO("vcl.gdi.opengl", "this=" << this << " " << nGlyphIndex << " old: " << maOpenGLGlyphCache);
-
- auto n = maOpenGLGlyphCache.begin();
- while (n != maOpenGLGlyphCache.end() &&
- nGlyphIndex > n->mnFirstGlyph)
- ++n;
- assert(n == maOpenGLGlyphCache.end() || nGlyphIndex < n->mnFirstGlyph);
-
- int nCount = DEFAULT_CHUNK_SIZE;
- if (n != maOpenGLGlyphCache.end() && nGlyphIndex + nCount >= n->mnFirstGlyph)
- nCount = n->mnFirstGlyph - nGlyphIndex;
-
- if (nCount < DEFAULT_CHUNK_SIZE)
- {
- if (n == maOpenGLGlyphCache.begin())
- {
- nGlyphIndex = std::max(0, n->mnFirstGlyph - DEFAULT_CHUNK_SIZE);
- }
- else
- {
- nGlyphIndex = std::max(n[-1].mnFirstGlyph + n[-1].mnGlyphCount,
- n->mnFirstGlyph - DEFAULT_CHUNK_SIZE);
- }
- nCount = n->mnFirstGlyph - nGlyphIndex;
- }
-
- OpenGLGlyphCacheChunk aChunk;
- aChunk.mnFirstGlyph = nGlyphIndex;
- aChunk.mnGlyphCount = nCount;
- aChunk.mbRealGlyphIndices = bRealGlyphIndices;
+ OpenGLGlyphDrawElement aElement;
+ aElement.mbRealGlyphIndices = bRealGlyphIndices;
- std::vector<uint32_t> aCodePointsOrGlyphIndices(nCount);
- for (int i = 0; i < nCount; i++)
- aCodePointsOrGlyphIndices[i] = nGlyphIndex + i;
+ std::vector<uint32_t> aCodePointsOrGlyphIndices(1);
+ aCodePointsOrGlyphIndices[0] = nGlyphIndex;
HDC hDC = CreateCompatibleDC(rLayout.mhDC);
if (hDC == NULL)
@@ -424,7 +334,7 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
return false;
}
}
- std::vector<WORD> aGlyphIndices(nCount);
+ std::vector<WORD> aGlyphIndices(1);
// Fetch the ink boxes and calculate the size of the atlas.
if (!bRealGlyphIndices)
{
@@ -436,69 +346,60 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
}
else
{
- for (int i = 0; i < nCount; i++)
- aGlyphIndices[i] = aCodePointsOrGlyphIndices[i];
+ aGlyphIndices[0] = aCodePointsOrGlyphIndices[0];
}
Rectangle bounds(0, 0, 0, 0);
- auto aInkBoxes = pTxt->GetGlyphInkBoxes(aGlyphIndices.data(), aGlyphIndices.data() + nCount);
+ auto aInkBoxes = pTxt->GetGlyphInkBoxes(aGlyphIndices.data(), aGlyphIndices.data() + 1);
for (auto &box : aInkBoxes)
bounds.Union(box + Point(bounds.Right(), 0));
// bounds.Top() is the offset from the baseline at (0,0) to the top of the
// inkbox.
- aChunk.mnBaselineOffset = -bounds.Top();
- aChunk.mnHeight = bounds.getHeight();
- aChunk.mbVertical = false;
-
- aChunk.maLeftOverhangs.resize(nCount);
- aChunk.maLocation.resize(nCount);
+ aElement.mnBaselineOffset = -bounds.Top();
+ aElement.mnHeight = bounds.getHeight();
+ aElement.mbVertical = false;
// Try hard to avoid overlap as we want to be able to use
// individual rectangles for each glyph. The ABC widths don't
// take anti-aliasing into consideration. Let's hope that leaving
// "extra" space between glyphs will help.
- std::vector<float> aGlyphAdv(nCount); // offsets between glyphs
- std::vector<DWRITE_GLYPH_OFFSET> aGlyphOffset(nCount, DWRITE_GLYPH_OFFSET{0.0f,0.0f});
- std::vector<int> aEnds(nCount); // end of each glyph box
+ std::vector<float> aGlyphAdv(1); // offsets between glyphs
+ std::vector<DWRITE_GLYPH_OFFSET> aGlyphOffset(1, DWRITE_GLYPH_OFFSET{0.0f, 0.0f});
+ std::vector<int> aEnds(1); // end of each glyph box
float totWidth = 0;
- for (int i = 0; i < nCount; ++i)
{
- int overhang = aInkBoxes[i].Left();
- int blackWidth = aInkBoxes[i].getWidth(); // width of non-AA pixels
- aChunk.maLeftOverhangs[i] = overhang;
+ int overhang = aInkBoxes[0].Left();
+ int blackWidth = aInkBoxes[0].getWidth(); // width of non-AA pixels
+ aElement.maLeftOverhangs = overhang;
- aGlyphAdv[i] = blackWidth + aChunk.getExtraSpace();
- aGlyphOffset[i].advanceOffset = -overhang;
+ aGlyphAdv[0] = blackWidth + aElement.getExtraSpace();
+ aGlyphOffset[0].advanceOffset = -overhang;
- totWidth += aGlyphAdv[i];
- aEnds[i] = totWidth;
+ totWidth += aGlyphAdv[0];
+ aEnds[0] = totWidth;
}
-
// Leave extra space also at top and bottom
- int nBitmapWidth = totWidth,
- nBitmapHeight = bounds.getHeight() + aChunk.getExtraSpace();
+ int nBitmapWidth = totWidth;
+ int nBitmapHeight = bounds.getHeight() + aElement.getExtraSpace();
- aChunk.maLocation.resize(nCount);
UINT nPos = 0;
- for (int i = 0; i < nCount; i++)
+
+ // FIXME: really I don't get why 'vertical' makes any difference [!] what does it mean !?
+ if (aElement.mbVertical)
{
- // FIXME: really I don't get why 'vertical' makes any difference [!] what does it mean !?
- if (aChunk.mbVertical)
- {
- aChunk.maLocation[i].Left() = 0;
- aChunk.maLocation[i].Right() = nBitmapWidth;
- aChunk.maLocation[i].Top() = nPos;
- aChunk.maLocation[i].Bottom() = nPos + aGlyphAdv[i] + aChunk.maLeftOverhangs[i];
- }
- else
- {
- aChunk.maLocation[i].Left() = nPos;
- aChunk.maLocation[i].Right() = aEnds[i];
- aChunk.maLocation[i].Top() = 0;
- aChunk.maLocation[i].Bottom() = bounds.getHeight() + aChunk.getExtraSpace();
- }
- nPos = aEnds[i];
+ aElement.maLocation.Left() = 0;
+ aElement.maLocation.Right() = nBitmapWidth;
+ aElement.maLocation.Top() = nPos;
+ aElement.maLocation.Bottom() = nPos + aGlyphAdv[0] + aElement.maLeftOverhangs;
+ }
+ else
+ {
+ aElement.maLocation.Left() = nPos;
+ aElement.maLocation.Right() = aEnds[0];
+ aElement.maLocation.Top() = 0;
+ aElement.maLocation.Bottom() = bounds.getHeight() + aElement.getExtraSpace();
}
+ nPos = aEnds[0];
OpenGLCompatibleDC aDC(rGraphics, 0, 0, nBitmapWidth, nBitmapHeight);
@@ -519,11 +420,15 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
return false;
}
- D2D1_POINT_2F baseline = { aChunk.getExtraOffset(), aChunk.getExtraOffset() + aChunk.mnBaselineOffset };
+ D2D1_POINT_2F baseline = {
+ aElement.getExtraOffset(),
+ aElement.getExtraOffset() + aElement.mnBaselineOffset
+ };
+
DWRITE_GLYPH_RUN glyphs = {
pTxt->GetFontFace(),
pTxt->GetEmHeight(),
- nCount,
+ 1,
aGlyphIndices.data(),
aGlyphAdv.data(),
aGlyphOffset.data(),
@@ -533,11 +438,11 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
pRT->BeginDraw();
pRT->DrawGlyphRun(baseline, &glyphs, pBrush);
- HRESULT hr = pRT->EndDraw();
+ HRESULT hResult = pRT->EndDraw();
pBrush->Release();
- switch (hr)
+ switch (hResult)
{
case S_OK:
break;
@@ -554,27 +459,28 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
pTxt->ReleaseFont();
- aChunk.mpTexture = std::unique_ptr<OpenGLTexture>(aDC.getTexture());
-
- maOpenGLGlyphCache.insert(n, aChunk);
+ maGlyphCache.ReserveTextureSpace(aElement, nBitmapWidth, nBitmapHeight);
+ aDC.copyToTexture(aElement.maTexture);
+ maGlyphCache.PutDrawElementInCache(aElement, nGlyphIndex);
SelectFont(aDC.getCompatibleHDC(), hOrigFont);
if (hNonAntialiasedFont != NULL)
DeleteObject(hNonAntialiasedFont);
-#ifdef SAL_LOG_INFO
- SAL_INFO("vcl.gdi.opengl", "this=" << this << " now: " << maOpenGLGlyphCache);
- DumpGlyphBitmap(aDC.getCompatibleHDC(), aChunk);
+ return true;
+}
- {
- std::ostringstream sLine;
- for (int i = 0; i < nCount; i++)
- sLine << aGlyphAdv[i] << ":" << aChunk.maLeftOverhangs[i] << " ";
- SAL_INFO("vcl.gdi.opengl", "DX:offset : " << sLine.str());
- }
-#endif
+inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth )
+{
+ maWidthMap[ nCharCode ] = nCharWidth;
+}
- return true;
+inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const
+{
+ IntMap::const_iterator it = maWidthMap.find( nCharCode );
+ if( it == maWidthMap.end() )
+ return -1;
+ return it->second;
}
SimpleWinLayout::SimpleWinLayout(HDC hDC, BYTE nCharSet, const ImplWinFontData& rWinFontData,
@@ -1273,16 +1179,6 @@ void SimpleWinLayout::Simplify( bool /*bIsBase*/ )
mnWidth = mnBaseAdv = 0;
}
-const OpenGLGlyphCacheChunk& ImplWinFontEntry::GetCachedGlyphChunkFor(int nGlyphIndex) const
-{
- auto i = maOpenGLGlyphCache.cbegin();
- while (i != maOpenGLGlyphCache.cend() && nGlyphIndex >= i->mnFirstGlyph + i->mnGlyphCount)
- ++i;
- assert(i != maOpenGLGlyphCache.cend());
- assert(nGlyphIndex >= i->mnFirstGlyph && nGlyphIndex < i->mnFirstGlyph + i->mnGlyphCount);
- return *i;
-}
-
void ImplWinFontEntry::setupGLyphy(HDC hDC)
{
if (mbGLyphySetupCalled)
@@ -1514,10 +1410,10 @@ bool SimpleWinLayout::CacheGlyphs(SalGraphics& rGraphics) const
nCodePoint = mpOutGlyphs[i];
}
- if (mrWinFontEntry.GlyphIsCached(nCodePoint))
+ if (mrWinFontEntry.GetGlyphCache().IsGlyphCached(nCodePoint))
continue;
- if (!mrWinFontEntry.AddChunkOfGlyphs(false, nCodePoint, *this, rGraphics))
+ if (!mrWinFontEntry.CacheGlyphToAtlas(false, nCodePoint, *this, rGraphics))
return false;
}
@@ -1539,8 +1435,6 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
if (!pImpl)
return false;
- pImpl->PreDraw();
-
HFONT hOrigFont = DisableFontScaling();
Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
@@ -1562,17 +1456,16 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
nCodePoint = mpOutGlyphs[i];
}
- assert(mrWinFontEntry.GlyphIsCached(nCodePoint));
+ OpenGLGlyphDrawElement& rElement(mrWinFontEntry.GetGlyphCache().GetDrawElement(nCodePoint));
+ OpenGLTexture& rTexture = rElement.maTexture;
- const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(nCodePoint);
- const int n = nCodePoint - rChunk.mnFirstGlyph;
+ SalTwoRect a2Rects(0, 0,
+ rTexture.GetWidth(), rTexture.GetHeight(),
+ nAdvance + aPos.X() - rElement.getExtraOffset() + rElement.maLeftOverhangs,
+ aPos.Y() - rElement.mnBaselineOffset - rElement.getExtraOffset(),
+ rTexture.GetWidth(), rTexture.GetHeight());
- SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(),
- rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
- 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(rTexture, salColor, a2Rects);
nAdvance += mpGlyphAdvances[i];
}
@@ -1580,8 +1473,6 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
if( hOrigFont )
DeleteFont(SelectFont(hDC, hOrigFont));
- pImpl->PostDraw();
-
return true;
}
@@ -2788,10 +2679,12 @@ bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const
{
for (int i = 0; i < mnGlyphCount; i++)
{
- if (mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i]))
+ int nCodePoint = mpOutGlyphs[i];
+
+ if (mrWinFontEntry.GetGlyphCache().IsGlyphCached(nCodePoint))
continue;
- if (!mrWinFontEntry.AddChunkOfGlyphs(true, mpOutGlyphs[i], *this, rGraphics))
+ if (!mrWinFontEntry.CacheGlyphToAtlas(true, nCodePoint, *this, rGraphics))
return false;
}
}
@@ -3002,8 +2895,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;
@@ -3051,32 +2942,33 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons
if (mpOutGlyphs[i] == DROPPED_OUTGLYPH)
continue;
- assert(mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i]));
-
- const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(mpOutGlyphs[i]);
- const int n = mpOutGlyphs[i] - rChunk.mnFirstGlyph;
+ OpenGLGlyphDrawElement& rElement = mrWinFontEntry.GetGlyphCache().GetDrawElement(mpOutGlyphs[i]);
+ OpenGLTexture& rTexture = rElement.maTexture;
- if (rChunk.mbVertical)
+ if (rElement.mbVertical)
{
- SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(),
- 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);
+ SalTwoRect a2Rects(0, 0,
+ rTexture.GetWidth(), rTexture.GetHeight(),
+ aPos.X() + rElement.maLeftOverhangs,
+ nAdvance + aPos.Y(),
+ rTexture.GetWidth(), rTexture.GetHeight());
+
+ pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
}
else
{
- SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(),
- rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
- 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);
+ SalTwoRect a2Rects(0, 0,
+ rTexture.GetWidth(), rTexture.GetHeight(),
+ nAdvance + aPos.X() + mpGlyphOffsets[i].du - rElement.getExtraOffset() + rElement.maLeftOverhangs,
+ aPos.Y() + mpGlyphOffsets[i].dv - rElement.mnBaselineOffset - rElement.getExtraOffset(),
+ rTexture.GetWidth(), rTexture.GetHeight());
+
+ pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
}
+
nAdvance += pGlyphWidths[i];
}
}
- pImpl->PostDraw();
return true;
}
More information about the Libreoffice-commits
mailing list