summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2019-10-23 11:29:22 +0200
committerLuboš Luňák <l.lunak@collabora.com>2019-11-27 09:55:10 +0100
commit619959827003814053a5e9ec81acfd07b3aa270a (patch)
tree29d77c1bc8a45f5102b62d04211bedd3d0ae41c7
parentc6b50a85a2371c1f49f75d1a9fccc8548e03e02f (diff)
implement pruning in SkiaGlobalWinGlyphCache
Currently based on identifying the SkBitmap's by their getPixels(), but this may need changed later since it's probably going to be more performant to use SkSurface. Also move the cache pruning out of AllocateTexture(), as that may possibly remove elements that would be used by DrawCachedGlyphs(). Change-Id: Ide2de752f634593b97573667af49b7aa9ec1f47f
-rw-r--r--vcl/inc/opengl/win/winlayout.hxx5
-rw-r--r--vcl/inc/skia/salbmp.hxx1
-rw-r--r--vcl/inc/skia/win/winlayout.hxx16
-rw-r--r--vcl/inc/win/winlayout.hxx6
-rw-r--r--vcl/opengl/win/winlayout.cxx9
-rw-r--r--vcl/skia/win/winlayout.cxx43
-rw-r--r--vcl/win/gdi/winlayout.cxx13
7 files changed, 86 insertions, 7 deletions
diff --git a/vcl/inc/opengl/win/winlayout.hxx b/vcl/inc/opengl/win/winlayout.hxx
index c6ce77bdad4e..24c2fc296b2c 100644
--- a/vcl/inc/opengl/win/winlayout.hxx
+++ b/vcl/inc/opengl/win/winlayout.hxx
@@ -33,12 +33,17 @@ struct OpenGLGlobalWinGlyphCache : public GlobalWinGlyphCache
PackedTextureAtlasManager maPackedTextureAtlas;
virtual bool AllocateTexture(WinGlyphDrawElement& rElement, int nWidth, int nHeight) override;
+ virtual void Prune() override;
};
class OpenGLWinGlyphCache : public WinGlyphCache
{
public:
void RemoveTextures(std::vector<GLuint>& rTextureIDs);
+
+private:
+ // This class just "adds" RemoveTextures() to the base class, it's never instantiatied.
+ OpenGLWinGlyphCache() = delete;
};
#endif // INCLUDED_VCL_INC_OPENGL_WIN_WINLAYOUT_HXX
diff --git a/vcl/inc/skia/salbmp.hxx b/vcl/inc/skia/salbmp.hxx
index 7c8ea900c241..b7d0bd25a1b6 100644
--- a/vcl/inc/skia/salbmp.hxx
+++ b/vcl/inc/skia/salbmp.hxx
@@ -78,6 +78,7 @@ private:
void verify() const {};
#endif
+ // TODO use something GPU-backed, or at least cache it for when drawing it to something GPU-backed?
SkBitmap mBitmap;
SkBitmap mAlphaBitmap; // TODO for use as an alpha channel or mask
BitmapPalette mPalette;
diff --git a/vcl/inc/skia/win/winlayout.hxx b/vcl/inc/skia/win/winlayout.hxx
index 2455c39d06e8..a577c357b84f 100644
--- a/vcl/inc/skia/win/winlayout.hxx
+++ b/vcl/inc/skia/win/winlayout.hxx
@@ -22,9 +22,25 @@
#include <win/winlayout.hxx>
+#include <vector>
+
struct SkiaGlobalWinGlyphCache : public GlobalWinGlyphCache
{
virtual bool AllocateTexture(WinGlyphDrawElement& rElement, int nWidth, int nHeight) override;
+ virtual void NotifyElementUsed(WinGlyphDrawElement& rElement) override;
+ virtual void Prune() override;
+ // The least recently used SkBitmap order, identified by SkBitmap::getPixels().
+ std::vector<void*> mLRUOrder;
+};
+
+class SkiaWinGlyphCache : public WinGlyphCache
+{
+public:
+ void RemoveTextures(const std::vector<void*>& pixels);
+
+private:
+ // This class just "adds" RemoveTexture() to the base class, it's never instantiatied.
+ SkiaWinGlyphCache() = delete;
};
#endif // INCLUDED_VCL_INC_SKIA_WIN_WINLAYOUT_HXX
diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx
index 0e819d7de369..0bd9222c0521 100644
--- a/vcl/inc/win/winlayout.hxx
+++ b/vcl/inc/win/winlayout.hxx
@@ -65,6 +65,8 @@ struct GlobalWinGlyphCache
static GlobalWinGlyphCache * get();
virtual bool AllocateTexture(WinGlyphDrawElement& rElement, int nWidth, int nHeight) = 0;
+ virtual void NotifyElementUsed(WinGlyphDrawElement& /*rElement*/) {}
+ virtual void Prune() {}
};
class WinGlyphCache
@@ -96,7 +98,9 @@ public:
{
assert(GlobalWinGlyphCache::get());
assert(IsGlyphCached(nGlyphIndex));
- return maWinTextureCache[nGlyphIndex];
+ WinGlyphDrawElement& element = maWinTextureCache[nGlyphIndex];
+ GlobalWinGlyphCache::get()->NotifyElementUsed(element);
+ return element;
}
bool IsGlyphCached(int nGlyphIndex) const
diff --git a/vcl/opengl/win/winlayout.cxx b/vcl/opengl/win/winlayout.cxx
index ddc72c8b28cf..52569682af06 100644
--- a/vcl/opengl/win/winlayout.cxx
+++ b/vcl/opengl/win/winlayout.cxx
@@ -20,16 +20,17 @@ bool OpenGLGlobalWinGlyphCache::AllocateTexture(WinGlyphDrawElement& rElement, i
texture->texture = maPackedTextureAtlas.Reserve(nWidth, nHeight);
if (!texture->texture)
return false;
+ return true;
+}
+
+void OpenGLGlobalWinGlyphCache::Prune()
+{
std::vector<GLuint> aTextureIDs = maPackedTextureAtlas.ReduceTextureNumber(8);
if (!aTextureIDs.empty())
{
for (auto& pWinGlyphCache : maWinGlyphCaches)
- {
- assert(dynamic_cast<OpenGLWinGlyphCache*>(pWinGlyphCache));
static_cast<OpenGLWinGlyphCache*>(pWinGlyphCache)->RemoveTextures(aTextureIDs);
- }
}
- return true;
}
void OpenGLWinGlyphCache::RemoveTextures(std::vector<GLuint>& rTextureIDs)
diff --git a/vcl/skia/win/winlayout.cxx b/vcl/skia/win/winlayout.cxx
index bd232c1d2bbf..5b38b0e63f81 100644
--- a/vcl/skia/win/winlayout.cxx
+++ b/vcl/skia/win/winlayout.cxx
@@ -17,10 +17,51 @@ bool SkiaGlobalWinGlyphCache::AllocateTexture(WinGlyphDrawElement& rElement, int
assert(rElement.maTexture.get() == nullptr);
SkiaCompatibleDC::Texture* texture = new SkiaCompatibleDC::Texture;
rElement.maTexture.reset(texture);
+ // TODO use something GPU-backed?
+ // TODO is it possible to have an atlas?
if (!texture->bitmap.tryAllocN32Pixels(nWidth, nHeight))
return false;
- // TODO prune cache
+ mLRUOrder.push_back(texture->bitmap.getPixels());
return true;
}
+void SkiaGlobalWinGlyphCache::Prune()
+{
+ const int MAXSIZE = 64; // TODO
+ if (mLRUOrder.size() > MAXSIZE)
+ {
+ size_t toRemove = mLRUOrder.size() - MAXSIZE;
+ std::vector<void*> pixelsToRemove(mLRUOrder.begin(), mLRUOrder.begin() + toRemove);
+ mLRUOrder.erase(mLRUOrder.begin(), mLRUOrder.begin() + toRemove);
+ for (auto& pWinGlyphCache : maWinGlyphCaches)
+ static_cast<SkiaWinGlyphCache*>(pWinGlyphCache)->RemoveTextures(pixelsToRemove);
+ }
+}
+
+void SkiaGlobalWinGlyphCache::NotifyElementUsed(WinGlyphDrawElement& rElement)
+{
+ SkiaCompatibleDC::Texture* texture
+ = static_cast<SkiaCompatibleDC::Texture*>(rElement.maTexture.get());
+ // make the most recently used
+ auto it = find(mLRUOrder.begin(), mLRUOrder.end(), texture->bitmap.getPixels());
+ if (it != mLRUOrder.end())
+ mLRUOrder.erase(it);
+ mLRUOrder.push_back(texture->bitmap.getPixels());
+}
+
+void SkiaWinGlyphCache::RemoveTextures(const std::vector<void*>& pixelsToRemove)
+{
+ auto it = maWinTextureCache.begin();
+ while (it != maWinTextureCache.end())
+ {
+ assert(dynamic_cast<SkiaCompatibleDC::Texture*>(it->second.maTexture.get()));
+ void* pixels = static_cast<SkiaCompatibleDC::Texture*>(it->second.maTexture.get())
+ ->bitmap.getPixels();
+ if (std::find(pixelsToRemove.begin(), pixelsToRemove.end(), pixels) != pixelsToRemove.end())
+ it = maWinTextureCache.erase(it);
+ else
+ ++it;
+ }
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index a3bc032c4844..906f8a35349b 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -522,6 +522,11 @@ bool WinSalGraphics::DrawCachedGlyphs(const GenericSalLayout& rLayout)
return true;
}
+static void PruneGlyphCache()
+{
+ GlobalWinGlyphCache::get()->Prune();
+}
+
void WinSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout, HDC hDC, bool bUseDWrite)
{
TextOutRenderer &render = TextOutRenderer::get(bUseDWrite);
@@ -549,8 +554,14 @@ void WinSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
::SelectFont(hDC, hOrigFont);
}
// if we can't draw the cached OpenGL glyphs, try to draw a full OpenGL layout
- else if (bForceGDI || !CacheGlyphs(rLayout) || !DrawCachedGlyphs(rLayout))
+ else if (!bForceGDI && CacheGlyphs(rLayout) && DrawCachedGlyphs(rLayout))
{
+ PruneGlyphCache();
+ }
+ else
+ {
+ PruneGlyphCache(); // prune the cache from the failed calls above
+
// We have to render the text to a hidden texture, and draw it.
//
// Note that Windows GDI does not really support the alpha correctly