Repository navigation
fix(shader): capture image descriptors read from constant buffers at uniform offsets - #5188
Conversation
…uniform offsets GetHandle refused every T# whose dwords are scalar buffer loads (ReadConstBuffer) before ValidateSource looked at them. Tables with a 32-byte stride and a wave-uniform key are planned as bindless tables before GetHandle runs, so the refusal only hit the other cases: a T# read at an offset the runtime walk can evaluate, like Resident Evil Village's mesh programs (48-byte records with the T# at +16, the record index read through two more constant buffers keyed by user data). ValidateSource already decides whether such a chain is a uniform runtime value, so leave the decision to it; the walk then reads the T# at each capture.
boykopovar#757 and boykopovar#758 add their image table checks where this check was, after verifyBindlessTable, so the pull requests conflicted.
* Metal semantics: run upstream image execution tests through the Metal driver The existing semantics shim binds only guest buffers. A second shim (tests/metal_semantics/driver_shim) runs the upstream execution tests that bind images, samplers and color targets through the native Metal driver: dispatches bind their descriptors with MetalShaderResources and draws go through MetalDraw::DrawSynchronously, as in a title. The tests' host arrays are the guest memory; the device borrows every range the shader's buffer and image descriptors and the color targets name. ImagePlaneAddressOnLine and ImageVolumeAddressOnPlane (already on main) now run on Metal and pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj * fix(shader): capture image descriptors read from constant buffers at uniform offsets Removes the tracker check that refused a T# whose dwords come from a ReadConstBuffer, so a T# loaded with s_buffer_load from a table record that user data selects is captured like any other runtime descriptor. Metal: tests/metal_semantics/ImageTableRecord.cpp runs the upstream program through the Metal driver (MetalShaderResources image binding) and checks that the record user data selects is the texture sampled. It fails on main with the removed "is not a valid runtime value" error. Ported from upstream PR boykopovar#5188 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj * fix(shader): accept TYPE=0 images during materialization A T# with TYPE=0 is null on AMD hardware even when its base and other words are nonzero; the materializer now accepts it as a null image instead of refusing it as invalid (reserved TYPE=1 is still refused). Upstream's frontend test is ported to tests/ShaderMemory.cpp. Metal: the Metal image binding already treats TYPE=0 as null (IsNullTextureResource), so such an image binds no texture. The Metal ImageTableRecord test now also samples a TYPE=0 record with a nonzero base and reads zero; on main it fails with "runtime image descriptor is invalid". Debt note added to docs/dev/TechnicalDebt.md. Ported from upstream PR boykopovar#5473 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj * fix(shader): read 1D T#s through 3D image_sample and image_load accesses A DIM 3D image_sample_lz, plain image_sample or mip-less image_load whose T# is 1D gets a runtime image mode that binds the 1D texture: the sample reads the texel u selects, and the load reads the x texel when z is 0 and zero otherwise, as measured on RDNA1. Other 3D accesses of such an image still throw. ImageResource gains flatVolumeLineCompatible, so the shader disk cache FormatVersion goes from 35 to 36. This is the only bump in this series: the later image-mode fields reuse it. Metal: the 1D mode binds through the existing Image1D shape (a 2D texture of height 1) with no new view. Upstream's ImageVolumeAddressOnLine execution test runs unchanged through the Metal driver (anyps5_metal_driver_semantics_imagevolumeaddressonline). It fails without the materializer hunk ("incompatible with the static runtime image interface"). Debt note added to docs/dev/TechnicalDebt.md. Ported from upstream PR boykopovar#5375 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj * fix(shader): sample single-level volumes through biased 2D accesses A pixel-stage, direct, plain 32-bit image_sample_b with DIM 2D whose T# is a one-slice, single-level 3D image gets the 3D runtime image mode: the sample supplies a zero third coordinate and keeps the bias, as measured on RDNA2. The binding requires a normalized point sampler and the descriptor one slice and mip zero; other cases throw. ImageResource gains singleMipPlaneBiasCompatible; it is encoded by the shader disk cache under the FormatVersion 36 bump of this series (upstream's own bump to 31 is not taken). Metal: the 3D mode binds the volume as the Image3D shape it already has, with no new view. Upstream's ImagePlaneBiasOnSingleLevelVolume execution test (a pixel draw) runs unchanged through MetalDraw (anyps5_metal_driver_semantics_imageplanebiasonsinglelevelvolume). It fails without the tracker hunk ("incompatible with the static runtime image interface"). Debt note added to docs/dev/TechnicalDebt.md. Ported from upstream PR boykopovar#5461 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj * fix(shader): decode forced degamma on biased RGBA8_UINT samples A direct RGBA8_UINT image sampled only by plain biased pixel accesses (the one-slice volume case of boykopovar#5461) through samplers that all set FORCE_DEGAMMA is materialized as RGBA8_SRGB, which returns the same decoded floats as the hardware. Mixed sampler states, indirect images, other accesses and formats still throw. Metal: MetalSampler refused every FORCE_DEGAMMA S#, so this (and the existing sRGB case of ImageSampleForceDegamma) could not bind. Metal now does what the Vulkan driver does: MetalShaderResources::Bindings creates the sampler with forceDegammaPaired and refuses a sampled image of a non-sRGB format paired with a forcing sampler (the same message as RequireDegammaFormat). The rewritten descriptor binds through the existing sRGB pixel-format view. Upstream's extended ImagePlaneBiasOnSingleLevelVolume and the existing ImageSampleForceDegamma tests now pass on Metal; both failed with "forces sRGB decoding which is not implemented". Debt note added to docs/dev/TechnicalDebt.md. Ported from upstream PR boykopovar#5472 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj * fix(shader): read cube T#s through DIM 2D image_sample and image_load as face 0 A DIM 2D image_sample_lz, plain image_sample, image_sample_l or mip-less image_load whose T# is a cube gets the cube runtime image mode and reads the T#'s BASE_ARRAY face with face coordinate 0, as measured on RDNA1. Other DIM 2D accesses through a cube T# still throw. ImageResource gains cubeFaceCompatible; encoded under the series' FormatVersion 36 bump. Metal: a cube T# is already a 2D-array texture of faces and the cube mode binds the Image2DArray shape, so no new view is needed. Upstream's ImagePlaneAddressOnCube execution test runs unchanged through the Metal driver (anyps5_metal_driver_semantics_imageplaneaddressoncube) and fails without the materializer hunk. Debt note added to docs/dev/TechnicalDebt.md. Ported from upstream PR boykopovar#5509 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj * fix(shader): compare through 2D image_sample_c on 1D T#s The flat-line (2D access through a 1D T#) compatibility now ignores the compare flag, so image_sample_c and image_sample_c_lz with DIM 2D on a 1D T# take the 1D mode like their non-compare forms. Metal: the 1D mode binds through the existing Image1D shape (a 2D texture of height 1), with no new view. Upstream's ImagePlaneCompareOnLine execution test runs unchanged through the Metal driver (anyps5_metal_driver_semantics_imageplanecompareonline) and fails without the tracker hunk. The debt note in docs/dev/TechnicalDebt.md is updated as upstream's. Ported from upstream PR boykopovar#5456 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj * fix(shader): apply the V# DST_SEL to formatted buffer stores buffer_store_format_* (D16 included) wrote memory component i from data VGPR i whatever the V#'s DST_SEL. A formatted store now writes each format component from the slot its selector names, only for the DST_SELs measured on RDNA2 or covered by conformance tests: the identity, Z,Y,X,W on 8_8_8_8_UNORM and 16_16_16_16_UINT, and 0,0,0,X on 8_UNORM and 8_UINT. Every other DST_SEL on a formatted store is refused: a host V# throws in DescriptorBindingBuilder::Prepare, and a GPU-selected V# records an invalid-descriptor BDA fault and skips the store. BufferResource gains formattedWritten; encoded under the series' FormatVersion 36 bump. Metal: the store is lowered in the shared SPIR-V (SpirvRuntimeBuffer), so no Metal binding change. Upstream's BufferStoreFormatDstSel execution test runs unchanged through the Metal driver (anyps5_metal_driver_semantics_bufferstoreformatdstsel). Without the SpirvRuntimeBuffer hunk it fails (Z,Y,X,W on 8_8_8_8_UNORM writes 0x4033bfff, expected 0x40ffbf33). Debt note added to docs/dev/TechnicalDebt.md. Ported from upstream PR boykopovar#5172 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Data point from another title. Marvel's Wolverine (PPSA03671, 01.001.005), Linux, RTX 3080 Ti (NVIDIA 615.71.09): on AI-assisted; the runs are from my machine. |
… table cannot express its operation An image table cannot store, update atomically or read PCK and BY2/BY4 through its records (#757): those operations fault and read zeros. #6243 turns a heap T# whose words and record offset the SRT walker evaluates into a selected one-record table, which kept that limitation although such a T# is one known descriptor, as #5188's direct images were. PlanTableColumns now binds such a T# directly, for every operation of the shader on it, when any of them is a store, an atomic, a packed or a BY2/BY4 access. A T# keyed per lane, or by a value the walker cannot evaluate, keeps its table and its unsupported-operation fault. The disk format moves to 37 so that plans cached by #6243's builds are not reused.
What
Resident Evil Village (PPSA01556, content 01.210.000) stops preparing one of its mesh programs while it creates its PSO cache:
The program reads its T# with
s_buffer_load_dwordx8from 48-byte records, with the T# at +16. The record index comes through two more constant-buffer loads keyed by user data. Everything in the chain is uniform per draw, so the CPU walk can evaluate it.ResourceTracker::GetHandlerefused every T# whose dwords are scalar buffer loads (ReadConstBuffer) beforeValidateSourcelooked at them. Tables with a 32-byte stride and a wave-uniform key are planned as bindless tables beforeGetHandleruns, so only the other cases hit the refusal: a T# read at an offset the walk can evaluate.ValidateSource(SrtRuntimeValidator) already acceptsReadConstBufferwith uniform operands and refuses the rest. The pre-check is removed, and the walk reads the T# at each capture.Tested
maina252fcd:agc_shader_memoryverifyUniformTableImage.s_buffer_load_dwordx8ats2 * 48 + 16.main'sResourceTracker.cppit fails with the title's message:GetImageResource dword 0 is not a valid runtime value; chain: ReadConstBuffer@pc=0x0000001c(...).s2 = 2ands2 = 1read the T#s of records 2 and 1.agc_shader_memory,agc_shader_bindless,agc_shader_srt_read_patching,agc_shader_frontend_pair,agc_shader_frontend_pair_offandagc_shader_disk_cachepass, also with the other two Resident Evil Village fixes (listed in Resident Evil Village (PPSA01556) #5169) merged in.maina252fcd: the same six tests pass.mainit stops at the first frame, fix(agc): start the sample location registers at their clear-state value #4949): the mesh program prepares, and the PSO cache build continues past it.python3 tools/check_conventions.py --base origin/main: passed.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)