Skip to content

feat(font): order writing line runs by embedding level and report their spacing - #3260

Merged
adriadam10 merged 3 commits into
boykopovar:mainfrom
fma-rc:feat/font-writing-line-order
Oct 11, 2026
Merged

adriadam10 merged 3 commits into
boykopovar:mainfrom
fma-rc:feat/font-writing-line-order

Conversation

@fma-rc

@fma-rc fma-rc commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

What

sceFontWritingLineWritesOrder threw for every writing attribute except 0. Astro's Playroom (PPSA01325) passes 0xFA | level << 8 with bits 30 and 31 set on some text runs and stops there with sceFontWritingLineWritesOrder: writing attribute 250 is not modelled.

The writing line now follows the PS4 11.00 libSceFont.sprx, read from its disassembly. That module exports the same functions under the same NIDs; the PS5 library was not measured.

  • WritesOrder takes the attribute as low byte 0xFA, embedding level in bits 8-15 (0 to 126), bit 30 / bit 31 for space before / after the run. Runs are linked in visual order by level (odd levels run the other way), and the space at each spaced join is summed for the line. Attribute 0 is still accepted, as level 0 without spacing.
  • RefersRenderStep walks the visual order from the left (form 0x12) or from the right (form 0x11, now accepted), reports how much of the line's spacing lies before each step in spacingProgress, and grows the render metrics as steps are consumed.
  • GetOrderingSpace returns the line advance, leading space, summed inline space and trailing space, in that order.

Where the PS4 module returns SCE_FONT_ERROR_INVALID_PARAMETER (null line, other attribute low byte, level above 126, null orderer, null metrics output) this throws, since no PS5 source confirms the codes. Kept from the old model and not from that module: attribute 0, form 0x10 (treated as left to right), the 0x0FD5 detail, throws for unknown handles and forms, host-allocated lines. All listed in TechnicalDebt.

Output order of GetOrderingSpace: Orbital's IDA types and SharpProspero name the outputs head, inline, tail, advance. The PS4 function writes advance, leading, inline, trailing through rsi, rdx, rcx, r8, and the one PS5 caller I have agrees with that: Playroom calls the export once (0x187d380) and computes out1 - out4 - out2 - 0.25 * out3, divided by a scale and compared with a width limit. With the other naming that would be head minus advance. The title subtracts both out2 and out4, so which of the two is leading and which trailing rests on the PS4 module alone.

Tested

Linux, GCC 16.2.1, Release.

  • guest_font_writing_line rewritten: plain and nested levels (including drops of several levels), spacing in both directions, render metrics while stepping, step adjustment, the throws. On main it aborts with writing form 17 is not modelled; with the change it passes, as do the two other font tests.
  • Differential run against the PS4 module itself (module mapped into the test process, its writing-line functions called directly, random sequences of writes, steps, metric and space reads and clears compared bit for bit): 411,762, 2,024,854 and 4,049,638 calls with levels up to 126 and a caller writing into the returned step, no difference; 806,277 calls with special floats, where 232 results differ only in the sign or payload of a NaN.
  • The harness, its README and vectors.txt are at https://github.com/fma-rc/AnyPS5/tree/evidence/font-writing-line-oracle (no firmware file in it; the README gives the sha256 of the module used). vectors.txt is the repository test run against the PS4 module in place of this implementation, with the module's output under each assertion; lines marked harness: are the listed departures.
  • Astro's Playroom on an RTX 5080, main eb15ddc plus this branch and nothing else: the title no longer stops in libSceFont, logs LoadLevelResources: opening and stops on sceAudioInHqOpen not implemented.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • AI-assisted: yes

@github-actions github-actions Bot added the intake paused Closed while PR intake is limited to authors with at least 10 PRs merged into main label Oct 11, 2026
@github-actions

Copy link
Copy Markdown

Thank you for your interest in the project! We are sorry, but we cannot accept more PRs while we work through the existing backlog. This PR has been automatically closed and labeled "intake paused". This is not a judgment of the quality of your changes.

@github-actions github-actions Bot closed this Oct 11, 2026
@oneandonlydean oneandonlydean removed the intake paused Closed while PR intake is limited to authors with at least 10 PRs merged into main label Oct 11, 2026

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the work; the ordering model builds and guest_font_writing_line passes here (fails on main, as it should). Things to fix before this can land:

  • WritingLine.cpp:256-259,321-323,331-337,249: the new SCE_FONT_ERROR_INVALID_PARAMETER returns (bad attribute, null line/orderer, null metrics) come only from the PS4 module. Unverified error codes/params should keep throwing (exact-or-throw) until a PS5 source confirms them.
  • WritingLine.cpp:257: attribute 0 was accepted on main and now returns an error. That is a behaviour change on PS4 evidence alone. Keep accepting it (or throw), and list it in TechnicalDebt.
  • WritingLine.cpp:330: the order of the four outputs of sceFontWritingLineGetOrderingSpace is swapped against the Orbital IDA types and the SharpProspero bindings, which are the PS5-side references. Please explain why the PS4 order wins for PS5, or keep the documented order until it is measured.
  • GuestFontWritingLine.cpp: the expected values are the model's own outputs; the differential harness is not in the repo, so nobody else can reproduce them. Please attach it (or its generated vectors) to this PR as evidence.
  • Please say in the description which of the three other changes Astro's Playroom needs are required for this path, so the test on the RTX 5080 can be tied to this PR.

@Mouhand-Kaddo

Copy link
Copy Markdown
Contributor

Additional platform validation of standalone PR head 25afd95d3598f3aa030d4efe88bb09fcb9ab5455 (2026-10-11):

Windows: passed — Windows 11, WinLibs GCC 15.2.0 UCRT/POSIX/SEH r7; CMake 4.3.1 / Ninja; Release, BUILD_TESTING=ON.

1 checks, 0 failures, 0 CTest skips. Built the selected targets and dependencies; this is focused validation, not a full build or full-suite run.

Checks: guest_font_writing_line.

Command after building: ctest --test-dir <build> --verbose --no-tests=error --timeout 30 -R "^guest_font_writing_line$".

No title/gameplay validation. These results cover the standalone head, not a merge with current main.

@github-actions

github-actions Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
#3294 docs/dev/TechnicalDebt.md L517-518

@fma-rc

fma-rc commented Oct 11, 2026

Copy link
Copy Markdown
Contributor Author

All five are in 5680c32 and the description.

The PS4-only error returns throw now (null line, attribute low byte, level above 126, null orderer, null metrics output), and attribute 0 is accepted again as level 0, with a TechnicalDebt line.

I kept the PS4 output order for sceFontWritingLineGetOrderingSpace because the one PS5 caller I have uses it. Astro's Playroom calls the export once, at 0x187d380, then computes out1 - out4 - out2 - 0.25 * out3, divides by a scale and compares with its width limit. That is the advance minus the two edge spaces minus a quarter of the inter-run spacing, which is what the PS4 function writes through rsi, rdx, rcx, r8. With the Orbital and SharpProspero names it would be head - advance - inline - 0.25 * tail. The title cannot tell out2 from out4, so that part is from the PS4 module only and TechnicalDebt says so.

The harness and its vectors are at https://github.com/fma-rc/AnyPS5/tree/evidence/font-writing-line-oracle. vectors.txt is the repository test itself run against the PS4 module, with the module's output under each assertion.

Playroom needs none of the other changes any more: on main eb15ddc plus this branch alone it passes the font stop and ends on sceAudioInHqOpen not implemented.

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Checked the rework: error returns that only exist in the PS4 module now throw, attribute 0 is still accepted, and TechnicalDebt lists the PS4-order GetOrderingSpace with the PPSA01325 call site as evidence. Built and ran guest_font_writing_line (passes; fails with the library changes reverted); merging.

One thing for you: the PR description still says these paths return SCE_FONT_ERROR_INVALID_PARAMETER and that attribute 0 is rejected. That no longer matches the code after 5680c32; please update it.

@adriadam10
adriadam10 merged commit 44395d9 into boykopovar:main Oct 11, 2026
15 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.

4 participants