Merge pull request #14701 from unknownbrackets/font-refcount

Handle font refcounting
This commit is contained in:
Henrik Rydgård 2021-08-08 16:00:13 +02:00 committed by GitHub
commit db63009864
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 43 deletions

View file

@ -32,10 +32,7 @@ enum {
ERROR_FONT_INVALID_FONT_DATA = 0x8046000a,
};
enum {
FONT_IS_CLOSED = 0,
FONT_IS_OPEN = 1,
};
constexpr int MAX_FONT_REFS = 4;
// For the save states.
static bool useAllocCallbacks = true;
@ -511,8 +508,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 +523,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;
}
@ -584,38 +581,51 @@ 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.
// 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 || fontRefCount_[foundFontIndex] >= MAX_FONT_REFS) {
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 +637,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 +645,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 +665,8 @@ public:
}
}
flushFont();
font->Close();
if (allowClose)
font->Close();
}
void flushFont() {
@ -665,7 +683,7 @@ public:
return;
Do(p, fonts_);
Do(p, isfontopen_);
Do(p, fontRefCount_);
Do(p, params_);
Do(p, fontHRes_);
Do(p, fontVRes_);
@ -708,8 +726,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<u32> fonts_;
std::vector<u32> isfontopen_;
std::vector<u32> fontRefCount_;
FontNewLibParams params_;
float fontHRes_;
@ -897,7 +938,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();
@ -997,14 +1038,16 @@ 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;
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
@ -1106,7 +1149,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);

View file

@ -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;