Repository navigation
feat(agc): draw radeonsi line and polygon smoothing (SAMPLE_COVERAGE, merged mixed samples) - #6530
Conversation
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
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.
|
|
Cross-validation on Windows 11 Pro 26220, NVIDIA GeForce RTX 4070 (driver 596.21), WinLibs MinGW-w64 GCC 15.2, PR head
OliSe Player PPSA01153 (02.001.000), the same setup as in the description:
The draw no longer stops the title, but the preset is not visible on this machine. After one Square press (the app's help says Cloud Play PPSA99600: main 1 run, this PR 2 runs, all reach 150 s with no stop line (2640; 2270 and 2597 frames). None of the three compiles a Not checked: AMD or Intel (where the merged path throws by design), a console, a run with a module playing, the untrimmed preset folder, the frame rate on an idle host, and Linux. Written with Claude Code assistance (validation by a subagent, reviewed in this session). |
|
@screamm thanks for the Windows run and the negative control. No module played in my runs either. My logs show the same lines as yours: On Linux (RTX 4070 Ti, NVIDIA 595.99) the preset was visible a few seconds after the first Square press. After "VISUALISER" the menu sits over the tunnel. After "VISUALISER FULL" the tunnel fills the window, at a guest I'll add your run to the description, including the black output on Windows, so it isn't presented as checked there. If you get to it, a frame dump would show whether the preset's own targets stay black or only the final composite does. No pressure, you've already covered a lot. AI-assisted: yes (Claude Code) |
|
Follow-up with the frame dumps, on Windows 11 Pro 26220, NVIDIA GeForce RTX 4070 (596.21), WinLibs MinGW-w64 GCC 15.2: this PR ( Short answer: the preset's own targets are not black. When the render targets bypass the resident-image path (
All of these reach the 150 s limit with no stop line (260 to 508 frames, guest Draws after Square (default path, about 140 s): 3145 draws, almost all into three 1920x1080 Per-draw target dumps ( Only on the default path, the log has Separate, for the rebase: on current main this PR's Not checked: reading the resident images directly on the default path, whether other presets go black on main for the same reason, Square pressed twice (FULL), Linux, AMD or Intel. Written with Claude Code assistance (validation by a subagent, reviewed in this session). |
087b633 to
1fd45dc
Compare
|
Thanks @screamm, both findings were useful. On your question: my Linux runs of this head (RTX 4070 Ti, Dark Ritual preset, the visualiser showing the tunnel) never log The rebase: you were right. 1fd45dc is on AI-assisted: yes |
|
AMD run with this head (1fd45dc) merged onto
AI-assisted: yes (Claude Code) |
1fd45dc to
faea7a2
Compare
|
Rechecked on head
Not checked: the Rovastar preset this time, AMD/Intel, Linux. Written with Claude Code assistance (validation by a subagent, reviewed in this session). |
|
Thanks @screamm, good catch on the journal. AI-assisted: yes (Claude Code) |
|
Rechecked on head
That closes the gap I pointed out. Not checked: the GPU pass, the non-GPU suite, title runs for this head, AMD/Intel, Linux. Written with Claude Code assistance (validation by a subagent, reviewed in this session). |
|
@milescoviello, about the storage uploads and #6189. I stacked this PR (
Both runs reach the limit with no stop line, and both log So #6202 removes the refresh write-backs but not the black visualiser and not the The preset targets do have #6189's two-slice array layout, but #6189 doesn't explain the black output. Written with Claude Code assistance (validation by a subagent, reviewed in this session). |
|
Thanks @screamm. Here is the same setup on Linux, to compare against your
So Linux uploads the same whole two-slice 1920x1080 image (0x10e0000 bytes), about 3 times per present. None of those uploads is That supports the earlier reading: on Windows, the resident targets are compared against guest memory rather than write-tracked (#6189's description of that path), and the black frame comes from there. It doesn't come from the merged-coverage draws in this PR. The 2.2 GiB per 10 s of whole-image CPU uploads on Linux is a cost worth looking at too. It's separate from this PR, which doesn't change storage handling. I didn't dump frames in these runs, so this table has no mean brightness. Earlier Linux runs on this preset showed the tunnel. AI-assisted: yes (Claude Code) |
6972f7a to
89d14bd
Compare
|
Rebased onto
AI-assisted: yes (Claude Code) |
89d14bd to
d1b6f08
Compare
SPI_PS_INPUT_ENA/ADDR bit 14 (SAMPLE_COVERAGE_ENA) gives the pixel shader one VGPR, after ANCILLARY, holding the samples the primitive covers. The decoder refused it and the recompiler never loaded the VGPR. It is now loaded from gl_SampleMaskIn[0] (sharing the input the partial quad sample mask already declares). On a multisampled draw the hardware word is the whole pixel's coverage while gl_SampleMaskIn holds only the invocation's samples when the pixel shader runs per sample, so that case, and sample-rate or ancillary inputs beside it, are refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…xed samples A radeonsi-style GL driver smooths lines and polygons by rasterizing four samples into a one-sample color target: PA_SC_AA_CONFIG has 4 samples, DB_EQAA.OVERRASTERIZATION_AMOUNT is log2(4), and the pixel shader reads SAMPLE_COVERAGE to scale alpha by the covered samples. The pixel is written when any of the four samples is covered. DecodeState refused the one-sample target as a sample-count mismatch. Such a draw (MSAA_ENABLE set, no depth target, no per-sample shading, every color target one-sample, OVERRASTERIZATION_AMOUNT matching the raster samples) now decodes with mergedCoverage. Its pipeline keeps the raster sample count, gives the color attachments one sample (VkAttachmentSampleCountInfoNV or the render pass) and merges coverage (VK_COVERAGE_REDUCTION_MODE_MERGE_NV). The device enables VK_NV_framebuffer_mixed_samples and VK_NV_coverage_reduction_mode when it reports that combination; elsewhere the pipeline throws. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pipeline creation and the pipeline store key read State::mergedCoverage, but the journal's state codec and CanonicalPipelineState dropped it, so a journalled merged-coverage pipeline replayed as a plain multisampled one and the draw built its pipeline again. The codec and the canonical state now carry it and the journal format becomes 4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t MSAA_ENABLE Since boykopovar#6196, a one-sample target under a multisampled rasterizer with MSAA_ENABLE clear is drawn as one sample instead of refused, so the overrasterized draw with MSAA_ENABLE clear now decodes as one sample without merged coverage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Rebased onto
The 596 tests matching AI-assisted: yes (Claude Code) |
d1b6f08 to
f0b208a
Compare
Resolves sameDecode in DrawRegisterKey.cpp, keeping this branch's sample-order comparison and #6530's merged-coverage comparison.
What
OliSe Player (PPSA01153, catalog 02.001.000) draws through a radeonsi-based GL driver (
ps5-galliumin its log). Its MilkDrop visualizer picks a random preset. With "Rovastar - Dark Ritual (Star Of Destiny Mix)" it smooths lines and polygons the way radeonsi does, andmainstops 20 s in:The draw (from a throwaway print):
PA_SC_AA_CONFIG0x0020c002: 4 samples, 4 exposedVK_FORMAT_R8G8B8A8_UNORM; no depth targetPA_SC_MODE_CNTL_0/_10x23(MSAA_ENABLE) /0x0DB_EQAA0x02130000: OVERRASTERIZATION_AMOUNT 2SPI_PS_INPUT_ENA/ADDR0x4002: PERSP_CENTER, SAMPLE_COVERAGEThis is radeonsi's smoothing setup. With a one-sample framebuffer,
si_emit_msaa_configrasterizesSI_NUM_SMOOTH_AA_SAMPLES= 4 coverage samples and setsOVERRASTERIZATION_AMOUNT(log2 4), so the pixel is written when any of them is covered.si_shader.cenables SAMPLE_COVERAGE_ENA fornir_lower_poly_line_smooth, which scales alpha by the number of covered samples.Two commits:
feat(shader): SAMPLE_COVERAGE.SPI_PS_INPUT_ENA/ADDRbit 14 gives the pixel shader one VGPR after ANCILLARY. The decoder refused it, and the recompiler never loaded that VGPR. It is now loaded fromgl_SampleMaskIn[0](new input kindSampleMask). It shares the variable the partial quad sample mask already declares, since a module may hold only oneSampleMaskinput. On a multisampled draw the hardware word is the whole pixel's coverage, but when the shader runs per samplegl_SampleMaskInholds only that invocation's samples. So per-sample shading is refused, and so are PERSP_SAMPLE, LINEAR_SAMPLE and ANCILLARY beside the coverage input (reading the sample index makes the host shade per sample).feat(agc): merged coverage. A draw with MSAA_ENABLE set, no depth target, no per-sample shading, only one-sample color targets andOVERRASTERIZATION_AMOUNTequal to log2 of the raster samples now decodes withState::mergedCoverage. Before, it threw "a color target's sample count differs from the rasterizer's". Its pipeline keeps the raster sample count, gives the color attachments one sample (VkAttachmentSampleCountInfoNV, or the render pass attachments) and merges coverage (VK_COVERAGE_REDUCTION_MODE_MERGE_NV). A one-sample color pixel is then covered when any raster sample is, andgl_SampleMaskIncarries the four bits. The device enablesVK_NV_framebuffer_mixed_samplesandVK_NV_coverage_reduction_modewhenvkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNVreports merge with one color sample and no depth. On other devices the pipeline throws, so the draw still stops, as it does onmain. Pipeline keys and the draw state comparison include the flag.Tests:
agc_driver_pixel_sample_coverage(new, GPU). A full-target triangle into a one-sample target reads 1 from SAMPLE_COVERAGE alone, after the perspective center pair, and after ANCILLARY. A triangle over half of the target, rasterized with 4 samples into the one-sample target, writes only masks from 1 to 15, at least one 15 and one partial edge mask, and leaves the rest untouched. On a device without merged coverage that part prints a skip line. Onmain's sources the first case fails at once: the first pixel holds (0, 0, 0, 1), as the VGPR is never loaded.agc_driver_graphics.0x4002decodes with the coverage VGPR at 2 and is read fromgl_SampleMaskIn. Beside a partial quad sample mask, the module declares oneSampleMaskinput. On a 2x target, SAMPLE_COVERAGE is refused with PS_ITER_SAMPLE and with an addressed PERSP_SAMPLE, LINEAR_SAMPLE or ANCILLARY. The register set above decodes as merged coverage, and a wrong overrasterization amount, PS_ITER_SAMPLE or MSAA_ENABLE clear are still refused. Onmain'sState.cppthis stops at "a color target's sample count differs from the rasterizer's".Tested
Linux (Ubuntu 24.04, GCC 13.3, Release), RTX 4070 Ti, NVIDIA 595.99:
ctest -R "agc|shader|recompiler|spirv|pixel": 611 of 613.agc_pending_key_storesandagc_driver_store_over_untrackedfail onmainhere too (perf(agc): clear a register fast clear without waiting for a known key store #6247, fix(agc): save pending storage results in every 64 KiB block that leaves the write watch #5671).presetsfolder trimmed to that one preset (so the visualizer always picks it), pad input, 120 s:main0029e62main03c4cb5 + the first commit onlya color target's sample count differs from the rasterizer'smain03c4cb5 + both commitsWith the full preset folder (a random preset each run), 2 of 2 180 s runs with both commits reach the limit. PPSA99600, the other app here that uses
ps5-gallium, reaches its 120 s limit onmainand with this PR. The branch is rebased ontomain44df216, where both test binaries pass 3 of 3.On Windows 11 (RTX 4070, NVIDIA 596.21), @screamm built 087b633, ran both test binaries 3 of 3, and confirmed that they fail with this PR's sources reverted. With OliSe,
mainstopped 2 of 2 on the same refusal and this PR reached the 150 s limit 3 of 3. There, though, the visualiser drew black: the menu at half brightness after one Square press, a black window after the second. In my Linux runs the tunnel is visible. Neither setup had a music module playing. screamm then traced the black frame. WithAPS5_NO_RESIDENT_TARGETS=1the three preset targets fill with the tunnel, and the final frame shows it behind the menu. Only the default resident-target path is black, and only there does the log showguest memory changed while GPU results were pending; keeping the CPU's blocks, together with 1,353 storage-image uploads with the reasonuntracked. My Linux runs of this head never log that line (thememory no longer registered; 135 pending ranges droppedline shows up 3 to 4 times on both). So the black frame looks like the Windows host-import comparison discarding the targets' GPU results, not these draws.screamm also caught that this PR's
agc_driver_graphicsfailed when merged with currentmain. #5882 now lets a multisampled scan without MSAA_ENABLE pastDecodeStatewhen there is no depth target, so my last smoothing case is refused at the color sample-count check instead. Rebased ontomain5d9dcc4 (1fd45dc), with that expectation updated.agc_driver_graphicspasses 3 of 3, and the 469 area tests give 468 passes, the remaining one beingmain'sagc_driver_store_over_untracked(#6385).@johnmaia ran the full suite on AMD (Radeon RX 7600, RADV NAVI33, Mesa 25.2.8, Ubuntu 24.04) with 1fd45dc on
main82ddae7. 1287 of 1288 tests pass, and the one failure ismain'sagc_driver_graphics(#6792).agc_driver_pixel_sample_coveragepasses, and with #6789 merged too,agc_driver_graphicspasses with and without this PR, so the newGraphics.cppcases run there.Rebased onto
main1b1f848 (faea7a2), which now has #5907 (simonbronk): multisampled draws into one-sample targets rasterize at sample 0's location, and a sample-coverage input is refused there. The two meet in the color sample-count check. An overrasterized draw (OVERRASTERIZATION_AMOUNTequal to log2 of the raster samples) still decodes as merged coverage, and any other one-sample draw takes #5907's sample-0 path. Two expectations changed with that:agc_driver_graphics,agc_driver_covered_centroid_stateandagc_driver_pixel_sample_coveragepass 3 of 3. Of the 898 area tests (the regex above plus^guest_|libc), all pass exceptmain'sagc_driver_store_over_untracked.6972f7a, after @screamm's recheck:
State::mergedCoverageis part of the pipeline store key and is read when the pipeline is created, but the pipeline journal's state codec andCanonicalPipelineStatedropped it. A journalled merged-coverage pipeline therefore replayed as a plain multisampled one, a lost prewarm as screamm noted. The codec and the canonical state now carry it, and the journal format becomes 4. A newagc_pipeline_journalcase round-trips a merged-coverage state and requires the decoded state to key the same pipeline. With the previousPipelineJournal.cppit fails withthe recipe dropped merged coverage; with the change it passes 3 of 3. The AGC area suite (504 tests) passes exceptagc_driver_store_over_untracked, as before. #6639 also moves the format to 4 for its own fields, so whichever of the two merges second will move it to 5.@screamm rechecked 6972f7a38 on Windows (RTX 4070, 596.21). The journal and coverage tests pass 3 of 3. Without the
encodeStateline, or without theCanonicalPipelineStateline, the journal tests fail. #6959 also moves the journal format to 4, like #6639, so whichever of these merges later takes the next number.Not checked in a title on AMD or Intel (where the merged path throws), or on a console.
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)🤖 Generated with Claude Code