Consolidate internal font/ft internals

Move internal font structs, aliases, and helpers out of font.cpp into shared internal headers/sources.
Promote shared ABI-facing types (including FontHandleOpaqueNative and layout/system-use structs) into font internal headers and remove function-local duplicates.
Move FreeType driver/renderer table construction into fontft_internal.cpp and wire fontft.cpp to internal getters.
Ensure internal.cpp implementations are declared in headers; deduplicate declarations and clean includes.
This commit is contained in:
w1naenator 2026-02-14 02:16:31 +02:00
parent 09fa10fd4d
commit bdb52525a5
6 changed files with 699 additions and 1353 deletions

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@
#include FT_TRUETYPE_TABLES_H
#include "core/libraries/font/fontft_internal.h"
#include "core/libraries/kernel/kernel.h"
namespace Libraries::Font::Internal {
@ -44,6 +45,15 @@ std::uint8_t g_sysfonts_ctx_stub{};
std::uint8_t g_external_fonts_ctx_stub{};
u32 g_device_cache_stub{};
std::string FormatNamedParams(std::initializer_list<NamedParam> params) {
fmt::memory_buffer buffer;
fmt::format_to(std::back_inserter(buffer), "params:\n");
for (const auto& p : params) {
fmt::format_to(std::back_inserter(buffer), "{}: {}\n", p.name, p.value);
}
return fmt::to_string(buffer);
}
bool HasSfntTables(const std::vector<unsigned char>& bytes);
FontState* TryGetState(Libraries::Font::OrbisFontHandle h);
std::string ReportSystemFaceRequest(FontState& st, Libraries::Font::OrbisFontHandle handle,
@ -104,7 +114,7 @@ void DestroyFreeTypeFace(FT_Face& face) {
namespace {
static std::optional<std::filesystem::path> ResolveKnownSysFontAlias(
static std::optional<std::filesystem::path> ResolveKnownSysFontAliasImpl(
const std::filesystem::path& sysfonts_dir, std::string_view ps4_filename) {
const auto resolve_existing =
[&](std::string_view filename) -> std::optional<std::filesystem::path> {
@ -217,6 +227,11 @@ static std::shared_ptr<std::vector<unsigned char>> GetCachedFontBytes(
} // namespace
std::optional<std::filesystem::path> ResolveKnownSysFontAlias(
const std::filesystem::path& sysfonts_dir, std::string_view ps4_filename) {
return ResolveKnownSysFontAliasImpl(sysfonts_dir, ps4_filename);
}
FontState::~FontState() {
DestroyFreeTypeFace(ext_ft_face);
for (auto& fb : system_fallback_faces) {
@ -362,18 +377,7 @@ bool BuildTrueOutline(GeneratedGlyph& gg) {
}
if (const std::uint8_t* range_rec =
FindSysFontRangeRecord(mapped_font_id, resolved_code)) {
struct SysFontRangeRecordLocal {
/*0x00*/ u32 start;
/*0x04*/ u32 end;
/*0x08*/ s16 shift_x;
/*0x0A*/ s16 shift_y;
/*0x0C*/ float scale_mul;
/*0x10*/ u32 reserved_0x10;
/*0x14*/ u32 reserved_0x14;
/*0x18*/ u32 reserved_0x18;
};
static_assert(sizeof(SysFontRangeRecordLocal) == 0x1C);
SysFontRangeRecordLocal rec{};
SysFontRangeRecord rec{};
std::memcpy(&rec, range_rec, sizeof(rec));
shift_x_units = static_cast<s32>(rec.shift_x);
shift_y_units += static_cast<s32>(rec.shift_y);
@ -518,14 +522,102 @@ LibraryState& GetLibState(Libraries::Font::OrbisFontLib lib) {
return g_library_state[lib];
}
void RemoveLibState(Libraries::Font::OrbisFontLib lib) {
std::scoped_lock lock(g_state_mutex);
if (auto it = g_library_state.find(lib); it != g_library_state.end()) {
if (it->second.owned_device_cache) {
delete[] static_cast<std::uint8_t*>(it->second.owned_device_cache);
bool AcquireLibraryLock(FontLibOpaque* lib, u32& out_prev_lock_word) {
if (!lib) {
return false;
}
for (;;) {
const u32 lock_word = lib->lock_word;
if (lib->magic != 0x0F01) {
return false;
}
if (static_cast<s32>(lock_word) < 0) {
Libraries::Kernel::sceKernelUsleep(0x1e);
continue;
}
std::atomic_ref<u32> ref(lib->lock_word);
u32 expected = lock_word;
if (ref.compare_exchange_weak(expected, lock_word | 0x80000000u,
std::memory_order_acq_rel)) {
out_prev_lock_word = lock_word;
return true;
}
Libraries::Kernel::sceKernelUsleep(0x1e);
}
}
void ReleaseLibraryLock(FontLibOpaque* lib, u32 prev_lock_word) {
if (!lib) {
return;
}
lib->lock_word = prev_lock_word & 0x7fffffff;
}
void RemoveLibState(Libraries::Font::OrbisFontLib lib) {
LibraryState state{};
{
std::scoped_lock lock(g_state_mutex);
auto it = g_library_state.find(lib);
if (it == g_library_state.end()) {
return;
}
state = std::move(it->second);
g_library_state.erase(it);
}
const auto free_fn = state.free_fn;
const auto alloc_ctx = state.alloc_ctx;
auto free_owned = [&](void* p) {
if (!p) {
return;
}
if (free_fn) {
const auto free_fn_guest =
reinterpret_cast<void(PS4_SYSV_ABI*)(void* object, void* p)>(free_fn);
Core::ExecuteGuest(free_fn_guest, alloc_ctx, p);
return;
}
std::free(p);
};
free_owned(state.owned_device_cache);
free_owned(state.owned_external_fonts_ctx);
free_owned(state.owned_sysfonts_ctx);
free_owned(state.owned_mspace);
}
void LogFontOpenError(s32 rc) {
switch (rc) {
case ORBIS_FONT_ERROR_INVALID_LIBRARY:
LOG_ERROR(Lib_Font, "INVALID_LIBRARY");
break;
case ORBIS_FONT_ERROR_INVALID_PARAMETER:
LOG_ERROR(Lib_Font, "INVALID_PARAMETER");
break;
case ORBIS_FONT_ERROR_ALLOCATION_FAILED:
LOG_ERROR(Lib_Font, "ALLOCATION_FAILED");
break;
case ORBIS_FONT_ERROR_FS_OPEN_FAILED:
LOG_ERROR(Lib_Font, "FS_OPEN_FAILED");
break;
case ORBIS_FONT_ERROR_NO_SUPPORT_FUNCTION:
LOG_ERROR(Lib_Font, "NO_SUPPORT_FUNCTION");
break;
case ORBIS_FONT_ERROR_NO_SUPPORT_FORMAT:
LOG_ERROR(Lib_Font, "NO_SUPPORT_FORMAT");
break;
case ORBIS_FONT_ERROR_NO_SUPPORT_FONTSET:
LOG_ERROR(Lib_Font, "NO_SUPPORT_FONTSET");
break;
case ORBIS_FONT_ERROR_FONT_OPEN_MAX:
LOG_ERROR(Lib_Font, "FONT_OPEN_MAX");
break;
default:
LOG_ERROR(Lib_Font, "FAILED");
break;
}
}
void LogExternalFormatSupport(u32 formats_mask) {
@ -1759,4 +1851,68 @@ std::string ReportSystemFaceRequest(FontState& st, Libraries::Font::OrbisFontHan
}
return {};
}
void LogCachedStyleOnce(Libraries::Font::OrbisFontHandle handle,
const Libraries::Font::FontHandleOpaqueNative& font) {
static std::mutex s_mutex;
static std::unordered_set<Libraries::Font::OrbisFontHandle> s_logged;
std::scoped_lock lock(s_mutex);
if (s_logged.find(handle) != s_logged.end()) {
return;
}
s_logged.insert(handle);
LOG_DEBUG(Lib_Font,
"BindRenderer: cached_style snapshot: hDpi={} vDpi={} scaleUnit={} baseScale={} "
"scalePixelW={} scalePixelH={} effectWeightX={} effectWeightY={} slantRatio={}",
font.cached_style.hDpi, font.cached_style.vDpi, font.cached_style.scaleUnit,
font.cached_style.baseScale, font.cached_style.scalePixelW,
font.cached_style.scalePixelH, font.cached_style.effectWeightX,
font.cached_style.effectWeightY, font.cached_style.slantRatio);
}
void LogRenderResultSample(Libraries::Font::OrbisFontHandle handle, u32 code,
const Libraries::Font::OrbisFontGlyphMetrics& metrics,
const Libraries::Font::OrbisFontRenderOutput& result) {
static std::mutex s_mutex;
static std::unordered_map<Libraries::Font::OrbisFontHandle, int> s_counts;
std::scoped_lock lock(s_mutex);
int& count = s_counts[handle];
if (count >= 5) {
return;
}
++count;
LOG_DEBUG(Lib_Font,
"RenderSample: handle={} code=U+{:04X} update=[{},{} {}x{}] img=[bx={} by={} adv={} "
"stride={} w={} h={}] metrics=[w={} h={} hbx={} hby={} hadv={}]",
static_cast<const void*>(handle), code, 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, metrics.width, metrics.height,
metrics.Horizontal.bearingX, metrics.Horizontal.bearingY, metrics.Horizontal.advance);
}
u8 CachedStyleCacheFlags(const Libraries::Font::OrbisFontStyleFrame& cached_style) {
return static_cast<u8>(cached_style.cache_flags_and_direction & 0xFFu);
}
void CachedStyleSetCacheFlags(Libraries::Font::OrbisFontStyleFrame& cached_style, u8 flags) {
cached_style.cache_flags_and_direction =
(cached_style.cache_flags_and_direction & 0xFFFFFF00u) | static_cast<u32>(flags);
}
void CachedStyleSetDirectionWord(Libraries::Font::OrbisFontStyleFrame& cached_style, u16 word) {
cached_style.cache_flags_and_direction =
(cached_style.cache_flags_and_direction & 0x0000FFFFu) | (static_cast<u32>(word) << 16);
}
float CachedStyleGetScalar(const Libraries::Font::OrbisFontStyleFrame& cached_style) {
float value = 0.0f;
std::memcpy(&value, &cached_style.cached_scalar_bits, sizeof(value));
return value;
}
void CachedStyleSetScalar(Libraries::Font::OrbisFontStyleFrame& cached_style, float value) {
std::memcpy(&cached_style.cached_scalar_bits, &value, sizeof(value));
}
} // namespace Libraries::Font::Internal

View File

@ -14,6 +14,7 @@
#include <cstring>
#include <filesystem>
#include <fstream>
#include <initializer_list>
#include <iterator>
#include <limits>
#include <memory>
@ -43,6 +44,10 @@
#include "core/libraries/libs.h"
#include "font_error.h"
namespace Libraries::Font {
struct FontHandleOpaqueNative;
}
namespace Libraries::Font::Internal {
struct FontLibOpaque;
@ -69,6 +74,18 @@ std::string DescribeValue(const T& value) {
}
}
struct NamedParam {
std::string_view name;
std::string value;
};
template <typename T>
NamedParam Param(std::string_view name, const T& value) {
return NamedParam{name, DescribeValue(value)};
}
std::string FormatNamedParams(std::initializer_list<NamedParam> params);
struct ParamRecord {
std::string name;
std::string initial;
@ -263,6 +280,27 @@ struct FontState {
~FontState();
};
using FontAllocFn = void*(PS4_SYSV_ABI*)(void* object, u32 size);
using FontFreeFn = void(PS4_SYSV_ABI*)(void* object, void* p);
struct FtExternalFaceObj {
u32 refcount;
u32 reserved04;
u32 reserved08;
u32 sub_font_index;
u64 reserved10;
FtExternalFaceObj* next;
u64 reserved20;
u64 reserved28;
FT_Face face;
const u8* font_data;
u32 font_size;
u32 sfnt_base;
};
static_assert(offsetof(FtExternalFaceObj, sub_font_index) == 0x0C);
static_assert(offsetof(FtExternalFaceObj, next) == 0x18);
static_assert(offsetof(FtExternalFaceObj, face) == 0x30);
struct LibraryState {
bool support_system = false;
bool support_external = false;
@ -271,6 +309,15 @@ struct LibraryState {
const Libraries::Font::OrbisFontMem* backing_memory = nullptr;
Libraries::Font::OrbisFontLibCreateParams create_params = nullptr;
u64 edition = 0;
void* alloc_ctx = nullptr;
FontAllocFn alloc_fn = nullptr;
FontFreeFn free_fn = nullptr;
void* owned_mspace = nullptr;
u32 owned_mspace_size = 0;
void* owned_sysfonts_ctx = nullptr;
u32 owned_sysfonts_ctx_size = 0;
void* owned_external_fonts_ctx = nullptr;
u32 owned_external_fonts_ctx_size = 0;
FontLibOpaque* native = nullptr;
void* owned_device_cache = nullptr;
u32 owned_device_cache_size = 0;
@ -601,6 +648,71 @@ static_assert(offsetof(FontLibOpaque, external_fonts_ctx) == 0xA8,
static_assert(offsetof(FontLibOpaque, device_cache_buf) == 0xB0,
"FontLibOpaque device_cache_buf offset");
#pragma pack(push, 1)
struct FontLibReserved1Main {
/*0x00*/ u32 reserved_0x00;
/*0x04*/ u32 mem_kind;
/*0x08*/ u32 region_size;
/*0x0C*/ void* region_base;
};
#pragma pack(pop)
static_assert(sizeof(FontLibReserved1Main) == sizeof(((FontLibOpaque*)nullptr)->reserved1),
"FontLibReserved1Main size");
static_assert(offsetof(FontLibReserved1Main, mem_kind) == 0x04,
"FontLibReserved1Main mem_kind offset");
static_assert(offsetof(FontLibReserved1Main, region_size) == 0x08,
"FontLibReserved1Main region_size offset");
static_assert(offsetof(FontLibReserved1Main, region_base) == 0x0C,
"FontLibReserved1Main region_base offset");
struct FontLibReserved2Iface {
/*0x00*/ u8 reserved_00[0x20];
/*0x20*/ std::uintptr_t alloc_fn;
/*0x28*/ std::uintptr_t dealloc_fn;
/*0x30*/ std::uintptr_t realloc_fn;
/*0x38*/ std::uintptr_t calloc_fn;
/*0x40*/ u8 reserved_40[0x10];
};
static_assert(sizeof(FontLibReserved2Iface) == sizeof(((FontLibOpaque*)nullptr)->reserved2),
"FontLibReserved2Iface size");
static_assert(offsetof(FontLibReserved2Iface, alloc_fn) == 0x20,
"FontLibReserved2Iface alloc_fn offset");
static_assert(offsetof(FontLibReserved2Iface, dealloc_fn) == 0x28,
"FontLibReserved2Iface dealloc_fn offset");
static_assert(offsetof(FontLibReserved2Iface, realloc_fn) == 0x30,
"FontLibReserved2Iface realloc_fn offset");
static_assert(offsetof(FontLibReserved2Iface, calloc_fn) == 0x38,
"FontLibReserved2Iface calloc_fn offset");
struct FontLibTail {
/*0x00*/ u8 reserved_00[0x04];
/*0x04*/ u32 workspace_size;
/*0x08*/ void* workspace;
/*0x10*/ u8 reserved_10[0x10];
/*0x20*/ void* list_head_ptr;
/*0x28*/ Libraries::Font::OrbisFontHandle list_head;
/*0x30*/ u8 reserved_30[0x18];
};
static_assert(offsetof(FontLibTail, workspace_size) == 0x04, "FontLibTail workspace_size offset");
static_assert(offsetof(FontLibTail, workspace) == 0x08, "FontLibTail workspace offset");
static_assert(offsetof(FontLibTail, list_head_ptr) == 0x20, "FontLibTail list_head_ptr offset");
static_assert(offsetof(FontLibTail, list_head) == 0x28, "FontLibTail list_head offset");
static_assert(sizeof(FontLibTail) == 0x48, "FontLibTail size");
#pragma pack(push, 1)
struct FontLibReserved1SysfontTail {
/*0x00*/ u32 reserved_0x00;
/*0x04*/ void* sysfont_desc_ptr;
/*0x0C*/ u64 sysfont_flags;
};
#pragma pack(pop)
static_assert(sizeof(FontLibReserved1SysfontTail) == sizeof(((FontLibOpaque*)nullptr)->reserved1),
"FontLibReserved1SysfontTail size");
static_assert(offsetof(FontLibReserved1SysfontTail, sysfont_desc_ptr) == 0x04,
"FontLibReserved1SysfontTail sysfont_desc_ptr offset");
static_assert(offsetof(FontLibReserved1SysfontTail, sysfont_flags) == 0x0C,
"FontLibReserved1SysfontTail sysfont_flags offset");
struct RendererOpaque {
/*0x00*/ u16 magic;
/*0x02*/ u16 reserved02;
@ -705,9 +817,14 @@ FontState* TryGetState(Libraries::Font::OrbisFontHandle h);
void RemoveState(Libraries::Font::OrbisFontHandle h);
LibraryState& GetLibState(Libraries::Font::OrbisFontLib lib);
void RemoveLibState(Libraries::Font::OrbisFontLib lib);
bool AcquireLibraryLock(FontLibOpaque* lib, u32& out_prev_lock_word);
void ReleaseLibraryLock(FontLibOpaque* lib, u32 prev_lock_word);
FT_Face CreateFreeTypeFaceFromBytes(const unsigned char* data, std::size_t size, u32 subfont_index);
void DestroyFreeTypeFace(FT_Face& face);
void LogFontOpenError(s32 rc);
void LogExternalFormatSupport(u32 formats_mask);
std::optional<std::filesystem::path> ResolveKnownSysFontAlias(
const std::filesystem::path& sysfonts_dir, std::string_view ps4_filename);
void LogFontOpenParams(const Libraries::Font::OrbisFontOpenParams* params);
std::filesystem::path ResolveGuestPath(const char* guest_path);
bool LoadGuestFileBytes(const std::filesystem::path& host_path,
@ -761,5 +878,15 @@ GeneratedGlyph* TryGetGeneratedGlyph(Libraries::Font::OrbisFontGlyph glyph);
void PopulateGlyphMetricVariants(GeneratedGlyph& gg);
void BuildBoundingOutline(GeneratedGlyph& gg);
bool BuildTrueOutline(GeneratedGlyph& gg);
void LogCachedStyleOnce(Libraries::Font::OrbisFontHandle handle,
const Libraries::Font::FontHandleOpaqueNative& font);
void LogRenderResultSample(Libraries::Font::OrbisFontHandle handle, u32 code,
const Libraries::Font::OrbisFontGlyphMetrics& metrics,
const Libraries::Font::OrbisFontRenderOutput& result);
u8 CachedStyleCacheFlags(const Libraries::Font::OrbisFontStyleFrame& cached_style);
void CachedStyleSetCacheFlags(Libraries::Font::OrbisFontStyleFrame& cached_style, u8 flags);
void CachedStyleSetDirectionWord(Libraries::Font::OrbisFontStyleFrame& cached_style, u16 word);
float CachedStyleGetScalar(const Libraries::Font::OrbisFontStyleFrame& cached_style);
void CachedStyleSetScalar(Libraries::Font::OrbisFontStyleFrame& cached_style, float value);
} // namespace Libraries::Font::Internal

View File

@ -1,10 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <cstdint>
#include <mutex>
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/font/font.h"
@ -15,67 +11,6 @@
namespace Libraries::FontFt {
namespace {
static std::once_flag g_driver_table_once;
alignas(Libraries::Font::Internal::SysDriver) static Libraries::Font::Internal::SysDriver
g_driver_table{};
static const OrbisFontLibrarySelection* GetDriverTable() {
std::call_once(g_driver_table_once, [] {
auto* selection = reinterpret_cast<OrbisFontLibrarySelection*>(&g_driver_table);
selection->magic = 0;
selection->reserved = 0;
selection->reserved_ptr1 = nullptr;
auto* driver = &g_driver_table;
driver->pixel_resolution = &Libraries::FontFt::Internal::LibraryGetPixelResolutionStub;
driver->init = &Libraries::FontFt::Internal::LibraryInitStub;
driver->term = &Libraries::FontFt::Internal::LibraryTermStub;
driver->support_formats = &Libraries::FontFt::Internal::LibrarySupportStub;
driver->open = &Libraries::FontFt::Internal::LibraryOpenFontMemoryStub;
driver->close = &Libraries::FontFt::Internal::LibraryCloseFontObjStub;
driver->scale = &Libraries::FontFt::Internal::LibraryGetFaceScaleStub;
driver->metric = &Libraries::FontFt::Internal::LibraryGetFaceMetricStub;
driver->glyph_index = &Libraries::FontFt::Internal::LibraryGetGlyphIndexStub;
driver->set_char_with_dpi = &Libraries::FontFt::Internal::LibrarySetCharSizeWithDpiStub;
driver->set_char_default_dpi =
&Libraries::FontFt::Internal::LibrarySetCharSizeDefaultDpiStub;
driver->compute_layout = &Libraries::FontFt::Internal::LibraryComputeLayoutBlockStub;
driver->compute_layout_alt = &Libraries::FontFt::Internal::LibraryComputeLayoutAltBlockStub;
driver->load_glyph_cached = &Libraries::FontFt::Internal::LibraryLoadGlyphCachedStub;
driver->get_glyph_metrics = &Libraries::FontFt::Internal::LibraryGetGlyphMetricsStub;
driver->apply_glyph_adjust = &Libraries::FontFt::Internal::LibraryApplyGlyphAdjustStub;
driver->configure_glyph = &Libraries::FontFt::Internal::LibraryConfigureGlyphStub;
});
return reinterpret_cast<const OrbisFontLibrarySelection*>(&g_driver_table);
}
static std::once_flag g_renderer_table_once;
alignas(OrbisFontRendererSelection) static OrbisFontRendererSelection g_renderer_table{};
static const OrbisFontRendererSelection* GetRendererSelectionTable() {
std::call_once(g_renderer_table_once, [] {
g_renderer_table.magic = 0;
g_renderer_table.size =
static_cast<u32>(sizeof(Libraries::Font::Internal::RendererFtOpaque));
g_renderer_table.create_fn =
reinterpret_cast<std::uintptr_t>(&Libraries::FontFt::Internal::FtRendererCreate);
g_renderer_table.destroy_fn =
reinterpret_cast<std::uintptr_t>(&Libraries::FontFt::Internal::FtRendererDestroy);
g_renderer_table.query_fn =
reinterpret_cast<std::uintptr_t>(&Libraries::FontFt::Internal::FtRendererQuery);
});
return &g_renderer_table;
}
} // namespace
s32 PS4_SYSV_ABI sceFontFtInitAliases() {
LOG_ERROR(Lib_FontFt, "(STUBBED) called");
return ORBIS_OK;
@ -175,7 +110,7 @@ const OrbisFontLibrarySelection* PS4_SYSV_ABI sceFontSelectLibraryFt(int value)
LOG_INFO(Lib_FontFt, "called");
LOG_DEBUG(Lib_FontFt, "params:\nvalue: {}\n", value);
if (value == 0) {
return GetDriverTable();
return Libraries::FontFt::Internal::GetDriverTable();
}
return nullptr;
}
@ -184,7 +119,7 @@ const OrbisFontRendererSelection* PS4_SYSV_ABI sceFontSelectRendererFt(int value
LOG_INFO(Lib_FontFt, "called");
LOG_DEBUG(Lib_FontFt, "params:\nvalue: {}\n", value);
if (value == 0) {
return GetRendererSelectionTable();
return Libraries::FontFt::Internal::GetRendererSelectionTable();
}
return nullptr;
}

View File

@ -44,11 +44,6 @@ using Libraries::Font::OrbisFontRenderSurface;
using Libraries::Font::OrbisFontStyleFrame;
namespace {
struct GetCharGlyphMetricsFailLogState {
u32 count = 0;
bool suppression_logged = false;
};
static thread_local GetCharGlyphMetricsFailLogState g_get_char_metrics_fail;
static void LogGetCharGlyphMetricsFailOnce(std::string_view stage, s32 rc, FT_Error ft_err,
@ -325,22 +320,6 @@ static std::uint64_t ResolveGposTagForCode(u32 codepoint) {
return 0;
}
#pragma pack(push, 1)
struct SysFontRangeRecord {
/*0x00*/ u32 start;
/*0x04*/ u32 end;
/*0x08*/ s16 shift_x;
/*0x0A*/ s16 shift_y;
/*0x0C*/ float scale_mul;
/*0x10*/ u32 reserved_0x10;
/*0x14*/ u32 reserved_0x14;
/*0x18*/ u32 reserved_0x18;
};
#pragma pack(pop)
static_assert(sizeof(SysFontRangeRecord) == 0x1C);
static_assert(offsetof(SysFontRangeRecord, shift_x) == 0x08);
static_assert(offsetof(SysFontRangeRecord, scale_mul) == 0x0C);
static float SysFontScaleFactor(u32 font_id) {
(void)font_id;
return 1.0f;
@ -652,11 +631,6 @@ s32 ComputeHorizontalLayoutBlocks(OrbisFontHandle fontHandle, const void* style_
float effect_for_baseline = 0.0f;
float effect_for_delta = 0.0f;
struct F32x2 {
float lo = 0.0f;
float hi = 0.0f;
};
F32x2 acc_u13_i8{};
F32x2 acc_x_bounds{};
@ -1516,19 +1490,11 @@ static StyleFrameScaleState ResolveStyleFrameScaleFromCachedStyle(const OrbisFon
namespace {
struct RenderSurfaceSystemUse {
Libraries::Font::OrbisFontStyleFrame* styleframe = nullptr;
float catchedScale = 0.0f;
std::uint8_t padding[88 - sizeof(Libraries::Font::OrbisFontStyleFrame*) - sizeof(float)]{};
};
static_assert(sizeof(RenderSurfaceSystemUse) ==
sizeof(((Libraries::Font::OrbisFontRenderSurface*)nullptr)->reserved_q),
"RenderSurfaceSystemUse layout must match OrbisFontRenderSurface::reserved_q");
inline RenderSurfaceSystemUse* GetSurfaceSystemUse(Libraries::Font::OrbisFontRenderSurface* surf) {
static inline RenderSurfaceSystemUse* GetSurfaceSystemUse(
Libraries::Font::OrbisFontRenderSurface* surf) {
return surf ? reinterpret_cast<RenderSurfaceSystemUse*>(surf->reserved_q) : nullptr;
}
inline const RenderSurfaceSystemUse* GetSurfaceSystemUse(
static inline const RenderSurfaceSystemUse* GetSurfaceSystemUse(
const Libraries::Font::OrbisFontRenderSurface* surf) {
return surf ? reinterpret_cast<const RenderSurfaceSystemUse*>(surf->reserved_q) : nullptr;
}
@ -1798,9 +1764,9 @@ static s32 RenderGlyphIndexToSurface(FontObj& font_obj, u32 glyph_index,
return ORBIS_OK;
}
StyleFrameScaleState ResolveMergedStyleFrameScale(const Libraries::Font::OrbisFontStyleFrame* base,
const Libraries::Font::OrbisFontStyleFrame* over,
const FontState& st) {
static StyleFrameScaleState ResolveMergedStyleFrameScale(
const Libraries::Font::OrbisFontStyleFrame* base,
const Libraries::Font::OrbisFontStyleFrame* over, const FontState& st) {
StyleFrameScaleState resolved = ResolveStyleFrameScale(base, st);
if (!ValidateStyleFramePtr(over)) {
return resolved;
@ -2364,16 +2330,17 @@ namespace Libraries::FontFt::Internal {
namespace {
static std::once_flag g_driver_table_once;
alignas(Libraries::Font::Internal::SysDriver) static Libraries::Font::Internal::SysDriver
g_driver_table{};
static std::once_flag g_renderer_table_once;
alignas(Libraries::FontFt::OrbisFontRendererSelection) static Libraries::FontFt::
OrbisFontRendererSelection g_renderer_table{};
using Libraries::Font::Internal::FontLibOpaque;
using Libraries::Font::Internal::FontObj;
struct FtLibraryCtx {
void* alloc_ctx;
void** alloc_vtbl;
FT_Memory ft_memory;
FT_Library ft_lib;
};
static constexpr float kOneOver64 = 1.0f / 64.0f;
static std::optional<std::filesystem::path> ResolveKnownSysFontAlias(
@ -2466,49 +2433,6 @@ static constexpr u32 MakeTag(char a, char b, char c, char d) {
(static_cast<u32>(static_cast<u8>(c)) << 8) | static_cast<u32>(static_cast<u8>(d));
}
struct BeU16 {
u8 b[2];
constexpr u16 value() const {
return static_cast<u16>((static_cast<u16>(b[0]) << 8) | static_cast<u16>(b[1]));
}
};
static_assert(sizeof(BeU16) == 2, "BeU16 size");
struct BeU32 {
u8 b[4];
constexpr u32 value() const {
return (static_cast<u32>(b[0]) << 24) | (static_cast<u32>(b[1]) << 16) |
(static_cast<u32>(b[2]) << 8) | static_cast<u32>(b[3]);
}
};
static_assert(sizeof(BeU32) == 4, "BeU32 size");
struct TtcHeader {
BeU32 tag;
BeU32 version;
BeU32 num_fonts;
};
static_assert(sizeof(TtcHeader) == 0x0C, "TtcHeader size");
struct SfntOffsetTable {
BeU32 version;
BeU16 num_tables;
BeU16 search_range;
BeU16 entry_selector;
BeU16 range_shift;
};
static_assert(sizeof(SfntOffsetTable) == 0x0C, "SfntOffsetTable size");
struct SfntTableRecord {
BeU32 tag;
BeU32 checksum;
BeU32 offset;
BeU32 length;
};
static_assert(sizeof(SfntTableRecord) == 0x10, "SfntTableRecord size");
static bool ResolveSfntBaseOffset(const u8* data, std::size_t size, u32 subFontIndex,
u32& out_base) {
out_base = 0;
@ -2602,13 +2526,6 @@ static bool ReadUnitsPerEm(const u8* data, std::size_t size, u32 base, u16& out_
return out_units != 0;
}
struct FontObjSidecar {
const u8* font_data = nullptr;
u32 font_size = 0;
u32 sfnt_base = 0;
void* owned_data = nullptr;
};
static std::mutex g_font_obj_sidecars_mutex;
static std::unordered_map<const FontObj*, FontObjSidecar> g_font_obj_sidecars;
@ -2642,8 +2559,7 @@ static void* FtAlloc(FT_Memory memory, long size) {
if (!ctx || !ctx->alloc_vtbl) {
return nullptr;
}
using AllocFn = void*(PS4_SYSV_ABI*)(void* object, u32 size);
const auto alloc_fn = reinterpret_cast<AllocFn>(ctx->alloc_vtbl[0]);
const auto alloc_fn = reinterpret_cast<GuestAllocFn>(ctx->alloc_vtbl[0]);
return alloc_fn ? Core::ExecuteGuest(alloc_fn, ctx->alloc_ctx, static_cast<u32>(size))
: nullptr;
}
@ -2656,8 +2572,7 @@ static void FtFree(FT_Memory memory, void* block) {
if (!ctx || !ctx->alloc_vtbl) {
return;
}
using FreeFn = void(PS4_SYSV_ABI*)(void* object, void* p);
const auto free_fn = reinterpret_cast<FreeFn>(ctx->alloc_vtbl[1]);
const auto free_fn = reinterpret_cast<GuestFreeFn>(ctx->alloc_vtbl[1]);
if (free_fn) {
Core::ExecuteGuest(free_fn, ctx->alloc_ctx, block);
}
@ -2671,8 +2586,7 @@ static void* FtRealloc(FT_Memory memory, long cur_size, long new_size, void* blo
if (!ctx || !ctx->alloc_vtbl) {
return nullptr;
}
using ReallocFn = void*(PS4_SYSV_ABI*)(void* object, void* p, u32 size);
const auto realloc_fn = reinterpret_cast<ReallocFn>(ctx->alloc_vtbl[2]);
const auto realloc_fn = reinterpret_cast<GuestReallocFn>(ctx->alloc_vtbl[2]);
if (realloc_fn) {
return Core::ExecuteGuest(realloc_fn, ctx->alloc_ctx, block, static_cast<u32>(new_size));
}
@ -2694,6 +2608,53 @@ static void* FtRealloc(FT_Memory memory, long cur_size, long new_size, void* blo
} // namespace
const Libraries::FontFt::OrbisFontLibrarySelection* GetDriverTable() {
std::call_once(g_driver_table_once, [] {
auto* selection =
reinterpret_cast<Libraries::FontFt::OrbisFontLibrarySelection*>(&g_driver_table);
selection->magic = 0;
selection->reserved = 0;
selection->reserved_ptr1 = nullptr;
auto* driver = &g_driver_table;
driver->pixel_resolution = &Libraries::FontFt::Internal::LibraryGetPixelResolutionStub;
driver->init = &Libraries::FontFt::Internal::LibraryInitStub;
driver->term = &Libraries::FontFt::Internal::LibraryTermStub;
driver->support_formats = &Libraries::FontFt::Internal::LibrarySupportStub;
driver->open = &Libraries::FontFt::Internal::LibraryOpenFontMemoryStub;
driver->close = &Libraries::FontFt::Internal::LibraryCloseFontObjStub;
driver->scale = &Libraries::FontFt::Internal::LibraryGetFaceScaleStub;
driver->metric = &Libraries::FontFt::Internal::LibraryGetFaceMetricStub;
driver->glyph_index = &Libraries::FontFt::Internal::LibraryGetGlyphIndexStub;
driver->set_char_with_dpi = &Libraries::FontFt::Internal::LibrarySetCharSizeWithDpiStub;
driver->set_char_default_dpi =
&Libraries::FontFt::Internal::LibrarySetCharSizeDefaultDpiStub;
driver->compute_layout = &Libraries::FontFt::Internal::LibraryComputeLayoutBlockStub;
driver->compute_layout_alt = &Libraries::FontFt::Internal::LibraryComputeLayoutAltBlockStub;
driver->load_glyph_cached = &Libraries::FontFt::Internal::LibraryLoadGlyphCachedStub;
driver->get_glyph_metrics = &Libraries::FontFt::Internal::LibraryGetGlyphMetricsStub;
driver->apply_glyph_adjust = &Libraries::FontFt::Internal::LibraryApplyGlyphAdjustStub;
driver->configure_glyph = &Libraries::FontFt::Internal::LibraryConfigureGlyphStub;
});
return reinterpret_cast<const Libraries::FontFt::OrbisFontLibrarySelection*>(&g_driver_table);
}
const Libraries::FontFt::OrbisFontRendererSelection* GetRendererSelectionTable() {
std::call_once(g_renderer_table_once, [] {
g_renderer_table.magic = 0;
g_renderer_table.size =
static_cast<u32>(sizeof(Libraries::Font::Internal::RendererFtOpaque));
g_renderer_table.create_fn =
reinterpret_cast<std::uintptr_t>(&Libraries::FontFt::Internal::FtRendererCreate);
g_renderer_table.destroy_fn =
reinterpret_cast<std::uintptr_t>(&Libraries::FontFt::Internal::FtRendererDestroy);
g_renderer_table.query_fn =
reinterpret_cast<std::uintptr_t>(&Libraries::FontFt::Internal::FtRendererQuery);
});
return &g_renderer_table;
}
u32 PS4_SYSV_ABI LibraryGetPixelResolutionStub() {
return 0x40;
}
@ -2708,10 +2669,8 @@ s32 PS4_SYSV_ABI LibraryInitStub(const void* memory, void* library) {
return ORBIS_FONT_ERROR_INVALID_MEMORY;
}
using AllocFn = void*(PS4_SYSV_ABI*)(void* object, u32 size);
using FreeFn = void(PS4_SYSV_ABI*)(void* object, void* p);
const auto alloc_fn = reinterpret_cast<AllocFn>(mem->iface->alloc);
const auto free_fn = reinterpret_cast<FreeFn>(mem->iface->dealloc);
const auto alloc_fn = reinterpret_cast<GuestAllocFn>(mem->iface->alloc);
const auto free_fn = reinterpret_cast<GuestFreeFn>(mem->iface->dealloc);
if (!alloc_fn || !free_fn) {
return ORBIS_FONT_ERROR_INVALID_MEMORY;
}
@ -2800,8 +2759,7 @@ s32 PS4_SYSV_ABI LibraryTermStub(void* library) {
auto* lib = static_cast<FontLibOpaque*>(library);
auto* alloc_ctx = lib->alloc_ctx;
auto* alloc_vtbl = lib->alloc_vtbl;
using FreeFn = void(PS4_SYSV_ABI*)(void* object, void* p);
const auto free_fn = alloc_vtbl ? reinterpret_cast<FreeFn>(alloc_vtbl[1]) : nullptr;
const auto free_fn = alloc_vtbl ? reinterpret_cast<GuestFreeFn>(alloc_vtbl[1]) : nullptr;
if (!free_fn) {
return ORBIS_FONT_ERROR_INVALID_PARAMETER;
}
@ -2881,10 +2839,8 @@ s32 PS4_SYSV_ABI LibraryOpenFontMemoryStub(void* library, u32 mode, const void*
auto* lib = static_cast<FontLibOpaque*>(library);
void* alloc_ctx = lib->alloc_ctx;
void** alloc_vtbl = lib->alloc_vtbl;
using AllocFn = void*(PS4_SYSV_ABI*)(void* object, u32 size);
using FreeFn = void(PS4_SYSV_ABI*)(void* object, void* p);
const auto alloc_fn = alloc_vtbl ? reinterpret_cast<AllocFn>(alloc_vtbl[0]) : nullptr;
const auto free_fn = alloc_vtbl ? reinterpret_cast<FreeFn>(alloc_vtbl[1]) : nullptr;
const auto alloc_fn = alloc_vtbl ? reinterpret_cast<GuestAllocFn>(alloc_vtbl[0]) : nullptr;
const auto free_fn = alloc_vtbl ? reinterpret_cast<GuestFreeFn>(alloc_vtbl[1]) : nullptr;
if (!alloc_fn || !free_fn) {
return ORBIS_FONT_ERROR_INVALID_PARAMETER;
}
@ -3042,9 +2998,8 @@ s32 PS4_SYSV_ABI LibraryCloseFontObjStub(void* fontObj, u32 /*flags*/) {
ctx = static_cast<FtLibraryCtx*>(face->memory->user);
}
using FreeFn = void(PS4_SYSV_ABI*)(void* object, void* p);
const auto free_fn =
(ctx && ctx->alloc_vtbl) ? reinterpret_cast<FreeFn>(ctx->alloc_vtbl[1]) : nullptr;
(ctx && ctx->alloc_vtbl) ? reinterpret_cast<GuestFreeFn>(ctx->alloc_vtbl[1]) : nullptr;
void* owned_data = nullptr;
if (const auto sidecar = TakeFontObjSidecar(obj)) {
owned_data = sidecar->owned_data;
@ -3261,42 +3216,6 @@ s32 PS4_SYSV_ABI LibraryComputeLayoutBlockStub(void* fontObj, const void* style_
half_effect_w_px += round_mul_16_16(static_cast<s64>(y_max_px), shear_16_16);
}
struct LayoutOutIo {
u8 (*words)[16];
struct F32Field {
u8* base;
std::size_t offset;
F32Field& operator=(float v) {
std::memcpy(base + offset, &v, sizeof(v));
return *this;
}
};
struct Fields {
F32Field line_advance;
F32Field baseline;
F32Field x_bound_0;
F32Field x_bound_1;
F32Field max_advance_width;
F32Field hhea_caret_rise_adjust;
F32Field effect_height;
F32Field half_effect_width;
F32Field left_adjust;
};
Fields fields() const {
return {
.line_advance = {words[0], 0x00},
.baseline = {words[0], 0x04},
.x_bound_0 = {words[0], 0x08},
.x_bound_1 = {words[0], 0x0C},
.max_advance_width = {words[1], 0x00},
.hhea_caret_rise_adjust = {words[1], 0x04},
.effect_height = {words[1], 0x08},
.half_effect_width = {words[1], 0x0C},
.left_adjust = {words[2], 0x00},
};
}
};
auto out = LayoutOutIo{out_words}.fields();
out.effect_height = out_effect_h;
out.left_adjust = static_cast<float>(left_adjust_px) * kOneOver64;
@ -3446,40 +3365,6 @@ s32 PS4_SYSV_ABI LibraryComputeLayoutAltBlockStub(void* fontObj, const void* sty
const s32 lane2 = round_fixed_mul(y_ascender, x_scale);
const s32 lane3 = round_fixed_mul(y_descender, x_scale);
struct LayoutAltOutIo {
u8 (*words)[16];
struct F32Field {
u8* base;
std::size_t offset;
F32Field& operator=(float v) {
std::memcpy(base + offset, &v, sizeof(v));
return *this;
}
};
struct Fields {
F32Field metrics_0x00;
F32Field metrics_0x04;
F32Field metrics_0x08;
F32Field metrics_0x0C;
F32Field adv_height;
F32Field effect_width;
F32Field slant_b;
F32Field slant_a;
};
Fields fields() const {
return {
.metrics_0x00 = {words[0], 0x00},
.metrics_0x04 = {words[0], 0x04},
.metrics_0x08 = {words[0], 0x08},
.metrics_0x0C = {words[0], 0x0C},
.adv_height = {words[1], 0x00},
.effect_width = {words[1], 0x04},
.slant_b = {words[1], 0x08},
.slant_a = {words[1], 0x0C},
};
}
};
auto out = LayoutAltOutIo{out_words}.fields();
out.metrics_0x00 = static_cast<float>(lane0) * kOneOver64;
out.metrics_0x04 = static_cast<float>(lane1) * kOneOver64;

View File

@ -9,7 +9,12 @@
#include <cstdint>
#include <cstring>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_SYSTEM_H
#include "core/libraries/font/font.h"
#include "core/libraries/font/fontft.h"
namespace Libraries::Font {
@ -448,6 +453,40 @@ static_assert(offsetof(VerticalLayoutAltBlocks, metrics) == 0x00,
static_assert(offsetof(VerticalLayoutAltBlocks, extras) == 0x10,
"VerticalLayoutAltBlocks extras offset");
struct GetCharGlyphMetricsFailLogState {
u32 count = 0;
bool suppression_logged = false;
};
struct SysFontRangeRecord {
/*0x00*/ u32 start;
/*0x04*/ u32 end;
/*0x08*/ s16 shift_x;
/*0x0A*/ s16 shift_y;
/*0x0C*/ float scale_mul;
/*0x10*/ u32 reserved_0x10;
/*0x14*/ u32 reserved_0x14;
/*0x18*/ u32 reserved_0x18;
};
static_assert(sizeof(SysFontRangeRecord) == 0x1C, "SysFontRangeRecord size");
static_assert(offsetof(SysFontRangeRecord, shift_x) == 0x08, "SysFontRangeRecord shift_x offset");
static_assert(offsetof(SysFontRangeRecord, scale_mul) == 0x0C,
"SysFontRangeRecord scale_mul offset");
struct F32x2 {
float lo = 0.0f;
float hi = 0.0f;
};
struct RenderSurfaceSystemUse {
Libraries::Font::OrbisFontStyleFrame* styleframe = nullptr;
float catchedScale = 0.0f;
std::uint8_t padding[88 - sizeof(Libraries::Font::OrbisFontStyleFrame*) - sizeof(float)]{};
};
static_assert(sizeof(RenderSurfaceSystemUse) ==
sizeof(((Libraries::Font::OrbisFontRenderSurface*)nullptr)->reserved_q),
"RenderSurfaceSystemUse layout must match OrbisFontRenderSurface::reserved_q");
s32 ComputeHorizontalLayoutBlocks(Libraries::Font::OrbisFontHandle fontHandle,
const void* style_state_block, u8 (*out_words)[16]);
s32 ComputeVerticalLayoutBlocks(Libraries::Font::OrbisFontHandle fontHandle,
@ -516,12 +555,6 @@ std::uint8_t* AcquireFontCtxEntry(std::uint8_t* ctx, u32 idx, u32 mode_low, void
void ReleaseFontObjectsForHandle(Libraries::Font::OrbisFontHandle fontHandle, int entryCount);
s32 ComputeHorizontalLayoutBlocks(Libraries::Font::OrbisFontHandle fontHandle,
const void* style_state_block, u8 (*out_words)[16]);
s32 ComputeVerticalLayoutBlocks(Libraries::Font::OrbisFontHandle fontHandle,
const void* style_state_block, u8 (*out_words)[16]);
s32 GetCharGlyphMetrics(Libraries::Font::OrbisFontHandle fontHandle, u32 code,
Libraries::Font::OrbisFontGlyphMetrics* metrics, bool use_cached_style);
@ -564,6 +597,148 @@ s32 StyleStateGetWeightScale(const void* style_state_block, float* weightXScale,
namespace Libraries::FontFt::Internal {
using GuestAllocFn = void*(PS4_SYSV_ABI*)(void* object, u32 size);
using GuestFreeFn = void(PS4_SYSV_ABI*)(void* object, void* p);
using GuestReallocFn = void*(PS4_SYSV_ABI*)(void* object, void* p, u32 size);
struct FtLibraryCtx {
void* alloc_ctx = nullptr;
void** alloc_vtbl = nullptr;
FT_Memory ft_memory = nullptr;
FT_Library ft_lib = nullptr;
};
struct BeU16 {
u8 b[2];
constexpr u16 value() const {
return static_cast<u16>((static_cast<u16>(b[0]) << 8) | static_cast<u16>(b[1]));
}
};
static_assert(sizeof(BeU16) == 2, "BeU16 size");
struct BeU32 {
u8 b[4];
constexpr u32 value() const {
return (static_cast<u32>(b[0]) << 24) | (static_cast<u32>(b[1]) << 16) |
(static_cast<u32>(b[2]) << 8) | static_cast<u32>(b[3]);
}
};
static_assert(sizeof(BeU32) == 4, "BeU32 size");
struct TtcHeader {
BeU32 tag;
BeU32 version;
BeU32 num_fonts;
};
static_assert(sizeof(TtcHeader) == 0x0C, "TtcHeader size");
struct SfntOffsetTable {
BeU32 version;
BeU16 num_tables;
BeU16 search_range;
BeU16 entry_selector;
BeU16 range_shift;
};
static_assert(sizeof(SfntOffsetTable) == 0x0C, "SfntOffsetTable size");
struct SfntTableRecord {
BeU32 tag;
BeU32 checksum;
BeU32 offset;
BeU32 length;
};
static_assert(sizeof(SfntTableRecord) == 0x10, "SfntTableRecord size");
struct FontObjSidecar {
const u8* font_data = nullptr;
u32 font_size = 0;
u32 sfnt_base = 0;
void* owned_data = nullptr;
};
struct LayoutOutIo {
u8 (*words)[16] = nullptr;
struct F32Field {
u8* base = nullptr;
std::size_t offset = 0;
F32Field& operator=(float v) {
std::memcpy(base + offset, &v, sizeof(v));
return *this;
}
};
struct Fields {
F32Field line_advance;
F32Field baseline;
F32Field x_bound_0;
F32Field x_bound_1;
F32Field max_advance_width;
F32Field hhea_caret_rise_adjust;
F32Field effect_height;
F32Field half_effect_width;
F32Field left_adjust;
};
Fields fields() const {
return {
.line_advance = {words[0], 0x00},
.baseline = {words[0], 0x04},
.x_bound_0 = {words[0], 0x08},
.x_bound_1 = {words[0], 0x0C},
.max_advance_width = {words[1], 0x00},
.hhea_caret_rise_adjust = {words[1], 0x04},
.effect_height = {words[1], 0x08},
.half_effect_width = {words[1], 0x0C},
.left_adjust = {words[2], 0x00},
};
}
};
struct LayoutAltOutIo {
u8 (*words)[16] = nullptr;
struct F32Field {
u8* base = nullptr;
std::size_t offset = 0;
F32Field& operator=(float v) {
std::memcpy(base + offset, &v, sizeof(v));
return *this;
}
};
struct Fields {
F32Field metrics_0x00;
F32Field metrics_0x04;
F32Field metrics_0x08;
F32Field metrics_0x0C;
F32Field adv_height;
F32Field effect_width;
F32Field slant_b;
F32Field slant_a;
};
Fields fields() const {
return {
.metrics_0x00 = {words[0], 0x00},
.metrics_0x04 = {words[0], 0x04},
.metrics_0x08 = {words[0], 0x08},
.metrics_0x0C = {words[0], 0x0C},
.adv_height = {words[1], 0x00},
.effect_width = {words[1], 0x04},
.slant_b = {words[1], 0x08},
.slant_a = {words[1], 0x0C},
};
}
};
const Libraries::FontFt::OrbisFontLibrarySelection* GetDriverTable();
const Libraries::FontFt::OrbisFontRendererSelection* GetRendererSelectionTable();
u32 PS4_SYSV_ABI LibraryGetPixelResolutionStub();
s32 PS4_SYSV_ABI LibraryInitStub(const void* memory, void* library);
s32 PS4_SYSV_ABI LibraryTermStub(void* library);