Commit Graph
119 Commits
Author SHA1 Message Date
Adrià ea5c27b53e Merge pull request #6025 from wh1trope/perf/dominator-bitsets
perf(shader): intersect dominator sets as bitsets
2026-10-17 05:30:45 +02:00
Alex ColliniandClaude Opus 5.5 7a6cc71786 feat(agc): carry spanned waves in the target and require full subgroups
APS5_SPANNED_WAVE is now read once by the driver, which sets
SpirvTarget::spannedWaves only on a device with 32-lane compute subgroup
control and computeFullSubgroups. The recompiler no longer reads the
environment. The field is part of the cache key and of the request
serialization (version 32), so a cached or replayed module keeps the mode
it was built in.

A spanned module numbers its lanes SubgroupId * 32 +
SubgroupLocalInvocationId, which needs two full 32-lane subgroups. The
artifact records this as fullSubgroups (disk cache and pipeline identity
included), and the driver creates those pipelines with
REQUIRE_FULL_SUBGROUPS. Compute pipeline captures accept the flag with a
required subgroup size.

The two-lane fallback now catches only SpannedWaveUnsupported, thrown for
a shuffle wider than 32 bits; other emit errors surface as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:12:58 +02:00
billybobpicklioandClaude Opus 5.5 a0347cfed5 feat(agc): draw line-strip output of NGG geometry programs as mesh lines
A geometry program with VGT_GS_OUT_PRIM_TYPE 1 was refused as an
unsupported output assembly. Each primitive export of an NGG line-strip
program is one line whose indices are packed like a triangle's, so the
mesh module now declares OutputLinesEXT with PrimitiveLineIndicesEXT for
it. A subgroup gets VGT_GS_MAX_VERT_OUT - 1 lines per input primitive and
at least GE_MAX_OUTPUT_PER_SUBGROUP line slots; fast launch keeps using
PRIM_AMP_FACTOR. The output size is part of the cache, draw, validation
and pipeline keys, and the request serialization version becomes 31.
Triangle-strip geometry is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 15:39:35 -04:00
NikoandClaude Opus 5.5 16ea32c97d feat(agc): blend into color targets with a reversed component order
8_8_8_8 and 16_16_16_16 targets with COMP_SWAP 2 or 3 keep the exported
alpha in their first channel and red or blue in their fourth, so a plain
Vulkan blend would run the alpha equation on a color channel. Such draws
threw "blending into a color target with a reversed component order is
not implemented" (Gran Turismo 7, #4782).

The AMD SI and CIK register references describe CB_TARGET_MASK in the
order of components after blending and before COMP_SWAP is applied, and
RADV programs CB_BLENDn_CONTROL without regard to the swap while it
renders R4G4B4A4, B4G4R4A4, R5G5B5A1 and B5G5R5A1 through SWAP_STD_REV
and SWAP_ALT_REV and passes the CTS blend tests on Navi10. The color
block is therefore taken to blend in export order: the alpha equation
and source-alpha factors use the exported alpha and the destination
alpha is the first channel.

TranslateReversedBlend keeps the factor pairs Vulkan applies per channel
in the pipeline. Other source factors are computed by the pixel shader
from its MRT0 export (clamped for UNORM targets, as BLEND_CLAMP says)
and handed to the blend as a dual-source second color, which the
fragment output post-pass adds at location 0 index 1; when both
positions need it, the export is premultiplied by its source factor.
The code is a pipeline specialization, serialized in request version
26, and stays out of the prepared shader key.

sRGB, SNORM and integer targets, constant and second-source factors,
destination alpha in the color equation, destination factors the two
equations do not share, different color and alpha operations, MIN or
MAX with factors other than ONE, other color exports when the shader
computes factors, and devices without dualSrcBlend still throw, now
with the blend control, mapping and format in the message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:51:27 +02:00
fdfawef324 1ffc5f672b feat(agc): emulate per-pixel multisample coverage masks
Decode the four PA_SC_AA_MASK fields at the rasterized sample count. Use the native Vulkan mask when all four pixels agree and apply varying masks in the fragment shader, preserving helpers and combining coverage with alpha-to-coverage and shader mask exports. Add the normalized masks to pipeline, draw and shader keys and the versioned replay request.

Refuse unsupported conservative-raster, centroid and early depth/stencil memory-write cases. Synthetic readbacks cover driver submission, depth/stencil suppression, fragment stores and one-sample and four-sample coverage.
2026-10-15 13:00:34 +13:00
Michon 72518f64fb feat(agc): single-sample sample masks as a per-quad-pixel discard
With one sample, PA_SC_AA_MASK leaves one coverage bit per pixel of the 2x2 quad,
so a draw can cover only some pixels of every quad (GTA V renders a target one
quarter of the pixels at a time this way). The pixel stage info carries that 4-bit
mask; a fragment shader whose mask is not full starts by killing the invocation
unless its gl_FragCoord quad position is covered, and runs without early fragment
tests. The mask is part of the recompile cache key and the serialized request
(version 24). Sample masks of multisampled draws stay refused.
2026-10-15 12:59:39 +13:00
XairRrR 8dbf06798c fix(shader): honour SPI_BARYC_CNTL.FRONT_FACE_ALL_BITS for the front-face input
The front-face VGPR was always +1.0 / -1.0, which is its form only while
FRONT_FACE_ALL_BITS is clear (current Mesa reads it with fgt 0 / fsign).
With the bit set, as Mesa 22.0 RADV programs it, a back face reads 0 and
a front face non-zero: ACO then tests it with v_cmp_lg_u32 0. Uncharted:
Legacy of Thieves Collection (PPSA05684) sets the bit and its two-sided
cloth shaders test v_cmp_lt_u32 0, so -1.0 (0xbf800000) made every back
face a front face: the insides of the menu skeleton's rags kept their
front normals and were lit white by the spot light behind them.

The pixel stage info now carries the bit (request version 26, cache and
draw keys), the decode reads SPI_BARYC_CNTL when FRONT_FACE is an active
input, and the translator turns the builtin into 0xffffffff / 0. The
exact front value is not measured (docs/dev/debt/shader.md).

AI-assisted: yes
2026-10-14 21:37:48 +02:00
wh1tropeandCursor b44ee9c45b perf(shader): intersect dominator sets as bitsets
Structurizing recomputes dominators after every CFG rewrite, and each block started from a vector of every block id. The same fixed point now runs on bitsets and still writes the sorted id lists.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 21:20:45 +02:00
TripyFoxandClaude Opus 5.5 3c1f43948b fix(shader): fault only where a table call misses its linked callees
An s_swappc_b64 whose target is not resolved compiles to a faulting call
only at the fallback the table-call linker emits; the linker lists those
calls in the request (GuestContext::linkedCallFallbacks), and every other
computed call is refused at compile time again, as on main. The new
agc_driver_compute_table_calls test runs a linked two-record table on
Vulkan in wave32 and wave64, with SCC 0 and 1 reaching the callee, and a
record past the table reporting the UnlinkedCall fault.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 06:44:25 +13:00
TripyFoxandClaude Opus 5.5 9c8fb780e8 feat(shader): link callees of calls whose target is loaded from a table
An s_swappc_b64 whose target pair comes from an s_buffer_load of a buffer
whose descriptor is loaded from user data now calls the targets that buffer
holds: at dispatch the driver reads the buffer, links one copy of each
distinct callee after the caller and rewrites the call into a compare chain
that s_call_b64s the matching copy. A target that matches no copy, and any
other computed call, records an UnlinkedCall fault that the driver reports,
instead of failing the shader at compile time.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 06:44:07 +13:00
Adrià 131171e772 Merge pull request #4840 from Lorkydey/feat/shader-fragment-user-data-tail
feat(shader): link raw fragment epilogs through user data
2026-10-14 14:56:34 +02:00
Adrià 781b33d3ca Merge pull request #4821 from Lorkydey/feat/shader-vertex-user-data-tail
feat(shader): link raw vertex prologs through user-data tails
2026-10-14 13:57:10 +02:00
Romans Pokrovskis c8b3a37533 feat(agc): emulate default eight-sample dithered alpha coverage 2026-10-14 12:58:43 +03:00
Dean 327249d4e9 Merge pull request #5028 from nikowolf123/perf/structurizer-attempt-budget
perf(recompiler): iterate structurizer fixpoints in post-order and bound shared merge splitting growth
2026-10-14 20:45:02 +13:00
Dean eac1e26e29 Merge pull request #4926 from nikowolf123/feat/structurizer-complete-fallback
feat(recompiler): structure every control-flow graph the structurizer refuses
2026-10-14 20:44:09 +13:00
Dean 5ee94cf571 Merge pull request #4201 from Celegans12/feat/agc-tessellation-relative-patch-data
feat(agc): rebuild the hull's relative patch index when it is used as data
2026-10-14 20:39:33 +13:00
Celegans12 2eda9f893c feat(agc): rebuild the hull's relative patch index when it is used as data
Hull programs whose relative patch index (v1 bits 7:0) reached anything
but a tessellation ring or LDS address threw, because the lowering runs
every Vulkan patch as relative patch 0. The quad terrain hull 0x80002fc700
in Ghost of Yotei is one, and so is the domain 0x8068fbd900 (v7).

Such hulls and domains now take (PrimitiveID mod GE_CNTL.PRIM_GRP_SIZE)
mod VGT_LS_HS_CONFIG.NUM_PATCHES, as if hull threadgroups took NUM_PATCHES
patches at a time out of each primitive group; both stages see the same
PrimitiveID for a patch. This holds only when every instance starts a new
threadgroup, so it needs GE_CNTL.BREAK_WAVE_AT_EOI (bit 18); with the bit
clear the instances share threadgroups and such programs still throw.
PRIM_GRP_SIZE and BREAK_WAVE_AT_EOI join the tessellation configuration
(draw keys, hull and domain cache keys, request version 24). A missing
GE_CNTL throws, and so do local programs, whose relative vertex index
depends on vertex reuse that Vulkan does not expose.
2026-10-14 04:59:07 +02:00
NikoandClaude Opus 5.5 2c53270b94 perf(recompiler): iterate structurizer fixpoints in post-order and bound shared merge splitting growth
The structurizer's attempts could spend more than 10 s on a graph of 20
blocks before they accepted or refused it; in a title that stalls shader
preparation. Nearly all of that time went to recomputing dominators and
post-dominator fixpoints while merge splitting grew the graph to
hundreds or thousands of blocks.

Dominators, post-dominators and the fixpoints in mergeBesideReturns,
iterationSelectionMerge and joinWithinIteration now sweep the blocks in
reverse post-order (dominators) or post-order (the others) instead of in
id order. Splitting appends its new blocks at the end, so id order needed
a sweep for almost every new block. Each fixpoint starts from the full
set and its equations are monotone, so every sweep order reaches the
same greatest fixed point and the result does not change.

Shared merge splitting also refuses an attempt once the graph has more
than 16 times its block count at the start of splitting (at least 64
blocks). Without it, splits that route through a new junction each round
grew some graphs past 4,000 blocks before the round budget ran out. A
refused attempt goes to the next attempt or to the reach-flag fallback,
as it does after the round budget.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:00:21 +02:00
NikoandClaude Opus 5.5 1c958de097 feat(recompiler): structurize refused control flow with reach flags
When every attempt of the structurizer ladder refuses a graph, the title
aborts. Rebuild such a graph from a hierarchical decomposition into
strongly connected components instead: each original block keeps one copy
and runs behind a guard on its own reach flag, and each component becomes
a loop with a single latch that repeats it while a back edge set its again
flag. Every edge sets the reach flag of its target, so exactly one flag
names the next original block and the blocks run in the input's order for
every branch decision. Irreducible and non-terminating graphs are handled
the same way, and no block is cloned.

The ladder runs first and its output is unchanged. The fallback only runs
when both attempt series refuse; if it cannot structure the graph, the
ladder's error is reported as before. Blocks that start the top-level
order unconditionally run unguarded, so the entry block's results reach
later blocks without a stale path. APS5_FORCE_STRUCTURIZER_FALLBACK=1
uses the construction for every supported graph, for tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 00:59:50 +02:00
lorkydey e229262449 feat(shader): link raw fragment user-data tails with a constant high half 2026-10-13 21:34:59 +02:00
lorkydey bbeec6d0b4 feat(shader): link raw vertex prologs through user-data tails 2026-10-13 21:18:49 +02:00
MarcZX100 2ad825f659 fix(shader): require the version 22 F16 request flag 2026-10-13 19:09:49 +00:00
MarcZX100 dffdb5002e fix(shader): read both version 21 request layouts 2026-10-13 19:09:49 +00:00
TideOPL de5279bc0c fix(shader): serialize the pixel layer export flag from request version 23
main allocates request version 22 to the tessellation patches per group, so a version 22 request has no layer export byte.
2026-10-13 15:23:21 +01:00
TideOPL 7015c0443e fix(shader): read the ancillary render target index from Layer when the draw exports it 2026-10-13 15:15:55 +01:00
Adrià 2cf23fcc56 Merge pull request #4114 from Celegans12/fix/agc-tessellation-num-patches
fix(agc): bound tessellation patch records by the draw's patch count
2026-10-13 15:40:48 +02:00
Celegans12 25a83722c7 fix(agc): bound tessellation patch records by the draw's patch count
TessellationLowering proved ring and LDS addresses affine over a
relative patch index of up to 256. A hull that lays its patch-constant
records out downwards, at 0x8000 - 208 * (rel + 1) like the quad
particle hull in Ghost of Yotei, then reached a negative address for
the last slot and aborted as "not affine". The relative patch index of
hull and domain programs stays below VGT_LS_HS_CONFIG.NUM_PATCHES
(bits 7:0, patches per threadgroup), which is 63 for that draw.

DecodeShaderStages now carries NUM_PATCHES as patchesPerGroup in the
tessellation configuration (draw keys, hull and domain cache keys,
recompile request version 22) and refuses zero, and the lowering bounds
the relative patch index by it. Configurations without it keep 256.
2026-10-13 13:50:27 +02:00
Karan Vora e4f212b2e2 perf(shader): convert f16 operands with UnpackHalf2x16 where f16 denormals are kept
Since #1463, every f16 operand read decodes sign, exponent and mantissa
with integer operations, 8 to 12 instructions more per read than
UnpackHalf2x16 on NVIDIA. The decode works around an AMD Windows driver
that folds the mask of a byte-selected half into UnpackHalf2x16.

A new target flag, float16DenormPreserve, is set when the device reports
shaderDenormPreserveFloat16 and denormBehaviorIndependence ALL, the same
rule as float64DenormPreserve. With it, EmitF16BitsToF32 uses
UnpackHalf2x16 and declares DenormPreserve for 16-bit floats, under
which SPV_KHR_float_controls keeps unpacked subnormal halves. NVIDIA
returns the default NaN for every NaN half, so the NaN bits are rebuilt
from the half: its sign at bit 31, its payload at bits 22:13. The
DenormPreserve 16 mode is declared once, shared with the native f32 to
f16 conversion. Without the flag (lavapipe; RADV reports 32_BIT_ONLY)
the integer decode stays. Halves of fields narrower than 16 bits, such
as SDWA byte selects, keep the integer decode on every device.

The flag is serialized (request version 17) and part of the cache key.

New test agc_driver_f16_to_f32_unpack converts all 65,536 halves, with
nonzero high bits, through v_cvt_f32_f16, and byte-selected halves
through v_add_f16 SDWA, with each decode the device supports, and
compares the bits with an exact decode. agc_driver_f16_to_f32_unpack_spirv
checks which decode the SPIR-V uses with and without the flag.
2026-10-13 12:15:00 +02:00
eljackjoestar-cmd 2ae227ef85 fix(agc): integrate merged position exports and request version 21 2026-10-13 13:03:12 +04:00
04138f50ad feat(agc): vertex clip and cull distances
PA_CL_VS_OUT_CNTL's clip and cull enables and its misc and distance vector bits reach the recompiler's vertex info (request version 20), the draw key, the vertex-info comparison and the recompile cache key. Registration and draw-time preparation set them the same way the draw does; a program without pos1..pos3 exports gets none, so its artifact does not depend on the register. Guest clip distances share main's gl_ClipDistance array with the all-zero position distance; cull distances need shaderCullDistance. Up to eight clip and cull distances are accepted.

Co-Authored-By: john.maia <hi@johnmaia.dev>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 21:37:49 +13:00
Dean Galvin c52321fab5 fix(shader): move the primitive class to request version 19 and compose the ancillary word with render target index 0
main reads target.vertexSubgroups at request version 18 since #4470, so
reading the pixel primitive class at 18 as well read a version 18
request written by main one byte short. The class is now written and
read at version 19. agc_shader_memory loads a version 18 request as
main writes it, and it fails with "truncated data" when the class is
read at 18.

The composed word no longer reads the Layer builtin for bits 16-28.
Draws render to a single layer and guest layer exports are ignored, so
no stage writes Layer, and AMD's Windows driver drops the writes of a
fragment shader that reads it unwritten (#4800). The field is the
constant 0 and pixel_ancillary checks that the composed program has no
Layer read. The debt entry names the bits that have no source and are
assumed zero (2-7, 12-15, 29-31), and says that a change which makes
draws export a layer must restore the read.
2026-10-13 13:18:51 +13:00
AlxcBTWandClaude Opus 5.5 18d9874a06 feat(shader): give reads the masked-select pass keeps the whole pixel ancillary word
A packed ancillary word that still reaches an export, or any other read
the masked-select pass cannot drop, no longer stops the recompile. After
that pass every remaining use gets the composed word: the primitive class
at bits 0-1, SampleId at bits 8-11 and Layer at bits 16-28, with every
other bit zero. Those lanes do export the ancillary VGPR on the console,
so the word has to be right, not just present.

The primitive class (0 point, 1 line, 2 triangle, 3 rectangle) comes from
the draw. RasterPrimitiveOf maps rect lists to 3, line lists on the vertex
path to 1 and everything else the driver accepts to 2, because its
geometry and tessellation paths only output triangles. It reaches the
shader as pipeline specialization constant 8233, the way dual-source
blending does: a request field that is folded into the specialized
module and is part of the result memo, the draw key and the serialized
request (version 17).

Only shaders that read the class pay for it. ShaderInfo records the read
(disk cache format 28), and only those shaders put the class in their
module key, so a shader that reads just the sample or layer field keeps
one module for every primitive class. The draw sets the class only when
the pixel shader loads the ancillary VGPR, so other draws keep the draw
cache entries they have today.

The VRS rates (bits 2-5) and the eye id (bit 7) are 0 because the driver
supports neither VRS nor multiview. SampleId is 0 because the driver
rejects MSAA and per-sample shading, and Layer is 0 while it ignores
vertex layer exports. TechnicalDebt.md records the layout sources and
these assumptions.

Tests:
- pixel_ancillary builds an export to target 0 whose two channels select
  between a packed value and a phi carrying the word. It checks the word
  for each primitive class, sample and layer, checks that the three
  shapes the masked-select pass keeps now compile with the composed word,
  and that a program whose select the pass drops reads no class.
- agc_driver_pixel_ancillary_word exports the word from a draw and reads
  back 2, 3 and 1 for triangle, rectangle and line. A shader that reads
  only the sample field shares one module across the classes, and the
  whole-word shader gets one per class. It also checks RasterPrimitiveOf.
- agc_shader_memory covers the version 17 round trip, and
  agc_shader_disk_cache the new flag.

Both ancillary tests fail with the old refusal when the composition is
disabled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:06:21 +13:00
Dean 0c75934f5f Merge pull request #4470 from overlordxrz-source/fix/vertex-one-lane-waves
fix(recompiler): run vertex programs as one-lane waves without vertex subgroups
2026-10-13 07:34:13 +13:00
Dean 5d933db02e Merge pull request #4364 from SleglJan/fix/structurizer-return-join
fix(recompiler): give an early-return selection a merge when its parent's other arm reaches the same join
2026-10-13 07:33:30 +13:00
overlordxrz-source 0bcff53b2c fix(recompiler): run vertex programs as one-lane waves without vertex subgroups
lavapipe and MoltenVK leave the vertex stage out of subgroupSupportedStages,
so the driver's shader validation refuses every vertex program that declares
GroupNonUniform ("subgroup capability 61 is unsupported for shader stage 1").
Most do, since the entry EXEC is a ballot.

The device target now records whether the vertex stage has subgroups. When
it does not, vertex and local programs get a host subgroup width of 1: s3
reports one vertex and one primitive, the lane id is 0, a ballot is the
invocation's own bit, a shuffle returns the invocation's value, an elect is
true and a half-wave reduction read is the key itself. Reads of other lanes
keep the existing narrow-host rules and throw where they did. Devices with
vertex subgroups emit the same SPIR-V as before.
2026-10-12 08:50:05 -04:00
Adrià 2979ae37a3 Merge pull request #4152 from adriadam10/feat/phase-b
perf(agc): build shader pipeline libraries when shaders are registered
2026-10-12 10:31:42 +02:00
Adrià FranchandClaude 361c7e2024 perf(agc): keep oversized shaders specialized and prebuild libraries on their own thread
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià FranchandClaude ddb6680667 perf(recompiler): read buffer V# words in the shader when modules are built at registration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:32 +02:00
Jan ŠléglandClaude Opus 5.5 7f5cd4480d fix(recompiler): give an early-return selection a merge when its parent's other arm reaches the same join
A selection outside loops whose one arm only returns and whose other arm
branches to a join it does not dominate gets an empty block on that edge
as its merge (splitOneReturnJoin), but only when every other predecessor
of the join dominates the selection or is dominated by it. When the
parent selection's other arm is a region that ends in the same join, the
selection has no structured merge and the shader fails to recompile.

When every structurization attempt fails, Structurize now runs them again
and accepts that split for any join the selection does not dominate. The
split only inserts an empty block on the edge from the selection to the
join. Graphs that structurize on main keep their result.

A synthetic CFG and a synthetic program cover the shape; both fail on main
with "conditional block N has no structured merge".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fnrk5Dazjb2tLooVSpdRQq
2026-10-12 09:11:25 +02:00
Dean Galvin 22d662eda7 fix(agc): export the stencil reference from pixel shaders with VK_EXT_shader_stencil_export 2026-10-12 19:44:41 +13:00
Dean 6b0ce1513d Merge pull request #4018 from Mouhand-Kaddo/fix/demons-loop-continue
fix(shader): keep Demon's Souls loop shader valid after optimization
2026-10-12 17:29:21 +13:00
Adrià f35bcafbee Merge pull request #3662 from Celegans12/perf/recompiler-iteration-selection-storage
perf(recompiler): reuse sorted sets for iteration selection merges
2026-10-11 23:44:59 +02:00
Mouhand Kaddo 9d8ee3de7d fix(shader): isolate single-block loop continue targets
Route semantic self-loops through a dedicated empty back-edge block. This prevents block merging from folding the continue target into the loop header when memory instructions emit nested selections. Add a synthetic loop-store regression that fails SPIR-V validation after optimization on main.
2026-10-12 01:26:17 +04:00
Celegans12 76fa2beceb perf(recompiler): reuse sorted sets for iteration selection merges
Seed each iteration-selection update from its first eligible successor
instead of rebuilding and intersecting the universe of block IDs.
Reuse the existing in-place intersection and sorted-insertion helpers
while preserving the original empty-successor and fixed-point behavior.
Keep a cache-neutral switch for same-binary output and timing comparisons.
Run the existing structurizer and control-flow fixtures in a separate
process with this optimization disabled as well as in their default mode.
2026-10-11 16:06:57 +02:00
Scramblrrrr 3943287d63 refactor(shader): drop the overlapping global loop join fallback 2026-10-11 10:00:07 -03:00
Scramblrrrr 3a80442635 fix(shader): validate conditional exits before accepting every fallback 2026-10-11 10:00:07 -03:00
Scramblrrrr b23b54a6d7 perf(shader): avoid rerouting synthetic loop-exit forwarders 2026-10-11 10:00:07 -03:00
Scramblrrrr 901c627862 fix(recompiler): preserve the guarded loop exit fallback before shared routing
Keep the AlxcBTW #24 fallback as a separate guarded attempt before enabling shared-exit and nested-continuation repairs. Add the reduced padded shader reported by orishamir on #2523 as an end-to-end regression; the abstract graph does not reproduce the same failure.
2026-10-11 10:00:07 -03:00
Scramblrrrr b0c86ec07f fix(recompiler): privatize shared continuations before loop gateways 2026-10-11 10:00:07 -03:00
Scramblrrrr e6c8e1e9c7 fix(recompiler): route shared loop exit selections in the guarded fallback 2026-10-11 10:00:07 -03:00