fix(font): keep the step fields the library leaves alone and test multi-level closing
This commit is contained in:
parent
eecba6888d
commit
25afd95d35
|
|
@ -281,7 +281,10 @@ const FontWritingLineStep* APS5_VABI sceFontWritingLineRefersRenderStep(void* wr
|
|||
ExtendRenderMetrics(*line);
|
||||
} else {
|
||||
line->steppedSpace = 0.0f;
|
||||
line->step = {};
|
||||
line->step.x = 0.0f;
|
||||
line->step.y = 0.0f;
|
||||
line->step.spacingProgress = 0.0f;
|
||||
line->step.Metrics = {};
|
||||
line->renderMetrics = {};
|
||||
}
|
||||
const bool rightToLeft = IsRightToLeft(*line);
|
||||
|
|
|
|||
|
|
@ -65,6 +65,20 @@ static bool StepIs(const FontWritingLineStep* step, float x, float progress, con
|
|||
step->Adjusting.y == 0.0f && Same(step->Metrics, run);
|
||||
}
|
||||
|
||||
static bool OrderIs(void* line, const std::uint64_t* levels, const std::size_t* order, std::size_t count) {
|
||||
static int orderers[16];
|
||||
const FontWritingMetrics run{1.0f, 0.0f, {-1.0f, 1.0f, 0.0f, 1.0f}};
|
||||
if (sceFontWritingLineClear(line) != SCE_FONT_OK) return false;
|
||||
for (std::size_t i = 0; i < count; ++i) {
|
||||
if (sceFontWritingLineWritesOrder(line, Attribute(levels[i]), &run, &orderers[i]) != SCE_FONT_OK) return false;
|
||||
}
|
||||
for (std::size_t i = 0; i < count; ++i) {
|
||||
const FontWritingLineStep* step = sceFontWritingLineRefersRenderStep(line);
|
||||
if (!step || step->writingOrderer != &orderers[order[i]]) return false;
|
||||
}
|
||||
return sceFontWritingLineRefersRenderStep(line) == nullptr;
|
||||
}
|
||||
|
||||
int main() {
|
||||
FontMemory memory{};
|
||||
void* line = nullptr;
|
||||
|
|
@ -180,6 +194,30 @@ int main() {
|
|||
Require(sceFontWritingLineRefersRenderStep(rtl) == nullptr);
|
||||
Require(sceFontWritingLineGetRenderMetrics(rtl, &metrics) == SCE_FONT_OK && Same(metrics, {18.0f, 0.0f, {-8.0f, 2.0f, 2.0f, 17.0f}}));
|
||||
|
||||
const std::uint64_t nested[] = {0, 1, 2, 3, 1, 1, 0};
|
||||
const std::size_t nestedOrder[] = {0, 5, 4, 2, 3, 1, 6};
|
||||
Require(OrderIs(ltr, nested, nestedOrder, 7));
|
||||
const std::uint64_t repeated[] = {0, 1, 1, 2, 2, 0, 1, 2, 2, 0};
|
||||
const std::size_t repeatedOrder[] = {0, 3, 4, 2, 1, 5, 7, 8, 6, 9};
|
||||
Require(OrderIs(ltr, repeated, repeatedOrder, 10));
|
||||
const std::uint64_t skipped[] = {0, 2, 3, 3, 2, 1, 0};
|
||||
const std::size_t skippedOrder[] = {0, 5, 1, 3, 2, 4, 6};
|
||||
Require(OrderIs(ltr, skipped, skippedOrder, 7));
|
||||
|
||||
const FontWritingMetrics runE{10.0f, 3.0f, {-8.0f, 2.0f, 1.0f, 9.0f}};
|
||||
const FontWritingMetrics runF{6.0f, -1.0f, {-12.0f, 3.0f, -1.0f, 5.0f}};
|
||||
Require(sceFontWritingLineClear(ltr) == SCE_FONT_OK);
|
||||
Require(sceFontWritingLineWritesOrder(ltr, Attribute(0), &runE, &a) == SCE_FONT_OK);
|
||||
Require(sceFontWritingLineWritesOrder(ltr, Attribute(0), &runF, &b) == SCE_FONT_OK);
|
||||
auto* adjusted = const_cast<FontWritingLineStep*>(sceFontWritingLineRefersRenderStep(ltr));
|
||||
Require(adjusted && adjusted->x == 0.0f && adjusted->y == 0.0f && adjusted->writingOrderer == &a);
|
||||
adjusted->Adjusting = {2.0f, 5.0f};
|
||||
const FontWritingLineStep* second = sceFontWritingLineRefersRenderStep(ltr);
|
||||
Require(second && second->x == 10.0f && second->y == 3.0f && second->Adjusting.x == 0.0f && second->Adjusting.y == 0.0f);
|
||||
Require(sceFontWritingLineGetRenderMetrics(ltr, &metrics) == SCE_FONT_OK && Same(metrics, {12.0f, 8.0f, {-3.0f, 7.0f, 3.0f, 11.0f}}));
|
||||
Require(sceFontWritingLineRefersRenderStep(ltr) == nullptr);
|
||||
Require(sceFontWritingLineGetRenderMetrics(ltr, &metrics) == SCE_FONT_OK && Same(metrics, {16.0f, 2.0f, {-9.0f, 7.0f, 3.0f, 15.0f}}));
|
||||
|
||||
float space = 7.0f;
|
||||
Require(sceFontWritingLineGetOrderingSpace(rtl, nullptr, nullptr, &space, nullptr) == SCE_FONT_OK && space == 15.0f);
|
||||
Require(Throws([&] { sceFontWritingLineGetOrderingSpace(rtl, &space, &space, &space, nullptr); }));
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- [Thread exit destructors](../../core/libs/prx/libSceLibcInternal/Export.cpp) (libSceLibcInternal) run when a libkernel thread finishes; on the main or a host thread only `_sceLibcInternalThreadDtors` runs them, as `exit` does, else they are dropped
|
||||
- [sceFontOpenFontSet](../../core/libs/prx/libSceFont/src/SystemFont.cpp) (libSceFont) opens only the primary file of a system font set. Characters the console takes from the set's other files (Hangul, Thai and Arabic in Japanese and Chinese sets, Arabic in European sets) are reported as unsupported glyphs. The console file names are those of the PS4 firmware; the names of the PS5-only JG2 sets (`0x1A......`) are unknown, so they use the SSTJpPro files. When a console file is missing, an openly licensed substitute (Noto Sans, Noto Sans Mono, Noto Sans Thai, Noto Sans CJK) is loaded instead. It is not the system font: its metrics differ, so text width, line height and wrapping differ from the console. System font faces are loaded by FreeType in host memory, not in the font memory the title passes to the library: FreeType needs about 1 MiB per CJK face, which the title's font memory is not sized for.
|
||||
- [sceFontGetCharGlyphMetrics, sceFontGetRenderCharGlyphMetrics](../../core/libs/prx/libSceFont/src/Layout.cpp) (libSceFont) report the vertical metrics the way the [FreeType driver](../../core/libs/prx/libSceFontFt/src/Driver.cpp) reports them for a rendered glyph, not confirmed on a title: FreeType's vertical advance, and for a face without vertical metrics a bearing of half the horizontal advance left of the horizontal bearing and of half the advance left over by the glyph height.
|
||||
- [Font writing lines](../../core/libs/prx/libSceFont/src/WritingLine.cpp) (libSceFont) - `sceFontWritingLineWritesOrder`, `sceFontWritingLineRefersRenderStep`, `sceFontWritingLineGetRenderMetrics`, `sceFontWritingLineGetOrderingSpace` and `sceFontWritingLineClear` follow the PS4 11.00 `libSceFont.sprx` (firmware module, read from its disassembly and compared call for call on random sequences): runs are linked in visual order by embedding level, the space at each spaced join is summed for the line, steps walk the visual order from the left (form `0x12`) or from the right (form `0x11`) and the render metrics grow as steps are consumed. The PS5 library was not measured. Not from that module: form `0x10` is accepted and treated as left to right and a detail with id `0x0FD5` is accepted (the PS4 library rejects both); an unknown writing form, another detail id, a null line pointer on creation and unknown handles throw instead of returning the PS4 error codes; `sceFontDestroyWritingLine` was not compared. Lines are allocated on the host, not in the font memory the title passes to the library: FreeType needs about 1 MiB per CJK face, which the title's font memory is not sized for.
|
||||
- [Font writing lines](../../core/libs/prx/libSceFont/src/WritingLine.cpp) (libSceFont) - `sceFontWritingLineWritesOrder`, `sceFontWritingLineRefersRenderStep`, `sceFontWritingLineGetRenderMetrics`, `sceFontWritingLineGetOrderingSpace` and `sceFontWritingLineClear` follow the PS4 11.00 `libSceFont.sprx` (firmware module, read from its disassembly and compared call for call on random sequences): runs are linked in visual order by embedding level, the space at each spaced join is summed for the line, steps walk the visual order from the left (form `0x12`) or from the right (form `0x11`) and the render metrics grow as steps are consumed. The PS5 library was not measured. Not from that module: form `0x10` is accepted and treated as left to right and a detail with id `0x0FD5` is accepted (the PS4 library rejects both); the memory argument of `sceFontCreateWritingLine` and the rest of the detail are not read (the PS4 library validates its library object there); an unknown writing form, another detail id, a null line pointer on creation and unknown handles throw instead of returning the PS4 error codes; `sceFontDestroyWritingLine` was not compared. Lines are allocated on the host, not in the font memory the title passes to the library: FreeType needs about 1 MiB per CJK face, which the title's font memory is not sized for.
|
||||
- [s_swappc_b64](../../core/shader/recompiler/Translation/src/ControlFlowInstructions.cpp) writes the link pair with the same model as `s_getpc_b64`: the guest return address `pc + 4` as a byte offset over `GetShaderBase`. Any other use of the link pair (arithmetic, compare, hash, store, or a second `s_swappc_b64` sharing it) throws; constant-offset folding over the link is not modeled. The special encoding `s_swappc_b64` with SDST 125 still decodes as `s_setpc_b64`, which matches the hardware: measured on RDNA2 (gfx1036) in wave32 and wave64, it branches to the source pair and leaves a marker SGPR pair untouched, and with an SGPR destination the link is `PC + 4`.
|
||||
- The [s_swappc_b64 fetch-shader call at vertex/local/tessellation/mesh entry](../../core/shader/recompiler/ControlFlow/src/GraphBuilder.cpp) assumes the called fetch-shader blob ends in `s_setpc_b64` to the link pair (the GNM fetch-shader shape shadPS4's `EmitFetch` copies); the blob is not part of the shader program, so its return closes the pairing by assumption and any in-program reader of the link pair throws. Attribute fetches are inlined from the request's parsed fetch-shader plan through the same `GetAttribute` path as the embedded fetch analyzer, honoring the buffer resource `dst_sel`; an attribute writing more than four registers, or an entry call without a parsed plan, throws. The vertex/instance offset accumulator inside the fetch blob is not replayed for external blobs.
|
||||
- The scalar aperture sources [src_shared_base, src_shared_limit, src_private_base, src_private_limit](../../core/shader/recompiler/RdnaDecoder/src/RdnaInstructionDecoder.cpp) (core/shader/recompiler) decode to their own operand kinds (scalar source codes 235 to 238, named as in LLVM's `SIRegisterInfo.td`), but their value is not modelled: reading one refuses with the source it refused named, because the wave's shared and private aperture bases and limits are unknown. Both the scalar-code read and the raw-operand read refuse; a shader that only carries the value into an address still prepares, one that reads it does not
|
||||
|
|
|
|||
Loading…
Reference in New Issue