From bf5ded9c02bc9a13f98f876b281de2960afbc406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 8 Nov 2025 15:46:00 +0100 Subject: [PATCH] Fix font loading for the UWP backend, although wacky rendering issues remain --- Common/Render/Text/draw_text_uwp.cpp | 167 +++++++++++++++------------ Common/Render/Text/draw_text_uwp.h | 10 +- UI/NativeApp.cpp | 5 +- UWP/UWP.vcxproj | 14 ++- UWP/UWP.vcxproj.filters | 14 ++- 5 files changed, 126 insertions(+), 84 deletions(-) diff --git a/Common/Render/Text/draw_text_uwp.cpp b/Common/Render/Text/draw_text_uwp.cpp index bf784d8fa9..e4c904759e 100644 --- a/Common/Render/Text/draw_text_uwp.cpp +++ b/Common/Render/Text/draw_text_uwp.cpp @@ -1,4 +1,5 @@ #include "ppsspp_config.h" + #include "Common/System/Display.h" #include "Common/GPU/thin3d.h" #include "Common/Data/Hash/Hash.h" @@ -6,17 +7,21 @@ #include "Common/Data/Encoding/Utf8.h" #include "Common/Render/Text/draw_text.h" #include "Common/Render/Text/draw_text_uwp.h" - +#include "Common/File/VFS/VFS.h" #include "Common/Log.h" #include "Common/StringUtils.h" +#include "Common/File/Path.h" #if PPSSPP_PLATFORM(UWP) +#include #include #include #include #include +using namespace Microsoft::WRL; + enum { MAX_TEXT_WIDTH = 4096, MAX_TEXT_HEIGHT = 512 @@ -24,47 +29,43 @@ enum { class TextDrawerFontContext { public: - ~TextDrawerFontContext() { - Destroy(); - } - - void Create() { - if (textFmt) { - Destroy(); + TextDrawerFontContext(const FontStyle &_style, float _dpiScale, IDWriteFactory4 *factory, IDWriteFontCollection1 *fontCollection) : style(_style), dpiScale(_dpiScale) { + DWRITE_FONT_STYLE fontStyle = DWRITE_FONT_STYLE_NORMAL; + DWRITE_FONT_WEIGHT weight = DWRITE_FONT_WEIGHT_NORMAL; + int height = style.sizePts; + FontStyleFlags styleFlags = FontStyleFlags::Default; + std::string fontName = GetFontNameForFontStyle(style, &styleFlags); + if (styleFlags & FontStyleFlags::Bold) { + weight = DWRITE_FONT_WEIGHT_BOLD; } - - if (!factory) { - return; + if (styleFlags & FontStyleFlags::Italic) { + fontStyle = DWRITE_FONT_STYLE_ITALIC; } HRESULT hr = factory->CreateTextFormat( - fname.c_str(), + ConvertUTF8ToWString(fontName).c_str(), fontCollection, weight, - italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, + fontStyle, DWRITE_FONT_STRETCH_NORMAL, (float)MulDiv(height, (int)(96.0f * (1.0f / dpiScale)), 72), - L"", + L"en-us", &textFmt ); if (FAILED(hr)) { - ERROR_LOG(Log::G3D, "Failed creating font %s", fname.c_str()); + ERROR_LOG(Log::G3D, "Failed creating text format for font %s", fontName.c_str()); } } - void Destroy() { + + ~TextDrawerFontContext() { if (textFmt) { textFmt->Release(); } textFmt = nullptr; } - IDWriteFactory4 *factory = nullptr; - IDWriteFontCollection1 *fontCollection = nullptr; IDWriteTextFormat *textFmt = nullptr; - std::wstring fname; - int height; - DWRITE_FONT_WEIGHT weight; - bool italic = false; + FontStyle style; float dpiScale; }; @@ -105,18 +106,65 @@ TextDrawerUWP::TextDrawerUWP(Draw::DrawContext *draw) : TextDrawer(draw), ctx_(n hr = m_d2dDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &m_d2dContext); if (FAILED(hr)) _assert_msg_(false, "D2D CreateDeviceContext failed"); - // Load the Roboto font - hr = m_dwriteFactory->CreateFontFileReference(L"Content/Roboto-Condensed.ttf", nullptr, &m_fontFile); - if (FAILED(hr)) ERROR_LOG(Log::System, "CreateFontFileReference failed"); hr = m_dwriteFactory->CreateFontSetBuilder(&m_fontSetBuilder); if (FAILED(hr)) ERROR_LOG(Log::System, "CreateFontSetBuilder failed"); - hr = m_fontSetBuilder->AddFontFile(m_fontFile); + + hr = m_dwriteFactory->CreateInMemoryFontFileLoader(&m_inMemoryLoader); + if (FAILED(hr)) { + // handle error + } + m_dwriteFactory->RegisterFontFileLoader(m_inMemoryLoader); + + // Load our fonts. + std::vector fontFilenames; + GetFilenamesForFontStyle(FontStyle{}, &fontFilenames, true); + for (const auto &fname : fontFilenames) { + size_t size; + uint8_t *data = g_VFS.ReadFile(fname.c_str(), &size); + + ComPtr fontFile; + hr = m_inMemoryLoader->CreateInMemoryFontFileReference( + m_dwriteFactory, + data, + static_cast(size), + nullptr, // optional last write time + &fontFile + ); + + m_fontSetBuilder->AddFontFile(fontFile.Get()); + + delete[] data; + m_fontFiles.push_back(fontFile); + } + hr = m_fontSetBuilder->CreateFontSet(&m_fontSet); hr = m_dwriteFactory->CreateFontCollectionFromFontSet(m_fontSet, &m_fontCollection); + UINT32 familyCount = m_fontCollection->GetFontFamilyCount(); + for (UINT32 i = 0; i < familyCount; ++i) { + IDWriteFontFamily *family; + m_fontCollection->GetFontFamily(i, &family); + + IDWriteLocalizedStrings *names; + family->GetFamilyNames(&names); + + UINT32 length = 0; + names->GetStringLength(0, &length); + + std::wstring name(length + 1, L'\0'); + names->GetString(0, &name[0], length + 1); + + std::string nname = ConvertWStringToUTF8(name); + + NOTICE_LOG(Log::G3D, "Font family: %s", nname.c_str()); + + names->Release(); + family->Release(); + } + ctx_ = new TextDrawerContext(); - D2D1_BITMAP_PROPERTIES1 properties; + D2D1_BITMAP_PROPERTIES1 properties{}; properties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; properties.dpiX = 96.0f; @@ -154,64 +202,38 @@ TextDrawerUWP::~TextDrawerUWP() { ctx_->bitmap->Release(); ctx_->mirror_bmp->Release(); + m_dwriteFactory->UnregisterFontFileLoader(m_inMemoryLoader); + m_fontCollection->Release(); + m_fontSet->Release(); + for (auto file : m_fontFiles) { + file->Release(); + } + m_fontFiles.clear(); + m_fontSetBuilder->Release(); + m_dwriteFactory->Release(); + m_inMemoryLoader->Release(); + m_d2dWhiteBrush->Release(); m_d2dContext->Release(); m_d2dDevice->Release(); m_d2dFactory->Release(); - - m_fontCollection->Release(); - m_fontSet->Release(); - m_fontFile->Release(); - m_fontSetBuilder->Release(); - m_dwriteFactory->Release(); delete ctx_; } -uint32_t TextDrawerUWP::SetOrCreateFont(const FontStyle &style) { - const uint32_t fontHash = style.Hash(); - - auto iter = fontMap_.find(fontHash); +void TextDrawerUWP::SetOrCreateFont(const FontStyle &style) { + auto iter = fontMap_.find(style); if (iter != fontMap_.end()) { - fontHash_ = fontHash; - return fontHash; + fontStyle_ = style; + return; } - std::wstring fname; - if (!style.fontName.empty()) - fname = ConvertUTF8ToWString(style.fontName); - else - fname = L"Tahoma"; - - TextDrawerFontContext *font = new TextDrawerFontContext(); - font->weight = DWRITE_FONT_WEIGHT_NORMAL; - if (style.flags & FontStyleFlags::Bold) { - font->weight = DWRITE_FONT_WEIGHT_BOLD; - } - if (style.flags & FontStyleFlags::Italic) { - font->italic = true; - } - font->height = style.sizePts; - font->fname = fname; - font->dpiScale = dpiScale_; - font->factory = m_dwriteFactory; - font->fontCollection = m_fontCollection; - font->Create(); - - fontMap_[fontHash] = std::unique_ptr(font); - fontHash_ = fontHash; - return fontHash; -} - -void TextDrawerUWP::SetFont(uint32_t fontHandle) { - auto iter = fontMap_.find(fontHandle); - if (iter != fontMap_.end()) { - fontHash_ = fontHandle; - } + fontMap_[style] = std::make_unique(style, dpiScale_, m_dwriteFactory, m_fontCollection); + fontStyle_ = style; } void TextDrawerUWP::MeasureStringInternal(std::string_view str, float *w, float *h) { IDWriteTextFormat* format = nullptr; - auto iter = fontMap_.find(fontHash_); + auto iter = fontMap_.find(fontStyle_); if (iter != fontMap_.end()) { format = iter->second->textFmt; } @@ -249,7 +271,7 @@ bool TextDrawerUWP::DrawStringBitmap(std::vector &bitmapData, TextStrin SIZE size; IDWriteTextFormat *format = nullptr; - auto iter = fontMap_.find(fontHash_); + auto iter = fontMap_.find(fontStyle_); if (iter != fontMap_.end()) { format = iter->second->textFmt; } @@ -377,7 +399,6 @@ bool TextDrawerUWP::DrawStringBitmap(std::vector &bitmapData, TextStrin void TextDrawerUWP::ClearFonts() { for (auto &iter : fontMap_) { iter.second->dpiScale = dpiScale_; - iter.second->Destroy(); } fontMap_.clear(); } diff --git a/Common/Render/Text/draw_text_uwp.h b/Common/Render/Text/draw_text_uwp.h index abb31239b5..f1c50f8e6f 100644 --- a/Common/Render/Text/draw_text_uwp.h +++ b/Common/Render/Text/draw_text_uwp.h @@ -9,6 +9,7 @@ #include #include +#include struct TextDrawerContext; // Internal struct but all details in .cpp file (pimpl to avoid pulling in excessive headers here) @@ -19,8 +20,7 @@ public: TextDrawerUWP(Draw::DrawContext *draw); ~TextDrawerUWP(); - uint32_t SetOrCreateFont(const FontStyle &style) override; - void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. + void SetOrCreateFont(const FontStyle &style) override; bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; protected: @@ -29,7 +29,7 @@ protected: void ClearFonts() override; TextDrawerContext *ctx_; - std::map> fontMap_; + std::map> fontMap_; // Direct2D drawing components. ID2D1Factory5* m_d2dFactory; @@ -39,11 +39,11 @@ protected: // DirectWrite drawing components. IDWriteFactory5* m_dwriteFactory; - IDWriteFontFile* m_fontFile; IDWriteFontSet* m_fontSet; IDWriteFontSetBuilder1* m_fontSetBuilder; IDWriteFontCollection1* m_fontCollection; - + IDWriteInMemoryFontFileLoader *m_inMemoryLoader; + std::vector> m_fontFiles; }; #endif diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 3ccda5c85d..dda8928c78 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -698,10 +698,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch auto des = GetI18NCategory(I18NCat::DESKTOPUI); -#if PPSSPP_PLATFORM(UWP) - // Roboto font is loaded in TextDrawerUWP. - g_Config.sFont = des->T("Font", "Roboto"); -#elif defined(USING_QT_UI) +#if defined(USING_QT_UI) size_t fontSize = 0; uint8_t *fontData = g_VFS.ReadFile("Roboto-Condensed.ttf", &fontSize); if (fontData) { diff --git a/UWP/UWP.vcxproj b/UWP/UWP.vcxproj index 34ad349efd..eb7bc46259 100644 --- a/UWP/UWP.vcxproj +++ b/UWP/UWP.vcxproj @@ -451,7 +451,19 @@ - + + Content\%(Filename)%(Extension) + + + Content\%(Filename)%(Extension) + + + Content\%(Filename)%(Extension) + + + Content\%(Filename)%(Extension) + + Content\%(Filename)%(Extension) diff --git a/UWP/UWP.vcxproj.filters b/UWP/UWP.vcxproj.filters index 1ae80fef1c..e9d9ff7c22 100644 --- a/UWP/UWP.vcxproj.filters +++ b/UWP/UWP.vcxproj.filters @@ -290,7 +290,19 @@ - + + Content + + + Content + + + Content + + + Content + + Content