aboutsummaryrefslogtreecommitdiff
path: root/src/shader_recompiler
Commit message (Collapse)AuthorAgeFilesLines
* Merge pull request #304 from rdenno/fix/hw-shader-loweringJonas27 hours1-10/+43
|\ | | | | shader: lower F2I.F16, TLD/TLD4.F16 and partial-mask TXD (Hyrule Warriors black gameplay)
| * Merge branch 'nx2-experimental' into fix/hw-shader-loweringrdenno37 hours2-95/+381
| |\ | | | | | | | | | | | | | | | | | | | | | nx2-experimental lowers partial-mask TXD as well (Splatoon Raiders). Keep its RZ second destination and this branch's odd register for a lone third channel; take its wider F2I mode check with the .H1 source. Assisted-by: Claude Opus 5.5 (conflict resolution)
| * | shader: lower TXD with any channel maskrdenno37 hours1-11/+17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | TXD was only lowered with all four channels (and rejected any instruction without a second destination, as RZ & 1 is set). Hyrule Warriors: Age of Imprisonment's gradient-sampling programs fetch one channel into Rd, or three channels with the third in the second destination, and were rejected ("native gradient texture mode"), so their draws were skipped. Pass the channel mask on to Maxwell TXD. The first two enabled channels go to Rd, Rd+1 and the others to the second destination; when those aren't consecutive, write to scratch and move them as the four-channel case already did. Assisted-by: Claude Opus 5.5 (diagnosis, fix and testing)
| * | shader: lower TLD and TLD4 with half-precision resultsrdenno37 hours1-0/+29
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | TLD.SCR and TLD4 with .F16 (bit 79) return their components packed in pairs: components 0 and 1 in Rd, 2 and 3 in the second destination. The lowering rejected them ("native texel fetch mode", "native texture gather mode"), so the compute programs using them never ran. In Hyrule Warriors: Age of Imprisonment these are compute programs that run once gameplay starts, and gameplay stayed black (the pause menu, drawn another way, showed the scene). Lower the F32 form into R248/R249 and R246/R247, then pack each pair the way F2FP.PACK_AB is lowered. Assisted-by: Claude Opus 5.5 (diagnosis, fix and testing)
| * | shader: lower F2I from a half with a sign or high-half selectorrdenno37 hours1-3/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | F2I from an F16 source was only lowered unsigned and from the low half. F2I.F16 (signed, bit 72) and F2I.U32.F16 Rd, Rs.H1 (bits 60-61) were rejected ("native float-to-integer conversion mode"); Hyrule Warriors: Age of Imprisonment has 24 such programs. Accept bit 72 as the other F2I forms do, and pick the high half for .H1. Assisted-by: Claude Opus 5.5 (diagnosis, fix and testing)
* | | shader: drop the slots of a failed handle subtree with its codeSssnowyyy31 hours1-4/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When BuildHandleProgram failed on a subtree it truncated the code back to where the subtree started, which removed the Tee ops of the values the subtree had kept, but their entries stayed in g_handle_slots. A Phi tries its other inputs after the first one fails; if one of them reused a value from the dropped subtree, it emitted a Load of a slot that nothing wrote, so the handle read 0. Number slots with a counter instead of counting map entries, and on failure erase the entries numbered from the subtree's first slot on and rewind the counter, so such a value is built again. Follow-up to 561f87abec. Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
* | | shader: restore the handle build depth when a build throwsSssnowyyy31 hours1-4/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | BuildHandleProgram incremented g_handle_depth and decremented it at the end, so a NotImplementedException from BuildHandleNode left the thread-local depth above zero. That thread never cleared g_handle_slots again, and stale IR::Inst* keys from an earlier program could match instructions of a later one (a freed instruction's address can be reused). Do the decrement and the outermost clear in SCOPE_EXIT. Follow-up to e23b0f2fab. Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
* | | shader: evaluate handle programs for image and texture buffer descriptorsSssnowyyy31 hours2-5/+38
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 561f87abec only gave TextureDescriptor a handle_program. Image load/store/atomics and texture/image buffers whose handle comes from a storage buffer still got the placeholder constant buffer address (index 0, offset 0), so the pipelines read cbuf 0 word 0 as the handle (and asserted if cbuf 0 was unbound). Add handle_program to TextureBufferDescriptor, ImageBufferDescriptor and ImageDescriptor, compare it when merging, and let all four pipelines evaluate it for every descriptor kind instead of only TextureDescriptor. ImageQueryDimensions on such a handle was always declared Color2D, so array, cube and 3D views got a 2D declaration. The instruction carries no type, so take it from another instruction using the same handle program, falling back to Color2D when there is none. Follow-up to 561f87abec. The OpenGL pipeline edits are the same change as the Vulkan ones but were not compiled here. Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
* | | shader: tell handle-program textures apart when adding descriptorsSssnowyyy31 hours1-1/+6
| |/ |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Every texture whose handle is computed per draw gets the same placeholder constant buffer address (index 0, offset 0), and Descriptors::Add did not compare handle_program. Two such textures of the same type and depth in one shader therefore shared a descriptor, so the second sampled the first, and one could also merge with a real texture bound at constant buffer 0 offset 0. Compare handle_program too. The pixel-format-integer lookup cached its last answer by (index, offset), which has the same problem for handle programs; skip that cache for them. Follow-up to 561f87abec. Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
* | Merge nx2 into nx2-experimentalkraibse37 hours2-98/+387
|\ \ | |/ |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Resolved by area: - audio feature_support.h: nx2's native revision handling. - fiber.cpp: ours, which also drops the unused rewind stack. - host_memory.cpp: ours granule bitmap and HintCold, plus nx2's fallocate hole punching per whole dirty granule on Linux. - texture_cache.h: nx2's old-age eviction pass, then our Collect(). - kepler_compute.cpp: shared upscale slots, then Fortune's Weave's, then the Kirby Air Riders scan. - nx2_gsv.h: ours, plus nx2's GetBufferMaxResolution and graphics device ids (1-based). - nvhost_ctrl_gpu.cpp: engine support flag bits 40-44. - lower_to_maxwell.h: ours as the base, with nx2's seven lowering commits applied one at a time. Second texture descriptor buffers are read bindless in TEX, TLD.SCR (level zero) and SUST; FSEL keeps its operand modifiers; TXD takes any channel mask. lower_to_maxwell.h lowers 837 Fortune's Weave and 1183 Mario Kart World shader dumps with the same rejects as nx2 and ours (12 and 0). Assisted-by: Claude Sonnet 5.5 (conflict analysis and drafting)
| * shader: keep root table reads the blit constants would zeroDuck9122 days1-1/+11
| | | | | | | | | | | | | | | | | | | | | | | | Fire Emblem: Fortune's Weave's enemy health gauges read only offset 0x40 of root table 0, which is inside the blit parameter block (title 4's zero dither bias). The pass replaced it with zero and the gauges drew black. A shader that reads only words the block leaves zero now keeps its reads: an unbound bank reads zero anyway, and a bound root table keeps its values. Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
| * video_core: keep root tables and bind table 0 as constant bank 17Duck9122 days1-0/+21
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The 3D methods 0x504/0x508 write eight 256-byte root tables, which shaders read as constant banks 24-31; NVN2 keeps push constants in table 0 (bank 17 after the Ampere lowering). Fire Emblem: Fortune's Weave keeps its material constants there and never binds bank 17, and the blit constants pass replaced those reads with render-target sizes, flooding its 3D scenes red. Maxwell3D now keeps the tables, the buffer cache streams table 0 as bank 17 when the game has not bound one, and the blit constants pass leaves shaders that read bank 17 outside its parameter block alone. Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
| * shader: count only register writes in the callee link checkDuck9122 days1-2/+7
| | | | | | | | | | | | | | | | | | | | | | The check that a native callee keeps its link register read bits 16-23 of every instruction as a destination. RET was exempt, but BRA, NOP and ISETP/FSETP (which write predicates) also have zero there, so callees with an R0 link that compare or branch were rejected. IMAD.WIDE writes a register pair, so its second register now counts as well. Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
| * shader: apply FSEL's floating operand modifiersDuck9122 days1-1/+3
| | | | | | | | | | | | | | | | | | | | FSEL dropped the negate and absolute value modifiers of its sources. Fire Emblem: Fortune's Weave's sky vertex shader builds its cube corners with FSEL R, -1.0 forms: every corner came out +1.0, the cube collapsed to one point and the sky was flat. SEL (integer) is unchanged. Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
| * shader: lower more conversion, comparison and memory formsDuck9122 days1-28/+66
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Other instruction forms Fire Emblem: Fortune's Weave's shaders use: - I2F.F32.U64/S64 from a register pair, and F2I.S32.TRUNC without FTZ. - FMNMX.NAN (an unordered pair gives the canonical NaN). - FSET.BF with a uniform register operand (0xc0a), used by battle scene shaders that were rejected and left the screen white. - MATCH.ALL.U32, next to U64. - IDP.2A.LO.U16.U8. - USHF with UR16-UR27 (was UR0-UR15). - STG with desc[URn][Ra.64] addressing, as LDG, and the LDG descriptor form with any URn (was UR0 only). Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
| * shader: lower more 64-bit integer carry formsDuck9122 days1-31/+171
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Address arithmetic in Fire Emblem: Fortune's Weave's shaders that the lowering rejected: - IADD3 with a third source, negated sources or two carry-outs, and IADD3.X with two carry-ins. - IMAD.X RZ, RZ, c, Pn and IMAD.X Ra, 1, ~c, Pn. - IMAD.WIDE (register, immediate and cbuf pair forms) and IMAD.HI with an addend, both with a carry-out. - LEA with a carry-out, LEA.HI with a high source (a funnel shift), and LEA with a uniform register (0xc11). Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
| * shader: lower warp reductions, shared atomics and descriptor loadsDuck9122 days1-15/+32
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Compute forms Fire Emblem: Fortune's Weave uses: - REDUX.OR and REDUX.MIN (unsigned), next to SUM and MAX. Inactive lanes give the identity (all ones for MIN). - ATOMS.MIN, MAX and OR (U32); the native operation field numbers them as Maxwell's. - LDG with desc[URn][Ra.64] addressing: the uniform pair is a memory descriptor (cache policy), so Ra alone is the address. - BAR.SYNC.DEFER_BLOCKING (bit 80), the usual workgroup barrier. Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting) Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com> Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
| * shader: lower more integer formsDuck9122 days1-20/+127
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Forms Fire Emblem: Fortune's Weave's shaders use that the lowering rejected, mostly 64-bit address and index arithmetic: - ISETP.EX: EQ/NE as the high comparison ANDed/ORed with the low words' predicate, unsigned LT/LE/GT/GE as (hi < or > hi) || (hi == hi && low). - IMAD.HI signed (bit 73), and with a constant buffer multiplier (0xa27). - IMAD.X Rd, Ra, 1, Rc, Pn (an add with carry). - IADD3.X with a register first source or a uniform operand, and IADD3 with a uniform operand and a carry out. - LEA.HI.X (carry in) with a register base, and LEA.HI.X.SX32 with a constant base. - SHF with a constant buffer shift amount (0xa19). - IMNMX with a negative immediate. - F2I.FTZ.U64.TRUNC (0x311). Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting) Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com> Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
| * shader: read extra texture descriptor buffers bindlessDuck9122 days1-43/+108
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Maxwell's bound texture instructions read every descriptor from one constant buffer per program, but Fire Emblem: Fortune's Weave's shaders sample from more than one (bindings 4-7, 14 and 15 next to an earlier one). The lowering rejected the second binding, so most of its graphics programs failed and 3D scenes stayed black. A binding that conflicts with the program's buffer is now read bindless: the handle is loaded from its buffer with an unpredicated MOV and passed as the first meta register of TEX.B, TLD.B or SUST.B. The TEXS fast path and the array depth form check the buffer instead of setting it to 2. Also lowered: TEX with the handle in a register (0x361, packed or not) or a uniform register (0xf60), TXQ on any binding and the mip count query, TXQ.B (0x370), TXD with any channel mask and .NODEP, and SUST.STRONG.GPU fenced with MEMBAR.GL on both sides. Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting) Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com> Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
* | Merge branch 'fix/nx2-hsetp2-register' into nx2-experimentalTakoroka44 hours1-3/+12
|\ \
| * | nx2: lower the HSETP2 register formTakoroka2 days1-3/+12
| | | | | | | | | | | | | | | | | | | | | | | | Mario Kart World has a compute shader with HSETP2.EQ.AND P0, PT, R44.H0_H0, R44.H1_H1, P0 (opcode 0x234), which only had the immediate form (0x434) and so rejected the whole program. Lower it to Maxwell HSETP2 (reg) the same way, with the B register, swizzle, abs and neg in bits 20-31.
| * | Revert "nx2/ampere: implement ISBERD (0x923) and accept ISBEWR (0x927)"kraibse2 days1-30/+0
| | | | | | | | | | | | This reverts commit d9e4ac8360b3b63b7ddba05757c87e867f9163fa.
| * | Revert "Code review, cleanup and fix"kraibse2 days1-27/+22
| | | | | | | | | | | | This reverts commit 67d53ce505814d7032de19d5a7417d0482d970aa.
| * | Code review, cleanup and fixnéo Luigi2 days1-22/+27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The skew bit was leaking into Maxwell's immediate, so the lane offset is now computed the outpur reads, immediates of `0x80` or more, and map reads with an immediate are rejected; Dropped ISBEWR writes are now logged; English comments and 3 unit tests AI disclosure: used Claude opus 5.5 (code cleanup & code comparaison)
| * | nx2/ampere: implement ISBERD (0x923) and accept ISBEWR (0x927)Paulo Rossatto2 days1-0/+30
| |/ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Mario Kart World submits native programs that use ISBERD/ISBEWR (stage buffer entry read/write, Ampere/Turing era). Both fell into the default branch and the whole program was rejected, so the objects and effects those programs draw popped in and out of the scene every frame. ISBERD has a direct Maxwell counterpart (maxwell.inc: "1110 1111 1101 0---"), and the Maxwell frontend already implements the full semantics (patches, primitives, indexed attributes and the per-lane skewed global read), so lower it there instead of failing: Ampere fields (Mesa NAK sm70_encode.rs, OpIsberd): dst 16-23, offset 24-31, imm 40-55, mem_type 74-75, access 76-77, skew 78, output 79. ISBEWR has no Maxwell equivalent. Rejecting the program makes the object disappear, so the write is dropped instead: the value written is a stage output, and losing it only leaves that one output stale. Measured on Mario Kart World (Windows 11, MSVC 19.44, AMD RX 5700): rejected native programs per session drop from 11 to 2, and the remaining two are the unrelated \"Unsupported native graphics shader stage 3/4\" path. Objects that used to flicker now render consistently.
* | nx2: lower the TXD and TXQ variants Splatoon Raiders uses latekraibse2 days1-1/+2
| | | | | | | | | | | | | | | | | | Three pixel shaders were rejected, skipping their draws (fog missing). TXD refused word 2 bit 90, which its own emit already forwards as NODEP; TXQ refused mask 4 (depth), whose Maxwell mask bit is passed through as for the other masks. (cherry picked from commit a42b4d4c744e12ce5262648eee50daecd1ca4681)
* | Merge commit 'e23b0f2fab9014225486beebd82fab8dbc0fe14c' into ↵Takoroka2 days1-12/+14
|\ \ | | | | | | | | | test/linux-all-prs-plus
| * | shader: keep the handle slot map thread-local instead of a pointer to itTakoroka2 days1-12/+14
| | | | | | | | | | | | | | | | | | | | | BuildHandleProgram stored the address of its outermost call's local map in a thread_local pointer for the nested calls, which GCC 15 rejects with -Werror=dangling-pointer. The map itself is thread_local now, and a depth counter tells the outermost call to clear it.
* | | Merge remote-tracking branch 'origin/fix/nx2-storage-buffer-texture-handles' ↵Takoroka2 days4-8/+552
|\| | | | | | | | | | | into test/linux-all-prs
| * | shader: compute texture handles read from storage buffers for each drawTakoroka3 days3-6/+543
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Switch 2 shaders can read a texture handle from a storage buffer (Switch Sports' scenery: a per-object entry of a table whose pointer is in the driver constant buffer). The bindless handle search looked through the load into its address and returned the table pointer's constant buffer word as the handle, which named an arbitrary descriptor; the game repoints that one at transient render targets every few seconds, so the island and menu lighting flipped between correct, dark and red. The search no longer looks into memory loads. A handle it cannot trace is now built into a small program over constant buffer words, storage buffer words and integer operations (Shader::Info::handle_programs), which the pipelines evaluate when they bind the texture. Handles a single evaluation cannot give (one that changes in a loop) keep the previous search.
| * | nx2: drop R2UR's unreachable keep-old-value select when unpredicatedTakoroka3 days1-2/+9
| |/ | | | | | | | | | | | | | | | | | | | | | | R2UR was lowered as "the value of the first lane in the ballot, else the uniform register's old value". With no execution predicate the ballot always holds the executing lane, so the fallback is never taken, but it stayed in the program as a second source of the result. The texture handle search found it first: in Switch Sports the uniform register had just held a storage buffer pointer loaded from the constant buffer, so the scenery's texture handle was traced to that pointer word instead of to the value the shader moved in. Write the broadcast value directly when the instruction is unpredicated.
* | video_core: keep task/mesh pipelines out of the disk pipeline cacheTakoroka2 days1-1/+2
| | | | | | | | | | | | | | | | | | Task and mesh programs are translated with the mesh registers and the pass-through geometry header, which the cache format does not carry: a stored pipeline loaded them as zero ("Mesh output topology 0"). Do not store these pipelines and skip any that were stored, so the format and CACHE_VERSION stay as they are (a version change would delete the cache other builds share). The topology error also shows SET_MESH_SHADER_A.
* | shader_recompiler: translate Switch 2 task and mesh programsTakoroka2 days30-8/+703
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Mario Kart World draws some of its geometry with NVN task and mesh programs (the task program culls and writes the mesh workgroup count and a payload to its stage buffer; each mesh workgroup reads it back and writes vertices and primitives). Add Task and Mesh stages and translate them for VK_EXT_mesh_shader: - the ISBE pseudo instruction from the lowering becomes reads and writes of an emulated stage buffer: the task's output region is the task payload, the mesh output regions live in workgroup memory - every EXIT of these stages jumps to one final return, so all invocations reach the epilogue: a barrier, then OpEmitMeshTasksEXT, or OpSetMeshOutputsEXT and a copy of the 32-element vertex and primitive groups (lines named by the mesh header's and the pass-through geometry header's output maps) to arrayed and per-primitive outputs - Sirit lacks the two mesh instructions: they are emitted as OpStore markers and replaced after assembly - fragment inputs a mesh program writes per primitive get PerPrimitiveEXT The captured task and mesh programs of the title translate to SPIR-V that spirv-val accepts.
* | nx2: keep ISBERD/ISBEWR and lower UPOPC for task and mesh programsTakoroka2 days1-0/+23
| | | | | | | | | | | | | | | | | | Mario Kart World draws some geometry with task and mesh programs that read and write the stage buffer (ISBE) with ISBERD and ISBEWR. Pass them through as an nx2 pseudo instruction in a free Maxwell opcode (0xefc0), with the register, offset, size, region, skew, output and write fields, for the frontend to translate per stage. Also lower UPOPC like the other uniform bit operations. Every dumped program of the title now lowers.
* | nx2: lower TLD.SCR with a texel offsetTakoroka2 days1-2/+8
| | | | | | | | | | | | Bit 76 puts a texel offset after the coordinates and level. For 2D it maps onto Maxwell TLDS 2D.LZ.AOFFI (x, y in Ra, Ra+1, offsets in Rb) and 2D.LL.AOFFI (level and offsets in Rb, Rb+1).
* | nx2: lower TLD4 with a texel offsetTakoroka2 days1-7/+16
| | | | | | | | | | Bit 76 puts a texel offset after the coordinates, as for TEX: x and y in Ra, Ra+1 and the offsets in Rb. Maxwell TLD4 takes it as AOFFI (bits 54-55) from Rb.
* | nx2: lower ISETP.EX, the high half of 64-bit comparesTakoroka2 days1-1/+32
| | | | | | | | | | | | | | | | ISETP.EX compares the high words and folds in the low words' result, passed as the predicate at bits 68-70 (negated by 71): EQ is high equal AND low, NE high different OR low, the orderings high strictly ordered OR (high equal AND low). Lower it to one or two Maxwell ISETPs into the destination. Switch Sports' scenery shaders null-check 64-bit texture handles this way; 168 of them were rejected and drew black.
* | nx2: keep the uniform clamp before a jump table when instructions sit betweenTakoroka2 days1-4/+19
| | | | | | | | | | | | | | | | | | | | | | | | A jump table index clamped with UISETP.LT.U32 UP0, UPT, URa, n and USEL URa, URa, n, UP0 is lowered to IMNMX.U32 so Maxwell's indirect branch tracker can size the table, but only when the UISETP came right before the USEL. Nintendo Switch Sports Resort's pixel shaders put ordinary ALU instructions between them, so the USEL became a SEL, the BRXU could not be tracked and 6 pipelines failed ("Failed to track indirect branch"). Look back up to 8 instructions, stopping at any that could write uniform state or branch, or that a branch seen so far lands on.
* | nx2: mirror uniform registers above UR27 below R216Takoroka2 days1-4/+21
| | | | | | | | | | | | | | | | | | | | Uniform registers have GPR mirrors only for UR0-UR27 (R216-R237, R240-R245). Kirby Air Riders' graphics shaders load a 64-bit base into UR28:UR29 (ULDC.64 UR28, c[0x0][0x510]) and address global loads with it (4 programs). When a program uses UR28 or above, lower it again with those registers mirrored just below R216 (UR28 at R(216 - n), n even so pairs stay adjacent) and that range kept from the program's own registers; other programs keep the same layout.
* | nx2: lower TMML.BTakoroka2 days1-10/+14
| | | | | | | | | | | | TMML.B.LOD RZ, R18, R12, R16, CUBE (Kirby Air Riders) takes the handle in Rb and every coordinate from Ra; lower it to Maxwell TMML.B, as the uniform-handle form is.
* | nx2: lower TEX.B with an explicit LODTakoroka2 days1-4/+5
| | | | | | | | | | | | | | | | Kirby Air Riders samples a cube texture at an explicit level through a bindless handle (TEX.B.LL R20, R16, R12, R16, CUBE): the coordinates stay in Ra (R12-R14) and Rb holds the handle, then the LOD (R16, R17), since five values do not split evenly. Place the values that way and take .LL and .LB (the bias in the LOD's place).
* | nx2: lower TLD4 with a uniform handleTakoroka2 days1-5/+17
| | | | | | | | | | | | TLD4.SCR.G with its handle in a uniform register (Kirby Air Riders; bit 91 set) becomes Maxwell TLD4.B, with the handle first in Rb and the component at bits 38-39.
* | nx2: lower TMML for 1D, 3D and cube textures and with a uniform handleTakoroka2 days1-14/+23
| | | | | | | | | | | | | | | | Kirby Air Riders queries the LOD of a cube texture whose handle is in a uniform register (TMML.LOD RZ, R43, R32, UR4, CUBE, 0x2, in 16 programs). Take the 1D/2D/3D/cube coordinate counts (all from Ra when Rb is RZ, otherwise split as for TEX), and emit Maxwell TMML.B with the handle first in Rb for the uniform form (bit 91).
* | nx2: lower TLD.B at level zeroTakoroka2 days1-0/+33
| | | | | | | | | | | | TLD.SCR.B.LZ (Kirby Air Riders, ARRAY_2D) lists the coordinates and then the handle over Ra and Rb (layer, x | y, handle: the handle is loaded into Rb+1). Maxwell TLD.B takes the handle first in its meta registers.
* | nx2: lower TXQ.B and TXQ with three or four outputsTakoroka2 days1-10/+26
| | | | | | | | | | | | | | | | TXQ.B (Kirby Air Riders) takes the handle in Ra and the level in Ra+1, as Maxwell's TXQ.B does. TXQ took only masks of the first two components: any one or two components now go to Rd, Rd+1, and with a second destination the third and fourth go there (TXQ R1, R2, R1, ..., 0x7 writes the depth to R1), copied out of packed scratch registers.
* | nx2: place TEX.B's handle after the coordinates; take .DC and .LZTakoroka2 days1-14/+19
| | | | | | | | | | | | | | | | | | | | | | | | Ampere TEX.B lists its values as the coordinates, then the handle, then the depth reference, split over Ra and Rb as for bound TEX: 2D.DC is (x, y | handle, reference) and ARRAY_2D.LZ is (layer, x | y, handle), as Kirby Air Riders' shaders build them (the handle is the register they load from the texture constant buffer). The lowering read the handle from Rb and all coordinates from Ra, which holds only without a depth reference for up to two coordinates; place the handle by the layout and take .DC and .LZ (101 TEX.B in 21 programs). Forms with a LOD value or offsets stay unlowered: their place next to the handle is unverified.
* | nx2: lower IADD3.X with a register and a constant buffer operandTakoroka2 days1-2/+3
| | | | | | | | | | | | The constant buffer IADD3.X lowering took only RZ as the first source. Kirby Air Riders adds a register (IADD3.X R32, R32, c[0x3][0x48], RZ, PT, !PT); add it to the carry before the constant.
* | nx2: lower REDUX.MINTakoroka2 days1-6/+10
| | | | | | | | | | | | REDUX.MIN (unsigned; Kirby Air Riders reduces a lane value with both .MIN and .MAX) is lowered as REDUX.MAX with IMNMX selecting the minimum, starting from ~0, with inactive lanes contributing ~0.
* | nx2: lower MATCH.ALL into P6Takoroka2 days1-7/+8
| | | | | | | | | | | | MATCH.ALL used P6 as its scratch predicate and so rejected P6 as the result. Kirby Air Riders' compute shaders write P6 (5 programs); use P5 as the scratch predicate for those.
* | nx2: lower USHF on uniform registers above UR15Takoroka2 days1-14/+18
| | | | | | | | | | | | The USHF lowering assumed UR0-UR15 (R216-R231). Kirby Air Riders shifts UR16 and UR18 (USHF.R.U32.HI UR5, URZ, 0x14, UR16, in 12 programs); map the registers with uniform_register, as the other uniform ops do.