Skip to content

feat(libSceFreeType): implement the six FreeType functions OpenOrbis samples use - #6376

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
Get-fix:ps4/libscefreetype
Oct 18, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
Get-fix:ps4/libscefreetype

Conversation

@Get-fix

@Get-fix Get-fix commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

What

PS4 homebrew built with the OpenOrbis toolchain draws text through the PS4 libSceFreeType. The OpenOrbis font, keyboard, threading, system and SDL2 samples import six of its functions and stop at start-up without them: FAIL: unresolved ELF import GNsiLzm4SH8 (FT_Init_FreeType), j-uMQE+unFY (FT_New_Face), lJxMIwj81SQ (FT_Set_Pixel_Sizes), obnSzeb-KXk (FT_Get_Char_Index), M156RuYoUbU (FT_Load_Glyph) and TCRmigbq7lc (FT_Render_Glyph).

This adds libSceFreeType with those six functions on top of the bundled FreeType 2.13.3.

  • Layout: the guest reads FreeType's structures directly, compiled for LP64, where FT_Long and FT_Pos are 64 bits. On Windows they are 32 bits, so the guest gets copies of the face, size, charmap and glyph slot in the LP64 layout, refreshed after each call that changes them. The offsets are checked with static_assert and match what the font sample reads: face->glyph at 0x98, slot->advance at 0x80, slot->bitmap at 0x98, slot->bitmap_left at 0xc0. Outline points are copied as 64-bit coordinates, and edits the guest makes to them are written back before FT_Render_Glyph.
  • Paths: FT_New_Face resolves the guest path, as libSceFont does, and opens the file from memory.
  • Argument handling follows FreeType: the order of the argument checks and their error codes; the face index masked to 31 bits and sign before it is narrowed; character codes truncated to 32 bits.
  • Exports: the bundled FreeType's own functions are kept out of the library's exports (--exclude-libs, as libSceSsl does). Another FreeType function a title imports still fails at start-up instead of resolving to a host function with the Windows calling convention.

The limits, such as private fields that are null, faces that are never freed and macOS exports, are in the new docs/dev/debt/libSceFreeType.md. Part of the PS4 homebrew work tracked in #3093.

Tested

Windows 11 Pro 26200, WinLibs GCC 15.2.0 r7, Release, full build with BUILD_TESTING=ON, on main 9811e9d4b:

  • The new guest_freetype test writes a one-glyph TrueType font to app0/ and opens it through the guest path /app0/font.ttf. It loads the same bytes with the host FreeType and compares every mirrored field of the face, size, charmap and slot, before and after rendering: metrics, bitmap bytes, outline points, tags and contours. It also checks:
    • the error codes for a null path, a null library, a missing file and a null aface;
    • a face index of 0x180000000 opening face 0 and 0x80000001 failing as index 1;
    • FT_Get_Char_Index(face, 0x100000041) returning the glyph of A;
    • an outline moved one pixel by the guest rendering one pixel to the right;
    • replaced outline arrays throwing.
  • Each of these makes the test fail: not passing the bitmap buffer; swapping the advance; not converting the outline points; not writing guest outline edits back; narrowing the face index without FreeType's mask; not refreshing the size metrics or the glyph slot; not setting the active charmap; opening the guest path unresolved; reporting a missing file with another error.
  • The patched libSceFreeType.prx exports the six NIDs and none of FreeType's own functions.
  • OpenOrbis samples on main 92cdc7b62 with fix(relinker): search libc.prx for libkernel-only Windows executables #5990 to fix(relinker): stop module syscall scans at the PLT and skip the PS4 loader path #5994, fix(relinker): accept section-relative guest module relocations #5138 and a local change that answers the Linux TIOCGWINSZ (0x5413) with ENOTTY, as fix(libkernel): return ENOTTY for malformed ioctl requests #5569 does:
    • font, keyboard, threading and SDL2 now start and draw their text: font draws "Hello, World!" in two sizes, and SDL2 draws its score, its game-over text and a debug overlay at 58 FPS.
    • The system sample imports the same six functions but was not run here, because Windows Defender flags its converted executable with a machine-learning heuristic.
    • The nine samples that started before still start.
  • Full ctest of that build: every test passes except four. prx_thread_local_destructors and agc_driver_store_over_untracked fail the same way on main 92cdc7b62 without these changes; agc_driver_preparation_scope_settle and guest_raise_exception pass when run alone.
  • tools/check_conventions.py --base origin/main passes.

Not tested on Linux or macOS.

Checklist

🤖 Generated with Claude Code

…samples use

PS4 homebrew built with the OpenOrbis toolchain draws text through the
PS4 libSceFreeType: the font, keyboard, threading, system and SDL2
samples stop at start-up with "unresolved ELF import GNsiLzm4SH8"
(FT_Init_FreeType) and the five other functions they import.

FT_Init_FreeType, FT_New_Face, FT_Set_Pixel_Sizes, FT_Get_Char_Index,
FT_Load_Glyph and FT_Render_Glyph now call the bundled FreeType. The
guest reads FreeType's structures directly with the LP64 layout, where
FT_Long and FT_Pos are 64 bits, so the face, size, charmap and glyph
slot it receives are copies in that layout, updated after each call;
outline points are converted and written back before rendering. Guest
font paths are resolved and the file is read into memory. The face
index is masked as FreeType does before it is narrowed, and character
codes are truncated to 32 bits as FreeType does. The bundled FreeType's
own functions are kept out of the library's exports.
@github-actions

Copy link
Copy Markdown

Progress report (0e4ea13 → 38fd195)

📈 System libraries: 88.71% (+0.01%, +6 implemented functions)

✅ 6 implemented
Library Name
libSceFreeType FT_Get_Char_Index_nid_postfix
libSceFreeType FT_Init_FreeType_nid_postfix
libSceFreeType FT_Load_Glyph_nid_postfix
libSceFreeType FT_New_Face_nid_postfix
libSceFreeType FT_Render_Glyph_nid_postfix
libSceFreeType FT_Set_Pixel_Sizes_nid_postfix

@jotitadev jotitadev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linux run (Ubuntu 26.04, Intel i7-8700, GCC 15.2, full build, non-GPU tests), head 38fd195e9 merged onto main 44df21632.

  • The new library configures, builds and passes NID patching; guest_freetype passes (no early exit; the whole main runs, exit 0).
  • No red run: the library is new, so the test cannot build without it.

Non-GPU suite (ctest -E "^agc"): same result as main; only file_writer_binary and file_writer_text fail, and they fail on main too on this machine (Ubuntu 26.04 coreutils).

Written with AI assistance (Claude Code). I ran the builds and tests above on my machine.

@Get-fix

Get-fix commented Oct 15, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the Linux run and the NID patching check, @jotitadev.

AI-assisted: yes (Claude Code).

🤖 Generated with Claude Code

@adriadam10 adriadam10 self-assigned this Oct 18, 2026
@adriadam10
adriadam10 merged commit 7732434 into boykopovar:main Oct 18, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants