From 843bec6f4ffd4298fafb9b1debcc411165efcdac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valdis=20Bogd=C4=81ns?= Date: Fri, 12 Jun 2026 23:02:22 +0300 Subject: [PATCH] Fontlib implemment stubs for knack2 (#4564) * Improve spec-correct V_CMP_U64 semantics * Clang-format * - implement libSceFont text-source, string, and writing object support - add OrbisFontTextSource, OrbisFontCreateStringDetail, OrbisFontString, and writing-related ABI structures and function declarations - implement font string lifecycle and parsing flow, including default-font handling, terminate state, and character storage management - implement writing-step and writing-metrics APIs, including render-step accessors and invisible-character masking - implement additional glyph and character query APIs for text/font code, glyph form, metrics form, scale, and metric references - implement library font open mode setter and string metadata getters - consolidate duplicated font helper math and system-font alias resolution into shared internal utilities - update font rendering metric snapping logic to use consistent ceil/floor handling for bearings, advance, and stride computation - clean up font internals by removing duplicate local helpers and redundant declarations - apply clang-format and line-ending cleanup to modified font sources --------- Co-authored-by: w1naenator --- src/core/libraries/font/font.cpp | 1423 ++++++++++++++++- src/core/libraries/font/font.h | 1360 +++++++++------- src/core/libraries/font/font_internal.cpp | 81 +- src/core/libraries/font/font_internal.h | 28 + src/core/libraries/font/fontft_internal.cpp | 139 +- .../frontend/translate/vector_alu.cpp | 70 +- .../renderer_vulkan/vk_instance.cpp | 10 +- .../renderer_vulkan/vk_pipeline_cache.cpp | 5 +- 8 files changed, 2235 insertions(+), 881 deletions(-) diff --git a/src/core/libraries/font/font.cpp b/src/core/libraries/font/font.cpp index af20ef85d..3164154fb 100644 --- a/src/core/libraries/font/font.cpp +++ b/src/core/libraries/font/font.cpp @@ -50,16 +50,449 @@ #endif namespace { +using Libraries::Font::OrbisFontCreateStringDetail; using Libraries::Font::OrbisFontGenerateGlyphParams; using Libraries::Font::OrbisFontGlyph; using Libraries::Font::OrbisFontGlyphMetrics; using Libraries::Font::OrbisFontGlyphOpaque; using Libraries::Font::OrbisFontGlyphOutline; using Libraries::Font::OrbisFontGlyphOutlinePoint; +using Libraries::Font::OrbisFontHandle; using Libraries::Font::OrbisFontMem; +using Libraries::Font::OrbisFontRenderCharacter; +using Libraries::Font::OrbisFontString; using Libraries::Font::OrbisFontStyleFrame; +using Libraries::Font::OrbisFontTextCharacter; +using Libraries::Font::OrbisFontTextParseFunction; +using Libraries::Font::OrbisFontTextSource; +using Libraries::Font::OrbisFontWriting; +using Libraries::Font::OrbisFontWritingLetterStep; +using Libraries::Font::OrbisFontWritingMetrics; +using Libraries::Font::OrbisFontWritingStep; using Libraries::Font::Internal::Param; +constexpr u16 kTextSourceMagic = 0x0F04; +constexpr u32 kWritingFormHorizontal = 0x10; +constexpr u32 kWritingFormHorizontalRtl = 0x11; +constexpr u32 kWritingFormHorizontalLtr = 0x12; +constexpr u16 kFontStringMagic = 0x0F05; +constexpr u16 kFontWritingMagic = 0x0F06; +constexpr u16 kCreateStringDetailMagic = 0x0FD4; +constexpr s32 kTextParserResultError = -1; +constexpr s32 kTextParserResultTerminate = 0; +constexpr s32 kTextParserResultFontCode = 1; +constexpr size_t kMaxParsedStringCharacters = 4096; +constexpr s32 kWritingMaskNone = 0; +constexpr s32 kWritingMaskFormatCharacters = 1; +constexpr u64 kCharacterFlagFormat = 1ull << 42; + +struct HleFontString { + u16 magic = kFontStringMagic; + u8 flags = 0; + u8 reserved0 = 0; + u32 writing_form = kWritingFormHorizontal; + + const OrbisFontMem* memory = nullptr; + OrbisFontTextSource* source = nullptr; + OrbisFontHandle default_font = nullptr; + + u32 terminate_code = 0; + void* terminate_order = nullptr; + + u32 text_count = 0; + u32 render_count = 0; + + struct HleFontCharacterStorage* character_storage = nullptr; +}; + +struct HleFontCharacterStorage { + std::atomic ref_count{1}; + std::vector characters{}; +}; + +struct HleFontWriting { + u16 magic = kFontWritingMagic; + u16 reserved0 = 0; + u32 writing_form = kWritingFormHorizontal; + + OrbisFontString string = nullptr; + HleFontCharacterStorage* character_storage = nullptr; + OrbisFontHandle default_font = nullptr; + size_t next_index = 0; + size_t current_index = 0; + float pen_x = 0.0f; + float pen_y = 0.0f; + bool has_aggregate_metrics = false; + bool has_current_step = false; + bool mask_format_characters = true; + bool owns_character_storage = false; + const char* debug_trace_label = nullptr; + + OrbisFontWritingStep step{}; + OrbisFontWritingMetrics metrics{}; + OrbisFontGlyphMetrics raw_glyph_metrics{}; + bool has_raw_glyph_metrics = false; +}; + +struct PromptRenderTraceState { + bool active = false; + const char* label = nullptr; + size_t index = 0; + u32 glyph_code = 0; + float step_x = 0.0f; + float step_y = 0.0f; +}; + +thread_local PromptRenderTraceState g_prompt_render_trace{}; + +static void FillWritingMetricsFromGlyph(HleFontWriting& writing, + const OrbisFontGlyphMetrics& glyph_metrics) { + writing.raw_glyph_metrics = glyph_metrics; + writing.has_raw_glyph_metrics = true; + writing.step.advanceX = glyph_metrics.Horizontal.advance; + writing.step.advanceY = glyph_metrics.Vertical.advance; + writing.step.GlyphMetrics = glyph_metrics; + // LLE keeps the writing-step anchor at the current pen position for the ordinary horizontal + // path and applies bearings only when expanding the aggregate extents. + writing.step.Positioning.x = writing.step.x; + writing.step.Positioning.y = writing.step.y; + writing.step.GlyphMetrics.width = writing.step.x; + writing.step.GlyphMetrics.height = writing.step.y; +} + +static void ZeroWritingMetrics(OrbisFontWritingMetrics* metrics) { + if (metrics) { + std::memset(metrics, 0, sizeof(*metrics)); + } +} + +static bool MatchesAsciiPrompt(const HleFontString& font_string, std::string_view expected) { + if (!font_string.character_storage || + font_string.character_storage->characters.size() != expected.size()) { + return false; + } + + for (size_t i = 0; i < expected.size(); ++i) { + if (font_string.character_storage->characters[i].characterCode != + static_cast(expected[i])) { + return false; + } + } + + return true; +} + +static bool ContainsAsciiText(const HleFontString& font_string, std::string_view needle) { + if (!font_string.character_storage || needle.empty() || + font_string.character_storage->characters.size() < needle.size()) { + return false; + } + + const auto& characters = font_string.character_storage->characters; + for (size_t start = 0; start + needle.size() <= characters.size(); ++start) { + bool match = true; + for (size_t i = 0; i < needle.size(); ++i) { + if (characters[start + i].characterCode != static_cast(needle[i])) { + match = false; + break; + } + } + if (match) { + return true; + } + } + + return false; +} + +static std::string ExtractAsciiText(const HleFontString& font_string) { + std::string text; + const auto* storage = font_string.character_storage; + if (!storage) { + return text; + } + + text.reserve(storage->characters.size()); + for (const auto& ch : storage->characters) { + const u32 code = ch.characterCode; + if (code == '\n' || code == '\r' || code == '\t') { + text.push_back(static_cast(code)); + continue; + } + if (code < 0x20 || code > 0x7e) { + return {}; + } + text.push_back(static_cast(code)); + } + return text; +} + +static void ResetWritingAggregateMetrics(HleFontWriting& writing) { + writing.has_aggregate_metrics = false; + ZeroWritingMetrics(&writing.metrics); +} + +static void AccumulateWritingMetrics(HleFontWriting& writing) { + const OrbisFontWritingMetrics previous_metrics = writing.metrics; + const bool had_aggregate_metrics = writing.has_aggregate_metrics; + const auto& glyph_metrics = + writing.has_raw_glyph_metrics ? writing.raw_glyph_metrics : writing.step.GlyphMetrics; + const float left = writing.step.x + glyph_metrics.Horizontal.bearingX; + const float right = left + glyph_metrics.width; + const float top = writing.step.y - glyph_metrics.Horizontal.bearingY; + const float bottom = top + glyph_metrics.height; + + writing.metrics.advanceX = writing.step.x + writing.step.advanceX; + writing.metrics.advanceY = writing.step.y + writing.step.advanceY; + + if (!had_aggregate_metrics) { + writing.metrics.Extent.left = left; + writing.metrics.Extent.right = right; + writing.metrics.Extent.top = top; + writing.metrics.Extent.bottom = bottom; + writing.has_aggregate_metrics = true; + return; + } + + writing.metrics.Extent.left = std::min(previous_metrics.Extent.left, left); + writing.metrics.Extent.right = std::max(previous_metrics.Extent.right, right); + writing.metrics.Extent.top = std::min(previous_metrics.Extent.top, top); + writing.metrics.Extent.bottom = std::max(previous_metrics.Extent.bottom, bottom); +} + +static HleFontString* GetHleFontString(OrbisFontString font_string) { + auto* s = reinterpret_cast(font_string); + if (!s || s->magic != kFontStringMagic) { + return nullptr; + } + return s; +} + +static HleFontWriting* GetHleFontWriting(OrbisFontWriting* font_writing) { + if (!font_writing) { + return nullptr; + } + + auto* w = reinterpret_cast(font_writing->systemUse); + if (w->magic != kFontWritingMagic) { + return nullptr; + } + + return w; +} + +static void AddRefCharacterStorage(HleFontCharacterStorage* storage) { + if (storage) { + storage->ref_count.fetch_add(1, std::memory_order_relaxed); + } +} + +static void ReleaseCharacterStorage(HleFontCharacterStorage*& storage) { + if (!storage) { + return; + } + + if (storage->ref_count.fetch_sub(1, std::memory_order_acq_rel) == 1) { + delete storage; + } + storage = nullptr; +} + +static void ReleaseWritingCharacterStorage(HleFontWriting& writing) { + if (!writing.owns_character_storage) { + return; + } + + ReleaseCharacterStorage(writing.character_storage); + writing.owns_character_storage = false; +} + +static u16 TextSourceMagic(const Libraries::Font::OrbisFontTextSource* text_source) { + return static_cast(text_source->systemUse0 & 0xffffu); +} + +static void SetTextSourceWritingForm(Libraries::Font::OrbisFontTextSource* text_source, + u32 writing_form) { + text_source->systemUse0 = + (text_source->systemUse0 & 0x00000000ffffffffULL) | (static_cast(writing_form) << 32); +} + +static bool IsWhitespaceCode(u32 code) { + switch (code) { + case 0x0009: + case 0x000A: + case 0x000B: + case 0x000C: + case 0x000D: + case 0x0020: + case 0x0085: + case 0x00A0: + case 0x1680: + case 0x2028: + case 0x2029: + case 0x202F: + case 0x205F: + case 0x3000: + return true; + default: + return code >= 0x2000 && code <= 0x200A; + } +} + +static bool IsFormatCode(u32 code) { + switch (code) { + case 0x00AD: + case 0x061C: + case 0x200B: + case 0x200C: + case 0x200D: + case 0x200E: + case 0x200F: + case 0x2060: + case 0x2061: + case 0x2062: + case 0x2063: + case 0x2064: + case 0x2066: + case 0x2067: + case 0x2068: + case 0x2069: + case 0xFE0E: + case 0xFE0F: + case 0xFEFF: + return true; + default: + return false; + } +} + +static u64 PackCharacterFlags(u8 char_type, u8 bidi_level, bool is_format) { + u64 flags = static_cast(char_type) << 8; + flags |= static_cast(bidi_level) << 24; + if (is_format) { + flags |= kCharacterFlagFormat; + } + return flags; +} + +static void InitializeCharacterNode(OrbisFontTextCharacter& character, OrbisFontHandle font, + u32 code, void* text_order) { + character.prev = nullptr; + character.next = nullptr; + character.textOrder = text_order; + character.font = font; + character.shapeEntry = nullptr; + character.characterCode = code; + std::memset(character.reserved_0x2c, 0, sizeof(character.reserved_0x2c)); + character.clusterSpan = 1; + character.clusterIndex = 0; + character.clusterKind = 0; + character.synthetic = 0; + std::memset(character.reserved_0x34, 0, sizeof(character.reserved_0x34)); + character.flags = PackCharacterFlags(IsWhitespaceCode(code) ? 0x0E : 0, 0, IsFormatCode(code)); + std::memset(character.reserved_0x40, 0, sizeof(character.reserved_0x40)); +} + +static void LinkCharacterNodes(std::vector& characters) { + for (size_t i = 0; i < characters.size(); ++i) { + characters[i].prev = (i == 0) ? nullptr : &characters[i - 1]; + characters[i].next = (i + 1 < characters.size()) ? &characters[i + 1] : nullptr; + } +} + +static OrbisFontTextCharacter* GetTextCharacters(HleFontString* font_string) { + return (font_string && font_string->character_storage && + !font_string->character_storage->characters.empty()) + ? font_string->character_storage->characters.data() + : nullptr; +} + +static ptrdiff_t FindCharacterIndex(const HleFontString* font_string, + const OrbisFontTextCharacter* character) { + if (!font_string || !font_string->character_storage || !character || + font_string->character_storage->characters.empty()) { + return -1; + } + + const auto* base = font_string->character_storage->characters.data(); + const auto* end = base + font_string->character_storage->characters.size(); + if (character < base || character >= end) { + return -1; + } + + return character - base; +} + +static OrbisFontHandle GetCharacterFont(const HleFontString* font_string, + const OrbisFontTextCharacter* character) { + if (character && character->font) { + return character->font; + } + + return font_string ? font_string->default_font : nullptr; +} + +static bool PopulateWritingStep(HleFontWriting& writing, HleFontString& font_string, size_t index) { + auto* storage = font_string.character_storage; + if (!storage || index >= storage->characters.size()) { + return false; + } + + const auto& character = storage->characters[index]; + const auto character_font = GetCharacterFont(&font_string, &character); + + writing.step.x = writing.pen_x; + writing.step.y = writing.pen_y; + writing.step.advanceX = 0.0f; + writing.step.advanceY = 0.0f; + writing.step.font = character_font; + writing.step.Profile = {}; + writing.step.Profile.characterCount = 1; + writing.step.glyphCode = character.characterCode; + writing.step.Positioning.x = 0.0f; + writing.step.Positioning.y = 0.0f; + std::memset(&writing.step.GlyphMetrics, 0, sizeof(writing.step.GlyphMetrics)); + std::memset(&writing.raw_glyph_metrics, 0, sizeof(writing.raw_glyph_metrics)); + writing.has_raw_glyph_metrics = false; + + if ((character.flags & kCharacterFlagFormat) != 0 && writing.mask_format_characters) { + writing.step.Profile.invisibleGlyph = 1; + } + + if (character_font && character.characterCode != 0) { + OrbisFontGlyphMetrics glyph_metrics{}; + s32 metrics_rc = sceFontGetRenderCharGlyphMetrics(character_font, character.characterCode, + &glyph_metrics); + if (metrics_rc != ORBIS_OK) { + metrics_rc = + sceFontGetCharGlyphMetrics(character_font, character.characterCode, &glyph_metrics); + } + + if (metrics_rc == ORBIS_OK) { + FillWritingMetricsFromGlyph(writing, glyph_metrics); + } else { + LOG_WARNING(Lib_Font, "sceFontWriting step metrics failed for code={} rc={} (index={})", + character.characterCode, metrics_rc, index); + } + } + + writing.pen_x += writing.step.advanceX; + writing.pen_y += writing.step.advanceY; + return true; +} + +static bool PopulateWritingStep(HleFontWriting& writing, size_t index, + OrbisFontHandle default_font) { + if (!writing.character_storage || index >= writing.character_storage->characters.size()) { + return false; + } + + HleFontString transient{}; + transient.default_font = default_font; + transient.character_storage = writing.character_storage; + return PopulateWritingStep(writing, transient, index); +} + static std::string formatParams( std::initializer_list params) { return Libraries::Font::Internal::FormatNamedParams(params); @@ -347,7 +780,7 @@ s32 PS4_SYSV_ABI sceFontCharacterGetBidiLevel(OrbisFontTextCharacter* textCharac return ORBIS_FONT_ERROR_INVALID_PARAMETER; } - *bidiLevel = textCharacter->bidiLevel; + *bidiLevel = static_cast((textCharacter->flags >> 24) & 0xFFu); return ORBIS_OK; } @@ -356,8 +789,23 @@ s32 PS4_SYSV_ABI sceFontCharacterGetSyllableStringState() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceFontCharacterGetTextFontCode() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceFontCharacterGetTextFontCode(OrbisFontTextCharacter* textCharacter, + OrbisFontHandle* pFontHandle, u32* textCode) { + if (!textCharacter) { + if (pFontHandle) { + *pFontHandle = nullptr; + } + if (textCode) { + *textCode = 0; + } + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + if (!pFontHandle || !textCode) { + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + *pFontHandle = textCharacter->font; + *textCode = textCharacter->characterCode; return ORBIS_OK; } @@ -383,7 +831,7 @@ u32 PS4_SYSV_ABI sceFontCharacterLooksFormatCharacters(OrbisFontTextCharacter* t return 0; } - return (textCharacter->formatFlags & 0x04) ? textCharacter->characterCode : 0; + return (textCharacter->flags & kCharacterFlagFormat) != 0 ? textCharacter->characterCode : 0; } u32 PS4_SYSV_ABI sceFontCharacterLooksWhiteSpace(OrbisFontTextCharacter* textCharacter) { @@ -391,7 +839,7 @@ u32 PS4_SYSV_ABI sceFontCharacterLooksWhiteSpace(OrbisFontTextCharacter* textCha return 0; } - return (textCharacter->charType == 0x0E) ? textCharacter->characterCode : 0; + return ((textCharacter->flags >> 8) & 0xFFu) == 0x0E ? textCharacter->characterCode : 0; } OrbisFontTextCharacter* PS4_SYSV_ABI @@ -401,7 +849,7 @@ sceFontCharacterRefersTextBack(OrbisFontTextCharacter* textCharacter) { OrbisFontTextCharacter* current = textCharacter->prev; while (current) { - if (current->unknown_0x31 == 0 && current->unknown_0x33 == 0) { + if (current->synthetic == 0 && current->clusterIndex == 0) { return current; } current = current->prev; @@ -417,7 +865,7 @@ sceFontCharacterRefersTextNext(OrbisFontTextCharacter* textCharacter) { OrbisFontTextCharacter* current = textCharacter->next; while (current) { - if (current->unknown_0x31 == 0 && current->unknown_0x33 == 0) { + if (current->synthetic == 0 && current->clusterIndex == 0) { return current; } current = current->next; @@ -836,8 +1284,179 @@ s32 PS4_SYSV_ABI sceFontCreateRendererWithEdition(const OrbisFontMem* memory, return rc; } -s32 PS4_SYSV_ABI sceFontCreateString() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceFontCreateString(const OrbisFontMem* fontMemory, + OrbisFontTextSource* fontTextSource, + const OrbisFontCreateStringDetail* stringDetail, + OrbisFontString* pFontString) { + LOG_INFO(Lib_Font, "called fontMemory={} fontTextSource={} stringDetail={} pFontString={}", + static_cast(fontMemory), static_cast(fontTextSource), + static_cast(stringDetail), static_cast(pFontString)); + + if (!fontMemory || !fontTextSource || !pFontString) { + if (pFontString) { + *pFontString = nullptr; + } + LOG_ERROR(Lib_Font, "INVALID_PARAMETER null argument"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + LOG_INFO(Lib_Font, + "probe textSource: systemUse0=0x{:016x} start={} end={} current={} parser={} " + "object={} defaultFont={}", + fontTextSource->systemUse0, fontTextSource->start, fontTextSource->end, + fontTextSource->current, reinterpret_cast(fontTextSource->textParser), + fontTextSource->textObject, static_cast(fontTextSource->defaultFont)); + + LOG_INFO(Lib_Font, + "probe memory: mem_kind=0x{:04x} attr_bits=0x{:04x} region_size=0x{:x} base={} " + "mspace={} iface={}", + fontMemory->mem_kind, fontMemory->attr_bits, fontMemory->region_size, + fontMemory->region_base, fontMemory->mspace_handle, + static_cast(fontMemory->iface)); + + if (!fontTextSource->textParser) { + if (pFontString) { + *pFontString = nullptr; + } + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + if (TextSourceMagic(fontTextSource) != kTextSourceMagic) { + *pFontString = nullptr; + LOG_ERROR(Lib_Font, "INVALID_TEXT_SOURCE"); + return ORBIS_FONT_ERROR_INVALID_TEXT_SOURCE; + } + + if (fontMemory->mem_kind != 0x0F00 || !fontMemory->iface || !fontMemory->iface->alloc || + !fontMemory->iface->dealloc) { + *pFontString = nullptr; + LOG_ERROR(Lib_Font, "INVALID_MEMORY"); + return ORBIS_FONT_ERROR_INVALID_MEMORY; + } + + if (stringDetail) { + const u32 valid_orders_mask = (1u << 0) | (1u << 1) | (1u << 2) | (1u << 31); + constexpr u8 kValidDetectionsMask = 0x07; + + if (stringDetail->detailId != kCreateStringDetailMagic || stringDetail->detailType > 1 || + (stringDetail->detections & ~kValidDetectionsMask) != 0 || + (stringDetail->ordersOption & ~valid_orders_mask) != 0) { + *pFontString = nullptr; + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + } + + const auto alloc_fn = reinterpret_cast(fontMemory->iface->alloc); + const auto free_fn = reinterpret_cast(fontMemory->iface->dealloc); + LOG_INFO(Lib_Font, "sceFontCreateString allocator probe: alloc_fn={} free_fn={} mspace={}", + reinterpret_cast(alloc_fn), reinterpret_cast(free_fn), + fontMemory->mspace_handle); + + auto* raw = alloc_fn(fontMemory->mspace_handle, sizeof(HleFontString)); + LOG_INFO(Lib_Font, "sceFontCreateString allocator returned {}", raw); + if (!raw) { + *pFontString = nullptr; + LOG_ERROR(Lib_Font, "ALLOCATION_FAILED"); + return ORBIS_FONT_ERROR_ALLOCATION_FAILED; + } + + auto* s = new (raw) HleFontString{}; + s->memory = fontMemory; + s->source = fontTextSource; + s->default_font = fontTextSource->defaultFont; + s->character_storage = new HleFontCharacterStorage{}; + + if (!s->default_font && stringDetail) { + s->default_font = stringDetail->defaultFont; + } + + s->writing_form = static_cast((fontTextSource->systemUse0 >> 32) & 0xffffffffu); + s->terminate_order = nullptr; + s->terminate_code = 0; + + auto parser_state = ORBIS_FONT_ERROR_INVALID_TEXT_SOURCE; + void* text_order = nullptr; + OrbisFontTextParseResult parse_result{}; + + for (size_t parsed = 0; parsed < kMaxParsedStringCharacters; ++parsed) { + std::memset(&parse_result, 0, sizeof(parse_result)); + parser_state = fontTextSource->textParser(fontTextSource, &text_order, &parse_result); + + if (parser_state == kTextParserResultFontCode) { + auto char_font = + parse_result.FontCode.font ? parse_result.FontCode.font : s->default_font; + if (!char_font) { + LOG_ERROR(Lib_Font, "INVALID_TEXT_SOURCE parser returned code={} without a font", + parse_result.FontCode.code); + parser_state = ORBIS_FONT_ERROR_INVALID_TEXT_SOURCE; + break; + } + + OrbisFontTextCharacter character{}; + InitializeCharacterNode(character, char_font, parse_result.FontCode.code, text_order); + s->character_storage->characters.push_back(character); + continue; + } + + if (parser_state == kTextParserResultTerminate) { + s->terminate_order = text_order; + s->terminate_code = parse_result.Terminate.terminateCode; + parser_state = ORBIS_OK; + break; + } + + if (parser_state == kTextParserResultError) { + parser_state = (parse_result.Error.errorCode < 0) + ? parse_result.Error.errorCode + : ORBIS_FONT_ERROR_INVALID_TEXT_SOURCE; + LOG_ERROR(Lib_Font, "sceFontCreateString parser reported error rc={}", parser_state); + break; + } + + LOG_ERROR(Lib_Font, "sceFontCreateString parser returned unexpected state {}", + parser_state); + parser_state = ORBIS_FONT_ERROR_INVALID_TEXT_SOURCE; + break; + } + + if (s->character_storage->characters.size() == kMaxParsedStringCharacters && + parser_state == kTextParserResultFontCode) { + parser_state = ORBIS_FONT_ERROR_INVALID_TEXT_SOURCE; + } + + if (s->character_storage->characters.size() == kMaxParsedStringCharacters && + parser_state != ORBIS_OK) { + LOG_ERROR(Lib_Font, "sceFontCreateString exceeded parser safety limit ({})", + kMaxParsedStringCharacters); + } + + if (parser_state != ORBIS_OK) { + ReleaseCharacterStorage(s->character_storage); + s->~HleFontString(); + free_fn(fontMemory->mspace_handle, raw); + *pFontString = nullptr; + return parser_state; + } + + LinkCharacterNodes(s->character_storage->characters); + s->text_count = static_cast(s->character_storage->characters.size()); + s->render_count = s->text_count; + + const std::string ascii_text = ExtractAsciiText(*s); + if (!ascii_text.empty() && ascii_text.size() <= 160) { + LOG_INFO(Lib_Font, "AsciiString: len={} text=\"{}\"", ascii_text.size(), ascii_text); + } + + *pFontString = reinterpret_cast(s); + LOG_INFO(Lib_Font, + "created HleFontString at {} (memory iface={} default_font={} text_count={} " + "first_code={} terminate_code={})", + static_cast(*pFontString), static_cast(fontMemory->iface), + static_cast(s->default_font), s->text_count, + s->text_count != 0 ? s->character_storage->characters.front().characterCode : 0, + s->terminate_code); return ORBIS_OK; } @@ -955,8 +1574,32 @@ s32 PS4_SYSV_ABI sceFontDestroyRenderer(OrbisFontRenderer* pRenderer) { return rc; } -s32 PS4_SYSV_ABI sceFontDestroyString() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceFontDestroyString(OrbisFontString* pFontString) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", formatParams({Param("pFontString", pFontString)})); + + if (!pFontString) { + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + auto* s = GetHleFontString(*pFontString); + if (!s) { + *pFontString = nullptr; + LOG_ERROR(Lib_Font, "INVALID_STRING"); + return ORBIS_FONT_ERROR_INVALID_STRING; + } + + const auto free_fn = reinterpret_cast(s->memory->iface->dealloc); + void* alloc_ctx = s->memory->mspace_handle; + void* raw = s; + ReleaseCharacterStorage(s->character_storage); + LOG_DEBUG(Lib_Font, "destroying HleFontString {} (memory iface={})", + static_cast(s), static_cast(s->memory->iface)); + s->~HleFontString(); + free_fn(alloc_ctx, raw); + *pFontString = nullptr; + return ORBIS_OK; } @@ -1086,8 +1729,6 @@ s32 PS4_SYSV_ABI sceFontGetCharGlyphCode() { s32 PS4_SYSV_ABI sceFontGetCharGlyphMetrics(OrbisFontHandle fontHandle, u32 code, OrbisFontGlyphMetrics* metrics) { - LOG_INFO(Lib_Font, "called"); - LOG_DEBUG(Lib_Font, "{}", formatParams({ Param("fontHandle", fontHandle), @@ -1101,8 +1742,6 @@ s32 PS4_SYSV_ABI sceFontGetCharGlyphMetrics(OrbisFontHandle fontHandle, u32 code LOG_ERROR(Lib_Font, "INVALID_HANDLE"); } else if (rc == ORBIS_FONT_ERROR_INVALID_PARAMETER) { LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); - } else if (rc == ORBIS_FONT_ERROR_NOT_BOUND_RENDERER) { - LOG_ERROR(Lib_Font, "NOT_BOUND_RENDERER"); } } return rc; @@ -1287,6 +1926,23 @@ s32 PS4_SYSV_ABI sceFontGetHorizontalLayout(OrbisFontHandle fontHandle, layout->baselineOffset = layout_blocks.baseline(); layout->lineAdvance = layout_blocks.line_advance(); layout->decorationExtent = layout_blocks.effect_height(); + const auto* style_frame = reinterpret_cast(font->style_frame); + if (style_frame) { + static std::atomic s_layout_trace_budget{120}; + const int remaining = s_layout_trace_budget.fetch_sub(1, std::memory_order_relaxed); + if (remaining > 0) { + LOG_INFO(Lib_Font, + "GetHorizontalLayoutTrace: handle={} flags=0x{:02X} unit={} dpi=({}, {}) " + "scalePx=({}, {}) weight=({}, {}) slant={} out baseline={} " + "lineAdvance={} decoration={}", + static_cast(fontHandle), + static_cast(style_frame->flags1), style_frame->scaleUnit, + style_frame->hDpi, style_frame->vDpi, style_frame->scalePixelW, + style_frame->scalePixelH, style_frame->effectWeightX, + style_frame->effectWeightY, style_frame->slantRatio, + layout->baselineOffset, layout->lineAdvance, layout->decorationExtent); + } + } LOG_DEBUG(Lib_Font, "GetHorizontalLayout: out baseLineY={} lineHeight={} effectHeight={}", layout->baselineOffset, layout->lineAdvance, layout->decorationExtent); return ORBIS_OK; @@ -1395,7 +2051,6 @@ s32 PS4_SYSV_ABI sceFontGetPixelResolution() { s32 PS4_SYSV_ABI sceFontGetRenderCharGlyphMetrics(OrbisFontHandle fontHandle, u32 codepoint, OrbisFontGlyphMetrics* out_metrics) { - LOG_INFO(Lib_Font, "called"); LOG_DEBUG(Lib_Font, "{}", formatParams({ Param("fontHandle", fontHandle), @@ -1409,8 +2064,6 @@ s32 PS4_SYSV_ABI sceFontGetRenderCharGlyphMetrics(OrbisFontHandle fontHandle, u3 LOG_ERROR(Lib_Font, "INVALID_HANDLE"); } else if (rc == ORBIS_FONT_ERROR_INVALID_PARAMETER) { LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); - } else if (rc == ORBIS_FONT_ERROR_NOT_BOUND_RENDERER) { - LOG_ERROR(Lib_Font, "NOT_BOUND_RENDERER"); } } return rc; @@ -1661,39 +2314,67 @@ s32 PS4_SYSV_ABI sceFontGlyphGetAttribute() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceFontGlyphGetGlyphForm() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceFontGlyphGetGlyphForm(OrbisFontGlyph fontGlyph) { + if (!fontGlyph || fontGlyph->magic != 0x0F03) { + return ORBIS_FONT_ERROR_INVALID_GLYPH; + } + return static_cast(fontGlyph->glyph_form); +} + +s32 PS4_SYSV_ABI sceFontGlyphGetMetricsForm(OrbisFontGlyph fontGlyph) { + if (!fontGlyph || fontGlyph->magic != 0x0F03) { + return ORBIS_FONT_ERROR_INVALID_GLYPH; + } + return static_cast(fontGlyph->metrics_form); +} + +s32 PS4_SYSV_ABI sceFontGlyphGetScalePixel(OrbisFontGlyph fontGlyph, float* w, float* h) { + if (!fontGlyph || fontGlyph->magic != 0x0F03 || (!w && !h)) { + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + if (w) { + *w = fontGlyph->scale_x; + } + if (h) { + *h = fontGlyph->base_scale; + } return ORBIS_OK; } -s32 PS4_SYSV_ABI sceFontGlyphGetMetricsForm() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +const OrbisFontGlyphMetrics* PS4_SYSV_ABI sceFontGlyphRefersMetrics(OrbisFontGlyph fontGlyph) { + auto* boxed = Internal::TryGetGeneratedGlyph(fontGlyph); + return boxed ? &boxed->metrics : nullptr; } -s32 PS4_SYSV_ABI sceFontGlyphGetScalePixel() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +const OrbisFontGlyphMetricsHorizontal* PS4_SYSV_ABI +sceFontGlyphRefersMetricsHorizontal(OrbisFontGlyph fontGlyph) { + auto* boxed = Internal::TryGetGeneratedGlyph(fontGlyph); + if (!boxed) { + return nullptr; + } + Internal::PopulateGlyphMetricVariants(*boxed); + return &boxed->metrics_horizontal; } -s32 PS4_SYSV_ABI sceFontGlyphRefersMetrics() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +const OrbisFontGlyphMetricsHorizontalAdvance* PS4_SYSV_ABI +sceFontGlyphRefersMetricsHorizontalAdvance(OrbisFontGlyph fontGlyph) { + auto* boxed = Internal::TryGetGeneratedGlyph(fontGlyph); + if (!boxed) { + return nullptr; + } + Internal::PopulateGlyphMetricVariants(*boxed); + return &boxed->metrics_horizontal_adv; } -s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontal() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontalAdvance() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontalX() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +const OrbisFontGlyphMetricsHorizontalX* PS4_SYSV_ABI +sceFontGlyphRefersMetricsHorizontalX(OrbisFontGlyph fontGlyph) { + auto* boxed = Internal::TryGetGeneratedGlyph(fontGlyph); + if (!boxed) { + return nullptr; + } + Internal::PopulateGlyphMetricVariants(*boxed); + return &boxed->metrics_horizontal_x; } OrbisFontGlyphOutline* PS4_SYSV_ABI sceFontGlyphRefersOutline(OrbisFontGlyph glyph) { @@ -4655,9 +5336,60 @@ s32 PS4_SYSV_ABI sceFontRenderCharGlyphImageHorizontal(OrbisFontHandle fontHandl if (rc != ORBIS_OK) { ClearRenderOutputs(metrics, result); - LOG_ERROR(Lib_Font, "FAILED"); + LOG_ERROR(Lib_Font, + "FAILED rc={} code={} surf(buffer={}, widthByte={}, pixelSizeByte={}, width={}, " + "height={}, styleFlag={})", + rc, code, surf->buffer, surf->widthByte, surf->pixelSizeByte, surf->width, + surf->height, surf->styleFlag); return rc; } + if (g_prompt_render_trace.active && g_prompt_render_trace.glyph_code == code) { + u32 coverage_nonzero = 0; + u32 coverage_sum = 0; + u8 coverage_max = 0; + const auto* surf_bytes = static_cast(surf->buffer); + const u32 update_x = result->UpdateRect.x; + const u32 update_y = result->UpdateRect.y; + const u32 update_w = result->UpdateRect.w; + const u32 update_h = result->UpdateRect.h; + const u32 surface_w = static_cast(std::max(surf->width, 0)); + const u32 surface_h = static_cast(std::max(surf->height, 0)); + if (surf_bytes && surf->pixelSizeByte == 1 && update_x < surface_w && + update_y < surface_h) { + const u32 sample_w = std::min(update_w, surface_w - update_x); + const u32 sample_h = std::min(update_h, surface_h - update_y); + for (u32 row = 0; row < sample_h; ++row) { + const auto* row_ptr = + surf_bytes + + static_cast(update_y + row) * static_cast(surf->widthByte) + + static_cast(update_x); + for (u32 col = 0; col < sample_w; ++col) { + const u8 cov = row_ptr[col]; + coverage_sum += cov; + coverage_nonzero += cov != 0; + coverage_max = std::max(coverage_max, cov); + } + } + } + LOG_INFO(Lib_Font, + "TextRender[{}]: index={} code=U+{:04X} call_xy=({}, {}) step_xy=({}, {}) " + "surf=[buffer={} widthByte={} pixelSizeByte={} width={} height={} scissor=({}, " + "{})-({}, {})] " + "surfaceImage.address={} " + "update=[{},{} {}x{}] img=[bx={} by={} adv={} stride={} w={} h={}] " + "coverage=[nz={} sum={} max={}]", + g_prompt_render_trace.label ? g_prompt_render_trace.label : "Text", + g_prompt_render_trace.index, code, x, y, g_prompt_render_trace.step_x, + g_prompt_render_trace.step_y, surf->buffer, surf->widthByte, surf->pixelSizeByte, + surf->width, surf->height, surf->sc_x0, surf->sc_y0, surf->sc_x1, surf->sc_y1, + static_cast(result->SurfaceImage.address), result->UpdateRect.x, + result->UpdateRect.y, result->UpdateRect.w, result->UpdateRect.h, + result->ImageMetrics.bearingX, result->ImageMetrics.bearingY, + result->ImageMetrics.advance, result->ImageMetrics.stride, + result->ImageMetrics.width, result->ImageMetrics.height, coverage_nonzero, + coverage_sum, coverage_max); + g_prompt_render_trace = {}; + } LogRenderResultSample(fontHandle, code, *metrics, *result); return ORBIS_OK; } @@ -5060,8 +5792,30 @@ s32 PS4_SYSV_ABI sceFontSetEffectWeight(OrbisFontHandle fontHandle, float weight return ORBIS_OK; } -s32 PS4_SYSV_ABI sceFontSetFontsOpenMode() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceFontSetFontsOpenMode(OrbisFontLib library, u32 openMode) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", + formatParams({ + Param("library", library), + Param("openMode", openMode), + })); + + if (!library) { + LOG_ERROR(Lib_Font, "INVALID_LIBRARY"); + return ORBIS_FONT_ERROR_INVALID_LIBRARY; + } + + auto* lib = static_cast(library); + if (lib->magic != 0x0F01) { + LOG_ERROR(Lib_Font, "INVALID_LIBRARY"); + return ORBIS_FONT_ERROR_INVALID_LIBRARY; + } + + if (openMode > 2) { + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + return ORBIS_OK; } @@ -5351,29 +6105,235 @@ s32 PS4_SYSV_ABI sceFontSetupRenderScalePoint(OrbisFontHandle fontHandle, float return rc; } -s32 PS4_SYSV_ABI sceFontStringGetTerminateCode() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +u32 PS4_SYSV_ABI sceFontStringGetTerminateCode(OrbisFontString fontString) { + auto* s = GetHleFontString(fontString); + return s ? s->terminate_code : 0; } -s32 PS4_SYSV_ABI sceFontStringGetTerminateOrder() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +void* PS4_SYSV_ABI sceFontStringGetTerminateOrder(OrbisFontString fontString) { + auto* s = GetHleFontString(fontString); + return s ? s->terminate_order : nullptr; } -s32 PS4_SYSV_ABI sceFontStringGetWritingForm() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +s32 PS4_SYSV_ABI sceFontStringGetWritingForm(OrbisFontString fontString) { + auto* s = GetHleFontString(fontString); + return s ? static_cast(s->writing_form) : 0; } -s32 PS4_SYSV_ABI sceFontStringRefersRenderCharacters() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +OrbisFontRenderCharacter PS4_SYSV_ABI sceFontStringRefersRenderCharacters( + OrbisFontString fontString, OrbisFontTextCharacter* startCharacter, + OrbisFontTextCharacter* lastCharacter, u32* characterCount) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", + formatParams({ + Param("fontString", fontString), + Param("startCharacter", startCharacter), + Param("lastCharacter", lastCharacter), + Param("characterCount", characterCount), + })); + + auto* s = GetHleFontString(fontString); + if (!s || !characterCount || s->render_count == 0) { + if (characterCount) { + *characterCount = 0; + } + return nullptr; + } + + auto* characters = GetTextCharacters(s); + if (!characters) { + *characterCount = 0; + return nullptr; + } + + const auto* begin = characters; + const auto* end = characters + s->render_count; + if (!startCharacter) { + startCharacter = characters; + } + if (startCharacter < begin || startCharacter >= end) { + *characterCount = 0; + return nullptr; + } + + if (lastCharacter && (lastCharacter < begin || lastCharacter >= end)) { + *characterCount = 0; + return nullptr; + } + + auto level_of = [](const OrbisFontTextCharacter* character) -> u32 { + return static_cast((character->flags >> 24) & 0xFFu); + }; + + auto* probe = startCharacter; + if (startCharacter->clusterKind > 1) { + do { + startCharacter = probe; + probe = startCharacter->prev; + if (!probe) { + break; + } + } while (probe->synthetic < 0); + } + + u32 start_flags = static_cast(startCharacter->flags); + const u32 paragraph_level = (s->writing_form >> 8) & 1u; + if ((start_flags & 0xFF00u) == 0x100u && startCharacter->prev != nullptr) { + auto* prev = startCharacter->prev; + if (prev->clusterKind == 1) { + startCharacter = prev; + } + start_flags = static_cast(startCharacter->flags); + } + + u32 start_level = start_flags >> 24; + u32 last_level = start_level; + u32 min_level = start_level; + u32 count = startCharacter->clusterIndex == 0 ? 1u : 0u; + probe = startCharacter; + while (probe != lastCharacter) { + probe = probe->next; + if (!probe) { + if (lastCharacter) { + *characterCount = 0; + return nullptr; + } + break; + } + if (probe->clusterIndex == 0) { + last_level = level_of(probe); + if (last_level < min_level && (((last_level ^ paragraph_level) & 1u) == 0)) { + min_level = last_level; + } + ++count; + } + } + + if (start_level != last_level || start_level != min_level) { + probe = startCharacter->prev; + while (probe) { + if (probe->clusterIndex == 0) { + if (level_of(probe) <= min_level) { + break; + } + ++count; + } + startCharacter = probe; + probe = probe->prev; + } + + if (lastCharacter) { + probe = lastCharacter->next; + while (probe) { + if (probe->clusterIndex == 0) { + if (level_of(probe) <= min_level) { + break; + } + ++count; + lastCharacter = probe; + } + probe = probe->next; + } + } else { + lastCharacter = nullptr; + } + } + + if (lastCharacter) { + probe = lastCharacter->next; + int cluster_trim = 0; + while (probe) { + int next_trim = cluster_trim; + if (probe->clusterIndex == 0) { + if (probe->synthetic == 0) { + break; + } + next_trim = 0; + auto* next_last = probe; + if (probe->synthetic < 1) { + if (probe->clusterKind == 1) { + break; + } + next_trim = cluster_trim + 1; + next_last = lastCharacter; + } + lastCharacter = next_last; + ++count; + } + probe = probe->next; + count -= static_cast(next_trim); + cluster_trim = next_trim; + } + } + + start_level = level_of(startCharacter); + if (start_level != paragraph_level) { + probe = startCharacter; + if (lastCharacter == nullptr || level_of(lastCharacter) != start_level) { + do { + probe = probe->next; + if (!probe) { + if (lastCharacter) { + startCharacter = nullptr; + } + break; + } + + auto* best = startCharacter; + u32 best_level = start_level; + if (probe->clusterIndex == 0) { + const u32 probe_level = level_of(probe); + if (probe_level <= paragraph_level) { + break; + } + best = probe; + best_level = probe_level; + if ((start_level & 1u) == paragraph_level && probe_level < start_level && + (probe_level & 1u) != paragraph_level) { + best = probe; + } else { + best = startCharacter; + best_level = start_level; + } + } + start_level = best_level; + startCharacter = best; + } while (probe != lastCharacter); + } else if ((level_of(startCharacter) & 1u) != paragraph_level) { + startCharacter = lastCharacter; + } + } + + if (!startCharacter) { + count = 0; + } + + *characterCount = count; + return startCharacter; } -s32 PS4_SYSV_ABI sceFontStringRefersTextCharacters() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +OrbisFontTextCharacter* PS4_SYSV_ABI sceFontStringRefersTextCharacters(OrbisFontString fontString, + u32* characterCount) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", + formatParams({ + Param("fontString", fontString), + Param("characterCount", characterCount), + })); + + auto* s = GetHleFontString(fontString); + if (!s || s->text_count == 0) { + if (characterCount) { + *characterCount = 0; + } + return nullptr; + } + + if (characterCount) { + *characterCount = s->text_count; + } + + return GetTextCharacters(s); } s32 PS4_SYSV_ABI sceFontStyleFrameGetEffectSlant(OrbisFontStyleFrame* styleFrame, @@ -5808,23 +6768,133 @@ s32 PS4_SYSV_ABI sceFontTextCodesStepNext() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceFontTextSourceInit() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceFontTextSourceInit(OrbisFontTextSource* fontTextSource, const void* textAddress, + u32 textSizeByte, OrbisFontTextParser textParser, + void* textObject) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", + formatParams({ + Param("fontTextSource", fontTextSource), + Param("textAddress", textAddress), + Param("textSizeByte", textSizeByte), + Param("textParser", reinterpret_cast(textParser)), + Param("textObject", textObject), + })); + + if (!fontTextSource) { + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + if (!textParser) { + std::memset(fontTextSource, 0, sizeof(*fontTextSource)); + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + const void* end = nullptr; + if (textSizeByte != 0) { + const auto start_addr = reinterpret_cast(textAddress); + end = reinterpret_cast(start_addr + static_cast(textSizeByte)); + } + + std::memset(fontTextSource, 0, sizeof(*fontTextSource)); + + fontTextSource->systemUse0 = + (static_cast(kWritingFormHorizontal) << 32) | kTextSourceMagic; + + fontTextSource->start = textAddress; + fontTextSource->end = end; + fontTextSource->current = textAddress; + fontTextSource->textParser = textParser; + fontTextSource->textObject = textObject; + fontTextSource->defaultFont = nullptr; + + fontTextSource->systemUse[0] = const_cast(textAddress); + fontTextSource->systemUse[1] = const_cast(end); + fontTextSource->systemUse[2] = reinterpret_cast(textParser); + fontTextSource->systemUse[3] = textObject; + fontTextSource->systemUse[4] = nullptr; + return ORBIS_OK; } -s32 PS4_SYSV_ABI sceFontTextSourceRewind() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceFontTextSourceRewind(OrbisFontTextSource* fontTextSource) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", formatParams({Param("fontTextSource", fontTextSource)})); + + if (!fontTextSource) { + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + if (TextSourceMagic(fontTextSource) != kTextSourceMagic) { + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + fontTextSource->start = fontTextSource->systemUse[0]; + fontTextSource->end = fontTextSource->systemUse[1]; + fontTextSource->current = fontTextSource->systemUse[0]; + fontTextSource->textParser = + reinterpret_cast(fontTextSource->systemUse[2]); + fontTextSource->textObject = fontTextSource->systemUse[3]; + fontTextSource->defaultFont = static_cast(fontTextSource->systemUse[4]); + return ORBIS_OK; } -s32 PS4_SYSV_ABI sceFontTextSourceSetDefaultFont() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceFontTextSourceSetDefaultFont(OrbisFontTextSource* fontTextSource, + OrbisFontHandle defaultFont) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", + formatParams({ + Param("fontTextSource", fontTextSource), + Param("defaultFont", defaultFont), + })); + + if (!fontTextSource) { + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + if (TextSourceMagic(fontTextSource) != kTextSourceMagic) { + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + fontTextSource->defaultFont = defaultFont; + fontTextSource->systemUse[4] = defaultFont; + return ORBIS_OK; } -s32 PS4_SYSV_ABI sceFontTextSourceSetWritingForm() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceFontTextSourceSetWritingForm(OrbisFontTextSource* fontTextSource, + s32 writingForm) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", + formatParams({ + Param("fontTextSource", fontTextSource), + Param("writingForm", writingForm), + })); + + if (!fontTextSource) { + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + if (TextSourceMagic(fontTextSource) != kTextSourceMagic) { + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + if (writingForm < static_cast(kWritingFormHorizontal) || + writingForm > static_cast(kWritingFormHorizontalLtr)) { + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + SetTextSourceWritingForm(fontTextSource, static_cast(writingForm)); return ORBIS_OK; } @@ -5869,13 +6939,111 @@ s32 PS4_SYSV_ABI sceFontWordsFindWordCharacters() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceFontWritingGetRenderMetrics() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceFontWritingGetRenderMetrics(OrbisFontWriting* fontWriting, + OrbisFontWritingMetrics* writingMetrics) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", + formatParams({ + Param("fontWriting", fontWriting), + Param("writingMetrics", writingMetrics), + })); + + if (!fontWriting || !writingMetrics) { + ZeroWritingMetrics(writingMetrics); + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + auto* w = GetHleFontWriting(fontWriting); + if (!w) { + ZeroWritingMetrics(writingMetrics); + LOG_ERROR(Lib_Font, "INVALID_WRITING"); + return ORBIS_FONT_ERROR_INVALID_WRITING; + } + + *writingMetrics = w->metrics; + if (w->debug_trace_label) { + LOG_INFO(Lib_Font, "TextMetrics[{}]: advanceX={} advanceY={} extent=[l={} r={} t={} b={}]", + w->debug_trace_label, writingMetrics->advanceX, writingMetrics->advanceY, + writingMetrics->Extent.left, writingMetrics->Extent.right, + writingMetrics->Extent.top, writingMetrics->Extent.bottom); + } return ORBIS_OK; } -s32 PS4_SYSV_ABI sceFontWritingInit() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceFontWritingInit(OrbisFontWriting* fontWriting, OrbisFontString fontString, + OrbisFontRenderCharacter fontCharacter) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", + formatParams({ + Param("fontWriting", fontWriting), + Param("fontString", fontString), + Param("fontCharacter", fontCharacter), + })); + + if (!fontWriting || !fontString || !fontCharacter) { + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + auto* s = GetHleFontString(fontString); + if (!s) { + LOG_ERROR(Lib_Font, "INVALID_STRING"); + return ORBIS_FONT_ERROR_INVALID_STRING; + } + + if (auto* old_w = GetHleFontWriting(fontWriting)) { + ReleaseWritingCharacterStorage(*old_w); + } + + std::memset(fontWriting, 0, sizeof(*fontWriting)); + + auto* w = reinterpret_cast(fontWriting->systemUse); + new (w) HleFontWriting{}; + + w->string = fontString; + w->character_storage = s->character_storage; + w->default_font = s->default_font; + AddRefCharacterStorage(w->character_storage); + w->owns_character_storage = true; + w->writing_form = s->writing_form; + if (MatchesAsciiPrompt(*s, "Press Any Button")) { + w->debug_trace_label = "Prompt"; + } else if (ContainsAsciiText(*s, "Some online features cannot be used") || + ContainsAsciiText(*s, "connected to the internet")) { + w->debug_trace_label = "Notice"; + } + const ptrdiff_t start_index = FindCharacterIndex(s, fontCharacter); + if (start_index < 0) { + ReleaseWritingCharacterStorage(*w); + LOG_ERROR(Lib_Font, "INVALID_PARAMETER render character does not belong to string"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + w->next_index = static_cast(start_index); + w->current_index = w->next_index; + w->has_current_step = false; + if (!PopulateWritingStep(*w, w->next_index, w->default_font)) { + ReleaseWritingCharacterStorage(*w); + LOG_ERROR(Lib_Font, "INVALID_PARAMETER failed to populate initial writing step"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; + } + + LOG_INFO( + Lib_Font, + "sceFontWritingInit: prepared first render step code={} advanceX={} width={} height={} " + "bearingX={} bearingY={}", + w->step.glyphCode, w->step.advanceX, w->step.GlyphMetrics.width, + w->step.GlyphMetrics.height, w->step.GlyphMetrics.Horizontal.bearingX, + w->step.GlyphMetrics.Horizontal.bearingY); + if (w->debug_trace_label) { + LOG_INFO(Lib_Font, "TextTrace[{}]: writing init start_index={} text_count={}", + w->debug_trace_label, static_cast(start_index), s->text_count); + } + w->pen_x = 0.0f; + w->pen_y = 0.0f; + ResetWritingAggregateMetrics(*w); + return ORBIS_OK; } @@ -5904,19 +7072,112 @@ s32 PS4_SYSV_ABI sceFontWritingLineWritesOrder() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceFontWritingRefersRenderStep() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +OrbisFontWritingRenderStep PS4_SYSV_ABI +sceFontWritingRefersRenderStep(OrbisFontWriting* fontWriting) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", formatParams({Param("fontWriting", fontWriting)})); + + auto* w = GetHleFontWriting(fontWriting); + if (!w) { + return nullptr; + } + + if (!w->character_storage || w->next_index >= w->character_storage->characters.size()) { + return nullptr; + } + + if (!PopulateWritingStep(*w, w->next_index, w->default_font)) { + return nullptr; + } + + w->current_index = w->next_index; + w->has_current_step = true; + AccumulateWritingMetrics(*w); + if (w->debug_trace_label) { + g_prompt_render_trace.active = true; + g_prompt_render_trace.label = w->debug_trace_label; + g_prompt_render_trace.index = w->next_index; + g_prompt_render_trace.glyph_code = w->step.glyphCode; + g_prompt_render_trace.step_x = w->step.x; + g_prompt_render_trace.step_y = w->step.y; + LOG_INFO(Lib_Font, + "TextTrace[{}]: step index={} code=U+{:04X} x={} y={} advanceX={} advanceY={} " + "anchor=({}, {}) bearingX={} bearingY={} width={} height={} profile[count={} " + "invisible={}]", + w->debug_trace_label, w->next_index, w->step.glyphCode, w->step.x, w->step.y, + w->step.advanceX, w->step.advanceY, w->step.Positioning.x, w->step.Positioning.y, + w->step.GlyphMetrics.Horizontal.bearingX, w->step.GlyphMetrics.Horizontal.bearingY, + w->step.GlyphMetrics.width, w->step.GlyphMetrics.height, + static_cast(w->step.Profile.characterCount), + static_cast(w->step.Profile.invisibleGlyph)); + } + ++w->next_index; + return &w->step; } -s32 PS4_SYSV_ABI sceFontWritingRefersRenderStepCharacter() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +OrbisFontTextCharacter* PS4_SYSV_ABI sceFontWritingRefersRenderStepCharacter( + OrbisFontWriting* fontWriting, OrbisFontWritingLetterStep* pLetterStep) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", + formatParams({ + Param("fontWriting", fontWriting), + Param("pLetterStep", pLetterStep), + })); + + if (pLetterStep) { + std::memset(pLetterStep, 0, sizeof(*pLetterStep)); + } + + auto* w = GetHleFontWriting(fontWriting); + if (!w || !w->has_current_step) { + return nullptr; + } + + if (!w->character_storage || w->current_index >= w->character_storage->characters.size()) { + return nullptr; + } + + if (pLetterStep) { + pLetterStep->x = w->step.x; + pLetterStep->y = w->step.y; + pLetterStep->advanceX = w->step.advanceX; + pLetterStep->advanceY = w->step.advanceY; + pLetterStep->Components.textsCount = 1; + pLetterStep->Components.textsIndex = static_cast(w->current_index); + pLetterStep->Components.glyphsCount = 1; + pLetterStep->Components.glyphsIndex = static_cast(w->current_index); + pLetterStep->Components.characterTextCount = + static_cast(std::max(static_cast(w->step.Profile.characterCount), 1)); + } + + return &w->character_storage->characters[w->current_index]; } -s32 PS4_SYSV_ABI sceFontWritingSetMaskInvisible() { - LOG_ERROR(Lib_Font, "(STUBBED) called"); - return ORBIS_OK; +s32 PS4_SYSV_ABI sceFontWritingSetMaskInvisible(OrbisFontWriting* fontWriting, s32 mask) { + LOG_INFO(Lib_Font, "called"); + LOG_DEBUG(Lib_Font, "{}", + formatParams({ + Param("fontWriting", fontWriting), + Param("mask", mask), + })); + + auto* w = GetHleFontWriting(fontWriting); + if (!w) { + LOG_ERROR(Lib_Font, "INVALID_WRITING"); + return ORBIS_FONT_ERROR_INVALID_WRITING; + } + + if (mask == kWritingMaskFormatCharacters) { + w->mask_format_characters = false; + return ORBIS_OK; + } + if (mask == kWritingMaskNone) { + w->mask_format_characters = true; + return ORBIS_OK; + } + + LOG_ERROR(Lib_Font, "INVALID_PARAMETER"); + return ORBIS_FONT_ERROR_INVALID_PARAMETER; } s32 PS4_SYSV_ABI Func_00F4D778F1C88CB3() { diff --git a/src/core/libraries/font/font.h b/src/core/libraries/font/font.h index 2608a99fb..9898d295e 100644 --- a/src/core/libraries/font/font.h +++ b/src/core/libraries/font/font.h @@ -1,589 +1,771 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later -#pragma once -#include -#include "common/types.h" -namespace Core::Loader { -class SymbolsResolver; -} -namespace Libraries::Font { - -struct OrbisFontHandleOpaque { - u32 reserved[64]; -}; - -using OrbisFontLib = void*; -using OrbisFontHandle = OrbisFontHandleOpaque*; -using OrbisFontRendererCreateParams = void*; -using OrbisFontRenderer = void*; -using OrbisFontLibCreateParams = void*; - -struct OrbisFontMem; - -struct OrbisFontOpenParams { - u16 tag; - u16 pad16; - u32 flags; - u32 subfont_index; - s32 unique_id; - const void* reserved_ptr2; - const void* reserved_ptr1; -}; - -// Fontlib APIs use Unicode scalar values (UTF-32 codepoints) in `u32` parameters such as `code` and -// `codepoint`. Codepoint-to-glyph resolution is performed via FreeType charmaps, with additional -// sysfont mapping and fallback behavior handled internally. -struct OrbisFontGlyphMetrics { - float width; - float height; - struct { - float bearingX; - float bearingY; - float advance; - } Horizontal; - struct { - float bearingX; - float bearingY; - float advance; - } Vertical; -}; - -struct OrbisFontGlyphMetricsHorizontal { - float width; - float height; - struct { - float bearing_x; - float bearing_y; - float advance; - } horizontal; -}; - -struct OrbisFontGlyphMetricsHorizontalX { - float width; - struct { - float bearing_x; - float advance; - } horizontal; -}; - -struct OrbisFontGlyphMetricsHorizontalAdvance { - struct { - float advance; - } horizontal; -}; - -struct OrbisFontKerning { - float offsetX; - float offsetY; - float positionX; - float positionY; -}; - -struct OrbisFontGlyphImageMetrics { - float bearingX; - float bearingY; - float advance; - float stride; - u32 width; - u32 height; -}; - -struct OrbisFontGenerateGlyphParams { - u16 id; - u16 res0; - // Bitmask copied into `OrbisFontGlyphOpaque::flags`. Only bits `0x01` and `0x10` are accepted - // by the public API; other bits are rejected as invalid. - u16 form_options; - u8 glyph_form; - u8 metrics_form; - const OrbisFontMem* mem; - void* res1; - void* res2; -}; - -struct OrbisFontGlyphOutlinePoint { - float x; - float y; -}; - -struct OrbisFontGlyphOutline { - s16 contours_cnt; - s16 points_cnt; - u32 outline_flags; - OrbisFontGlyphOutlinePoint* points_ptr; - u8* tags_ptr; - u16* contour_end_idx; -}; - -struct OrbisFontGlyphOpaque { - u16 magic; - // Encoded flags copied from `OrbisFontGenerateGlyphParams::form_options`. - u16 flags; - u8 glyph_form; - u8 metrics_form; - u16 em_size; - u16 baseline; - u16 height_px; - u16 origin_x; - u16 origin_y; - float scale_x; - float base_scale; - const OrbisFontMem* memory; -}; - -using OrbisFontGlyph = OrbisFontGlyphOpaque*; - -struct OrbisFontResultStage { - u8* p_00; - u32 u32_08; - u32 u32_0C; - u32 u32_10; -}; - -struct OrbisFontSurfaceImage { - u8* address; - u32 widthByte; - u8 pixelSizeByte; - u8 pixelFormat; - u16 pad16; -}; - -struct OrbisFontRenderOutput { - const OrbisFontResultStage* stage; - OrbisFontSurfaceImage SurfaceImage; - struct { - u32 x; - u32 y; - u32 w; - u32 h; - } UpdateRect; - OrbisFontGlyphImageMetrics ImageMetrics; -}; - -using OrbisFontAllocFn = void*(void* object, u32 size); -using OrbisFontFreeFn = void(void* object, void* p); -using OrbisFontReallocFn = void*(void* object, void* p, u32 newSize); -using OrbisFontCallocFn = void*(void* object, u32 nBlock, u32 size); -using OrbisFontMspaceCreateFn = void*(void* parent, const char* name, void* address, u32 size, - u32 attr); -using OrbisFontMspaceDestroyFn = void(void* parent, void* mspace); -using OrbisFontMemDestroyFn = void(OrbisFontMem* fontMemory, void* object, void* destroyArg); - -using OrbisFontAllocCb = OrbisFontAllocFn*; -using OrbisFontFreeCb = OrbisFontFreeFn*; -using OrbisFontReallocCb = OrbisFontReallocFn*; -using OrbisFontCallocCb = OrbisFontCallocFn*; -using OrbisFontMspaceCreateCb = OrbisFontMspaceCreateFn*; -using OrbisFontMspaceDestroyCb = OrbisFontMspaceDestroyFn*; -using OrbisFontMemDestroyCb = OrbisFontMemDestroyFn*; - -struct OrbisFontMemInterface { - OrbisFontAllocCb alloc{}; - OrbisFontFreeCb dealloc{}; - OrbisFontReallocCb realloc_fn{}; - OrbisFontCallocCb calloc_fn{}; - OrbisFontMspaceCreateCb mspace_create{}; - OrbisFontMspaceDestroyCb mspace_destroy{}; -}; - -struct OrbisFontMem { - u16 mem_kind; - u16 attr_bits; - u32 region_size; - void* region_base; - void* mspace_handle; - const OrbisFontMemInterface* iface; - OrbisFontMemDestroyCb on_destroy; - void* destroy_ctx; - void* some_ctx1; - void* some_ctx2; -}; - -struct OrbisFontTextCharacter { - struct OrbisFontTextCharacter* next; - struct OrbisFontTextCharacter* prev; - void* textOrder; - u32 characterCode; - u8 unknown_0x31; - u8 unknown_0x33; - u8 charType; - u8 bidiLevel; - u8 formatFlags; -}; - -struct OrbisFontRenderSurface { - void* buffer; - s32 widthByte; - s8 pixelSizeByte; - u8 pad0; - u8 styleFlag; - u8 pad2; - s32 width, height; - u32 sc_x0; - u32 sc_y0; - u32 sc_x1; - u32 sc_y1; - u64 reserved_q[11]; -}; - -struct OrbisFontStyleFrame { - /*0x00*/ u16 magic; - // `flags1` controls which fields are considered valid overrides: - // - bit0: scale override present (scaleUnit/scalePixelW/scalePixelH) - // - bit1: slant override present (slantRatio) - // - bit2: weight override present (effectWeightX/effectWeightY) - /*0x02*/ u8 flags1; - /*0x03*/ u8 flags2; - /*0x04*/ u32 hDpi; - /*0x08*/ u32 vDpi; - // `scaleUnit` selects how scale fields are interpreted: - // - 0: pixel scale (`scalePixelW/scalePixelH`) - // - 1: point scale (converted via DPI by style-state getters) - /*0x0C*/ u32 scaleUnit; - /*0x10*/ float baseScale; - /*0x14*/ float scalePixelW; - /*0x18*/ float scalePixelH; - /*0x1C*/ float effectWeightX; - /*0x20*/ float effectWeightY; - /*0x24*/ float slantRatio; - /*0x28*/ u32 reserved_0x28; - /*0x2C*/ u32 layout_cache_state; - // Packed cache metadata: - // - bits [7:0] cache flags - // - bits [31:16] direction word - /*0x30*/ u32 cache_flags_and_direction; - /*0x34*/ u32 cache_lock_word; - /*0x38*/ u8 layout_cache_bytes[0x20]; - /*0x58*/ u32 reserved_0x58; - /*0x5C*/ u32 cached_scalar_bits; -}; - -static_assert(sizeof(OrbisFontStyleFrame) == 0x60, "OrbisFontStyleFrame size"); -static_assert(offsetof(OrbisFontStyleFrame, magic) == 0x00, "OrbisFontStyleFrame magic offset"); -static_assert(offsetof(OrbisFontStyleFrame, flags1) == 0x02, "OrbisFontStyleFrame flags1 offset"); -static_assert(offsetof(OrbisFontStyleFrame, hDpi) == 0x04, "OrbisFontStyleFrame hDpi offset"); -static_assert(offsetof(OrbisFontStyleFrame, vDpi) == 0x08, "OrbisFontStyleFrame vDpi offset"); -static_assert(offsetof(OrbisFontStyleFrame, scaleUnit) == 0x0C, - "OrbisFontStyleFrame scaleUnit offset"); -static_assert(offsetof(OrbisFontStyleFrame, scalePixelW) == 0x14, - "OrbisFontStyleFrame scalePixelW offset"); -static_assert(offsetof(OrbisFontStyleFrame, scalePixelH) == 0x18, - "OrbisFontStyleFrame scalePixelH offset"); -static_assert(offsetof(OrbisFontStyleFrame, cache_lock_word) == 0x34, - "OrbisFontStyleFrame cache_lock_word offset"); -static_assert(offsetof(OrbisFontStyleFrame, reserved_0x58) == 0x58, - "OrbisFontStyleFrame reserved_0x58 offset"); - -static_assert(sizeof(OrbisFontGlyphMetrics) == 0x20, "OrbisFontGlyphMetrics size"); -static_assert(sizeof(OrbisFontResultStage) == 0x18, "OrbisFontTransImage size"); -static_assert(sizeof(OrbisFontSurfaceImage) == 0x10, "OrbisFontSurfaceImage size"); -static_assert(sizeof(OrbisFontRenderOutput) == 0x40, "OrbisFontRenderOutput size"); - -struct OrbisFontHorizontalLayout { - float baselineOffset; - float lineAdvance; - float decorationExtent; -}; -struct OrbisFontVerticalLayout { - float baselineOffsetX; - float columnAdvance; - float decorationSpan; -}; - -#if INTPTR_MAX == INT64_MAX -static_assert(sizeof(OrbisFontOpenParams) == 32, "OrbisFontOpenParams size"); -static_assert(sizeof(OrbisFontGlyphMetrics) == 32, "OrbisFontGlyphMetrics size"); -static_assert(sizeof(OrbisFontKerning) == 16, "OrbisFontKerning size"); -static_assert(sizeof(OrbisFontRenderSurface) == 128, "OrbisFontRenderSurface ABI size"); -static_assert(sizeof(OrbisFontGlyphImageMetrics) == 24, "OrbisFontGlyphImageMetrics ABI size"); -static_assert(sizeof(OrbisFontRenderOutput) == 64, "OrbisFontRenderOutput ABI size"); -static_assert(sizeof(OrbisFontMem) == 64, "OrbisFontMem ABI size"); -#endif - -s32 PS4_SYSV_ABI sceFontAttachDeviceCacheBuffer(OrbisFontLib library, void* buffer, u32 size); -s32 PS4_SYSV_ABI sceFontBindRenderer(OrbisFontHandle fontHandle, OrbisFontRenderer renderer); -s32 PS4_SYSV_ABI sceFontCharacterGetBidiLevel(OrbisFontTextCharacter* textCharacter, - int* bidiLevel); -s32 PS4_SYSV_ABI sceFontCharacterGetSyllableStringState(); -s32 PS4_SYSV_ABI sceFontCharacterGetTextFontCode(); -s32 PS4_SYSV_ABI sceFontCharacterGetTextOrder(OrbisFontTextCharacter* textCharacter, - void** pTextOrder); -u32 PS4_SYSV_ABI sceFontCharacterLooksFormatCharacters(OrbisFontTextCharacter* textCharacter); -u32 PS4_SYSV_ABI sceFontCharacterLooksWhiteSpace(OrbisFontTextCharacter* textCharacter); -OrbisFontTextCharacter* PS4_SYSV_ABI -sceFontCharacterRefersTextBack(OrbisFontTextCharacter* textCharacter); -OrbisFontTextCharacter* PS4_SYSV_ABI -sceFontCharacterRefersTextNext(OrbisFontTextCharacter* textCharacter); -s32 PS4_SYSV_ABI sceFontCharactersRefersTextCodes(); -s32 PS4_SYSV_ABI sceFontClearDeviceCache(OrbisFontLib library); -s32 PS4_SYSV_ABI sceFontCloseFont(); -s32 PS4_SYSV_ABI sceFontControl(); -s32 PS4_SYSV_ABI sceFontCreateGraphicsDevice(); -s32 PS4_SYSV_ABI sceFontCreateGraphicsService(); -s32 PS4_SYSV_ABI sceFontCreateGraphicsServiceWithEdition(); -s32 PS4_SYSV_ABI sceFontCreateLibrary(const OrbisFontMem* memory, - OrbisFontLibCreateParams create_params, - OrbisFontLib* pLibrary); -s32 PS4_SYSV_ABI sceFontCreateLibraryWithEdition(const OrbisFontMem* memory, - OrbisFontLibCreateParams create_params, - u64 edition, OrbisFontLib* pLibrary); -s32 PS4_SYSV_ABI sceFontCreateRenderer(const OrbisFontMem* memory, - OrbisFontRendererCreateParams create_params, - OrbisFontRenderer* pRenderer); -s32 PS4_SYSV_ABI sceFontCreateRendererWithEdition(const OrbisFontMem* memory, - OrbisFontRendererCreateParams create_params, - u64 edition, OrbisFontRenderer* pRenderer); -s32 PS4_SYSV_ABI sceFontCreateString(); -s32 PS4_SYSV_ABI sceFontCreateWords(); -s32 PS4_SYSV_ABI sceFontCreateWritingLine(); -s32 PS4_SYSV_ABI sceFontDefineAttribute(); -s32 PS4_SYSV_ABI sceFontDeleteGlyph(const OrbisFontMem* memory, OrbisFontGlyph* glyph); -s32 PS4_SYSV_ABI sceFontDestroyGraphicsDevice(); -s32 PS4_SYSV_ABI sceFontDestroyGraphicsService(); -s32 PS4_SYSV_ABI sceFontDestroyLibrary(OrbisFontLib* pLibrary); -s32 PS4_SYSV_ABI sceFontDestroyRenderer(OrbisFontRenderer* pRenderer); -s32 PS4_SYSV_ABI sceFontDestroyString(); -s32 PS4_SYSV_ABI sceFontDestroyWords(); -s32 PS4_SYSV_ABI sceFontDestroyWritingLine(); -s32 PS4_SYSV_ABI sceFontDettachDeviceCacheBuffer(); -s32 PS4_SYSV_ABI sceFontGenerateCharGlyph(OrbisFontHandle glyph_handle, u32 codepoint, - const OrbisFontGenerateGlyphParams* gen_params, - OrbisFontGlyph* glyph_out); -s32 PS4_SYSV_ABI sceFontGetAttribute(); -s32 PS4_SYSV_ABI sceFontGetCharGlyphCode(); -s32 PS4_SYSV_ABI sceFontGetCharGlyphMetrics(OrbisFontHandle fontHandle, u32 code, - OrbisFontGlyphMetrics* metrics); -s32 PS4_SYSV_ABI sceFontGetEffectSlant(OrbisFontHandle fontHandle, float* slantRatio); -s32 PS4_SYSV_ABI sceFontGetEffectWeight(OrbisFontHandle fontHandle, float* weightXScale, - float* weightYScale, u32* mode); -s32 PS4_SYSV_ABI sceFontGetFontGlyphsCount(); -s32 PS4_SYSV_ABI sceFontGetFontGlyphsOutlineProfile(); -s32 PS4_SYSV_ABI sceFontGetFontMetrics(); -s32 PS4_SYSV_ABI sceFontGetFontResolution(); -s32 PS4_SYSV_ABI sceFontGetFontStyleInformation(); -s32 PS4_SYSV_ABI sceFontGetGlyphExpandBufferState(); -s32 PS4_SYSV_ABI sceFontGetHorizontalLayout(OrbisFontHandle fontHandle, - OrbisFontHorizontalLayout* layout); -s32 PS4_SYSV_ABI sceFontGetKerning(OrbisFontHandle fontHandle, u32 preCode, u32 code, - OrbisFontKerning* kerning); -s32 PS4_SYSV_ABI sceFontGetLibrary(OrbisFontHandle fontHandle, OrbisFontLib* pLibrary); -s32 PS4_SYSV_ABI sceFontGetPixelResolution(); -s32 PS4_SYSV_ABI sceFontGetRenderCharGlyphMetrics(OrbisFontHandle fontHandle, u32 codepoint, - OrbisFontGlyphMetrics* out_metrics); -s32 PS4_SYSV_ABI sceFontGetRenderEffectSlant(OrbisFontHandle fontHandle, float* slantRatio); -s32 PS4_SYSV_ABI sceFontGetRenderEffectWeight(OrbisFontHandle fontHandle, float* weightXScale, - float* weightYScale, u32* mode); -s32 PS4_SYSV_ABI sceFontGetRenderScaledKerning(); -s32 PS4_SYSV_ABI sceFontGetRenderScalePixel(OrbisFontHandle fontHandle, float* out_w, float* out_h); -s32 PS4_SYSV_ABI sceFontGetRenderScalePoint(OrbisFontHandle fontHandle, float* out_w, float* out_h); -s32 PS4_SYSV_ABI sceFontGetResolutionDpi(); -s32 PS4_SYSV_ABI sceFontGetScalePixel(OrbisFontHandle fontHandle, float* out_w, float* out_h); -s32 PS4_SYSV_ABI sceFontGetScalePoint(OrbisFontHandle fontHandle, float* out_w, float* out_h); -s32 PS4_SYSV_ABI sceFontGetScriptLanguage(); -s32 PS4_SYSV_ABI sceFontGetTypographicDesign(); -s32 PS4_SYSV_ABI sceFontGetVerticalLayout(OrbisFontHandle fontHandle, - OrbisFontVerticalLayout* layout); -s32 PS4_SYSV_ABI sceFontGlyphDefineAttribute(); -s32 PS4_SYSV_ABI sceFontGlyphGetAttribute(); -s32 PS4_SYSV_ABI sceFontGlyphGetGlyphForm(); -s32 PS4_SYSV_ABI sceFontGlyphGetMetricsForm(); -s32 PS4_SYSV_ABI sceFontGlyphGetScalePixel(); -s32 PS4_SYSV_ABI sceFontGlyphRefersMetrics(); -s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontal(); -s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontalAdvance(); -s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontalX(); -OrbisFontGlyphOutline* PS4_SYSV_ABI sceFontGlyphRefersOutline(OrbisFontGlyph glyph); -s32 PS4_SYSV_ABI sceFontGlyphRenderImage(); -s32 PS4_SYSV_ABI sceFontGlyphRenderImageHorizontal(); -s32 PS4_SYSV_ABI sceFontGlyphRenderImageVertical(); -s32 PS4_SYSV_ABI sceFontGraphicsBeginFrame(); -s32 PS4_SYSV_ABI sceFontGraphicsDrawingCancel(); -s32 PS4_SYSV_ABI sceFontGraphicsDrawingFinish(); -s32 PS4_SYSV_ABI sceFontGraphicsEndFrame(); -s32 PS4_SYSV_ABI sceFontGraphicsExchangeResource(); -s32 PS4_SYSV_ABI sceFontGraphicsFillMethodInit(); -s32 PS4_SYSV_ABI sceFontGraphicsFillPlotInit(); -s32 PS4_SYSV_ABI sceFontGraphicsFillPlotSetLayout(); -s32 PS4_SYSV_ABI sceFontGraphicsFillPlotSetMapping(); -s32 PS4_SYSV_ABI sceFontGraphicsFillRatesInit(); -s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetFillEffect(); -s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetLayout(); -s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetMapping(); -s32 PS4_SYSV_ABI sceFontGraphicsGetDeviceUsage(); -s32 PS4_SYSV_ABI sceFontGraphicsRegionInit(); -s32 PS4_SYSV_ABI sceFontGraphicsRegionInitCircular(); -s32 PS4_SYSV_ABI sceFontGraphicsRegionInitRoundish(); -s32 PS4_SYSV_ABI sceFontGraphicsRelease(); -s32 PS4_SYSV_ABI sceFontGraphicsRenderResource(); -s32 PS4_SYSV_ABI sceFontGraphicsSetFramePolicy(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupClipping(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupColorRates(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupFillMethod(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupFillRates(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupGlyphFill(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupGlyphFillPlot(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupHandleDefault(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupLocation(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupPositioning(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupRotation(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupScaling(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupShapeFill(); -s32 PS4_SYSV_ABI sceFontGraphicsSetupShapeFillPlot(); -s32 PS4_SYSV_ABI sceFontGraphicsStructureCanvas(); -s32 PS4_SYSV_ABI sceFontGraphicsStructureCanvasSequence(); -s32 PS4_SYSV_ABI sceFontGraphicsStructureDesign(); -s32 PS4_SYSV_ABI sceFontGraphicsStructureDesignResource(); -s32 PS4_SYSV_ABI sceFontGraphicsStructureSurfaceTexture(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdateClipping(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdateColorRates(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdateFillMethod(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdateFillRates(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdateGlyphFill(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdateGlyphFillPlot(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdateLocation(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdatePositioning(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdateRotation(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdateScaling(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdateShapeFill(); -s32 PS4_SYSV_ABI sceFontGraphicsUpdateShapeFillPlot(); -s32 PS4_SYSV_ABI sceFontMemoryInit(OrbisFontMem* mem_desc, void* region_addr, u32 region_size, - const OrbisFontMemInterface* iface, void* mspace_obj, - OrbisFontMemDestroyCb destroy_cb, void* destroy_ctx); -s32 PS4_SYSV_ABI sceFontMemoryTerm(OrbisFontMem* mem_desc); -s32 PS4_SYSV_ABI sceFontOpenFontFile(OrbisFontLib library, const char* guest_path, u32 open_mode, - const OrbisFontOpenParams* open_detail, - OrbisFontHandle* out_handle); -s32 PS4_SYSV_ABI sceFontOpenFontInstance(OrbisFontHandle fontHandle, OrbisFontHandle templateFont, - OrbisFontHandle* pFontHandle); -s32 PS4_SYSV_ABI sceFontOpenFontMemory(OrbisFontLib library, const void* fontAddress, u32 fontSize, - const OrbisFontOpenParams* open_params, - OrbisFontHandle* pFontHandle); -s32 PS4_SYSV_ABI sceFontOpenFontSet(OrbisFontLib library, u32 fontSetType, u32 openMode, - const OrbisFontOpenParams* open_params, - OrbisFontHandle* pFontHandle); -s32 PS4_SYSV_ABI sceFontRebindRenderer(OrbisFontHandle fontHandle); -s32 PS4_SYSV_ABI sceFontRenderCharGlyphImage(OrbisFontHandle fontHandle, u32 code, - OrbisFontRenderSurface* surf, float x, float y, - OrbisFontGlyphMetrics* metrics, - OrbisFontRenderOutput* result); -s32 PS4_SYSV_ABI sceFontRenderCharGlyphImageHorizontal(OrbisFontHandle fontHandle, u32 code, - OrbisFontRenderSurface* surf, float x, - float y, OrbisFontGlyphMetrics* metrics, - OrbisFontRenderOutput* result); -s32 PS4_SYSV_ABI sceFontRenderCharGlyphImageVertical(OrbisFontHandle fontHandle, u32 code, - OrbisFontRenderSurface* surf, float x, float y, - OrbisFontGlyphMetrics* metrics, - OrbisFontRenderOutput* result); -s32 PS4_SYSV_ABI sceFontRendererGetOutlineBufferSize(OrbisFontRenderer fontRenderer, u32* size); -s32 PS4_SYSV_ABI sceFontRendererResetOutlineBuffer(OrbisFontRenderer fontRenderer); -s32 PS4_SYSV_ABI sceFontRendererSetOutlineBufferPolicy(OrbisFontRenderer fontRenderer, - u64 bufferPolicy, u32 basalSize, - u32 limitSize); -void PS4_SYSV_ABI sceFontRenderSurfaceInit(OrbisFontRenderSurface* renderSurface, void* buffer, - int bufWidthByte, int pixelSizeByte, int widthPixel, - int heightPixel); -void PS4_SYSV_ABI sceFontRenderSurfaceSetScissor(OrbisFontRenderSurface* renderSurface, int x0, - int y0, int w, int h); -s32 PS4_SYSV_ABI sceFontRenderSurfaceSetStyleFrame(OrbisFontRenderSurface* renderSurface, - OrbisFontStyleFrame* styleFrame); -s32 PS4_SYSV_ABI sceFontSetEffectSlant(OrbisFontHandle fontHandle, float slantRatio); -s32 PS4_SYSV_ABI sceFontSetEffectWeight(OrbisFontHandle fontHandle, float weightXScale, - float weightYScale, u32 mode); -s32 PS4_SYSV_ABI sceFontSetFontsOpenMode(); -s32 PS4_SYSV_ABI sceFontSetResolutionDpi(OrbisFontHandle fontHandle, u32 h_dpi, u32 v_dpi); -s32 PS4_SYSV_ABI sceFontSetScalePixel(OrbisFontHandle fontHandle, float w, float h); -s32 PS4_SYSV_ABI sceFontSetScalePoint(OrbisFontHandle fontHandle, float w, float h); -s32 PS4_SYSV_ABI sceFontSetScriptLanguage(); -s32 PS4_SYSV_ABI sceFontSetTypographicDesign(); -s32 PS4_SYSV_ABI sceFontSetupRenderEffectSlant(OrbisFontHandle fontHandle, float slantRatio); -s32 PS4_SYSV_ABI sceFontSetupRenderEffectWeight(OrbisFontHandle fontHandle, float weightXScale, - float weightYScale, u32 mode); -s32 PS4_SYSV_ABI sceFontSetupRenderScalePixel(OrbisFontHandle fontHandle, float w, float h); -s32 PS4_SYSV_ABI sceFontSetupRenderScalePoint(OrbisFontHandle fontHandle, float w, float h); -s32 PS4_SYSV_ABI sceFontStringGetTerminateCode(); -s32 PS4_SYSV_ABI sceFontStringGetTerminateOrder(); -s32 PS4_SYSV_ABI sceFontStringGetWritingForm(); -s32 PS4_SYSV_ABI sceFontStringRefersRenderCharacters(); -s32 PS4_SYSV_ABI sceFontStringRefersTextCharacters(); -s32 PS4_SYSV_ABI sceFontStyleFrameGetEffectSlant(OrbisFontStyleFrame* styleFrame, - float* slantRatio); -s32 PS4_SYSV_ABI sceFontStyleFrameGetEffectWeight(OrbisFontStyleFrame* fontStyleFrame, - float* weightXScale, float* weightYScale, - uint32_t* mode); -s32 PS4_SYSV_ABI sceFontStyleFrameGetResolutionDpi(const OrbisFontStyleFrame* styleFrame, - u32* h_dpi, u32* v_dpi); -s32 PS4_SYSV_ABI sceFontStyleFrameGetScalePixel(const OrbisFontStyleFrame* styleFrame, float* w, - float* h); -s32 PS4_SYSV_ABI sceFontStyleFrameGetScalePoint(const OrbisFontStyleFrame* styleFrame, float* w, - float* h); -s32 PS4_SYSV_ABI sceFontStyleFrameInit(OrbisFontStyleFrame* styleFrame); -s32 PS4_SYSV_ABI sceFontStyleFrameSetEffectSlant(OrbisFontStyleFrame* styleFrame, float slantRatio); -s32 PS4_SYSV_ABI sceFontStyleFrameSetEffectWeight(OrbisFontStyleFrame* styleFrame, - float weightXScale, float weightYScale, u32 mode); -s32 PS4_SYSV_ABI sceFontStyleFrameSetResolutionDpi(OrbisFontStyleFrame* styleFrame, u32 h_dpi, - u32 v_dpi); -s32 PS4_SYSV_ABI sceFontStyleFrameSetScalePixel(OrbisFontStyleFrame* styleFrame, float w, float h); -s32 PS4_SYSV_ABI sceFontStyleFrameSetScalePoint(OrbisFontStyleFrame* styleFrame, float w, float h); -s32 PS4_SYSV_ABI sceFontStyleFrameUnsetEffectSlant(OrbisFontStyleFrame* styleFrame); -s32 PS4_SYSV_ABI sceFontStyleFrameUnsetEffectWeight(OrbisFontStyleFrame* styleFrame); -s32 PS4_SYSV_ABI sceFontStyleFrameUnsetScale(OrbisFontStyleFrame* styleFrame); -s32 PS4_SYSV_ABI sceFontSupportExternalFonts(OrbisFontLib library, u32 fontMax, u32 formats); -s32 PS4_SYSV_ABI sceFontSupportGlyphs(); -s32 PS4_SYSV_ABI sceFontSupportSystemFonts(OrbisFontLib library); -s32 PS4_SYSV_ABI sceFontTextCodesStepBack(); -s32 PS4_SYSV_ABI sceFontTextCodesStepNext(); -s32 PS4_SYSV_ABI sceFontTextSourceInit(); -s32 PS4_SYSV_ABI sceFontTextSourceRewind(); -s32 PS4_SYSV_ABI sceFontTextSourceSetDefaultFont(); -s32 PS4_SYSV_ABI sceFontTextSourceSetWritingForm(); -s32 PS4_SYSV_ABI sceFontUnbindRenderer(OrbisFontHandle fontHandle); -s32 PS4_SYSV_ABI sceFontWordsFindWordCharacters(); -s32 PS4_SYSV_ABI sceFontWritingGetRenderMetrics(); -s32 PS4_SYSV_ABI sceFontWritingInit(); -s32 PS4_SYSV_ABI sceFontWritingLineClear(); -s32 PS4_SYSV_ABI sceFontWritingLineGetOrderingSpace(); -s32 PS4_SYSV_ABI sceFontWritingLineGetRenderMetrics(); -s32 PS4_SYSV_ABI sceFontWritingLineRefersRenderStep(); -s32 PS4_SYSV_ABI sceFontWritingLineWritesOrder(); -s32 PS4_SYSV_ABI sceFontWritingRefersRenderStep(); -s32 PS4_SYSV_ABI sceFontWritingRefersRenderStepCharacter(); -s32 PS4_SYSV_ABI sceFontWritingSetMaskInvisible(); -s32 PS4_SYSV_ABI Func_00F4D778F1C88CB3(); -s32 PS4_SYSV_ABI Func_03C650025FBB0DE7(); -s32 PS4_SYSV_ABI Func_07EAB8A163B27E1A(); -s32 PS4_SYSV_ABI Func_09408E88E4F97CE3(); -s32 PS4_SYSV_ABI Func_09F92905ED82A814(); -s32 PS4_SYSV_ABI Func_0D142CEE1AB21ABE(); -s32 PS4_SYSV_ABI Func_14BD2E9E119C16F2(); -s32 PS4_SYSV_ABI Func_1AC53C9EDEAE8D75(); -s32 PS4_SYSV_ABI Func_1D401185D5E24C3D(); -s32 PS4_SYSV_ABI Func_1E83CD20C2CC996F(); -s32 PS4_SYSV_ABI Func_314B1F765B9FE78A(); -s32 PS4_SYSV_ABI Func_350E6725FEDE29E1(); -s32 PS4_SYSV_ABI Func_3DB773F0A604BF39(); -s32 PS4_SYSV_ABI Func_4FF49DD21E311B1C(); -s32 PS4_SYSV_ABI Func_526287664A493981(); -s32 PS4_SYSV_ABI Func_55CA718DBC84A6E9(); -s32 PS4_SYSV_ABI Func_563FC5F0706A8B4D(); -s32 PS4_SYSV_ABI Func_569E2ECD34290F45(); -s32 PS4_SYSV_ABI Func_5A04775B6BE47685(); -s32 PS4_SYSV_ABI Func_5FD93BCAB6F79750(); -s32 PS4_SYSV_ABI Func_62B5398F864BD3B4(); -s32 PS4_SYSV_ABI Func_6F9010294D822367(); -s32 PS4_SYSV_ABI Func_7757E947423A7A67(); -s32 PS4_SYSV_ABI Func_7E06BA52077F54FA(); -s32 PS4_SYSV_ABI Func_93B36DEA021311D6(); -s32 PS4_SYSV_ABI Func_94B0891E7111598A(); -s32 PS4_SYSV_ABI Func_9785C9128C2FE7CD(); -s32 PS4_SYSV_ABI Func_97DFBC9B65FBC0E1(); -s32 PS4_SYSV_ABI Func_ACD9717405D7D3CA(); -s32 PS4_SYSV_ABI Func_B19A8AEC3FD4F16F(); -s32 PS4_SYSV_ABI Func_C10F488AD7CF103D(); -s32 PS4_SYSV_ABI Func_D0C8B5FF4A6826C7(); -s32 PS4_SYSV_ABI Func_E48D3CD01C342A33(); -s32 PS4_SYSV_ABI Func_EAC96B2186B71E14(); -s32 PS4_SYSV_ABI Func_FE4788A96EF46256(); -s32 PS4_SYSV_ABI Func_FE7E5AE95D3058F5(); - -void RegisterlibSceFont(Core::Loader::SymbolsResolver* sym); -} // namespace Libraries::Font +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once +#include +#include "common/types.h" +namespace Core::Loader { +class SymbolsResolver; +} +namespace Libraries::Font { + +struct OrbisFontHandleOpaque { + u32 reserved[64]; +}; + +using OrbisFontLib = void*; +using OrbisFontHandle = OrbisFontHandleOpaque*; +using OrbisFontRendererCreateParams = void*; +using OrbisFontRenderer = void*; +using OrbisFontLibCreateParams = void*; + +struct OrbisFontMem; + +struct OrbisFontOpenParams { + u16 tag; + u16 pad16; + u32 flags; + u32 subfont_index; + s32 unique_id; + const void* reserved_ptr2; + const void* reserved_ptr1; +}; + +// Fontlib APIs use Unicode scalar values (UTF-32 codepoints) in `u32` parameters such as `code` and +// `codepoint`. Codepoint-to-glyph resolution is performed via FreeType charmaps, with additional +// sysfont mapping and fallback behavior handled internally. +struct OrbisFontGlyphMetrics { + float width; + float height; + struct { + float bearingX; + float bearingY; + float advance; + } Horizontal; + struct { + float bearingX; + float bearingY; + float advance; + } Vertical; +}; + +struct OrbisFontGlyphMetricsHorizontal { + float width; + float height; + struct { + float bearing_x; + float bearing_y; + float advance; + } horizontal; +}; + +struct OrbisFontGlyphMetricsHorizontalX { + float width; + struct { + float bearing_x; + float advance; + } horizontal; +}; + +struct OrbisFontGlyphMetricsHorizontalAdvance { + struct { + float advance; + } horizontal; +}; + +struct OrbisFontKerning { + float offsetX; + float offsetY; + float positionX; + float positionY; +}; + +struct OrbisFontGlyphImageMetrics { + float bearingX; + float bearingY; + float advance; + float stride; + u32 width; + u32 height; +}; + +struct OrbisFontGenerateGlyphParams { + u16 id; + u16 res0; + // Bitmask copied into `OrbisFontGlyphOpaque::flags`. Only bits `0x01` and `0x10` are accepted + // by the public API; other bits are rejected as invalid. + u16 form_options; + u8 glyph_form; + u8 metrics_form; + const OrbisFontMem* mem; + void* res1; + void* res2; +}; + +struct OrbisFontGlyphOutlinePoint { + float x; + float y; +}; + +struct OrbisFontGlyphOutline { + s16 contours_cnt; + s16 points_cnt; + u32 outline_flags; + OrbisFontGlyphOutlinePoint* points_ptr; + u8* tags_ptr; + u16* contour_end_idx; +}; + +struct OrbisFontGlyphOpaque { + u16 magic; + // Encoded flags copied from `OrbisFontGenerateGlyphParams::form_options`. + u16 flags; + u8 glyph_form; + u8 metrics_form; + u16 em_size; + u16 baseline; + u16 height_px; + u16 origin_x; + u16 origin_y; + float scale_x; + float base_scale; + const OrbisFontMem* memory; +}; + +using OrbisFontGlyph = OrbisFontGlyphOpaque*; + +struct OrbisFontResultStage { + u8* p_00; + u32 u32_08; + u32 u32_0C; + u32 u32_10; +}; + +struct OrbisFontSurfaceImage { + u8* address; + u32 widthByte; + u8 pixelSizeByte; + u8 pixelFormat; + u16 pad16; +}; + +struct OrbisFontRenderOutput { + const OrbisFontResultStage* stage; + OrbisFontSurfaceImage SurfaceImage; + struct { + u32 x; + u32 y; + u32 w; + u32 h; + } UpdateRect; + OrbisFontGlyphImageMetrics ImageMetrics; +}; + +using OrbisFontAllocFn = void*(void* object, u32 size); +using OrbisFontFreeFn = void(void* object, void* p); +using OrbisFontReallocFn = void*(void* object, void* p, u32 newSize); +using OrbisFontCallocFn = void*(void* object, u32 nBlock, u32 size); +using OrbisFontMspaceCreateFn = void*(void* parent, const char* name, void* address, u32 size, + u32 attr); +using OrbisFontMspaceDestroyFn = void(void* parent, void* mspace); +using OrbisFontMemDestroyFn = void(OrbisFontMem* fontMemory, void* object, void* destroyArg); + +using OrbisFontAllocCb = OrbisFontAllocFn*; +using OrbisFontFreeCb = OrbisFontFreeFn*; +using OrbisFontReallocCb = OrbisFontReallocFn*; +using OrbisFontCallocCb = OrbisFontCallocFn*; +using OrbisFontMspaceCreateCb = OrbisFontMspaceCreateFn*; +using OrbisFontMspaceDestroyCb = OrbisFontMspaceDestroyFn*; +using OrbisFontMemDestroyCb = OrbisFontMemDestroyFn*; + +struct OrbisFontMemInterface { + OrbisFontAllocCb alloc{}; + OrbisFontFreeCb dealloc{}; + OrbisFontReallocCb realloc_fn{}; + OrbisFontCallocCb calloc_fn{}; + OrbisFontMspaceCreateCb mspace_create{}; + OrbisFontMspaceDestroyCb mspace_destroy{}; +}; + +struct OrbisFontMem { + u16 mem_kind; + u16 attr_bits; + u32 region_size; + void* region_base; + void* mspace_handle; + const OrbisFontMemInterface* iface; + OrbisFontMemDestroyCb on_destroy; + void* destroy_ctx; + void* some_ctx1; + void* some_ctx2; +}; + +struct OrbisFontTextCharacter { + struct OrbisFontTextCharacter* prev; + struct OrbisFontTextCharacter* next; + void* textOrder; + OrbisFontHandle font; + void* shapeEntry; + u32 characterCode; + u8 reserved_0x2c[4]; + u8 clusterSpan; + u8 clusterIndex; + u8 clusterKind; + s8 synthetic; + u8 reserved_0x34[4]; + u64 flags; + u8 reserved_0x40[136]; +}; + +struct OrbisFontRenderSurface { + void* buffer; + s32 widthByte; + s8 pixelSizeByte; + u8 pad0; + u8 styleFlag; + u8 pad2; + s32 width, height; + u32 sc_x0; + u32 sc_y0; + u32 sc_x1; + u32 sc_y1; + u64 reserved_q[11]; +}; + +struct OrbisFontStyleFrame { + /*0x00*/ u16 magic; + // `flags1` controls which fields are considered valid overrides: + // - bit0: scale override present (scaleUnit/scalePixelW/scalePixelH) + // - bit1: slant override present (slantRatio) + // - bit2: weight override present (effectWeightX/effectWeightY) + /*0x02*/ u8 flags1; + /*0x03*/ u8 flags2; + /*0x04*/ u32 hDpi; + /*0x08*/ u32 vDpi; + // `scaleUnit` selects how scale fields are interpreted: + // - 0: pixel scale (`scalePixelW/scalePixelH`) + // - 1: point scale (converted via DPI by style-state getters) + /*0x0C*/ u32 scaleUnit; + /*0x10*/ float baseScale; + /*0x14*/ float scalePixelW; + /*0x18*/ float scalePixelH; + /*0x1C*/ float effectWeightX; + /*0x20*/ float effectWeightY; + /*0x24*/ float slantRatio; + /*0x28*/ u32 reserved_0x28; + /*0x2C*/ u32 layout_cache_state; + // Packed cache metadata: + // - bits [7:0] cache flags + // - bits [31:16] direction word + /*0x30*/ u32 cache_flags_and_direction; + /*0x34*/ u32 cache_lock_word; + /*0x38*/ u8 layout_cache_bytes[0x20]; + /*0x58*/ u32 reserved_0x58; + /*0x5C*/ u32 cached_scalar_bits; +}; + +struct OrbisFontTextSource; + +union OrbisFontTextParseResult { + void* reserved[4]; + + struct { + OrbisFontHandle font; + u32 code; + } FontCode; + + struct { + void* reserved; + u32 terminateCode; + } Terminate; + + struct { + void* reserved; + s32 errorCode; + } Error; +}; + +using OrbisFontTextParseFunction = s32(PS4_SYSV_ABI*)(OrbisFontTextSource* fontTextSource, + void** order, + OrbisFontTextParseResult* result); + +using OrbisFontTextParser = OrbisFontTextParseFunction; + +struct OrbisFontTextSource { + u64 systemUse0; + + const void* start; + const void* end; + const void* current; + OrbisFontTextParseFunction textParser; + void* textObject; + + OrbisFontHandle defaultFont; + + void* systemUse[5]; +}; + +static_assert(sizeof(OrbisFontStyleFrame) == 0x60, "OrbisFontStyleFrame size"); +static_assert(offsetof(OrbisFontStyleFrame, magic) == 0x00, "OrbisFontStyleFrame magic offset"); +static_assert(offsetof(OrbisFontStyleFrame, flags1) == 0x02, "OrbisFontStyleFrame flags1 offset"); +static_assert(offsetof(OrbisFontStyleFrame, hDpi) == 0x04, "OrbisFontStyleFrame hDpi offset"); +static_assert(offsetof(OrbisFontStyleFrame, vDpi) == 0x08, "OrbisFontStyleFrame vDpi offset"); +static_assert(offsetof(OrbisFontStyleFrame, scaleUnit) == 0x0C, + "OrbisFontStyleFrame scaleUnit offset"); +static_assert(offsetof(OrbisFontStyleFrame, scalePixelW) == 0x14, + "OrbisFontStyleFrame scalePixelW offset"); +static_assert(offsetof(OrbisFontStyleFrame, scalePixelH) == 0x18, + "OrbisFontStyleFrame scalePixelH offset"); +static_assert(offsetof(OrbisFontStyleFrame, cache_lock_word) == 0x34, + "OrbisFontStyleFrame cache_lock_word offset"); +static_assert(offsetof(OrbisFontStyleFrame, reserved_0x58) == 0x58, + "OrbisFontStyleFrame reserved_0x58 offset"); + +static_assert(sizeof(OrbisFontGlyphMetrics) == 0x20, "OrbisFontGlyphMetrics size"); +static_assert(sizeof(OrbisFontResultStage) == 0x18, "OrbisFontTransImage size"); +static_assert(sizeof(OrbisFontSurfaceImage) == 0x10, "OrbisFontSurfaceImage size"); +static_assert(sizeof(OrbisFontRenderOutput) == 0x40, "OrbisFontRenderOutput size"); + +static_assert(sizeof(OrbisFontTextSource) == 0x60, "OrbisFontTextSource ABI size"); +static_assert(offsetof(OrbisFontTextSource, systemUse0) == 0x00, + "OrbisFontTextSource systemUse0 offset"); +static_assert(offsetof(OrbisFontTextSource, start) == 0x08, "OrbisFontTextSource start offset"); +static_assert(offsetof(OrbisFontTextSource, end) == 0x10, "OrbisFontTextSource end offset"); +static_assert(offsetof(OrbisFontTextSource, current) == 0x18, "OrbisFontTextSource current offset"); +static_assert(offsetof(OrbisFontTextSource, textParser) == 0x20, + "OrbisFontTextSource textParser offset"); +static_assert(offsetof(OrbisFontTextSource, textObject) == 0x28, + "OrbisFontTextSource textObject offset"); +static_assert(offsetof(OrbisFontTextSource, defaultFont) == 0x30, + "OrbisFontTextSource defaultFont offset"); +static_assert(offsetof(OrbisFontTextSource, systemUse) == 0x38, + "OrbisFontTextSource systemUse offset"); + +struct OrbisFontCreateStringDetail { + u16 detailId; + u8 detailType; + u8 detections; + u32 ordersOption; + + OrbisFontHandle defaultFont; + + union { + struct { + void* function; + void* object; + } Callback; + } Orders; +}; + +static_assert(sizeof(OrbisFontCreateStringDetail) == 0x20, "OrbisFontCreateStringDetail ABI size"); + +struct OrbisFontStringOpaque; +using OrbisFontString = OrbisFontStringOpaque*; + +using OrbisFontCharacter = const OrbisFontTextCharacter*; +using OrbisFontRenderCharacter = const OrbisFontTextCharacter*; + +struct OrbisFontWriting { + void* systemUse[32]; +}; + +static_assert(sizeof(OrbisFontWriting) == 0x100, "OrbisFontWriting ABI size"); + +struct OrbisFontWritingProfile { + u32 characterCount : 8; + u32 invisibleGlyph : 1; + u32 reserved : 23; +}; + +static_assert(sizeof(OrbisFontWritingProfile) == sizeof(u32), "OrbisFontWritingProfile ABI size"); + +struct OrbisFontWritingStep { + float x; + float y; + float advanceX; + float advanceY; + + OrbisFontHandle font; + OrbisFontWritingProfile Profile; + u32 glyphCode; + + struct { + float x; + float y; + } Positioning; + + OrbisFontGlyphMetrics GlyphMetrics; +}; + +using OrbisFontWritingRenderStep = const OrbisFontWritingStep*; + +struct OrbisFontWritingLetterStep { + float x; + float y; + float advanceX; + float advanceY; + + struct { + u32 textsCount; + u32 textsIndex; + u32 glyphsCount; + u32 glyphsIndex; + u8 baseComponentsCount; + u8 baseComponentsIndex; + u8 baseFocusCount; + u8 baseFocusIndex; + u8 oppositeDirection; + u8 characterTextCount; + u8 baseTextCount; + u8 markTextCount; + u32 marksTextCount; + u32 marksTextNumber; + u32 reserved[3]; + s32 textLetterOffset; + } Components; +}; + +static_assert(sizeof(OrbisFontWritingLetterStep) == 0x40, "OrbisFontWritingLetterStep ABI size"); + +struct OrbisFontWritingExtent { + float top; + float bottom; + float left; + float right; +}; + +struct OrbisFontWritingMetrics { + float advanceX; + float advanceY; + OrbisFontWritingExtent Extent; +}; + +static_assert(sizeof(OrbisFontWritingMetrics) == 0x18, "OrbisFontWritingMetrics ABI size"); +struct OrbisFontHorizontalLayout { + float baselineOffset; + float lineAdvance; + float decorationExtent; +}; +struct OrbisFontVerticalLayout { + float baselineOffsetX; + float columnAdvance; + float decorationSpan; +}; + +#if INTPTR_MAX == INT64_MAX +static_assert(sizeof(OrbisFontOpenParams) == 32, "OrbisFontOpenParams size"); +static_assert(sizeof(OrbisFontGlyphMetrics) == 32, "OrbisFontGlyphMetrics size"); +static_assert(sizeof(OrbisFontKerning) == 16, "OrbisFontKerning size"); +static_assert(sizeof(OrbisFontRenderSurface) == 128, "OrbisFontRenderSurface ABI size"); +static_assert(sizeof(OrbisFontGlyphImageMetrics) == 24, "OrbisFontGlyphImageMetrics ABI size"); +static_assert(sizeof(OrbisFontRenderOutput) == 64, "OrbisFontRenderOutput ABI size"); +static_assert(sizeof(OrbisFontMem) == 64, "OrbisFontMem ABI size"); +#endif + +s32 PS4_SYSV_ABI sceFontAttachDeviceCacheBuffer(OrbisFontLib library, void* buffer, u32 size); +s32 PS4_SYSV_ABI sceFontBindRenderer(OrbisFontHandle fontHandle, OrbisFontRenderer renderer); +s32 PS4_SYSV_ABI sceFontCharacterGetBidiLevel(OrbisFontTextCharacter* textCharacter, + int* bidiLevel); +s32 PS4_SYSV_ABI sceFontCharacterGetSyllableStringState(); +s32 PS4_SYSV_ABI sceFontCharacterGetTextFontCode(OrbisFontTextCharacter* textCharacter, + OrbisFontHandle* pFontHandle, u32* textCode); +s32 PS4_SYSV_ABI sceFontCharacterGetTextOrder(OrbisFontTextCharacter* textCharacter, + void** pTextOrder); +u32 PS4_SYSV_ABI sceFontCharacterLooksFormatCharacters(OrbisFontTextCharacter* textCharacter); +u32 PS4_SYSV_ABI sceFontCharacterLooksWhiteSpace(OrbisFontTextCharacter* textCharacter); +OrbisFontTextCharacter* PS4_SYSV_ABI +sceFontCharacterRefersTextBack(OrbisFontTextCharacter* textCharacter); +OrbisFontTextCharacter* PS4_SYSV_ABI +sceFontCharacterRefersTextNext(OrbisFontTextCharacter* textCharacter); +s32 PS4_SYSV_ABI sceFontCharactersRefersTextCodes(); +s32 PS4_SYSV_ABI sceFontClearDeviceCache(OrbisFontLib library); +s32 PS4_SYSV_ABI sceFontCloseFont(); +s32 PS4_SYSV_ABI sceFontControl(); +s32 PS4_SYSV_ABI sceFontCreateGraphicsDevice(); +s32 PS4_SYSV_ABI sceFontCreateGraphicsService(); +s32 PS4_SYSV_ABI sceFontCreateGraphicsServiceWithEdition(); +s32 PS4_SYSV_ABI sceFontCreateLibrary(const OrbisFontMem* memory, + OrbisFontLibCreateParams create_params, + OrbisFontLib* pLibrary); +s32 PS4_SYSV_ABI sceFontCreateLibraryWithEdition(const OrbisFontMem* memory, + OrbisFontLibCreateParams create_params, + u64 edition, OrbisFontLib* pLibrary); +s32 PS4_SYSV_ABI sceFontCreateRenderer(const OrbisFontMem* memory, + OrbisFontRendererCreateParams create_params, + OrbisFontRenderer* pRenderer); +s32 PS4_SYSV_ABI sceFontCreateRendererWithEdition(const OrbisFontMem* memory, + OrbisFontRendererCreateParams create_params, + u64 edition, OrbisFontRenderer* pRenderer); +s32 PS4_SYSV_ABI sceFontCreateString(const OrbisFontMem* fontMemory, + OrbisFontTextSource* fontTextSource, + const OrbisFontCreateStringDetail* stringDetail, + OrbisFontString* pFontString); +s32 PS4_SYSV_ABI sceFontCreateWords(); +s32 PS4_SYSV_ABI sceFontCreateWritingLine(); +s32 PS4_SYSV_ABI sceFontDefineAttribute(); +s32 PS4_SYSV_ABI sceFontDeleteGlyph(const OrbisFontMem* memory, OrbisFontGlyph* glyph); +s32 PS4_SYSV_ABI sceFontDestroyGraphicsDevice(); +s32 PS4_SYSV_ABI sceFontDestroyGraphicsService(); +s32 PS4_SYSV_ABI sceFontDestroyLibrary(OrbisFontLib* pLibrary); +s32 PS4_SYSV_ABI sceFontDestroyRenderer(OrbisFontRenderer* pRenderer); +s32 PS4_SYSV_ABI sceFontDestroyString(OrbisFontString* pFontString); +s32 PS4_SYSV_ABI sceFontDestroyWords(); +s32 PS4_SYSV_ABI sceFontDestroyWritingLine(); +s32 PS4_SYSV_ABI sceFontDettachDeviceCacheBuffer(); +s32 PS4_SYSV_ABI sceFontGenerateCharGlyph(OrbisFontHandle glyph_handle, u32 codepoint, + const OrbisFontGenerateGlyphParams* gen_params, + OrbisFontGlyph* glyph_out); +s32 PS4_SYSV_ABI sceFontGetAttribute(); +s32 PS4_SYSV_ABI sceFontGetCharGlyphCode(); +s32 PS4_SYSV_ABI sceFontGetCharGlyphMetrics(OrbisFontHandle fontHandle, u32 code, + OrbisFontGlyphMetrics* metrics); +s32 PS4_SYSV_ABI sceFontGetEffectSlant(OrbisFontHandle fontHandle, float* slantRatio); +s32 PS4_SYSV_ABI sceFontGetEffectWeight(OrbisFontHandle fontHandle, float* weightXScale, + float* weightYScale, u32* mode); +s32 PS4_SYSV_ABI sceFontGetFontGlyphsCount(); +s32 PS4_SYSV_ABI sceFontGetFontGlyphsOutlineProfile(); +s32 PS4_SYSV_ABI sceFontGetFontMetrics(); +s32 PS4_SYSV_ABI sceFontGetFontResolution(); +s32 PS4_SYSV_ABI sceFontGetFontStyleInformation(); +s32 PS4_SYSV_ABI sceFontGetGlyphExpandBufferState(); +s32 PS4_SYSV_ABI sceFontGetHorizontalLayout(OrbisFontHandle fontHandle, + OrbisFontHorizontalLayout* layout); +s32 PS4_SYSV_ABI sceFontGetKerning(OrbisFontHandle fontHandle, u32 preCode, u32 code, + OrbisFontKerning* kerning); +s32 PS4_SYSV_ABI sceFontGetLibrary(OrbisFontHandle fontHandle, OrbisFontLib* pLibrary); +s32 PS4_SYSV_ABI sceFontGetPixelResolution(); +s32 PS4_SYSV_ABI sceFontGetRenderCharGlyphMetrics(OrbisFontHandle fontHandle, u32 codepoint, + OrbisFontGlyphMetrics* out_metrics); +s32 PS4_SYSV_ABI sceFontGetRenderEffectSlant(OrbisFontHandle fontHandle, float* slantRatio); +s32 PS4_SYSV_ABI sceFontGetRenderEffectWeight(OrbisFontHandle fontHandle, float* weightXScale, + float* weightYScale, u32* mode); +s32 PS4_SYSV_ABI sceFontGetRenderScaledKerning(); +s32 PS4_SYSV_ABI sceFontGetRenderScalePixel(OrbisFontHandle fontHandle, float* out_w, float* out_h); +s32 PS4_SYSV_ABI sceFontGetRenderScalePoint(OrbisFontHandle fontHandle, float* out_w, float* out_h); +s32 PS4_SYSV_ABI sceFontGetResolutionDpi(); +s32 PS4_SYSV_ABI sceFontGetScalePixel(OrbisFontHandle fontHandle, float* out_w, float* out_h); +s32 PS4_SYSV_ABI sceFontGetScalePoint(OrbisFontHandle fontHandle, float* out_w, float* out_h); +s32 PS4_SYSV_ABI sceFontGetScriptLanguage(); +s32 PS4_SYSV_ABI sceFontGetTypographicDesign(); +s32 PS4_SYSV_ABI sceFontGetVerticalLayout(OrbisFontHandle fontHandle, + OrbisFontVerticalLayout* layout); +s32 PS4_SYSV_ABI sceFontGlyphDefineAttribute(); +s32 PS4_SYSV_ABI sceFontGlyphGetAttribute(); +s32 PS4_SYSV_ABI sceFontGlyphGetGlyphForm(OrbisFontGlyph fontGlyph); +s32 PS4_SYSV_ABI sceFontGlyphGetMetricsForm(OrbisFontGlyph fontGlyph); +s32 PS4_SYSV_ABI sceFontGlyphGetScalePixel(OrbisFontGlyph fontGlyph, float* w, float* h); +const OrbisFontGlyphMetrics* PS4_SYSV_ABI sceFontGlyphRefersMetrics(OrbisFontGlyph fontGlyph); +const OrbisFontGlyphMetricsHorizontal* PS4_SYSV_ABI +sceFontGlyphRefersMetricsHorizontal(OrbisFontGlyph fontGlyph); +const OrbisFontGlyphMetricsHorizontalAdvance* PS4_SYSV_ABI +sceFontGlyphRefersMetricsHorizontalAdvance(OrbisFontGlyph fontGlyph); +const OrbisFontGlyphMetricsHorizontalX* PS4_SYSV_ABI +sceFontGlyphRefersMetricsHorizontalX(OrbisFontGlyph fontGlyph); +OrbisFontGlyphOutline* PS4_SYSV_ABI sceFontGlyphRefersOutline(OrbisFontGlyph glyph); +s32 PS4_SYSV_ABI sceFontGlyphRenderImage(); +s32 PS4_SYSV_ABI sceFontGlyphRenderImageHorizontal(); +s32 PS4_SYSV_ABI sceFontGlyphRenderImageVertical(); +s32 PS4_SYSV_ABI sceFontGraphicsBeginFrame(); +s32 PS4_SYSV_ABI sceFontGraphicsDrawingCancel(); +s32 PS4_SYSV_ABI sceFontGraphicsDrawingFinish(); +s32 PS4_SYSV_ABI sceFontGraphicsEndFrame(); +s32 PS4_SYSV_ABI sceFontGraphicsExchangeResource(); +s32 PS4_SYSV_ABI sceFontGraphicsFillMethodInit(); +s32 PS4_SYSV_ABI sceFontGraphicsFillPlotInit(); +s32 PS4_SYSV_ABI sceFontGraphicsFillPlotSetLayout(); +s32 PS4_SYSV_ABI sceFontGraphicsFillPlotSetMapping(); +s32 PS4_SYSV_ABI sceFontGraphicsFillRatesInit(); +s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetFillEffect(); +s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetLayout(); +s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetMapping(); +s32 PS4_SYSV_ABI sceFontGraphicsGetDeviceUsage(); +s32 PS4_SYSV_ABI sceFontGraphicsRegionInit(); +s32 PS4_SYSV_ABI sceFontGraphicsRegionInitCircular(); +s32 PS4_SYSV_ABI sceFontGraphicsRegionInitRoundish(); +s32 PS4_SYSV_ABI sceFontGraphicsRelease(); +s32 PS4_SYSV_ABI sceFontGraphicsRenderResource(); +s32 PS4_SYSV_ABI sceFontGraphicsSetFramePolicy(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupClipping(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupColorRates(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupFillMethod(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupFillRates(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupGlyphFill(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupGlyphFillPlot(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupHandleDefault(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupLocation(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupPositioning(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupRotation(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupScaling(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupShapeFill(); +s32 PS4_SYSV_ABI sceFontGraphicsSetupShapeFillPlot(); +s32 PS4_SYSV_ABI sceFontGraphicsStructureCanvas(); +s32 PS4_SYSV_ABI sceFontGraphicsStructureCanvasSequence(); +s32 PS4_SYSV_ABI sceFontGraphicsStructureDesign(); +s32 PS4_SYSV_ABI sceFontGraphicsStructureDesignResource(); +s32 PS4_SYSV_ABI sceFontGraphicsStructureSurfaceTexture(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdateClipping(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdateColorRates(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdateFillMethod(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdateFillRates(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdateGlyphFill(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdateGlyphFillPlot(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdateLocation(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdatePositioning(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdateRotation(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdateScaling(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdateShapeFill(); +s32 PS4_SYSV_ABI sceFontGraphicsUpdateShapeFillPlot(); +s32 PS4_SYSV_ABI sceFontMemoryInit(OrbisFontMem* mem_desc, void* region_addr, u32 region_size, + const OrbisFontMemInterface* iface, void* mspace_obj, + OrbisFontMemDestroyCb destroy_cb, void* destroy_ctx); +s32 PS4_SYSV_ABI sceFontMemoryTerm(OrbisFontMem* mem_desc); +s32 PS4_SYSV_ABI sceFontOpenFontFile(OrbisFontLib library, const char* guest_path, u32 open_mode, + const OrbisFontOpenParams* open_detail, + OrbisFontHandle* out_handle); +s32 PS4_SYSV_ABI sceFontOpenFontInstance(OrbisFontHandle fontHandle, OrbisFontHandle templateFont, + OrbisFontHandle* pFontHandle); +s32 PS4_SYSV_ABI sceFontOpenFontMemory(OrbisFontLib library, const void* fontAddress, u32 fontSize, + const OrbisFontOpenParams* open_params, + OrbisFontHandle* pFontHandle); +s32 PS4_SYSV_ABI sceFontOpenFontSet(OrbisFontLib library, u32 fontSetType, u32 openMode, + const OrbisFontOpenParams* open_params, + OrbisFontHandle* pFontHandle); +s32 PS4_SYSV_ABI sceFontRebindRenderer(OrbisFontHandle fontHandle); +s32 PS4_SYSV_ABI sceFontRenderCharGlyphImage(OrbisFontHandle fontHandle, u32 code, + OrbisFontRenderSurface* surf, float x, float y, + OrbisFontGlyphMetrics* metrics, + OrbisFontRenderOutput* result); +s32 PS4_SYSV_ABI sceFontRenderCharGlyphImageHorizontal(OrbisFontHandle fontHandle, u32 code, + OrbisFontRenderSurface* surf, float x, + float y, OrbisFontGlyphMetrics* metrics, + OrbisFontRenderOutput* result); +s32 PS4_SYSV_ABI sceFontRenderCharGlyphImageVertical(OrbisFontHandle fontHandle, u32 code, + OrbisFontRenderSurface* surf, float x, float y, + OrbisFontGlyphMetrics* metrics, + OrbisFontRenderOutput* result); +s32 PS4_SYSV_ABI sceFontRendererGetOutlineBufferSize(OrbisFontRenderer fontRenderer, u32* size); +s32 PS4_SYSV_ABI sceFontRendererResetOutlineBuffer(OrbisFontRenderer fontRenderer); +s32 PS4_SYSV_ABI sceFontRendererSetOutlineBufferPolicy(OrbisFontRenderer fontRenderer, + u64 bufferPolicy, u32 basalSize, + u32 limitSize); +void PS4_SYSV_ABI sceFontRenderSurfaceInit(OrbisFontRenderSurface* renderSurface, void* buffer, + int bufWidthByte, int pixelSizeByte, int widthPixel, + int heightPixel); +void PS4_SYSV_ABI sceFontRenderSurfaceSetScissor(OrbisFontRenderSurface* renderSurface, int x0, + int y0, int w, int h); +s32 PS4_SYSV_ABI sceFontRenderSurfaceSetStyleFrame(OrbisFontRenderSurface* renderSurface, + OrbisFontStyleFrame* styleFrame); +s32 PS4_SYSV_ABI sceFontSetEffectSlant(OrbisFontHandle fontHandle, float slantRatio); +s32 PS4_SYSV_ABI sceFontSetEffectWeight(OrbisFontHandle fontHandle, float weightXScale, + float weightYScale, u32 mode); +s32 PS4_SYSV_ABI sceFontSetFontsOpenMode(OrbisFontLib library, u32 openMode); +s32 PS4_SYSV_ABI sceFontSetResolutionDpi(OrbisFontHandle fontHandle, u32 h_dpi, u32 v_dpi); +s32 PS4_SYSV_ABI sceFontSetScalePixel(OrbisFontHandle fontHandle, float w, float h); +s32 PS4_SYSV_ABI sceFontSetScalePoint(OrbisFontHandle fontHandle, float w, float h); +s32 PS4_SYSV_ABI sceFontSetScriptLanguage(); +s32 PS4_SYSV_ABI sceFontSetTypographicDesign(); +s32 PS4_SYSV_ABI sceFontSetupRenderEffectSlant(OrbisFontHandle fontHandle, float slantRatio); +s32 PS4_SYSV_ABI sceFontSetupRenderEffectWeight(OrbisFontHandle fontHandle, float weightXScale, + float weightYScale, u32 mode); +s32 PS4_SYSV_ABI sceFontSetupRenderScalePixel(OrbisFontHandle fontHandle, float w, float h); +s32 PS4_SYSV_ABI sceFontSetupRenderScalePoint(OrbisFontHandle fontHandle, float w, float h); +u32 PS4_SYSV_ABI sceFontStringGetTerminateCode(OrbisFontString fontString); +void* PS4_SYSV_ABI sceFontStringGetTerminateOrder(OrbisFontString fontString); +s32 PS4_SYSV_ABI sceFontStringGetWritingForm(OrbisFontString fontString); +OrbisFontRenderCharacter PS4_SYSV_ABI sceFontStringRefersRenderCharacters( + OrbisFontString fontString, OrbisFontTextCharacter* startCharacter, + OrbisFontTextCharacter* lastCharacter, u32* characterCount); +OrbisFontTextCharacter* PS4_SYSV_ABI sceFontStringRefersTextCharacters(OrbisFontString fontString, + u32* characterCount); +s32 PS4_SYSV_ABI sceFontStyleFrameGetEffectSlant(OrbisFontStyleFrame* styleFrame, + float* slantRatio); +s32 PS4_SYSV_ABI sceFontStyleFrameGetEffectWeight(OrbisFontStyleFrame* fontStyleFrame, + float* weightXScale, float* weightYScale, + uint32_t* mode); +s32 PS4_SYSV_ABI sceFontStyleFrameGetResolutionDpi(const OrbisFontStyleFrame* styleFrame, + u32* h_dpi, u32* v_dpi); +s32 PS4_SYSV_ABI sceFontStyleFrameGetScalePixel(const OrbisFontStyleFrame* styleFrame, float* w, + float* h); +s32 PS4_SYSV_ABI sceFontStyleFrameGetScalePoint(const OrbisFontStyleFrame* styleFrame, float* w, + float* h); +s32 PS4_SYSV_ABI sceFontStyleFrameInit(OrbisFontStyleFrame* styleFrame); +s32 PS4_SYSV_ABI sceFontStyleFrameSetEffectSlant(OrbisFontStyleFrame* styleFrame, float slantRatio); +s32 PS4_SYSV_ABI sceFontStyleFrameSetEffectWeight(OrbisFontStyleFrame* styleFrame, + float weightXScale, float weightYScale, u32 mode); +s32 PS4_SYSV_ABI sceFontStyleFrameSetResolutionDpi(OrbisFontStyleFrame* styleFrame, u32 h_dpi, + u32 v_dpi); +s32 PS4_SYSV_ABI sceFontStyleFrameSetScalePixel(OrbisFontStyleFrame* styleFrame, float w, float h); +s32 PS4_SYSV_ABI sceFontStyleFrameSetScalePoint(OrbisFontStyleFrame* styleFrame, float w, float h); +s32 PS4_SYSV_ABI sceFontStyleFrameUnsetEffectSlant(OrbisFontStyleFrame* styleFrame); +s32 PS4_SYSV_ABI sceFontStyleFrameUnsetEffectWeight(OrbisFontStyleFrame* styleFrame); +s32 PS4_SYSV_ABI sceFontStyleFrameUnsetScale(OrbisFontStyleFrame* styleFrame); +s32 PS4_SYSV_ABI sceFontSupportExternalFonts(OrbisFontLib library, u32 fontMax, u32 formats); +s32 PS4_SYSV_ABI sceFontSupportGlyphs(); +s32 PS4_SYSV_ABI sceFontSupportSystemFonts(OrbisFontLib library); +s32 PS4_SYSV_ABI sceFontTextCodesStepBack(); +s32 PS4_SYSV_ABI sceFontTextCodesStepNext(); +s32 PS4_SYSV_ABI sceFontTextSourceInit(OrbisFontTextSource* fontTextSource, const void* textAddress, + u32 textSizeByte, OrbisFontTextParser textParser, + void* textObject); + +s32 PS4_SYSV_ABI sceFontTextSourceRewind(OrbisFontTextSource* fontTextSource); + +s32 PS4_SYSV_ABI sceFontTextSourceSetDefaultFont(OrbisFontTextSource* fontTextSource, + OrbisFontHandle defaultFont); + +s32 PS4_SYSV_ABI sceFontTextSourceSetWritingForm(OrbisFontTextSource* fontTextSource, + s32 writingForm); +s32 PS4_SYSV_ABI sceFontUnbindRenderer(OrbisFontHandle fontHandle); +s32 PS4_SYSV_ABI sceFontWordsFindWordCharacters(); +s32 PS4_SYSV_ABI sceFontWritingGetRenderMetrics(OrbisFontWriting* fontWriting, + OrbisFontWritingMetrics* writingMetrics); +s32 PS4_SYSV_ABI sceFontWritingInit(OrbisFontWriting* fontWriting, OrbisFontString fontString, + OrbisFontRenderCharacter fontCharacter); +s32 PS4_SYSV_ABI sceFontWritingLineClear(); +s32 PS4_SYSV_ABI sceFontWritingLineGetOrderingSpace(); +s32 PS4_SYSV_ABI sceFontWritingLineGetRenderMetrics(); +s32 PS4_SYSV_ABI sceFontWritingLineRefersRenderStep(); +s32 PS4_SYSV_ABI sceFontWritingLineWritesOrder(); +OrbisFontWritingRenderStep PS4_SYSV_ABI +sceFontWritingRefersRenderStep(OrbisFontWriting* fontWriting); +OrbisFontTextCharacter* PS4_SYSV_ABI sceFontWritingRefersRenderStepCharacter( + OrbisFontWriting* fontWriting, OrbisFontWritingLetterStep* pLetterStep); +s32 PS4_SYSV_ABI sceFontWritingSetMaskInvisible(OrbisFontWriting* fontWriting, s32 mask); +s32 PS4_SYSV_ABI Func_00F4D778F1C88CB3(); +s32 PS4_SYSV_ABI Func_03C650025FBB0DE7(); +s32 PS4_SYSV_ABI Func_07EAB8A163B27E1A(); +s32 PS4_SYSV_ABI Func_09408E88E4F97CE3(); +s32 PS4_SYSV_ABI Func_09F92905ED82A814(); +s32 PS4_SYSV_ABI Func_0D142CEE1AB21ABE(); +s32 PS4_SYSV_ABI Func_14BD2E9E119C16F2(); +s32 PS4_SYSV_ABI Func_1AC53C9EDEAE8D75(); +s32 PS4_SYSV_ABI Func_1D401185D5E24C3D(); +s32 PS4_SYSV_ABI Func_1E83CD20C2CC996F(); +s32 PS4_SYSV_ABI Func_314B1F765B9FE78A(); +s32 PS4_SYSV_ABI Func_350E6725FEDE29E1(); +s32 PS4_SYSV_ABI Func_3DB773F0A604BF39(); +s32 PS4_SYSV_ABI Func_4FF49DD21E311B1C(); +s32 PS4_SYSV_ABI Func_526287664A493981(); +s32 PS4_SYSV_ABI Func_55CA718DBC84A6E9(); +s32 PS4_SYSV_ABI Func_563FC5F0706A8B4D(); +s32 PS4_SYSV_ABI Func_569E2ECD34290F45(); +s32 PS4_SYSV_ABI Func_5A04775B6BE47685(); +s32 PS4_SYSV_ABI Func_5FD93BCAB6F79750(); +s32 PS4_SYSV_ABI Func_62B5398F864BD3B4(); +s32 PS4_SYSV_ABI Func_6F9010294D822367(); +s32 PS4_SYSV_ABI Func_7757E947423A7A67(); +s32 PS4_SYSV_ABI Func_7E06BA52077F54FA(); +s32 PS4_SYSV_ABI Func_93B36DEA021311D6(); +s32 PS4_SYSV_ABI Func_94B0891E7111598A(); +s32 PS4_SYSV_ABI Func_9785C9128C2FE7CD(); +s32 PS4_SYSV_ABI Func_97DFBC9B65FBC0E1(); +s32 PS4_SYSV_ABI Func_ACD9717405D7D3CA(); +s32 PS4_SYSV_ABI Func_B19A8AEC3FD4F16F(); +s32 PS4_SYSV_ABI Func_C10F488AD7CF103D(); +s32 PS4_SYSV_ABI Func_D0C8B5FF4A6826C7(); +s32 PS4_SYSV_ABI Func_E48D3CD01C342A33(); +s32 PS4_SYSV_ABI Func_EAC96B2186B71E14(); +s32 PS4_SYSV_ABI Func_FE4788A96EF46256(); +s32 PS4_SYSV_ABI Func_FE7E5AE95D3058F5(); + +void RegisterlibSceFont(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::Font diff --git a/src/core/libraries/font/font_internal.cpp b/src/core/libraries/font/font_internal.cpp index 3dffefb4a..9489038f9 100644 --- a/src/core/libraries/font/font_internal.cpp +++ b/src/core/libraries/font/font_internal.cpp @@ -58,7 +58,6 @@ std::string FormatNamedParams(std::initializer_list params) { } bool HasSfntTables(const std::vector& bytes); -FontState* TryGetState(Libraries::Font::OrbisFontHandle h); std::string ReportSystemFaceRequest(FontState& st, Libraries::Font::OrbisFontHandle handle, bool& attached_out); @@ -83,34 +82,6 @@ static constexpr FT_Int32 kFtLoadFlagsBase = static constexpr FT_Int32 kFtLoadFlagsRender = static_cast(kFtLoadFlagsBase | FT_LOAD_RENDER); -static s32 RoundFixedMul16x16ToS32(long fixed_16_16, s32 value) { - const long long prod = static_cast(fixed_16_16) * static_cast(value); - const long long sign_adj = - (static_cast(~static_cast(value)) >> 63) * -0x10000LL; - const long long base = sign_adj + prod; - long long tmp = base - 0x8000LL; - if (tmp < 0) { - tmp = base + 0x7FFFLL; - } - return static_cast(static_cast(tmp) >> 16); -} - -static int FloorIntCompat(float v) { - int i = static_cast(std::trunc(v)); - if (static_cast(i) > v) { - --i; - } - return i; -} - -static int CeilIntCompat(float v) { - int i = static_cast(std::trunc(v)); - if (static_cast(i) < v) { - ++i; - } - return i; -} - } // namespace FT_Face CreateFreeTypeFaceFromBytes(const unsigned char* data, std::size_t size, @@ -1398,25 +1369,27 @@ s32 RenderCodepointToSurface(FontState& st, Libraries::Font::OrbisFontHandle han const float bottom_f = top_f - metrics->height; const int left_i = FloorIntCompat(left_f); - const int top_i = FloorIntCompat(top_f); + const int top_i = CeilIntCompat(top_f); const int right_i = CeilIntCompat(right_f); - const int bottom_i = CeilIntCompat(bottom_f); + const int bottom_i = FloorIntCompat(bottom_f); const float adv_f = x + metrics->Horizontal.advance; - const float adv_snapped = static_cast(FloorIntCompat(adv_f)) - x; + const int adv_i = CeilIntCompat(adv_f); + const float adv_snapped = static_cast(adv_i) - x; result->ImageMetrics.bearingX = static_cast(left_i) - x; result->ImageMetrics.bearingY = static_cast(top_i) - y; result->ImageMetrics.advance = adv_snapped; - int stride_i = right_i + 1; - const float adjust = static_cast(right_i) - right_f; - const int tmp_i = FloorIntCompat(adv_f + adjust); - const int adv_trunc_i = static_cast(std::trunc(adv_f)); - if (adv_trunc_i == 0) { - stride_i = tmp_i; - } - if (stride_i < tmp_i) { - stride_i = tmp_i; + int stride_i = adv_i; + if (adv_f != static_cast(adv_i)) { + const int tmp_i = static_cast((static_cast(right_i) - right_f) + adv_f); + stride_i = right_i + 1; + if (adv_f <= right_f) { + stride_i = tmp_i; + } + if (stride_i < tmp_i) { + stride_i = tmp_i; + } } result->ImageMetrics.stride = static_cast(stride_i) - x; result->ImageMetrics.width = static_cast(std::max(0, right_i - left_i)); @@ -1629,25 +1602,27 @@ s32 RenderCodepointToSurfaceWithScale(FontState& st, Libraries::Font::OrbisFontH const float bottom_f = top_f - m->height; const int left_i = FloorIntCompat(left_f); - const int top_i = FloorIntCompat(top_f); + const int top_i = CeilIntCompat(top_f); const int right_i = CeilIntCompat(right_f); - const int bottom_i = CeilIntCompat(bottom_f); + const int bottom_i = FloorIntCompat(bottom_f); const float adv_f = x + m->Horizontal.advance; - const float adv_snapped = static_cast(FloorIntCompat(adv_f)) - x; + const int adv_i = CeilIntCompat(adv_f); + const float adv_snapped = static_cast(adv_i) - x; result->ImageMetrics.bearingX = static_cast(left_i) - x; result->ImageMetrics.bearingY = static_cast(top_i) - y; result->ImageMetrics.advance = adv_snapped; - int stride_i = right_i + 1; - const float adjust = static_cast(right_i) - right_f; - const int tmp_i = FloorIntCompat(adv_f + adjust); - const int adv_trunc_i = static_cast(std::trunc(adv_f)); - if (adv_trunc_i == 0) { - stride_i = tmp_i; - } - if (stride_i < tmp_i) { - stride_i = tmp_i; + int stride_i = adv_i; + if (adv_f != static_cast(adv_i)) { + const int tmp_i = static_cast((static_cast(right_i) - right_f) + adv_f); + stride_i = right_i + 1; + if (adv_f <= right_f) { + stride_i = tmp_i; + } + if (stride_i < tmp_i) { + stride_i = tmp_i; + } } result->ImageMetrics.stride = static_cast(stride_i) - x; result->ImageMetrics.width = static_cast(std::max(0, right_i - left_i)); diff --git a/src/core/libraries/font/font_internal.h b/src/core/libraries/font/font_internal.h index f278a3a80..cca526a4a 100644 --- a/src/core/libraries/font/font_internal.h +++ b/src/core/libraries/font/font_internal.h @@ -197,6 +197,34 @@ inline void log_debug(std::string_view message) { LOG_DEBUG(Lib_Font, "{}", message); } +inline s32 RoundFixedMul16x16ToS32(long fixed_16_16, s32 value) { + const long long prod = static_cast(fixed_16_16) * static_cast(value); + const long long sign_adj = + (static_cast(~static_cast(value)) >> 63) * -0x10000LL; + const long long base = sign_adj + prod; + long long tmp = base - 0x8000LL; + if (tmp < 0) { + tmp = base + 0x7FFFLL; + } + return static_cast(static_cast(tmp) >> 16); +} + +inline int FloorIntCompat(float v) { + int i = static_cast(std::trunc(v)); + if (static_cast(i) > v) { + --i; + } + return i; +} + +inline int CeilIntCompat(float v) { + int i = static_cast(std::trunc(v)); + if (static_cast(i) < v) { + ++i; + } + return i; +} + #define formatParams(...) formatParamsImpl(#__VA_ARGS__ __VA_OPT__(, ) __VA_ARGS__) struct FontSetSelector; diff --git a/src/core/libraries/font/fontft_internal.cpp b/src/core/libraries/font/fontft_internal.cpp index 794d0611e..e6c94f3a8 100644 --- a/src/core/libraries/font/fontft_internal.cpp +++ b/src/core/libraries/font/fontft_internal.cpp @@ -225,34 +225,6 @@ static float MaxSsCompat(float a, float b) { return a; } -static s32 RoundFixedMul16x16ToS32(long fixed_16_16, s32 value) { - const long long prod = static_cast(fixed_16_16) * static_cast(value); - const long long sign_adj = - (static_cast(~static_cast(value)) >> 63) * -0x10000LL; - const long long base = sign_adj + prod; - long long tmp = base - 0x8000LL; - if (tmp < 0) { - tmp = base + 0x7FFFLL; - } - return static_cast(static_cast(tmp) >> 16); -} - -static int FloorIntCompat(float v) { - int i = static_cast(std::trunc(v)); - if (static_cast(i) > v) { - --i; - } - return i; -} - -static int CeilIntCompat(float v) { - int i = static_cast(std::trunc(v)); - if (static_cast(i) < v) { - ++i; - } - return i; -} - float FixedMulUnitsToF26Dot6(long fixed_16_16, u16 units_per_em) { constexpr float kOneOver64Local = 1.0f / 64.0f; const long prod = static_cast(static_cast(fixed_16_16) * @@ -1944,25 +1916,27 @@ static s32 RenderGlyphIndexToSurface(FontObj& font_obj, u32 glyph_index, const float bottom_f = top_f - metrics->height; const int left_i = FloorIntCompat(left_f); - const int top_i = FloorIntCompat(top_f); + const int top_i = CeilIntCompat(top_f); const int right_i = CeilIntCompat(right_f); const int bottom_i = FloorIntCompat(bottom_f); const float adv_f = x + metrics->Horizontal.advance; - const float adv_snapped = static_cast(FloorIntCompat(adv_f)) - x; + const int adv_i = CeilIntCompat(adv_f); + const float adv_snapped = static_cast(adv_i) - x; result->ImageMetrics.bearingX = static_cast(left_i) - x; result->ImageMetrics.bearingY = static_cast(top_i) - y; result->ImageMetrics.advance = adv_snapped; - int stride_i = right_i + 1; - const float adjust = static_cast(right_i) - right_f; - const int tmp_i = FloorIntCompat(adv_f + adjust); - const int adv_trunc_i = static_cast(std::trunc(adv_f)); - if (adv_trunc_i == 0) { - stride_i = tmp_i; - } - if (stride_i < tmp_i) { - stride_i = tmp_i; + int stride_i = adv_i; + if (adv_f != static_cast(adv_i)) { + const int tmp_i = static_cast((static_cast(right_i) - right_f) + adv_f); + stride_i = right_i + 1; + if (adv_f <= right_f) { + stride_i = tmp_i; + } + if (stride_i < tmp_i) { + stride_i = tmp_i; + } } result->ImageMetrics.stride = static_cast(stride_i) - x; result->ImageMetrics.width = static_cast(std::max(0, right_i - left_i)); @@ -2583,90 +2557,6 @@ static float to_f26dot6_s64(s64 value) { return static_cast(value) * kOneOver64; } -static std::optional ResolveKnownSysFontAlias( - const std::filesystem::path& sysfonts_dir, std::string_view ps4_filename) { - const auto resolve_existing = - [&](std::string_view filename) -> std::optional { - const std::filesystem::path file_path{std::string(filename)}; - std::error_code ec; - { - const auto candidate = sysfonts_dir / file_path; - if (std::filesystem::exists(candidate, ec)) { - return candidate; - } - } - { - const auto candidate = sysfonts_dir / "font" / file_path; - if (std::filesystem::exists(candidate, ec)) { - return candidate; - } - } - { - const auto candidate = sysfonts_dir / "font2" / file_path; - if (std::filesystem::exists(candidate, ec)) { - return candidate; - } - } - return std::nullopt; - }; - - static constexpr std::array, 41> kAliases = {{ - {"SST-EU-ROMAN-L.OTF", "SST-Light.otf"}, - {"SST-EU-ROMAN.OTF", "SST-Roman.otf"}, - {"SST-EU-ROMAN-M.OTF", "SST-Medium.otf"}, - {"SST-EU-ROMAN-R.OTF", "SST-Roman.otf"}, - {"SST-EU-ROMAN-I.OTF", "SST-Italic.otf"}, - {"SST-EU-ROMAN-B.OTF", "SST-Bold.otf"}, - {"SST-EU-ROMAN-BI.OTF", "SST-BoldItalic.otf"}, - {"SST-ITALIC-L.OTF", "SST-LightItalic.otf"}, - {"SST-ITALIC-R.OTF", "SST-Italic.otf"}, - {"SST-ITALIC-M.OTF", "SST-MediumItalic.otf"}, - {"SST-ITALIC-B.OTF", "SST-BoldItalic.otf"}, - {"SST-TYPEWRITER-R.OTF", "SSTTypewriter-Roman.otf"}, - {"SST-TYPEWRITER-B.OTF", "SSTTypewriter-Bd.otf"}, - {"SST-JPPRO-R.OTF", "SSTJpPro-Regular.otf"}, - {"SST-JPPRO-B.OTF", "SSTJpPro-Bold.otf"}, - {"SST-CNGB-HEI-R.TTF", "DFHEI5-SONY.ttf"}, - {"SST-ARIB-STD-B24-R.TTF", "SSTAribStdB24-Regular.ttf"}, - {"SST-ARABIC-R.OTF", "SSTArabic-Roman.otf"}, - {"SST-ARABIC-L.OTF", "SSTArabic-Light.otf"}, - {"SST-ARABIC-M.OTF", "SSTArabic-Medium.otf"}, - {"SST-ARABIC-B.OTF", "SSTArabic-Bold.otf"}, - {"SCE-EXT-HANGUL-L.OTF", "SCEPS4Yoongd-Light.otf"}, - {"SCE-EXT-HANGUL-R.OTF", "SCEPS4Yoongd-Medium.otf"}, - {"SCE-EXT-HANGUL-B.OTF", "SCEPS4Yoongd-Bold.otf"}, - {"SSTCC-SERIF-MONO.OTF", "e046323ms.ttf"}, - {"SSTCC-SERIF.OTF", "e046323ts.ttf"}, - {"SSTCC-SANSSERIF-MONO.OTF", "n023055ms.ttf"}, - {"SSTCC-SANSSERIF.OTF", "n023055ts.ttf"}, - {"SSTCC-CUSUAL.OTF", "d013013ds.ttf"}, - {"SSTCC-CURSIVE.OTF", "k006004ds.ttf"}, - {"SSTCC-SMALLCAPITAL.OTF", "c041056ts.ttf"}, - {"SCE-JP-CATTLEYA-L.OTF", "SCE-RDC-R-JPN.otf"}, - {"SCE-JP-CATTLEYA-B.OTF", "SCE-RDC-B-JPN.otf"}, - {"SST-THAI-L.OTF", "SSTThai-Light.otf"}, - {"SST-THAI-R.OTF", "SSTThai-Roman.otf"}, - {"SST-THAI-M.OTF", "SSTThai-Medium.otf"}, - {"SST-THAI-B.OTF", "SSTThai-Bold.otf"}, - {"SST-VIETNAMESE-L.OTF", "SSTVietnamese-Light.otf"}, - {"SST-VIETNAMESE-R.OTF", "SSTVietnamese-Roman.otf"}, - {"SST-VIETNAMESE-M.OTF", "SSTVietnamese-Medium.otf"}, - {"SST-VIETNAMESE-B.OTF", "SSTVietnamese-Bold.otf"}, - }}; - - for (const auto& [from, to] : kAliases) { - if (ps4_filename == from) { - return resolve_existing(to); - } - if (ps4_filename == to) { - if (auto reverse = resolve_existing(from)) { - return reverse; - } - } - } - return std::nullopt; -} - static constexpr u32 MakeTag(char a, char b, char c, char d) { return (static_cast(static_cast(a)) << 24) | (static_cast(static_cast(b)) << 16) | @@ -3137,7 +3027,8 @@ s32 PS4_SYSV_ABI LibraryOpenFontMemoryStub(void* library, u32 mode, const void* const std::filesystem::path file_path{ps4_name}; candidates.emplace_back((sysfonts_dir / "font" / file_path).string()); candidates.emplace_back((sysfonts_dir / "font2" / file_path).string()); - if (const auto alias = ResolveKnownSysFontAlias(sysfonts_dir, ps4_name)) { + if (const auto alias = + Libraries::Font::Internal::ResolveKnownSysFontAlias(sysfonts_dir, ps4_name)) { candidates.emplace_back(alias->string()); } } diff --git a/src/shader_recompiler/frontend/translate/vector_alu.cpp b/src/shader_recompiler/frontend/translate/vector_alu.cpp index 436bd65c6..243b2f0dd 100644 --- a/src/shader_recompiler/frontend/translate/vector_alu.cpp +++ b/src/shader_recompiler/frontend/translate/vector_alu.cpp @@ -960,7 +960,7 @@ void Translator::V_CVT_FLR_I32_F32(const GcnInst& inst) { void Translator::V_CVT_OFF_F32_I4(const GcnInst& inst) { const IR::U32 src0{GetSrc(inst.src[0])}; - ASSERT(src0.IsImmediate()); + ASSERT_MSG(src0.IsImmediate(), "V_CVT_OFF_F32_I4 expects an immediate source operand"); static constexpr std::array IntToFloat = { 0.0f, 0.0625f, 0.1250f, 0.1875f, 0.2500f, 0.3125f, 0.3750f, 0.4375f, -0.5000f, -0.4375f, -0.3750f, -0.3125f, -0.2500f, -0.1875f, -0.1250f, -0.0625f}; @@ -1252,45 +1252,57 @@ void Translator::V_CMP_U32(ConditionOp op, bool is_signed, bool set_exec, const } void Translator::V_CMP_U64(ConditionOp op, bool is_signed, bool set_exec, const GcnInst& inst) { - const bool is_zero = inst.src[1].field == OperandField::ConstZero; - const bool is_neg_one = inst.src[1].field == OperandField::SignedConstIntNeg; - ASSERT(is_zero || is_neg_one); - if (is_neg_one) { - ASSERT_MSG(-s32(inst.src[1].code) + SignedConstIntNegMin - 1 == -1, - "SignedConstIntNeg must be -1"); - } + // AMD VOPC semantics: + // V_CMP_* : D/VCC[threadId] = compare(S0, S1) + // V_CMPX_* : EXEC[threadId] = D/VCC[threadId] = compare(S0, S1) + // + // Do not use subgroup reductions here. Result must stay per-lane. - const IR::U1 src0 = [&] { - switch (inst.src[0].field) { - case OperandField::ScalarGPR: - return ir.GetThreadBitScalarReg(IR::ScalarReg(inst.src[0].code)); - case OperandField::VccLo: - return ir.GetVcc(); - default: - UNREACHABLE_MSG("src0 = {}", u32(inst.src[0].field)); + const auto set_result = [&](IR::U1 result) { + if (set_exec) { + ir.SetExec(result); } - }(); - const IR::U1 result = [&] { + SetDst1(inst.dst[1], result); + }; + + const auto make_compare = [&](IR::U64 src0, IR::U64 src1) -> IR::U1 { switch (op) { + case ConditionOp::F: + return ir.Imm1(false); + case ConditionOp::TRU: + return ir.Imm1(true); case ConditionOp::EQ: - return is_zero ? ir.LogicalNot(src0) : src0; + return ir.IEqual(src0, src1); case ConditionOp::LG: // NE - return is_zero ? src0 : ir.LogicalNot(src0); + return ir.INotEqual(src0, src1); + case ConditionOp::LT: + return ir.ILessThan(src0, src1, is_signed); + case ConditionOp::LE: + return ir.ILessThanEqual(src0, src1, is_signed); case ConditionOp::GT: - ASSERT(is_zero); - return ir.GroupAny(ir.GetThreadBitScalarReg(IR::ScalarReg(inst.src[0].code))); + return ir.IGreaterThan(src0, src1, is_signed); + case ConditionOp::GE: + return ir.IGreaterThanEqual(src0, src1, is_signed); default: - UNREACHABLE_MSG("Unsupported V_CMP_U64 condition operation: {}", u32(op)); + UNREACHABLE_MSG("Unsupported V_CMP_{}64 condition: {}", is_signed ? "I" : "U", u32(op)); } - }(); + }; - if (is_signed) { - UNREACHABLE_MSG("V_CMP_U64 with signed integers is not supported"); + // Cheap constants first. These are always spec-correct. + if (op == ConditionOp::F) { + set_result(ir.Imm1(false)); + return; } - if (set_exec) { - UNREACHABLE_MSG("Exec setting for V_CMP_U64 is not supported"); + + if (op == ConditionOp::TRU) { + set_result(ir.Imm1(true)); + return; } - SetDst1(inst.dst[1], result); + + const IR::U64 src0 = GetSrc64(inst.src[0]); + const IR::U64 src1 = GetSrc64(inst.src[1]); + + set_result(make_compare(src0, src1)); } void Translator::V_CMP_CLASS_F32(const GcnInst& inst) { diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 681437762..c69eda24a 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -239,9 +239,13 @@ bool Instance::CreateDevice() { }; // Required - ASSERT(add_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)); - ASSERT(add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME)); - ASSERT(add_extension(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)); + ASSERT_MSG(add_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME), + "Required Vulkan extension unavailable: {}", VK_KHR_SWAPCHAIN_EXTENSION_NAME); + ASSERT_MSG(add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME), + "Required Vulkan extension unavailable: {}", VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); + ASSERT_MSG(add_extension(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME), + "Required Vulkan extension unavailable: {}", + VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); // Optional maintenance_8 = add_extension(VK_KHR_MAINTENANCE_8_EXTENSION_NAME); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 46eda1728..90365c307 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -310,7 +310,6 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_, .needs_clip_distance_emulation = instance.GetDriverID() == vk::DriverId::eNvidiaProprietary, .supports_shader_stencil_export = instance_.IsShaderStencilExportSupported(), }; - WarmUp(); auto [cache_result, cache] = instance.GetDevice().createPipelineCacheUnique({}); @@ -589,7 +588,9 @@ bool PipelineCache::RefreshGraphicsStages() { u32 vertex_binding = 0; for (const auto& attrib : fetch_shader->attributes) { const auto& buffer = attrib.GetSharp(*vs_info); - ASSERT(vertex_binding < MaxVertexBufferCount); + ASSERT_MSG(vertex_binding < MaxVertexBufferCount, + "Vertex attribute binding count exceeded limit: {} >= {}", vertex_binding, + MaxVertexBufferCount); key.vertex_buffer_formats[vertex_binding++] = Vulkan::LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()); }