[Libreoffice-commits] core.git: Branch 'feature/skia' - vcl/inc vcl/opengl vcl/skia vcl/win

Luboš Luňák (via logerrit) logerrit at kemper.freedesktop.org
Wed Oct 23 09:59:39 UTC 2019


 vcl/inc/opengl/win/winlayout.hxx |    5 ++++
 vcl/inc/skia/salbmp.hxx          |    1 
 vcl/inc/skia/win/winlayout.hxx   |   16 ++++++++++++++
 vcl/inc/win/winlayout.hxx        |    6 ++++-
 vcl/opengl/win/winlayout.cxx     |    9 ++++----
 vcl/skia/win/winlayout.cxx       |   43 ++++++++++++++++++++++++++++++++++++++-
 vcl/win/gdi/winlayout.cxx        |   13 ++++++++++-
 7 files changed, 86 insertions(+), 7 deletions(-)

New commits:
commit ffdaff4d3d3a70bcd90cb520e049cbe36b320ea1
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Wed Oct 23 11:29:22 2019 +0200
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Wed Oct 23 11:58:22 2019 +0200

    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

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 aed6956b7ceb..f679ccf50011 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 d6baa6586b9e..f92f16d4e732 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -479,6 +479,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);
@@ -506,8 +511,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


More information about the Libreoffice-commits mailing list