The PS5 3.20 export inventory and verified NID-name database identify 92 exports in this library. The decrypted local PS5 13.60 libSceFreeTypeOl.sprx (SHA-256 61E0CDB1628968A9D26790D8F6C2874C0CBF86193DC1762BA83E434CF229BADA) was analyzed locally with Ghidra; no binary or decompilation is included in this repository. The analysis informed the FreeType wrapper signatures and shared-library module lifecycle; no byte-for-byte console call trace is included.
Implemented wrappers are in ModuleWrappers.cpp; the remaining NID aliases are in Export.cpp.
Forty-six exports now forward to the bundled FreeType implementation: built-in add/remove helpers for the 18 available module classes, seven module support helpers, allocator/free, and glyph-slot destruction. Library handles are translated through GuestLibrary::host, and glyph-slot destruction operates on the native slot owned by the corresponding GuestFace. Focused guest-bridge coverage is in GuestFreeTypeOlModules.cpp.
NID labels and the 92-export inventory come from the verified NID-name mapping. The decrypted 13.60 disassembly inspected with Ghidra informed the wrapper call shapes, cross-checked against FreeType's module API declarations. This port uses the existing 64-bit guest-pointer representations (GuestLibrary*, GuestFaceRec* and GuestGlyphSlotRec*), 32-bit int error results, and 64-bit guest allocation sizes (std::int64_t) and callbacks from the existing libSceFreeType guest types. These choices are inferred bridge types, not a claim that every original Sony argument or return width was independently established from an instrumented console trace.
The native built-in module descriptors used inside the add/support wrappers and their fields come from the bundled FreeType internal headers freetype/internal/ftobjs.h and ftdrv.h (FreeType 2.13.3 on the original PR base; FreeType 2.15.0 was subsequently merged into upstream main in #12523). Validation against the new internal module tables is still required. They are native FT_Module_Class / FT_Driver_ClassRec / FT_Renderer_Class objects, not a separately reconstructed Sony guest module-class layout. In particular, native FT_Long fields are host-width and may differ from 64-bit PS5 expectations on Windows, and native callback pointers are not guest ABI trampolines. Guest-defined module classes and callbacks still require a dedicated bridge. Consequently all 18 export-module entry points, the two generic guest-supplied module registration entry points, and module-interface lookup are kept throwing instead of exposing native pointers across the guest boundary.
The FreeType guest bridge owns its guest faces in GuestLibrary::faces. Native FT_Remove_Module normally destroys every face associated with a removed font driver; the guest adapter would otherwise retain dangling host-face pointers. To prevent use-after-free, sceFreeTypeOlFtaRemoveModule* returns FT_Err_Invalid_Argument (6) without removing the driver when a tracked, live guest face belongs to it. The face remains usable by FT_Select_Charmap, FT_Get_Char_Index, and FT_Done_Face. Once the last such guest face is destroyed, removing the driver succeeds. This refusal differs from native FreeType removal semantics; the PS5 console's behaviour is unmeasured. Non-guest native faces are not tracked by this guard.
sceFreeTypeOlDoneGlyphSlot destroys the face's native glyph slot, leaving the guest face->glyph pointer null and not replacing the slot. A later glyph load on that face is not expected to work normally and may return an error; a subsequent load has not been independently tested here. Whether the PS5 implementation allows recreation after explicit slot destruction is unmeasured.
With ANYPS5_USE_SYSTEM_DEPS=ON, the freetype CMake target is an INTERFACE wrapper around the installed library. Bundled GX/OpenType validation C sources, private FreeType headers and module-class objects are not present. In this mode the 46 module-wrapper NIDs compile as explicit throwing stubs and the other 46 remain unchanged, preserving all 92 export aliases without calling unavailable internals. The bundled-only module regression test is omitted; the existing outline-border tests remain registered. The 46-export implementation is built only with bundled FreeType.
The remaining 46 exports deliberately retain NotImplemented_nid_no_patch because they require unavailable Sony-specific modules/state or a guest/native bridge that is not yet implemented:
- Module class exports (18), the generic
FT_Add_Module/FtaAddModulewrappers (2), andFT_Get_Module_Interface(1): hostFT_Module_Classfields differ from the 64-bit guest ABI on some platforms; native FreeType callback and interface pointers are not guest-callable trampolines. A guest module-class layout and callback bridge are required before safe implementation. Their NIDs retain their original labels inExport.cpp. - Raster5 add/export/remove/support (
wbyY8kfNfaI,6zDeyzjWz-8,SKUldaN3e2A,Tzm-z36UYKg): the Sony Raster5 module is absent from the bundled FreeType sources. See its unimplemented exports. - Smooth LCD and LCD vertical add/export/remove/support (
NLA7bmDS1jc,xcJCXHqBrjE,+bRRhPeBqZI,q7kTOFaQrW4,xtb9fOR6ilA,6z2P2V2XCiI,M94SjXo-UVA,Ns9a-LjOcDw): Sony exports distinct renderer descriptors; the bundled library has one smooth renderer, so aliasing these descriptors would give incorrect add/remove behavior. See its unimplemented exports. - Composite format/module configuration (
JuzrPZClLew,sylevnx-fqk,0RSuGozMl9o,J3HnvW8FJV8,YpxR8CqGMIM,83qtpn8+XnA,g2p7fkJpuC0,xqjAbn8VNGo,oM0zMNCfXKM): these routines combine module registration with Sony-specific support-mask state. Implementing registration alone would omit observable state updates. See its unimplemented exports. FT_Attach_Stream,FT_CMap_New, andFT_CMap_Done(ZqvTX8u1bEc,wLqQQWyOdpc,h0n4Fb9j2R8): direct native calls bypass the existing guest face/charmap layout, stream/callback ABI, and lifecycle ownership. These require a dedicated guest bridge before implementation.FT_Done_Memory(UTumVjeIQtg): the export has no parameter and operates on a Sony-owned global memory manager; the host FreeType library exposes a separate manager for each library. See its unimplemented export.
Each remaining export keeps its original NID alias and throws through NotImplemented_nid_no_patch until its required implementation or state mapping is available.