Word 2016 queries a lot of font glyph bounding boxes and bitmaps with translation matrices. The result of these queries is not cached because the transform matrix is not the identity matrix. However, the translation offsets don't affect FreeType font operations at all, which can be verified in ft_matrix_from_dwrite_matrix() called by get_glyph_transform(). So these results with translation matrices can be cached as well. With this patch, Word 2016 stuttering is reduced significantly.
-- v3: dwrite: Use cache when font transform matrix contains only translation offsets.
From: Zhiyi Zhang zzhang@codeweavers.com
Word 2016 queries a lot of font glyph bounding boxes and bitmaps with translation matrices. The result of these queries is not cached because the transform matrix is not the identity matrix. However, the translation offsets don't affect FreeType font operations at all, which can be verified in ft_matrix_from_dwrite_matrix() called by get_glyph_transform(). So these results with translation matrices can be cached as well. With this patch, Word 2016 stuttering is reduced significantly. --- dlls/dwrite/dwrite_private.h | 19 +++++++++++++++++++ dlls/dwrite/font.c | 17 +++++++++++++---- dlls/dwrite/freetype.c | 12 ++++++------ dlls/dwrite/unixlib.h | 5 +++-- 4 files changed, 41 insertions(+), 12 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index d0ed1db97ef..1e84f8191c4 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -16,6 +16,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#ifndef __WINE_DWRITE_PRIVATE_H +#define __WINE_DWRITE_PRIVATE_H + #include "dwrite_3.h" #include "d2d1.h" #include "winternl.h" @@ -27,6 +30,14 @@ #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B') #define MS_GPOS_TAG DWRITE_MAKE_OPENTYPE_TAG('G','P','O','S')
+typedef struct DWRITE_MATRIX_2X2 +{ + FLOAT m11; + FLOAT m12; + FLOAT m21; + FLOAT m22; +} DWRITE_MATRIX_2X2; + static const DWRITE_MATRIX identity = { 1.0f, 0.0f, @@ -34,6 +45,12 @@ static const DWRITE_MATRIX identity = 0.0f, 0.0f };
+static const DWRITE_MATRIX_2X2 identity_2x2 = +{ + 1.0f, 0.0f, + 0.0f, 1.0f, +}; + static inline LPWSTR heap_strdupnW(const WCHAR *str, UINT32 len) { WCHAR *ret = NULL; @@ -820,3 +837,5 @@ struct font_data_context; extern HMODULE dwrite_module DECLSPEC_HIDDEN;
extern void dwrite_fontface_get_glyph_bbox(IDWriteFontFace *fontface, struct dwrite_glyphbitmap *bitmap) DECLSPEC_HIDDEN; + +#endif /* __WINE_DWRITE_PRIVATE_H */ diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 9dce26a17c2..5189be8f8ef 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -69,6 +69,15 @@ struct cache_entry unsigned int has_bitmap : 1; };
+/* Ignore dx and dy because FreeType doesn't actually use it */ +static inline void dwrite_matrix_2x2_from_matrix(DWRITE_MATRIX_2X2 *m1, const DWRITE_MATRIX *m2) +{ + m1->m11 = m2->m11; + m1->m12 = m2->m12; + m1->m21 = m2->m21; + m1->m22 = m2->m22; +} + static void fontface_release_cache_entry(struct cache_entry *entry) { free(entry->bitmap); @@ -157,11 +166,11 @@ void dwrite_fontface_get_glyph_bbox(IDWriteFontFace *iface, struct dwrite_glyphb params.simulations = bitmap->simulations; params.glyph = bitmap->glyph; params.emsize = bitmap->emsize; - params.m = bitmap->m ? *bitmap->m : identity; + dwrite_matrix_2x2_from_matrix(¶ms.m, bitmap->m ? bitmap->m : &identity);
EnterCriticalSection(&fontface->cs); /* For now bypass cache for transformed cases. */ - if (bitmap->m && memcmp(bitmap->m, &identity, sizeof(*bitmap->m))) + if (bitmap->m && memcmp(¶ms.m, &identity_2x2, sizeof(params.m))) { params.bbox = &bitmap->bbox; UNIX_CALL(get_glyph_bbox, ¶ms); @@ -202,15 +211,15 @@ static HRESULT dwrite_fontface_get_glyph_bitmap(struct dwrite_fontface *fontface params.glyph = bitmap->glyph; params.mode = rendering_mode; params.emsize = bitmap->emsize; - params.m = bitmap->m ? *bitmap->m : identity; params.bbox = bitmap->bbox; params.pitch = bitmap->pitch; params.bitmap = bitmap->buf; params.is_1bpp = is_1bpp; + dwrite_matrix_2x2_from_matrix(¶ms.m, bitmap->m ? bitmap->m : &identity);
EnterCriticalSection(&fontface->cs); /* For now bypass cache for transformed cases. */ - if (memcmp(¶ms.m, &identity, sizeof(params.m))) + if (bitmap->m && memcmp(¶ms.m, &identity_2x2, sizeof(params.m))) { UNIX_CALL(get_glyph_bitmap, ¶ms); } diff --git a/dlls/dwrite/freetype.c b/dlls/dwrite/freetype.c index 0caf2b03696..f471d5d98e9 100644 --- a/dlls/dwrite/freetype.c +++ b/dlls/dwrite/freetype.c @@ -496,7 +496,7 @@ static NTSTATUS get_glyph_count(void *args) return STATUS_SUCCESS; }
-static inline void ft_matrix_from_dwrite_matrix(const DWRITE_MATRIX *m, FT_Matrix *ft_matrix) +static inline void ft_matrix_from_dwrite_matrix_2x2(const DWRITE_MATRIX_2X2 *m, FT_Matrix *ft_matrix) { ft_matrix->xx = m->m11 * 0x10000; ft_matrix->xy = -m->m21 * 0x10000; @@ -504,7 +504,7 @@ static inline void ft_matrix_from_dwrite_matrix(const DWRITE_MATRIX *m, FT_Matri ft_matrix->yy = m->m22 * 0x10000; }
-static BOOL get_glyph_transform(unsigned int simulations, const DWRITE_MATRIX *m, FT_Matrix *ret) +static BOOL get_glyph_transform(unsigned int simulations, const DWRITE_MATRIX_2X2 *m, FT_Matrix *ret) { FT_Matrix ftm;
@@ -515,7 +515,7 @@ static BOOL get_glyph_transform(unsigned int simulations, const DWRITE_MATRIX *m
/* Some fonts provide mostly bitmaps and very few outlines, for example for .notdef. Disable transform if that's the case. */ - if (!memcmp(m, &identity, sizeof(*m)) && !simulations) + if (!memcmp(m, &identity_2x2, sizeof(*m)) && !simulations) return FALSE;
if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) @@ -527,7 +527,7 @@ static BOOL get_glyph_transform(unsigned int simulations, const DWRITE_MATRIX *m pFT_Matrix_Multiply(&ftm, ret); }
- ft_matrix_from_dwrite_matrix(m, &ftm); + ft_matrix_from_dwrite_matrix_2x2(m, &ftm); pFT_Matrix_Multiply(&ftm, ret);
return TRUE; @@ -955,7 +955,7 @@ static NTSTATUS wow64_get_glyph_bbox(void *args) ULONG simulations; ULONG glyph; float emsize; - DWRITE_MATRIX m; + DWRITE_MATRIX_2X2 m; PTR32 bbox; } const *params32 = args; struct get_glyph_bbox_params params = @@ -980,7 +980,7 @@ static NTSTATUS wow64_get_glyph_bitmap(void *args) ULONG glyph; ULONG mode; float emsize; - DWRITE_MATRIX m; + DWRITE_MATRIX_2X2 m; RECT bbox; int pitch; PTR32 bitmap; diff --git a/dlls/dwrite/unixlib.h b/dlls/dwrite/unixlib.h index c63d5bea722..383b7532a57 100644 --- a/dlls/dwrite/unixlib.h +++ b/dlls/dwrite/unixlib.h @@ -20,6 +20,7 @@ #include "windef.h" #include "winternl.h" #include "dwrite.h" +#include "dwrite_private.h" #include "wine/unixlib.h"
struct create_font_object_params @@ -66,7 +67,7 @@ struct get_glyph_bbox_params unsigned int simulations; unsigned int glyph; float emsize; - DWRITE_MATRIX m; + DWRITE_MATRIX_2X2 m; RECT *bbox; };
@@ -77,7 +78,7 @@ struct get_glyph_bitmap_params unsigned int glyph; unsigned int mode; float emsize; - DWRITE_MATRIX m; + DWRITE_MATRIX_2X2 m; RECT bbox; int pitch; BYTE *bitmap;
On Mon Mar 27 04:05:49 2023 +0000, **** wrote:
Marvin replied on the mailing list:
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details: The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=131093 Your paranoid android. === debian11b (build log) === ../wine/dlls/dwrite/freetype.c:967:9: error: incompatible types when initializing type ???float??? using type ???DWRITE_MATRIX??? ../wine/dlls/dwrite/freetype.c:968:9: error: incompatible types when initializing type ???float??? using type ???void *??? ../wine/dlls/dwrite/freetype.c:996:9: error: incompatible types when initializing type ???float??? using type ???DWRITE_MATRIX??? ../wine/dlls/dwrite/freetype.c:997:9: error: incompatible types when initializing type ???float??? using type ???RECT??? {aka ???const struct tagRECT???} ../wine/dlls/dwrite/freetype.c:999:9: error: incompatible types when initializing type ???float??? using type ???void *??? Task: The wow64 Wine build failed
This is from the older revision. It's fixed now.
Nikolay Sivov (@nsivov) commented about dlls/dwrite/dwrite_private.h:
#define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B') #define MS_GPOS_TAG DWRITE_MAKE_OPENTYPE_TAG('G','P','O','S')
+typedef struct DWRITE_MATRIX_2X2 +{
- FLOAT m11;
- FLOAT m12;
- FLOAT m21;
- FLOAT m22;
+} DWRITE_MATRIX_2X2;
This looks fine, but let's give this one a more private name without DWRITE_ prefix, and with "float".