diff --git a/CMakeLists.txt b/CMakeLists.txt index f72e8cf6f..33e4787a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -267,7 +267,7 @@ set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services src/core/services/act.cpp src/core/services/nfc.cpp src/core/services/dlp_srvr.cpp src/core/services/ir_user.cpp src/core/services/http.cpp src/core/services/soc.cpp src/core/services/ssl.cpp src/core/services/news_u.cpp src/core/services/amiibo_device.cpp - src/core/services/csnd.cpp src/core/services/nwm_uds.cpp + src/core/services/csnd.cpp src/core/services/nwm_uds.cpp src/core/services/fonts.cpp ) set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA/shader_unit.cpp src/core/PICA/shader_interpreter.cpp src/core/PICA/dynapica/shader_rec.cpp @@ -326,14 +326,14 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp include/audio/hle_core.hpp include/capstone.hpp include/audio/aac.hpp include/PICA/pica_frag_config.hpp include/PICA/pica_frag_uniforms.hpp include/PICA/shader_gen_types.hpp include/PICA/shader_decompiler.hpp include/PICA/pica_vert_config.hpp include/sdl_sensors.hpp include/PICA/draw_acceleration.hpp include/renderdoc.hpp - include/align.hpp include/audio/aac_decoder.hpp include/PICA/pica_simd.hpp + include/align.hpp include/audio/aac_decoder.hpp include/PICA/pica_simd.hpp include/services/fonts.hpp ) cmrc_add_resource_library( resources_console_fonts NAMESPACE ConsoleFonts WHENCE "src/core/services/fonts/" - "src/core/services/fonts/CitraSharedFontUSRelocated.bin" + "src/core/services/fonts/SharedFontReplacement.bin" ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/PICA/dynapica/pica_recs.hpp b/include/PICA/dynapica/pica_recs.hpp index acfd226eb..eb0cf4044 100644 --- a/include/PICA/dynapica/pica_recs.hpp +++ b/include/PICA/dynapica/pica_recs.hpp @@ -2,7 +2,7 @@ #include "helpers.hpp" #include "vertex_loader_rec.hpp" -// Common file for our PICA JITs (From vertex config -> CPU assembly and from PICA shader -> CPU assembly) +// Common file for our PICA JITs (From PICA shader -> CPU assembly) namespace Dynapica { #ifdef PANDA3DS_DYNAPICA_SUPPORTED diff --git a/include/memory.hpp b/include/memory.hpp index 2f01aa35b..bd002c540 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -298,5 +298,5 @@ class Memory { bool allocateMainThreadStack(u32 size); Regions getConsoleRegion(); - void copySharedFont(u8* ptr); + void copySharedFont(u8* ptr, u32 vaddr); }; diff --git a/include/services/fonts.hpp b/include/services/fonts.hpp new file mode 100644 index 000000000..9fa84be1c --- /dev/null +++ b/include/services/fonts.hpp @@ -0,0 +1,84 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +// Adapted from https://github.com/PabloMK7/citra/blob/master/src/core/hle/service/apt/bcfnt/bcfnt.h + +#pragma once + +#include + +#include "helpers.hpp" +#include "swap.hpp" + +namespace HLE::Fonts { + struct CFNT { + u8 magic[4]; + u16_le endianness; + u16_le headerSize; + u32_le version; + u32_le fileSize; + u32_le numBlocks; + }; + + struct SectionHeader { + u8 magic[4]; + u32_le sectionSize; + }; + + struct FINF { + u8 magic[4]; + u32_le sectionSize; + u8 fontType; + u8 lineFeed; + u16_le alterCharIndex; + u8 default_width[3]; + u8 encoding; + u32_le tglpOffset; + u32_le cwdhOffset; + u32_le cmapOffset; + u8 height; + u8 width; + u8 ascent; + u8 reserved; + }; + + struct TGLP { + u8 magic[4]; + u32_le sectionSize; + u8 cellWidth; + u8 cellHeight; + u8 baselinePosition; + u8 maxCharacterWidth; + u32_le sheetSize; + u16_le numSheets; + u16_le sheetImageFormat; + u16_le numColumns; + u16_le numRows; + u16_le sheetWidth; + u16_le sheetHeight; + u32_le sheetDataOffset; + }; + + struct CMAP { + u8 magic[4]; + u32_le sectionSize; + u16_le codeBegin; + u16_le codeEnd; + u16_le mappingMethod; + u16_le reserved; + u32_le nextCmapOffset; + }; + + struct CWDH { + u8 magic[4]; + u32_le sectionSize; + u16_le startIndex; + u16_le endIndex; + u32_le nextCwdhOffset; + }; + + // Relocates the internal addresses of the BCFNT Shared Font to the new base. The current base will + // be auto-detected based on the file headers. + void relocateSharedFont(u8* sharedFont, u32 newAddress); +} // namespace HLE::Fonts \ No newline at end of file diff --git a/src/core/kernel/memory_management.cpp b/src/core/kernel/memory_management.cpp index aeac6269c..26f500235 100644 --- a/src/core/kernel/memory_management.cpp +++ b/src/core/kernel/memory_management.cpp @@ -136,7 +136,7 @@ void Kernel::mapMemoryBlock() { break; case KernelHandles::FontSharedMemHandle: - mem.copySharedFont(ptr); + mem.copySharedFont(ptr, addr); break; case KernelHandles::CSNDSharedMemHandle: diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 09b49eee2..57eac8ca2 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -7,6 +7,7 @@ #include "config_mem.hpp" #include "resource_limits.hpp" +#include "services/fonts.hpp" #include "services/ptm.hpp" CMRC_DECLARE(ConsoleFonts); @@ -51,7 +52,7 @@ void Memory::reset() { if (e.handle == KernelHandles::FontSharedMemHandle) { // Read font size from the cmrc filesystem the font is stored in auto fonts = cmrc::ConsoleFonts::get_filesystem(); - e.size = fonts.open("CitraSharedFontUSRelocated.bin").size(); + e.size = fonts.open("SharedFontReplacement.bin").size(); } e.mapped = false; @@ -520,10 +521,13 @@ Regions Memory::getConsoleRegion() { return region; } -void Memory::copySharedFont(u8* pointer) { +void Memory::copySharedFont(u8* pointer, u32 vaddr) { auto fonts = cmrc::ConsoleFonts::get_filesystem(); - auto font = fonts.open("CitraSharedFontUSRelocated.bin"); + auto font = fonts.open("SharedFontReplacement.bin"); std::memcpy(pointer, font.begin(), font.size()); + + // Relocate shared font to the address it's being loaded to + HLE::Fonts::relocateSharedFont(pointer, vaddr); } std::optional Memory::getProgramID() { diff --git a/src/core/services/fonts.cpp b/src/core/services/fonts.cpp new file mode 100644 index 000000000..512902982 --- /dev/null +++ b/src/core/services/fonts.cpp @@ -0,0 +1,107 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +// Adapted from https://github.com/PabloMK7/citra/blob/master/src/core/hle/service/apt/bcfnt/bcfnt.cpp + +#include "services/fonts.hpp" + +namespace HLE::Fonts { + void relocateSharedFont(u8* sharedFont, u32 newAddress) { + constexpr u32 sharedFontStartOffset = 0x80; + const u8* cfntData = &sharedFont[sharedFontStartOffset]; + + CFNT cfnt; + std::memcpy(&cfnt, cfntData, sizeof(cfnt)); + + u32 assumedCmapOffset = 0; + u32 assumedCwdhOffset = 0; + u32 assumedTglpOffset = 0; + u32 firstCmapOffset = 0; + u32 firstCwdhOffset = 0; + u32 firstTglpOffset = 0; + + // First discover the location of sections so that the rebase offset can be auto-detected + u32 currentOffset = sharedFontStartOffset + cfnt.headerSize; + for (uint block = 0; block < cfnt.numBlocks; ++block) { + const u8* data = &sharedFont[currentOffset]; + + SectionHeader sectionHeader; + std::memcpy(§ionHeader, data, sizeof(sectionHeader)); + + if (firstCmapOffset == 0 && std::memcmp(sectionHeader.magic, "CMAP", 4) == 0) { + firstCmapOffset = currentOffset; + } else if (firstCwdhOffset == 0 && std::memcmp(sectionHeader.magic, "CWDH", 4) == 0) { + firstCwdhOffset = currentOffset; + } else if (firstTglpOffset == 0 && std::memcmp(sectionHeader.magic, "TGLP", 4) == 0) { + firstTglpOffset = currentOffset; + } else if (std::memcmp(sectionHeader.magic, "FINF", 4) == 0) { + Fonts::FINF finf; + std::memcpy(&finf, data, sizeof(finf)); + + assumedCmapOffset = finf.cmapOffset - sizeof(SectionHeader); + assumedCwdhOffset = finf.cwdhOffset - sizeof(SectionHeader); + assumedTglpOffset = finf.tglpOffset - sizeof(SectionHeader); + } + + currentOffset += sectionHeader.sectionSize; + } + + u32 previousBase = assumedCmapOffset - firstCmapOffset; + if ((previousBase != assumedCwdhOffset - firstCwdhOffset) || (previousBase != assumedTglpOffset - firstTglpOffset)) { + Helpers::warn("You shouldn't be seeing this. Shared Font file offsets might be borked?"); + } + + u32 offset = newAddress - previousBase; + + // Reset pointer back to start of sections and do the actual rebase + currentOffset = sharedFontStartOffset + cfnt.headerSize; + for (uint block = 0; block < cfnt.numBlocks; ++block) { + u8* data = &sharedFont[currentOffset]; + + SectionHeader sectionHeader; + std::memcpy(§ionHeader, data, sizeof(sectionHeader)); + + if (std::memcmp(sectionHeader.magic, "FINF", 4) == 0) { + Fonts::FINF finf; + std::memcpy(&finf, data, sizeof(finf)); + + // Relocate the offsets in the FINF section + finf.cmapOffset += offset; + finf.cwdhOffset += offset; + finf.tglpOffset += offset; + + std::memcpy(data, &finf, sizeof(finf)); + } else if (std::memcmp(sectionHeader.magic, "CMAP", 4) == 0) { + Fonts::CMAP cmap; + std::memcpy(&cmap, data, sizeof(cmap)); + + // Relocate the offsets in the CMAP section + if (cmap.nextCmapOffset != 0) { + cmap.nextCmapOffset += offset; + } + + std::memcpy(data, &cmap, sizeof(cmap)); + } else if (std::memcmp(sectionHeader.magic, "CWDH", 4) == 0) { + Fonts::CWDH cwdh; + std::memcpy(&cwdh, data, sizeof(cwdh)); + + // Relocate the offsets in the CWDH section + if (cwdh.nextCwdhOffset != 0) { + cwdh.nextCwdhOffset += offset; + } + + std::memcpy(data, &cwdh, sizeof(cwdh)); + } else if (std::memcmp(sectionHeader.magic, "TGLP", 4) == 0) { + Fonts::TGLP tglp; + std::memcpy(&tglp, data, sizeof(tglp)); + + // Relocate the offsets in the TGLP section + tglp.sheetDataOffset += offset; + std::memcpy(data, &tglp, sizeof(tglp)); + } + + currentOffset += sectionHeader.sectionSize; + } + } +} // namespace HLE::Fonts \ No newline at end of file diff --git a/src/core/services/fonts/CitraSharedFontUSRelocated.bin b/src/core/services/fonts/SharedFontReplacement.bin similarity index 100% rename from src/core/services/fonts/CitraSharedFontUSRelocated.bin rename to src/core/services/fonts/SharedFontReplacement.bin