[PATCH] usp10: Re-use script caches for the same DC.

Thomas Faber thomas.faber at reactos.org
Sat Jan 13 09:10:52 CST 2018


This significantly (50% in my tests) speeds up loading large files in
notepad. Tests show that native seems to do something similar.
-------------- next part --------------
From a1a958ec8045667becc6902cb1e70de156f0a777 Mon Sep 17 00:00:00 2001
From: Thomas Faber <thomas.faber at reactos.org>
Date: Fri, 12 Jan 2018 14:30:13 +0100
Subject: usp10: Re-use script caches for the same DC.

This makes the caching much more efficient, in particular for cases
like the EDIT control, which calls ScriptStringAnalyse once per line
of text.
Speeds up loading large files in notepad (bug 23193).

Signed-off-by: Thomas Faber <thomas.faber at reactos.org>
---
 dlls/usp10/tests/usp10.c    | 11 ++++++++++
 dlls/usp10/usp10.c          | 53 +++++++++++++++++++++++++++++++++++++++++++++
 dlls/usp10/usp10_internal.h |  6 +++++
 3 files changed, 70 insertions(+)

diff --git a/dlls/usp10/tests/usp10.c b/dlls/usp10/tests/usp10.c
index 35cdec545b88..1acf22f30e5d 100644
--- a/dlls/usp10/tests/usp10.c
+++ b/dlls/usp10/tests/usp10.c
@@ -1833,6 +1833,7 @@ static void test_ScriptShape(HDC hdc)
     static const WCHAR test3[] = {0x30b7};
     HRESULT hr;
     SCRIPT_CACHE sc = NULL;
+    SCRIPT_CACHE sc2 = NULL;
     WORD glyphs[4], glyphs2[4], logclust[4], glyphs3[4];
     SCRIPT_VISATTR attrs[4];
     SCRIPT_ITEM items[4];
@@ -1862,6 +1863,10 @@ static void test_ScriptShape(HDC hdc)
     ok(hr == S_OK, "ScriptShape should return S_OK not %08x\n", hr);
     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
 
+    hr = ScriptShape(hdc, &sc2, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb);
+    ok(hr == S_OK, "ScriptShape should return S_OK not %08x\n", hr);
+    ok(sc2 == sc, "caches %p, %p not identical\n", sc, sc2);
+    ScriptFreeCache(&sc2);
 
     memset(glyphs,-1,sizeof(glyphs));
     memset(logclust,-1,sizeof(logclust));
@@ -2087,6 +2092,7 @@ static void test_ScriptPlace(HDC hdc)
     BOOL ret;
     HRESULT hr;
     SCRIPT_CACHE sc = NULL;
+    SCRIPT_CACHE sc2 = NULL;
     WORD glyphs[4], logclust[4];
     SCRIPT_VISATTR attrs[4];
     SCRIPT_ITEM items[2];
@@ -2124,6 +2130,11 @@ static void test_ScriptPlace(HDC hdc)
     ok(hr == S_OK, "ScriptPlace should return S_OK not %08x\n", hr);
     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
 
+    hr = ScriptPlace(hdc, &sc2, glyphs, 4, attrs, &items[0].a, widths, offset, NULL);
+    ok(hr == S_OK, "ScriptPlace should return S_OK not %08x\n", hr);
+    ok(sc2 == sc, "caches %p, %p not identical\n", sc, sc2);
+    ScriptFreeCache(&sc2);
+
     if (widths[0] != 0)
     {
         int old_width = widths[0];
diff --git a/dlls/usp10/usp10.c b/dlls/usp10/usp10.c
index 5d257b2c1c0a..bcbc42acd74b 100644
--- a/dlls/usp10/usp10.c
+++ b/dlls/usp10/usp10.c
@@ -675,6 +675,16 @@ static const SCRIPT_PROPERTIES *script_props[] =
     &scriptInformation[80].props, &scriptInformation[81].props
 };
 
+static CRITICAL_SECTION cs_script_cache;
+static CRITICAL_SECTION_DEBUG cs_script_cache_dbg =
+{
+    0, 0, &cs_script_cache,
+    { &cs_script_cache_dbg.ProcessLocksList, &cs_script_cache_dbg.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": script_cache") }
+};
+static CRITICAL_SECTION cs_script_cache = { &cs_script_cache_dbg, -1, 0, 0, 0, 0 };
+static struct list script_cache_list = LIST_INIT(script_cache_list);
+
 typedef struct {
     ScriptCache *sc;
     int numGlyphs;
@@ -859,6 +869,19 @@ static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
     if (*psc) return S_OK;
     if (!hdc) return E_PENDING;
 
+    EnterCriticalSection(&cs_script_cache);
+    LIST_FOR_EACH_ENTRY(sc, &script_cache_list, ScriptCache, entry)
+    {
+        if (sc->hdc == hdc)
+        {
+            sc->refcount++;
+            LeaveCriticalSection(&cs_script_cache);
+            *psc = sc;
+            return S_OK;
+        }
+    }
+    LeaveCriticalSection(&cs_script_cache);
+
     if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
     if (!GetTextMetricsW(hdc, &sc->tm))
     {
@@ -883,7 +906,26 @@ static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
         heap_free(sc);
         return E_INVALIDARG;
     }
+    sc->hdc = hdc;
+    sc->refcount = 1;
     *psc = sc;
+
+    EnterCriticalSection(&cs_script_cache);
+    list_add_head(&script_cache_list, &sc->entry);
+    LIST_FOR_EACH_ENTRY(sc, &script_cache_list, ScriptCache, entry)
+    {
+        if (sc != *psc && sc->hdc == hdc)
+        {
+            /* Another thread won the race. Use their cache instead of ours */
+            list_remove(&sc->entry);
+            sc->refcount++;
+            LeaveCriticalSection(&cs_script_cache);
+            heap_free(*psc);
+            *psc = sc;
+            return S_OK;
+        }
+    }
+    LeaveCriticalSection(&cs_script_cache);
     TRACE("<- %p\n", sc);
     return S_OK;
 }
@@ -1036,6 +1078,17 @@ HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
     {
         unsigned int i;
         INT n;
+
+        EnterCriticalSection(&cs_script_cache);
+        if (--((ScriptCache *)*psc)->refcount > 0)
+        {
+            LeaveCriticalSection(&cs_script_cache);
+            *psc = NULL;
+            return S_OK;
+        }
+        list_remove(&((ScriptCache *)*psc)->entry);
+        LeaveCriticalSection(&cs_script_cache);
+
         for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
         {
             heap_free(((ScriptCache *)*psc)->widths[i]);
diff --git a/dlls/usp10/usp10_internal.h b/dlls/usp10/usp10_internal.h
index 2dfca86ca7fe..10700590be64 100644
--- a/dlls/usp10/usp10_internal.h
+++ b/dlls/usp10/usp10_internal.h
@@ -18,6 +18,9 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
  */
+
+#include "wine/list.h"
+
 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
           ( ( (ULONG)_x4 << 24 ) |     \
             ( (ULONG)_x3 << 16 ) |     \
@@ -174,6 +177,9 @@ typedef struct {
 } CacheGlyphPage;
 
 typedef struct {
+    struct list entry;
+    HDC hdc;
+    DWORD refcount;
     LOGFONTW lf;
     TEXTMETRICW tm;
     OUTLINETEXTMETRICW *otm;
-- 
2.15.1



More information about the wine-devel mailing list