From 323d06bbc21e1350b46c12615988966b486c2250 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Aug 2021 17:35:37 -0700 Subject: [PATCH 1/5] Font: Reuse alloc when reopening internal fonts. As shown in the font/open test. --- Core/HLE/sceFont.cpp | 108 ++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 38 deletions(-) diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 89d5f79a38..f6dfa4631d 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -32,11 +32,6 @@ enum { ERROR_FONT_INVALID_FONT_DATA = 0x8046000a, }; -enum { - FONT_IS_CLOSED = 0, - FONT_IS_OPEN = 1, -}; - // For the save states. static bool useAllocCallbacks = true; @@ -511,8 +506,8 @@ public: void Done() { for (size_t i = 0; i < fonts_.size(); i++) { - if (isfontopen_[i] == FONT_IS_OPEN) { - CloseFont(fontMap[fonts_[i]]); + if (fontRefCount_[i] > 0) { + CloseFont(fontMap[fonts_[i]], true); delete fontMap[fonts_[i]]; fontMap.erase(fonts_[i]); } @@ -526,18 +521,18 @@ public: } handle_ = 0; fonts_.clear(); - isfontopen_.clear(); + fontRefCount_.clear(); openAllocatedAddresses_.clear(); } void AllocDone(u32 allocatedAddr) { handle_ = allocatedAddr; fonts_.resize(params_.numFonts); - isfontopen_.resize(params_.numFonts); + fontRefCount_.resize(params_.numFonts); openAllocatedAddresses_.resize(params_.numFonts); for (size_t i = 0; i < fonts_.size(); i++) { u32 addr = allocatedAddr + 0x4C + (u32)i * 0x4C; - isfontopen_[i] = 0; + fontRefCount_[i] = 0; fonts_[i] = addr; } @@ -588,34 +583,40 @@ public: LoadedFont *OpenFont(Font *font, FontOpenMode mode, int &error) { // TODO: Do something with mode, possibly save it where the PSP does in the struct. // Maybe needed in Font, though? Handlers seem... difficult to emulate. - int freeFontIndex = -1; - for (size_t i = 0; i < fonts_.size(); i++) { - if (isfontopen_[i] == 0) { - freeFontIndex = (int)i; - break; - } - } - if (freeFontIndex < 0) { + + // First, check if the font is already open. We need to refcount, see font/open test. + int foundFontIndex = FindExistingIndex(font); + if (foundFontIndex < 0) + foundFontIndex = FindFreeIndex(); + + if (foundFontIndex < 0) { ERROR_LOG(SCEFONT, "Too many fonts opened in FontLib"); error = ERROR_FONT_TOO_MANY_OPEN_FONTS; - return 0; + return nullptr; } if (!font->IsValid()) { ERROR_LOG(SCEFONT, "Invalid font data"); error = ERROR_FONT_INVALID_FONT_DATA; - return 0; + return nullptr; } - LoadedFont *loadedFont = new LoadedFont(font, mode, GetListID(), fonts_[freeFontIndex]); - isfontopen_[freeFontIndex] = 1; - auto prevFont = fontMap.find(loadedFont->Handle()); - if (prevFont != fontMap.end()) { - // Before replacing it and forgetting about it, let's free it. - delete prevFont->second; + LoadedFont *loadedFont = nullptr; + if (fontRefCount_[foundFontIndex] == 0) { + loadedFont = new LoadedFont(font, mode, GetListID(), fonts_[foundFontIndex]); + + auto prevFont = fontMap.find(loadedFont->Handle()); + if (prevFont != fontMap.end()) { + // Before replacing it and forgetting about it, let's free it. + delete prevFont->second; + } + fontMap[loadedFont->Handle()] = loadedFont; + } else { + loadedFont = fontMap[fonts_[foundFontIndex]]; } - fontMap[loadedFont->Handle()] = loadedFont; + fontRefCount_[foundFontIndex]++; - if (!useAllocCallbacks) + // Only need to allocate the first time. + if (!useAllocCallbacks || fontRefCount_[foundFontIndex] > 1) return loadedFont; u32 allocSize = 12; @@ -627,7 +628,7 @@ public: PostOpenAllocCallback *action = (PostOpenAllocCallback *)__KernelCreateAction(actionPostOpenAllocCallback); action->SetFontLib(GetListID()); - action->SetFont(loadedFont->Handle(), freeFontIndex); + action->SetFont(loadedFont->Handle(), foundFontIndex); u32 args[2] = { userDataAddr(), allocSize }; hleEnqueueCall(allocFuncAddr(), 2, args, action); @@ -635,11 +636,18 @@ public: return loadedFont; } - void CloseFont(LoadedFont *font) { + void CloseFont(LoadedFont *font, bool releaseAll) { + bool allowClose = true; for (size_t i = 0; i < fonts_.size(); i++) { - if (fonts_[i] == font->Handle()) { - isfontopen_[i] = 0; - if (openAllocatedAddresses_[i] != 0 && coreState != CORE_POWERDOWN) { + if (fonts_[i] == font->Handle() && fontRefCount_[i] > 0) { + if (releaseAll) + fontRefCount_[i] = 0; + else + fontRefCount_[i]--; + + allowClose = fontRefCount_[i] == 0; + bool deallocate = allowClose && openAllocatedAddresses_[i] != 0; + if (deallocate && coreState != CORE_POWERDOWN) { u32 args[2] = { userDataAddr(), openAllocatedAddresses_[i] }; hleEnqueueCall(freeFuncAddr(), 2, args); openAllocatedAddresses_[i] = 0; @@ -648,7 +656,8 @@ public: } } flushFont(); - font->Close(); + if (allowClose) + font->Close(); } void flushFont() { @@ -665,7 +674,7 @@ public: return; Do(p, fonts_); - Do(p, isfontopen_); + Do(p, fontRefCount_); Do(p, params_); Do(p, fontHRes_); Do(p, fontVRes_); @@ -708,8 +717,31 @@ public: void SetCharInfoBitmapAddress(u32 addr) { charInfoBitmapAddress_ = addr; } private: + int FindExistingIndex(Font *font) const { + // TODO: Should this also match for memory fonts, or only internal fonts? + for (auto it : fontMap) { + if (it.second->GetFont() != font || it.second->GetFontLib() != this) + continue; + for (size_t i = 0; i < fonts_.size(); i++) { + if (fonts_[i] == it.first) { + return (int)i; + } + } + } + return -1; + } + + int FindFreeIndex() const { + for (size_t i = 0; i < fonts_.size(); i++) { + if (fontRefCount_[i] == 0) { + return (int)i; + } + } + return -1; + } + std::vector fonts_; - std::vector isfontopen_; + std::vector fontRefCount_; FontNewLibParams params_; float fontHRes_; @@ -897,7 +929,7 @@ void __FontShutdown() { for (auto iter = fontMap.begin(); iter != fontMap.end(); iter++) { FontLib *fontLib = iter->second->GetFontLib(); if (fontLib) - fontLib->CloseFont(iter->second); + fontLib->CloseFont(iter->second, true); delete iter->second; } fontMap.clear(); @@ -1106,7 +1138,7 @@ static int sceFontClose(u32 fontHandle) { DEBUG_LOG(SCEFONT, "sceFontClose(%x)", fontHandle); FontLib *fontLib = font->GetFontLib(); if (fontLib) { - fontLib->CloseFont(font); + fontLib->CloseFont(font, false); } } else ERROR_LOG(SCEFONT, "sceFontClose(%x) - font not open?", fontHandle); From cb5954c9e31010edc5fa08f7ea8b4ccf73971a10 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Aug 2021 17:36:29 -0700 Subject: [PATCH 2/5] Font: Delay only on first open of internal font. --- Core/HLE/sceFont.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index f6dfa4631d..80b4a716b3 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -579,6 +579,13 @@ public: return fonts_[index]; } + int GetFontRefCount(Font *font) const { + int foundFontIndex = FindExistingIndex(font); + if (foundFontIndex >= 0) + return fontRefCount_.at(foundFontIndex); + return 0; + } + // For FONT_OPEN_USER* modes, the font will automatically be freed. LoadedFont *OpenFont(Font *font, FontOpenMode mode, int &error) { // TODO: Do something with mode, possibly save it where the PSP does in the struct. @@ -1033,10 +1040,12 @@ static u32 sceFontOpen(u32 libHandle, u32 index, u32 mode, u32 errorCodePtr) { LoadedFont *font = fontLib->OpenFont(internalFonts[index], openMode, *errorCode); if (font) { *errorCode = 0; - return hleDelayResult(font->Handle(), "font open", 10000); - } else { - return 0; + // Delay only on the first open. + if (fontLib->GetFontRefCount(internalFonts[index]) == 1) + return hleDelayResult(font->Handle(), "font open", 10000); + return font->Handle(); } + return 0; } // Open a user font in RAM into a FontLib From 0772557a493a7eac1ba43c9bd45fbe041a59e63c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Aug 2021 17:44:40 -0700 Subject: [PATCH 3/5] Font: Limit max references to fonts. This seems to match the font/open test behavior. --- Core/HLE/sceFont.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 80b4a716b3..91be1080a8 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -32,6 +32,8 @@ enum { ERROR_FONT_INVALID_FONT_DATA = 0x8046000a, }; +constexpr int MAX_FONT_REFS = 4; + // For the save states. static bool useAllocCallbacks = true; @@ -596,7 +598,7 @@ public: if (foundFontIndex < 0) foundFontIndex = FindFreeIndex(); - if (foundFontIndex < 0) { + if (foundFontIndex < 0 || fontRefCount_[foundFontIndex] >= MAX_FONT_REFS) { ERROR_LOG(SCEFONT, "Too many fonts opened in FontLib"); error = ERROR_FONT_TOO_MANY_OPEN_FONTS; return nullptr; From 9882f2854a6a4aa577888172cd13dca9a45fcffb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Aug 2021 17:54:39 -0700 Subject: [PATCH 4/5] Font: Match stingy selection per test. --- Core/HLE/sceFont.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 91be1080a8..251dbebdf5 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -1038,7 +1038,7 @@ static u32 sceFontOpen(u32 libHandle, u32 index, u32 mode, u32 errorCodePtr) { return 0; } - FontOpenMode openMode = mode == 0 ? FONT_OPEN_INTERNAL_STINGY : FONT_OPEN_INTERNAL_FULL; + FontOpenMode openMode = mode != 1 ? FONT_OPEN_INTERNAL_STINGY : FONT_OPEN_INTERNAL_FULL; LoadedFont *font = fontLib->OpenFont(internalFonts[index], openMode, *errorCode); if (font) { *errorCode = 0; From 0a5a3d4ef4fa9f6042aa77638ecc6910c96e4ee6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Aug 2021 17:55:04 -0700 Subject: [PATCH 5/5] Headless: Cleanup extraneous output. --- headless/Headless.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/headless/Headless.cpp b/headless/Headless.cpp index a0bc857169..0f3fc8f276 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -332,8 +332,6 @@ int main(int argc, const char* argv[]) if (testFilenames.empty()) return printUsage(argv[0], argc <= 1 ? NULL : "No executables specified"); - g_threadManager.Init(cpu_info.num_cores, cpu_info.logical_cpu_count); - LogManager::Init(&g_Config.bEnableLogging); LogManager *logman = LogManager::GetInstance(); @@ -346,6 +344,9 @@ int main(int argc, const char* argv[]) } logman->AddListener(printfLogger); + // Needs to be after log so we don't interfere with test output. + g_threadManager.Init(cpu_info.num_cores, cpu_info.logical_cpu_count); + HeadlessHost *headlessHost = getHost(gpuCore); headlessHost->SetGraphicsCore(gpuCore); host = headlessHost;