From 69728a0cb05b5600602b40a9ce5a26b05592db99 Mon Sep 17 00:00:00 2001 From: Achraf Reyani Date: Mon, 12 Oct 2026 19:05:04 +0900 Subject: [PATCH] fix(agc): rasterize a single-sample scan into a multisampled target at the pixel center With PA_SC_AA_CONFIG at one sample and MSAA_ENABLE off, the hardware scans each pixel once and gives every sample of a multisampled color target its result: radeonsi programs exactly this when GL multisampling is disabled on a multisampled framebuffer (si_emit_msaa_config leaves sc_aa_config 0), and GL defines it as single-sample rasterization with full coverage. Such a draw without depth or alpha-to-coverage now rasterizes the target's sample count with every sample location at the pixel center, which covers all samples exactly when the center is covered. Co-Authored-By: Claude Opus 5.5 --- core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp | 5 +++++ core/libs/prx/libSceAgcDriver/tests/Graphics.cpp | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp index e52258b6c..3f48f81b6 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp @@ -794,6 +794,11 @@ State DecodeState(const QueueState& queue, bool vertexWorkgroup) { if (slotExport == 7 && ((read(cx, 0x31c + slot * 0xfu) >> 8u) & 7u) != 4u) throw std::runtime_error("AGC graphics: color export format 7 (UINT16_ABGR) into a target that is not unsigned integer is unsupported"); color.exportIndex = index; color.uintExport = slotExport == 7; + if (color.samples > 1 && result.samples == 1 && result.colors.empty() && !result.depth && !result.alphaToCoverage && (read(cx, 0x292) & 1u) == 0) { + result.samples = color.samples; + result.customSampleLocations = true; + result.sampleLocations.fill(0); + } Require(color.samples == result.samples, "a color target's sample count differs from the rasterizer's"); APS5_LOG_OUT_DEBUG("Color %u address=0x%llx extent=%ux%u bytes=%llu VkFormat=%u", slot, static_cast(color.address), color.extent.width, color.extent.height, static_cast(color.bytes), static_cast(color.format)); if (result.colors.empty()) { diff --git a/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp b/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp index b57cb808e..9a739e8b2 100644 --- a/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp @@ -1855,6 +1855,16 @@ void multisampleTests() { queue.context[0x302] = 0x44cc; expectFailure([&] { DecodeState(queue); }, "nonstandard sample locations"); queue = multisampled(); + queue.context[0x2f8] = 0; + queue.context[0x292] = 2; + queue.context[0x31d] = 0x12000; + state = DecodeState(queue); + Require(state.samples == 4 && state.colors.size() == 1 && state.colors[0].samples == 4 && state.customSampleLocations, "single-sample scan conversion into a 4x target did not rasterize the target's samples"); + const auto centered = AgcDriver::Graphics::SampleLocations(state); + for (std::uint32_t sample = 0; sample < state.samples; ++sample) Require(centered[sample].x == 0.5f && centered[sample].y == 0.5f, "single-sample scan conversion did not place every sample at the pixel center"); + queue.context[0x292] = 3; + expectFailure([&] { DecodeState(queue); }, "MSAA_ENABLE on a single-sample target"); + queue = multisampled(); queue.context[0x2f8] = 0x00300003; queue.context[0x31d] = 0x1b000; for (std::uint32_t pixel = 0; pixel < 4; ++pixel) {