fix(agc): start the sample location registers at their clear-state value
A draw with PA_SC_AA_CONFIG.MSAA_NUM_SAMPLES > 0 whose context never wrote PA_SC_AA_SAMPLE_LOCS_PIXEL_* (context 0x2fe-0x30d) was rejected with "missing register in context bank at DWORD 0x2fe", because the registers were absent from the initial context (PPSA07411 stops on it after two frames). The MSAA_ENABLE single-sample path read them the same way. The sixteen registers now start at 0, both initially and after CLEAR_STATE. That is the value in libSceAgc's own register defaults (sceAgcGetRegisterDefaults2, every public table that holds context registers, the tables the initial context already follows for PA_SU_VTX_CNTL and PA_SC_CONSERVATIVE_RASTERIZATION_CNTL), in amdgpu's GFX10 clear-state table (clearstate_gfx10.h, gfx10_SECT_CONTEXT_def_8, loaded by gfx_v10_0_cp_gfx_start before CLEAR_STATE) and the GC 10.3 register reset value (gc_10_3_0_default.h). RADV, radeonsi and PAL always write the locations themselves and do not settle the unwritten value. 0 puts every sample at the pixel center. That is not the standard pattern for any sample count, so such a draw decodes as custom locations at the center, as a single-sample scan into a multisampled target already does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
18c438b109
commit
15955c089e
|
|
@ -240,6 +240,7 @@ inline Registers BuildInitialContextRegisters() {
|
|||
result.emplace(0x31c + 0xfu * i, 0);
|
||||
}
|
||||
for (std::uint32_t i = 0; i < 16; ++i) {
|
||||
result.emplace(0x2fe + i, 0);
|
||||
result.emplace(0x94 + 2 * i, 0x80000000);
|
||||
result.emplace(0x95 + 2 * i, 0x40004000);
|
||||
result.emplace(0xb4 + 2 * i, 0);
|
||||
|
|
|
|||
|
|
@ -452,6 +452,58 @@ void hardwareScreenOffsetTests() {
|
|||
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "missing register");
|
||||
}
|
||||
|
||||
void UnwrittenSampleLocationTests() {
|
||||
using AgcDriver::Graphics::DecodeState;
|
||||
using AgcDriver::Graphics::DrawRejection;
|
||||
using AgcDriver::Graphics::SampleLocations;
|
||||
const auto fresh = [](std::uint32_t config, std::uint32_t attributes, std::uint32_t scanMode = 3) {
|
||||
auto written = makeState();
|
||||
written.context[0x2f8] = config;
|
||||
written.context[0x292] = scanMode;
|
||||
written.context[0x3b8] = 0x0dc00000u;
|
||||
written.context[0x31d] = attributes;
|
||||
written.context[0x1b3] = 2;
|
||||
written.context[0x1b4] = 2;
|
||||
AgcDriver::QueueState queue;
|
||||
queue.shader = written.shader;
|
||||
queue.userConfig = written.userConfig;
|
||||
written.context.ForEach([&](std::uint32_t offset, std::uint32_t value) { queue.context[offset] = value; });
|
||||
return queue;
|
||||
};
|
||||
AgcDriver::QueueState initial;
|
||||
for (std::uint32_t offset = 0x2fe; offset <= 0x30d; ++offset) Require(initial.context.contains(offset) && initial.context.at(offset) == 0, "an unwritten PA_SC_AA_SAMPLE_LOCS register did not hold its clear-state value 0");
|
||||
for (const auto samples : {2u, 4u, 8u}) {
|
||||
const auto log2 = static_cast<std::uint32_t>(std::countr_zero(samples));
|
||||
auto queue = fresh((log2 << 20u) | log2, (log2 << 12u) | (log2 << 15u));
|
||||
const auto state = DecodeState(queue);
|
||||
Require(state.samples == samples && state.colors.size() == 1 && state.colors[0].samples == samples, "a multisampled draw with unwritten sample locations did not decode its sample count");
|
||||
Require(state.customSampleLocations, "unwritten sample locations did not decode as the clear-state pattern");
|
||||
for (std::uint32_t sample = 0; sample < samples; ++sample) Require(state.sampleLocations[sample] == 0, "an unwritten sample location was not at the pixel center");
|
||||
const auto centered = SampleLocations(state);
|
||||
for (std::uint32_t sample = 0; sample < samples; ++sample) Require(centered[sample].x == 0.5f && centered[sample].y == 0.5f, "unwritten sample locations did not place every sample at the pixel center");
|
||||
const auto rejection = DrawRejection(queue, false);
|
||||
Require(rejection.empty(), "the precheck refused a multisampled draw with unwritten sample locations: " + rejection);
|
||||
}
|
||||
auto queue = fresh(0x00200002, 0x12000);
|
||||
for (std::uint32_t pixel = 0; pixel < 4; ++pixel) queue.context[0x2fe + pixel * 4u] = 0x622ae6ae;
|
||||
auto state = DecodeState(queue);
|
||||
Require(state.samples == 4 && !state.customSampleLocations, "explicit standard 4x sample locations changed");
|
||||
queue = fresh(0x00200002, 0x12000);
|
||||
for (std::uint32_t pixel = 0; pixel < 4; ++pixel) queue.context[0x2fe + pixel * 4u] = 0x22eea66a;
|
||||
state = DecodeState(queue);
|
||||
Require(state.samples == 4 && state.customSampleLocations, "explicit custom 4x sample locations changed");
|
||||
const auto custom = SampleLocations(state);
|
||||
const std::array<VkSampleLocationEXT, 4> expected{{{0.125f, 0.875f}, {0.875f, 0.125f}, {0.375f, 0.375f}, {0.625f, 0.625f}}};
|
||||
for (std::size_t sample = 0; sample < expected.size(); ++sample) Require(custom[sample].x == expected[sample].x && custom[sample].y == expected[sample].y, "explicit custom 4x sample coordinates changed");
|
||||
queue.ClearContext();
|
||||
for (std::uint32_t offset = 0x2fe; offset <= 0x30d; ++offset) Require(queue.context.at(offset) == 0, "CLEAR_STATE did not reset PA_SC_AA_SAMPLE_LOCS");
|
||||
expectFailure([&] { DecodeState(fresh(0x00400004, 0x12000)); }, "more than eight samples");
|
||||
expectFailure([&] { DecodeState(fresh(0x00100002, 0x12000)); }, "exposing fewer samples");
|
||||
queue = fresh(0, 0, 3);
|
||||
state = DecodeState(queue);
|
||||
Require(state.samples == 1 && DrawRejection(queue, false).empty(), "MSAA_ENABLE on a single-sample target with unwritten sample locations was refused");
|
||||
}
|
||||
|
||||
void MsaaEnableSingleSampleTests() {
|
||||
using AgcDriver::Graphics::DecodeState;
|
||||
using AgcDriver::Graphics::DrawRejection;
|
||||
|
|
@ -5627,6 +5679,7 @@ int main(int argc, char** argv) {
|
|||
MsaaEnableSingleSampleTests();
|
||||
clipDistanceTests();
|
||||
framebufferLayerTests();
|
||||
UnwrittenSampleLocationTests();
|
||||
ShaderStageTests();
|
||||
NggVertexWorkgroupTests();
|
||||
TuningFieldTests();
|
||||
|
|
|
|||
Loading…
Reference in New Issue