16 KiB
16 KiB
libSceAgc technical debt
Unknown function info
- PPSA01341 imports declared without parameters, signatures unknown: sceAgcSetSemaphoreMemory. Name from the shadPS4 aerolib NID list
- sceAgcWaitRegMemPatchMask (libSceAgc) - follows
sceAgcWaitRegMemPatchReference: the mask is taken as a 32-bit value and written to the low mask word of a 32- or 64-bit wait, as OpenAGC does; sharpemu writes both words of a 64-bit wait's mask. A mask above 32 bits throws - sceAgcDcbSetCfRegisterDirect, sceAgcDcbSetCfRegisterRangeDirect (libSceAgc) - signatures follow OpenAGC and SharpProspero, which agree; the SET_CONFIG_REG (0x68) packet is OpenAGC's. The driver does not execute SET_CONFIG_REG, so a submitted packet throws
- Command buffer cursors (libSceAgc) - a null
cursor_downis taken as a buffer without downward allocations, whose limit istop. PPSA16064 builds one-packet buffers of 8 dwords that way; the console's handling is unconfirmed - sceAgcGetRegisterDefaultsInternal (libSceAgc) - returns the version 0 internal table, as
sceAgcGetRegisterDefaultsreturns the version 0 public one; OpenAGC returns the table of the version passed tosceAgcInitinstead, and null before it - sceAgcInit (libSceAgc) - unsupported register-default versions return
0x80890001following OpenAGC; AnyPS5 keeps version 13 support because its register-default tables include it, while that reference accepts only versions 0–12. The upper version accepted by PS5 firmware is unverified - sceAgcSetSubmitMode (libSceAgc) - mode values unknown; only 0 is accepted
- sceAgcGetGsOversubscription (libSceAgc) - signature and occupancy formula (base and expanded vertex/export capacities, budget shift,
GE_PC_ALLOC/SPI_SHADER_PGM_RSRC4_GSencoding) follow KytyPS5 only, not confirmed on hardware or a title; a negative or NaN factor that gives a negative target, a missing GS context register or a zeroGE_MAX_OUTPUT_PER_SUBGROUPthrows - sceAgcGetGsPrimPayload (libSceAgc) - the search does not stop at an
SPI_SHADER_IDX_FORMAT(0x1C2) entry whose format is notSPI_SHADER_2COMP, as the analysis of the library declared in the pull request describes (its origin and firmware version are not identified), while OpenAGC stops there; not verified on PS5 hardware. A null payload, a null shader or a register count with a null register array throws instead of faulting on the memory access - sceAgcCbCondWrite (libSceAgc) - argument order and the 9-dword COND_WRITE layout follow the clean-room OpenAGC and sharpemu, which agree on them; SharpProspero lists another order. The write space is accepted only as 1 (memory), the one value both encode the same way, and other values throw.
- sceAgcAcbAtomicGds_0900 (libSceAgc) - signature, control/mode bit mapping and the 11-dword ATOMIC_GDS (0x1d) layout follow the clean-room OpenAGC only, which derives them from the library's disassembly; KytyPS5 and shadPS4 have no body for it. Not confirmed on hardware or a title (PPSA07286 imports it, nothing was run), and the driver has no ATOMIC_GDS handler (opcode 0x1d is not executed as an atomic GDS operation)
- sceAgcGetIsTrinityMode (libSceAgc) - signature from the only PPSA26344 call (a pointer to a one-byte flag, result ignored); a null pointer throws because its error code is unknown
- sceAgcDcbAtomicGds_0900 (libSceAgc) - name from its NID (
zARR5aCmkoY), the DCB counterpart ofsceAgcAcbAtomicGds_0900, signature unknown - sceAgcDcbContextStateOpGetSize (libSceAgc) - sizes from KytyPS5 only (5, 27, 27 and 32 dwords), equal to what
sceAgcDcbContextStateOp_0100writes; KytyPS5 returns 0 for an operation above 3, here it throws - sceAgcBranchPatchSetThenTarget_0300, sceAgcBranchPatchSetElseTarget_0300 (libSceAgc) - names from their NIDs (
7Wa3aeJgeVU,rP5xLdOf26k); the(packet, cachePolicy, target, sizeInDwords)signature is inferred from PPSA28416's calls (a branch packet, 0, an aligned target, 4), with the policy stored wheresceAgcCbBranchputs it - sceAgcDcbSet{Cx,Sh,Uc}RegistersIndirectGetSize (libSceAgc) - the count argument is ignored: PPSA28416 calls them with leftover register contents (0xf5f5039c), so the real functions likely take none; the size is 20 bytes either way
- sceAgcUpdateInterpolantMapping_0100 (libSceAgc) - name from its NID (
k0E7vkgqAuE); the(regs, vs, ps)arguments are the declared ones, behaviour unknown - sceAgcWriteDataPatchSetDst, sceAgcWriteDataPatchSetCachePolicy and their Async forms (libSceAgc) - the signatures
(packet, uint8 value)are inferred from the other patch functions, as no public declaration was found; the value is taken in the encoding of thedstandcachePolicyarguments ofsceAgcDcbWriteData(graphics) andsceAgcAcbWriteData(Async, compute), and the patched packet is the one those calls would write.sceAgcAsyncWriteDataPatchSetAddressOrOffsetis assumed to patch the address likesceAgcWriteDataPatchSetAddressOrOffset, as the compute WRITE_DATA packet keeps it in the same dwords - dbOlWdppb4o (libSceAgc) - unknown name; same arguments as
sceAgcCreateInterpolantMapping_0100; theSPI_PS_INPUT_CNTLbits foris_f162 inputs follow KytyPS5, not confirmed on hardware - sceAgcGetDataPacketPayloadRange (libSceAgc) - signature, the
{base, size in bytes}output and the type 0 range (header + 1, one dword longer than the type 1 payload) from KytyPS5 only, matchingsceAgcGetDataPacketPayloadAddress_0090; prosper returns header + 2 for both types from that address function - sceAgcAsyncCondExecPatchSetCommandAddress, sceAgcAsyncCondExecPatchSetEnd (libSceAgc) - no reference has a body for them; they are assumed to patch the COND_EXEC packet like
sceAgcCondExecPatchSetCommandAddressandsceAgcCondExecPatchSetEnd, sincesceAgcAcbCondExecwrites the same packet assceAgcDcbCondExec, assceAgcAsyncRewindPatchSetRewindStatedoes for REWIND - sceAgcAcbAtomicGds_0900 (libSceAgc) - name from its NID (
gQkqkLttcpw), signature unknown - sceAgcDcbPrimeUtcl2 (libSceAgc) - assumed to write the packet
sceAgcAcbPrimeUtcl2writes: PRIME_UTCL2 has the same 5 dwords on the graphics and compute rings. Not confirmed on a title. Both write a NOP of that size, as there is no TLB to prime - sceAgcDcbQueueEndOfShaderActionGetSize (libSceAgc) - the builder is inline in the SDK and not exported; the size is assumed to be that of the RELEASE_MEM packet
sceAgcCbReleaseMemwrites (32 bytes), the same assceAgcAcbQueueEndOfShaderActionGetSize, as in OpenAGC and REmu - vieBRwlh1Lw (libSceAgc) - unknown name; the
(regs, gs, ps)arguments ofsceAgcCreateInterpolantMapping_0100come from OpenAGC only - sceAgcDcbSetZPassPredicationEnableGetSize, sceAgcDcbSetPredicationDisableGetSize, sceAgcDcbSetBoolPredicationEnableGetSize (libSceAgc) - the builders are inline in the SDK and not exported; the size is assumed to be that of the SET_PREDICATION packet
sceAgcDcbSetPredicationwrites (16 bytes) - vieBRwlh1Lw (libSceAgc) follows OpenAGC only, not confirmed on hardware: the
dbOlWdppb4otransform without the identity tail, so it writes one register per pixel shader input and none for a pixel shader without inputs, and a null pixel shader throws. For anis_f161 or 3 input whosedefault_valueanddefault_value_hidiffer it throws: OpenAGC takesDEFAULT_VALfromdefault_value_hi, while KytyPS5, sharpemu anddbOlWdppb4ohere take it fromdefault_value - sceAgcAcbWaitUntilSafeForRendering (libSceAgc) -
(buffer, videoOutHandle, displayBufferIndex), the declared arguments, which PPSA12544 (01.000.010) passes insidewaitUntilSafeForRenderingandwaitUntilSafeForRendering VRmarkers on an asynchronous compute command buffer, ignoring the result. It writes the same rendering-wait packet assceAgcDcbWaitUntilSafeForRendering, which the driver now accepts on compute queues too; the wait blocks only that queue's worker. Whether the console encodes the compute variant differently is not known
Functional
- sceAgcDebugRaiseException (libSceAgc) - logs the exception id and returns 0, as retail hardware does nothing per OpenAGC; the trap (
ud2) OpenAGC describes for development hardware is not reproduced. Neither is verified on a console. Theuint32exception id is KytyPS5's claim; OpenAGC declares no arguments, so the logged id may be leftover register contents - sceAgcSetAmmSemaphoreMemory, sceAgcGetSemaphoreLabel (libSceAgc) - the
(memory, sizeInBytes)and(index, label)signatures, the 16 KiB alignment of the memory and its size, the single registration, the 32-byte labels and the zeroed first 8 bytes of each are what OpenAGC and sharpemu agree on; KytyPS5 has neither function. OpenAGC clears the whole memory and sharpemu only those 8 bytes, so a registration whose labels hold data past them throws. The two return different errors for every rejected call (OpenAGC0x8a6c0002,0x8a6c000b,0x8a6c0048and0x8a6c0049, sharpemu generic invalid-argument and already-exists errors), so every rejected call throws, including a lookup before registration. Not measured on the console; PPSA02801 imports both (OpenAGC's import analysis), no title is shown calling them. - sceAgcDcbSetWorkloadsActive and sceAgcDcbSetWorkloadComplete (libSceAgc) and sceAgcDriverRegisterWorkloadStream (libSceAgcDriver) - the driver call records only the stream id (1 to 31; it returns 0 for any argument and keeps no stream record), and the DCB calls write the packets KytyPS5 writes: an 18-dword (active) or 12-dword (complete)
IT_NOPpacket with the stream id, and for active the 64-bit mask of the workload ids, for complete the workload id and the 64-bit clear mask of that id. Both return null for a null command buffer, an unregistered or out-of-range stream, a workload id above 63, and for active a duplicate id or a count of 0 or above 63. The layouts and checks come from KytyPS5 alone; the console oracle in prosper measures the null return only for unregistered streams, not the packet contents of a registered one. The error codes the console driver returns for an invalid or repeated registration are unknown, so registration never fails here. PPSA29866 calls sceAgcDcbSetWorkloadsActive while building its command buffers (sceAgcDcbSetWorkloadComplete was not observed); nothing else was observed. - sceAgcDcbSetWorkloadStreamInactive and sceAgcAcbSetWorkloadsActive, sceAgcAcbSetWorkloadComplete, sceAgcAcbSetWorkloadStreamInactive (libSceAgc) - return null without writing to the buffer for a null command buffer or a stream that is not registered (out-of-range ids included), and throw for a registered stream. The console oracle in prosper measured only that null return, with no stream registered, three argument patterns each and nothing written (ACB, DCB); the packet a registered stream gets is not measured. KytyPS5 has no body for these four, and its
IT_NOPlayout for the DCB active and complete calls differs from the SET_UCONFIG_REG, WRITE_DATA and SET_WORKLOAD sequence OpenAGC derives from the driver, so neither is taken. The(buf, streamId),(buf, streamId, workloadId)and(buf, streamId, workloadIds, workloadCount)signatures are those of the DCB calls in OpenAGC, which says the ACB calls use the same driver builders; no ACB declaration was found.sceAgcDcbSetWorkloadsActivechecks the stream before it reads the workload ids, as OpenAGC does: the console returned null for stream 1 with the ids at address 2 (measured) without faulting - sceAgcCreatePrimState (libSceAgc) - the
ge_user_vgpr_enspecial is passed to the user configuration registers at whatever offset the shader header stores, as the SPRX does according to OpenAGC, which copies all four specials verbatim (KytyPS5 stops on any other offset). PPSA99039, PPSA99505, PPSA99515 and PPSA99997 build their headers by hand with it at 0x25c (GE_USER_VGPR1) instead of 0x262 (GE_USER_VGPR_EN), value 0, and run on the console; it is not moved to 0x262, and the driver reads neither register.ge_cntl,vgt_shader_stages_enand a usedvgt_gs_out_prim_typemust still be at their own offsets, since the driver reads those registers there, so a header that stores one elsewhere throws naming the offset, although by OpenAGC the SPRX would copy it as well