Skip to content

Recompiler: a deferred compute shader is dispatched and aborts: s_swappc_b64 through a per-lane function table (Ratchet & Clank: Rift Apart) #3274

Closed

Description

@Tamalero

This is the follow-up @EdouardSence mentioned in #1817: a shader deferred by #1836 that a title actually dispatches. In Ratchet & Clank: Rift Apart, 98 shaders are deferred with "calls a computed target". Once the title gets far enough (frame ~437, see #3272), one of them is dispatched and the run aborts:

compute shader 0x116bb5d700: ShaderRecompiler::Recompile: computed/data-dependent s_swappc_b64 call target at program counter 0x00001ac4 is not statically resolvable

The call is not a user-data target like #1817 or #2302. It is a function table: each lane reads a 16-byte record from a buffer, takes the 64-bit code address in it, and calls it in a waterfall loop, one group of lanes per distinct entry. This works like a ray-tracing shader binding table or a material function table: the code that runs is chosen per lane at run time. That is the "arbitrary indirect calls" entry in TechnicalDebt.md, so I am filing it as data for that design rather than proposing a patch.

Details

Title: Ratchet & Clank: Rift Apart (PPSA01474, content 01.005.003)
Where it stops: frame ~437, 1 of 1 runs with APS5_EAGER_WRITEBACK=1. Without it the title instead freezes at frame 456 (#3272) and never dispatches this shader. AnyPS5 f1ae427b plus local patches (listed in #3272). CachyOS, RTX 4090, driver 615.78.

The call site (described, not the game's code)

The shader is 0x5980 bytes and has one computed call. The block before it does this:

index  = v13 + v11                         ; per-lane table index
loop:
  id   = readfirstlane(index)
  exec = lanes where index == id
  desc = s_load_dwordx4  user_data[12:13] + 0x270     ; buffer descriptor
  rec  = s_buffer_load_dwordx4 desc, id * 16           ; {target_lo, target_hi, arg0, arg1}
  s[14:15] = rec.target ; s[16:17] = rec.args
  s_swappc_b64 s[14:15], s[14:15]                     ; link pair == target pair
  restore exec; repeat while lanes remain
  • The target comes from guest memory through a descriptor read from user data, per lane. It is not s_getpc plus a constant, not a user-data pair, and not a code-resident jump table.
  • The link pair is the target pair (s[14:15]), and the call returns with the callee's s_setpc_b64.
  • The same shader also has three bounded s_call_b64 at 0x8ec, 0x4168 and 0x416c that share the link pair s[64:65]. Those may hit the one-call-per-link-pair limit once this one is handled.

What I don't know

  • The table contents. I didn't capture the dispatch's user data, so I don't know how many distinct callees there are, or whether they are other registered shaders.
  • I can dump APS5_TRACE_DISPATCH_IO/user data for this dispatch if that helps choose between a per-dispatch callee set and a registered-callee switch.

Related: #1817, #1836, #2062, #2749 (Stray, same message at many PCs), #2302 (closed: per-dispatch inlining).

Tested and written by Claude (AI assistant) on a contributor's machine.

Activity

  1. MarcZX10 commented on Oct 12, 2026

    @MarcZX10
    Contributor

    The dispatch trace would be useful for deciding whether this can be implemented and tested safely. Could you share the APS5_TRACE_DISPATCH_IO output or equivalent user-data dump for the failing dispatch, especially the function-table entries (target addresses) and which callees are registered or reached? That should clarify the call targets and give us a concrete regression case.

  2. MarcZX10 commented on Oct 14, 2026

    @MarcZX10
    Contributor

    This blocker now has a merged fix: PR #4706 implements linking for table-loaded s_swappc_b64 targets, including the per-dispatch table callee set. The in-game follow-up on that PR reports Ratchet & Clank no longer aborts with this issue’s computed/data-dependent s_swappc_b64 error and reaches a later descriptor-materialization stop. That later stop is separate from the function-table call covered here. Based on that mainline run, #3274 appears resolved by #4706.

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