Skip to content

Teardown (PPSA15246): libSceCesCs Cp1251 profile and MbcsUcsContextInit imports #3701

Closed

Description

@xXPBSXx

AI-assisted (Claude Code), reviewed by the contributor.

Teardown (PPSA15246, from the owner's own dump), Windows. The title needs three things before its first real stop. Relinked from reconstructed ELFs (eboot.bin, sce_module/libc.prx, and the root module pros.sdk.Prospero-9.000.prx, which the executable lists as needed).

  1. Two imports of the module named libSceCesCs-module that no library exports: sceCesMbcsUcsContextInit and sceCesRefersUcsProfileCp1251. Fix on a branch on current main (a11c8f7): https://github.com/xXPBSXx/AnyPS5/tree/fix/ces-cp1251-profile (one commit by a helper session, which I reviewed and rebuilt myself). sceCesRefersUcsProfileCp1251 returns a profile for sceCesSbcToUtf8/sceCesUtf8ToSbc; the Windows-1251 table matches Python's cp1251 codec for all 127 assigned bytes, and byte 0x98 (unassigned in the codec) maps to U+0098 as in Microsoft's bestfit1251.txt. sceCesMbcsUcsContextInit succeeds without storing anything (context layout unknown; null context returns the invalid-parameter error); both signatures follow the Orbital type database (sceCesMbcsUcsContextInit(union*, const union*), sceCesRefersUcsProfileCp1251(void)). New target libSceCesCs-module for the module-named import; guest_ces (extended) and the conventions check pass; the entry is in TechnicalDebt.md.
  2. With it the import audit shows 0 absent imports and the title runs for a while, then stops at sceNpAuthGetIdTokenV3 not implemented (an NP online-authentication call; I have not looked at what an offline answer should be).

Not established: what the title does with the returned profile or context (I did not look at the window), and how the console treats byte 0x98.

Activity

  1. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    Follow-up from PPSA15246 (Teardown), run 60 s on fix/ces-cp1251-profile (6616544) merged with the head of #3604 (935e5c1); both built together, no other changes:

    • The loader passes the Ces imports, and sceNpAuthGetIdTokenV3 no longer throws with feat(libSceNpAuth): implement offline auth requests #3604.
    • The title then reaches savedata (mount3 dir=SAVEDATA), starts presenting and stops at a graphics error: compute shader 0x7ff72c5dc300: runtime image descriptor is invalid (ResourceMaterializer.cpp:491). I searched the issues for that text and found no issue or PR that names it; feat(agc): implement image tables loaded through 64-bit pointers #758 (image tables loaded through 64-bit pointers) is the closest topic but I have not tested it.
    • Not checked: whether the title relies on the id token result, and any behaviour on a console.

    AI-assisted (Claude Code).

  2. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    Narrowing the Teardown (PPSA15246) graphics stop. I printed the descriptor in the thrown message (local debug edit in ResourceMaterializer.cpp, not proposed). The log line is presentation failed: compute shader 0x7ff72c5dc300: runtime image descriptor is invalid, so it is raised on the video-out presentation path, and the 8 dwords of the image descriptor are:

    06400000 00040002 00040000 00014204 00000200 00040000 00000002 0dcf13c8, r128=0

    • Reading them as a gfx10 T# (my reading of the existing validImageDescriptor checks, not verified against hardware): dword 3 bits 31:28 (type) are 0, and dword 1 bits 28:20 (format) are 0. The check type < Color1D || format == Invalid therefore fails, and nullImageDescriptor does not accept it because dword 0 is not 0.
    • feat(agc): implement image tables loaded through 64-bit pointers #758 (image tables loaded through 64-bit pointers, merged locally on top of the Ces branch and feat(libSceNpAuth): implement offline auth requests #3604) does not change this: the same words and the same stop.
    • Not known: which register or user-data slot the descriptor is read from, and whether the title writes a valid descriptor later than this read.

    AI-assisted (Claude Code).

  3. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    Correction to my previous comment on the Teardown (PPSA15246) stop: I read the 8 dwords as a T#, but the first four fit a buffer descriptor (V#) much better, so the image check fails because the slot holds something else, not because an image descriptor is half-initialised.

    06400000 00040002 00040000 00014204 | 00000200 00040000 00000002 0dcf13c8

    • Read as a gfx10 V# (my reading of the layout, not checked against hardware or a source): dword 0 and dword 1 bits 15:0 give base address 0x2_0640_0000 = 0x206400000 (the same 8–9 GB range where the title's other GPU-visible memory sits, e.g. the 0x200400000+... imports in the log), dword 1 bits 29:16 give stride 4, dword 2 gives 262144 records (1 MiB). A plausible texel/structured buffer.
    • Dwords 4–7 do not look like a T# either (0x200, 0x40000, 2, 0x0dcf13c8). They could be the next object in a table or an SRT.
    • So the materializer reached a slot that an image resource of this compute shader expects as 32 bytes of T#, and found a V# followed by other data. Either the source offset of that image in the plan is wrong (e.g. the table entry size or an SRT offset), or the shader is classified with an image where the title uses a buffer. I have not looked at the shader itself, and feat(agc): implement image tables loaded through 64-bit pointers #758 did not change the words.

    Next step if someone with the shader dump wants to continue: print plan.descriptorSources[image.source] (its user-data register or SRT offset) next to the dwords in ResourceMaterializer.cpp:491. Not done here.

    AI-assisted (Claude Code).

  4. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    More on the Teardown (PPSA15246) stop, with the whole resource list of the failing compute shader printed (local debug edit in ResourceMaterializer.cpp, not proposed; run on the Ces branch + #3604 + #758). It looks like the same class as #3709 and #3055: the shader and the descriptors it is given do not belong together.

    The shader (0x7ff72c5dc300) declares 2 buffers and 6 images, built from only 4 descriptor sources, all active:

    Resource Source Words read What the words look like (my reading of the gfx10 layout, unverified)
    buffer 0 s0 4 06400000 00040002 00040000 00014204: a V# (base 0x206400000, stride 4, 262144 records)
    buffer 1 s2 4 020ef3a0 c1400000 007fc07f 90500204: dword 3 bits 31:28 = 9, a T# (2D), not a V#
    images 0–2 s0 8 the V# above, then 00000200 00040000 00000002 0dcf13c8
    images 3–5 s2 8 the T# above, then 00000000 00700000 00000000 00000000

    So each source is read both as a buffer (4 words) and as an image (8 words), and in each pair one of the two readings cannot be right: s0 holds a V# but is used as three images, s2 holds a T# but is used as a buffer.

    Experiment (local, not proposed): replacing the "runtime image descriptor is invalid" throw with a zero descriptor moves the stop to buffer descriptor uses an unsupported type, which is the T# at s2 read as a V#. The same message and the same "type 2" appear in #3709 for Puyo Puyo Tetris 2, where the dispatch ran with a program that does not match its tables.

    I cannot tell from this whether the dispatch is captured with the wrong program, whether the tables are captured before the title wrote them (#3055), or whether the shader is a generic routine that picks buffer or image at run time. Not checked: the shader's instructions.

    AI-assisted (Claude Code).

  5. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    Answer to the open question about the Teardown (PPSA15246) stop (is this the #3709 case, a dispatch whose user data belong to a different program?): the extra debug print (local, not proposed) says the user data are not the problem here.

    • The failing compute shader 0x7ff72c5dc300 uses only 2 user-data words: ud[0] = 0171ff74, ud[1] = 00000002, i.e. one 64-bit pointer, 0x2_0171ff74. The dispatch is therefore not the 14-word layout of Puyo Puyo Tetris 2 (PPSA01530): a 14-word image-descriptor dispatch runs with the fill kernel's program (no shader load before it in its submission) #3709.
    • All descriptors come from the memory that pointer addresses (an SRT), through 4 descriptor sources: source 0 (8 dwords), source 1 (4), source 2 (8), source 3 (4).
    • From the earlier dump: source 1 is the V# and source 3 the T#, and sources 0 and 2 start with exactly the same four dwords. So the shader reads the same two addresses twice, once as 4 dwords (buffer) and once as 8 dwords (image), and in each pair only one reading is a valid descriptor of that kind.

    I cannot tell from this alone whether the SRT block is filled correctly when the dispatch is captured (#3055 describes a block still all 0xFF at capture, which is not the case here: the words are real descriptors) or whether the shader has a run-time path that selects between a buffer and an image use. Next step would be to read the shader's s_load_dwordx4/s_load_dwordx8 and the image_*/buffer_* instructions that use them; I have not done that.

    AI-assisted (Claude Code).

  6. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    Read the failing Teardown (PPSA15246) compute shader 0x7ff72c5dc300 (212 code words, 8x8x1, APS5_DUMP_SHADERS=1 + agc_shader_replay --asm). It is a generic copy kernel that picks buffer or image at run time, so the "two readings of the same address" are two different branches, and only the taken one is valid. The offline replay itself stops earlier with ReadConst(GetSrtResource ...) because the dump does not contain the SRT block, so the decode below is from the raw words (instruction families read from the encodings: f4.. SMEM, f0.. MIMG, e0.. MUBUF).

    Source side, then destination side, each with the same shape:

    0x38 s_load_dwordx4 s[12:15]            ; mode word s12 read from the SRT
    ...  s_cmp_eq_u32 0/1/2, s12 ; s_cbranch_scc1 -> variant 0/1/2
    0x9c s_load_dwordx8 s[4:11]             ; T# (8 dwords)     -- variant 0, 1, 2
    0xa8 image_load (MIMG op 0) ... s[4:11]  ; one per variant (3 of them)
    0xe4 s_load_dwordx2 / 0xfc s_load_dwordx4 s[4:7] ; fallthrough: V# (4 dwords)
    0x110 buffer_*(MUBUF op 3) ... s[4:7]    ; the buffer variant
    ...
    0x118 s_load_dword -> vcc_lo ; s_cmp_eq_u32 0..3, vcc_lo ; same pattern for the store:
    0x150 image_store (MIMG op 8) ... (3 variants) or 0x1b8 buffer store (MUBUF op 7)
    

    That gives exactly the 2 buffers + 6 images from 4 sources in the debug print: the source is read as a V# (buffer variant) or as a T# (3 image variants), the destination as a T# (3 image variants) or a V# (buffer variant). In this dispatch the source address holds a V# (06400000 00040002 00040000 00014204, stride 4) and the destination holds a T# (type 9 = 2D): a buffer-to-image copy. The three image-load variants on the V# and the buffer-store variant on the T# are never executed; the hardware never looks at them.

    So this is not a capture or SRT problem: the SRT is filled correctly. The materializer validates every source of the plan eagerly, including those that sit behind a branch on a run-time value (s12, vcc_lo), and throws on the untaken ones (runtime image descriptor is invalid, and, once that is relaxed locally, buffer descriptor uses an unsupported type). All four sources were reported active=1, so the activation analysis (activeSources) did not resolve these branches although s12 is a value loaded from memory the walker can read; I have not looked at why.

    Possible directions (not done, not proposed as a patch): resolve the branch from the loaded mode word so the untaken sources are inactive, or accept an invalid descriptor for a source whose use is behind a run-time branch and let the generated code skip it. Which is right is a design choice for whoever owns ResourceMaterializer / SrtWalker. I have not verified how Puyo's #3709 dispatch relates; it may be the same kernel family or not.

    AI-assisted (Claude Code).

  7. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    Correction to my earlier comment here: I wrote that the Teardown stop is "the same class as #3709 and #3055". It is not. In #3709 (Puyo) the failing kernel is a dword-pattern fill with a single buffer-store path and the T# really sits in COMPUTE_USER_DATA_0..7; in #3055 (GTA V) the V# words are ffffffff because the block is not yet written at capture. The Teardown shader is different: a generic copy kernel with run-time branches between a buffer and an image path (see my later comment with the instruction extract), and its SRT is filled correctly. A change that skips the untaken paths would not change the result of #3709 or #3055.

    AI-assisted (Claude Code).

  8. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    Update on the Teardown (PPSA15246) stops, with the branch behind #3952 (now two commits: sources, then images) plus #3824 and #3604:

    • The second stop (image descriptor is incompatible with the static runtime image interface: descriptor format 20 decodes to {class 2, dim 3 ...}; modes: {class 1, dim 4 ...}) has the same cause one level down. RuntimeImageMode (ResourceMaterializer.cpp, the throw near the end) runs for every image resource, and the three image_store variants of the copy kernel have different dimensions but sit on the same T# address, so they share one descriptor source and the source stays active while the taken variant needs it. fix(recompiler): leave out descriptor sources behind a branch the capture decides #3952 now tracks the images a block uses as well (ResourceBlock::images), and an image used only behind a branch the capture does not take is bound as a null descriptor. The T# is 2D (dim 3 in the printed enum, Dim2D); the variant that is taken matches it, the others (Dim3D, ...) do not.
    • With that, the copy kernel compiles and the title runs on. The next stops are sceNpTrophy2GetGroupInfo: invalid argument (std::invalid_argument, abort) and AGC graphics: CMASK fast clears of a mipmapped, 3D or array color target are unsupported. I have not looked at either yet.

    AI-assisted (Claude Code).

  9. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    Teardown (PPSA15246): the next stop after the copy kernel (with #3952, #3824, #3604 and #3517 applied) is AGC graphics: CMASK fast clears of a mipmapped, 3D or array color target are unsupported (Graphics/src/State.cpp:912, the Require(maxMip == 0 && !volume && slice == 0, ...) under if ((info & 0x2000u) != 0)). A local print before that Require gives the case:

    maxMip=5 viewMip=1 volume=0 slice=0 CB_COLOR_INFO=0000a028 attrib2=500a4029 attrib3=4dc6c000 extent=21x21 CB_COLOR_VIEW=04000000

    So it is none of the "3D or array" cases: a 6-level color target (base about 42x42, the view extent is 21x21) is bound at mip level 1, slice 0, with the FAST_CLEAR bit (0x2000) set in CB_COLOR_INFO.

    Reference reading, from Session C (Mesa radeonsi/si_clear.c, si_fast_clear, GFX10 branch; Mesa is not PS5-specific): Mesa only does a CMASK fast clear for level 0 and never for a view of another mip level, and does none for several layers together with several mips. So there is no Mesa case for what the title does here; I did not check how the console handles it and I am not proposing to loosen the check.

    Not known: whether this is a clear at all (the bit might stay set on a normal draw into the mip) and what CMASK region the hardware uses for level 1.

    AI-assisted (Claude Code).

  10. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    On the open question of whether CB_COLOR_INFO.FAST_CLEAR (bit 13, 0x2000; Linux gc_10_1_0_sh_mask.h CB_COLOR0_INFO__FAST_CLEAR_MASK) marks a real CMASK clear or just stays set: in Mesa's radeonsi it is a sticky per-texture state flag, not a per-clear one. si_clear.c (around line 109) does tex->cb_color_info |= S_028C70_FAST_CLEAR(1) when a texture is first fast-cleared, and si_state.c (around line 2760) ORs tex->cb_color_info into every later framebuffer setup, so ordinary draws to that texture carry the bit. For GFX < 11 it then removes the bit again when the bound level is above 0 (if (cb_psurf->level > 0) cb_surf.cb_color_info &= C_028C70_FAST_CLEAR;), because CMASK only covers level 0. So Mesa never programs FAST_CLEAR together with a view on mip 1; the title here (maxMip=5, viewMip=1, CB_COLOR_INFO=0x0000a028, as quoted above) does, which Mesa does not explain either way. What the sources support is only the first half: the bit alone does not prove that a clear happens in this draw, so a draw with the bit set and no CMASK clear in the stream is not necessarily a fast clear. I found no shadPS4 or KytyPS5 code on this bit (no search hit) and no console documentation; Mesa is a non-PS5 source, so this is not evidence of what the console does at mip 1.

    AI-assisted (Claude Code).

  11. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    Status of the PRs this issue lists (open, checked now): #3824 (mergeable, approved), #3952 (mergeable), #758 and #3604 (both with changes requested and conflicting with main). None of them is merged, so the Teardown stops described here are not fixed on main; I did not run the title for this comment.

    AI-assisted (Claude Code).

  12. oneandonlydean commented on Oct 13, 2026

    @oneandonlydean
    Collaborator

    #3824, #3952 and #3604 are on main now. What is the first stop of PPSA15246 on plain main?

  13. pushkarreddyy commented on Oct 13, 2026

    @pushkarreddyy
    Contributor

    @oneandonlydean With #3824, #3952, #3604, and #3517 (sceNpTrophy2GetGroupInfo) all on main, the first stop of PPSA15246 (Teardown) on plain main is:

    AGC graphics: CMASK fast clears of a mipmapped, 3D or array color target are unsupported
    

    with register state:

    maxMip=5 viewMip=1 volume=0 slice=0 CB_COLOR_INFO=0000a028 attrib2=500a4029 attrib3=4dc6c000 extent=21x21 CB_COLOR_VIEW=04000000
    

    This is addressed in #4965: on single-sample views with viewMip > 0, CMASK fast-clear decoding is skipped (cmaskAddress = 0, cmaskFastClear = false) since AMD hardware CMASK metadata only spans base mip 0 (matching Mesa radeonsi's handling in si_state.c where FAST_CLEAR is masked off for level > 0).

  14. oneandonlydean commented on Oct 14, 2026

    @oneandonlydean
    Collaborator

    Closing: fixed on main by #3824 (the two libSceCesCs imports), #3604 (sceNpAuthGetIdTokenV3) and #4965 (the CMASK fast-clear stop on mip > 0 views). If it still happens on current main, comment here with the title ID and the log line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions