diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2019-10-23 11:29:22 +0200 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2019-11-27 09:55:10 +0100 |
commit | 619959827003814053a5e9ec81acfd07b3aa270a (patch) | |
tree | 29d77c1bc8a45f5102b62d04211bedd3d0ae41c7 | |
parent | c6b50a85a2371c1f49f75d1a9fccc8548e03e02f (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.hxx | 5 | ||||
-rw-r--r-- | vcl/inc/skia/salbmp.hxx | 1 | ||||
-rw-r--r-- | vcl/inc/skia/win/winlayout.hxx | 16 | ||||
-rw-r--r-- | vcl/inc/win/winlayout.hxx | 6 | ||||
-rw-r--r-- | vcl/opengl/win/winlayout.cxx | 9 | ||||
-rw-r--r-- | vcl/skia/win/winlayout.cxx | 43 | ||||
-rw-r--r-- | vcl/win/gdi/winlayout.cxx | 13 |
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 |