Skip to content

fix(shader): emit nothing for a vertex s_barrier that precedes every memory access - #6613

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
milescoviello:fix/vertex-barrier-before-memory
Oct 19, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
milescoviello:fix/vertex-barrier-before-memory

Conversation

@milescoviello

@milescoviello milescoviello commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

What

A vertex-path program that touches LDS or GDS or writes memory refuses any s_barrier:

SPIR-V emission failed: ... opcode=Barrier reason=s_barrier in a vertex program that accesses LDS or GDS or writes memory is not implemented

NGG passthrough programs (VGT_SHADER_STAGES_EN PRIMGEN_EN + PRIMGEN_PASSTHRU_EN) start with the s_barrier that orders GS_ALLOC_REQ. Crimson Desert (PPSA25286) registers one, routing 0x2402000, 2133 instructions. Its only barrier is at pc 0x20, after a few scalar instructions, and it writes a buffer about 7 KB later (buffer_atomic_add at 0x1e78, then three buffer_store_dwordx4). Its registration preparation fails with the line above, and the draw that uses it rethrows it.

A barrier that runs before every memory access of the program has nothing to order: no load, store, atomic, image or LDS access can happen before it in any wave. Such a barrier now emits nothing, the same as the barrier of a program with no memory access. The check walks the entry block and its straight-line successors. A barrier behind a memory access, a branch or a merge still throws.

Tested

Linux (Ubuntu 24.04, GCC 13.3, Release), RTX 4070 Ti, NVIDIA 595.99.

  • agc_vertex_barrier: a vertex program with s_barrier before a ds_write_b32, and one with a scalar instruction ahead of the barrier, compile without an OpControlBarrier. The existing case with the LDS write before the barrier is still refused. With main's SpirvFlowEmitter.cpp the new cases fail with the refusal above. 3 of 3 runs pass.
  • ctest (^agc_vertex_barrier|^agc_driver_(ngg|vertex|mesh|graphics|prepared|tessellation)): 30 of 30 pass.

Crimson Desert (PPSA25286) with #6612, which gets it past its first stop:

Build Result
main 5d9dcc4 + #6612 stops 123 s in on the refusal above
main 5d9dcc4 + #6612 + this PR reaches the 150 s limit with no stop

Validated on Windows 11 with an AMD Radeon 860M (RDNA 3.5, driver 32.0.13058.8001) by @LeandroLP23 (comment), in one build of main 6efb726 with this head and 13 other pull requests: agc_vertex_barrier passes 3 runs of 3. 713 of 716 agc_* tests pass; the 3 that fail fail the same way on main there.

Not checked on Intel or on a console.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none (the title runs need feat(agc): draw tessellation followed by an NGG geometry stage #6612)
  • Unblocks: none
  • GPUs tested: NVIDIA GeForce RTX 4070 Ti, driver 595.99, Ubuntu 24.04; AMD Radeon 860M, driver 32.0.13058.8001, Windows 11 (tests, by @LeandroLP23)
  • AI-assisted: yes

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 4072 core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
PR 5021 core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
docs/dev/debt/shader.md
PR 5371 docs/dev/debt/shader.md
PR 5426 docs/dev/debt/shader.md
PR 5500 docs/dev/debt/shader.md
PR 5941 docs/dev/debt/shader.md
PR 6009 docs/dev/debt/shader.md
PR 6235 docs/dev/debt/shader.md
PR 6674 docs/dev/debt/shader.md
PR 6767 docs/dev/debt/shader.md
PR 6924 docs/dev/debt/shader.md
PR 6947 core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
PR 6977 docs/dev/debt/shader.md
PR 7085 docs/dev/debt/shader.md
PR 7223 docs/dev/debt/shader.md
PR 7332 core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
docs/dev/debt/shader.md
PR 7392 core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
docs/dev/debt/shader.md
PR 7395 docs/dev/debt/shader.md
PR 7429 core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
docs/dev/debt/shader.md
PR 7484 docs/dev/debt/shader.md
PR 7642 core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp

@LeandroLP23

Copy link
Copy Markdown
Contributor

AMD on Windows: the tests this PR names pass on an RDNA 3.5 GPU.

Radeon 860M (RDNA 3.5, driver 32.0.13058.8001), Windows 11 26300, WinLibs GCC 15.2.0 r7, Release. main 6efb7261b with this PR (1ce582ebc) merged, together with #7296, #7446, #7377, #7445, #6708, #6748, #6785, #6706, #7449, #7391, #7489, #7484, #7514. They were built once, so the result is for the combination; each merge was clean.

  • agc_vertex_barrier: pass, 3 runs of 3.
  • Every agc_* test on the combined build: 713 of 716 pass. The 3 that fail, agc_driver_host_import_lifetime, agc_driver_quad_pixel_mask and agc_driver_layered_volume_vertex_no_gpl, fail the same way on unchanged main here, so none comes from these PRs.

AI-assisted

@milescoviello

Copy link
Copy Markdown
Contributor Author

Thanks @LeandroLP23 for the AMD run on Windows. I added it to the description.

AI-assisted: yes (Claude Code)

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 18, 2026
…memory access

A vertex-path program with LDS, GDS or memory writes refused any s_barrier. NGG passthrough
programs start with the s_barrier that orders GS_ALLOC_REQ, before any memory access, and some
write buffers later. A barrier that runs before every load, store, atomic, image or LDS access of
the program has nothing to order, so it emits no instruction, like the barrier of a program
without memory access. Barriers after a memory access still throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@milescoviello
milescoviello force-pushed the fix/vertex-barrier-before-memory branch from 1ce582e to 7092dde Compare October 19, 2026 01:21
@milescoviello

Copy link
Copy Markdown
Contributor Author

Rebased onto main 0c25997 (7092dde). The only conflict was in docs/dev/debt/shader.md, where main had updated the clip/cull distance entry next to this PR's s_barrier entry. Both are kept: this PR's s_barrier text and main's clip/cull text. The 35 tests matching ^agc_vertex_barrier|^agc_driver_(ngg|vertex|mesh|graphics|prepared|tessellation) pass.

AI-assisted: yes (Claude Code)

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 19, 2026
@adriadam10 adriadam10 self-assigned this Oct 19, 2026
@adriadam10
adriadam10 merged commit 9bfbedc into boykopovar:main Oct 19, 2026
10 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the entry-block walk (entry has no predecessors, any branch/merge stops it, memory-access set covers const, LDS, buffer, address and image ops), the new tests (fail on main without the change; the LDS-before-barrier case still throws) and the TechnicalDebt line. Merging through the queue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* docs shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants