test(agc): cover NGG vertex programs routed to the mesh path

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Scott Schuster 2026-10-08 15:31:07 -05:00 committed by Adrià Franch
parent a48b39e933
commit 0a1b31f5c4
2 changed files with 47 additions and 0 deletions

View File

@ -468,6 +468,36 @@ void ShaderStageTests() {
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "missing register");
}
void NggVertexWorkgroupTests() {
auto queue = makeState();
queue.context[0x2d5] = 0x12010;
queue.userConfig[0x242] = 4;
queue.userConfig[0x25b] = 0x10080;
queue.context[0x1ff] = 0x80;
queue.context[0x2ce] = 0;
queue.context[0x29b] = 2;
queue.context[0x2ab] = 1;
queue.shader[0x8a] = 0x222c0009;
queue.shader[0x8b] = 0x43001e;
queue.context[0x1b3] = 2;
queue.context[0x1b4] = 2;
Require(AgcDriver::Graphics::DecodeState(queue).stages.path == AgcDriver::Graphics::ShaderPath::Vertex, "an NGG vertex program without a workgroup left the vertex path");
auto state = AgcDriver::Graphics::DecodeState(queue, true);
Require(state.stages.path == AgcDriver::Graphics::ShaderPath::Geometry && state.stages.mesh, "an NGG vertex program that needs a workgroup did not take the mesh path");
auto mesh = *state.stages.mesh;
Require(mesh.inputPrimitive == 4 && mesh.primitivesPerGroup == 42 && mesh.verticesPerGroup == 126 && mesh.maxVertices == 128 && mesh.maxPrimitives == 128 && mesh.threadsPerGroup == 128 && mesh.ldsSizeDwords == 1024 && mesh.esgsItemSize == 1, "the NGG vertex subgroup of a triangle list changed");
queue.userConfig[0x242] = 6;
mesh = *AgcDriver::Graphics::DecodeState(queue, true).stages.mesh;
Require(mesh.primitivesPerGroup == 126 && mesh.verticesPerGroup == 128 && mesh.maxPrimitives == 128, "the NGG vertex subgroup of a triangle strip is not bounded by its vertex budget");
queue.context[0x1ff] = 2;
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue, true); }, "invalid geometry subgroup output");
queue.context[0x1ff] = 0x80;
for (const auto stages : {0x02012010u, 0x00012030u, 0x00010010u}) {
queue.context[0x2d5] = stages;
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue, true); }, "requires PRIMGEN_EN without GS_EN, PRIMGEN_PASSTHRU_EN or tessellation");
}
}
constexpr std::array<std::uint8_t, 8> IdentityExports{0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u};
std::vector<spv::BuiltIn> pixelBuiltinsRead(std::uint32_t ena, std::uint32_t addr, std::uint32_t source) {
@ -4043,6 +4073,7 @@ int main() {
uint16ExportTests();
uint8x4TargetTests();
ShaderStageTests();
NggVertexWorkgroupTests();
TuningFieldTests();
PixelInputLayoutTests();
ColorPipeBankXorTests();

View File

@ -602,6 +602,21 @@ void testProgramSnapshots() {
check(AgcDriver::DriverDetail::DecodeProgramsCurrent(decode, shaders), "a decode with the rewritten program was not current");
}
void testProgramWorkgroupUse() {
const auto snapshot = [](std::vector<std::uint32_t> code) {
AgcDriver::DriverDetail::ShaderSnapshot result{0x1000, 0, 2, std::move(code), {}};
return result;
};
const auto plain = snapshot({0xbf800000, 0xbf810000});
check(!AgcDriver::DriverDetail::ProgramUsesWorkgroup(plain, 0) && !AgcDriver::DriverDetail::ProgramUsesWorkgroup(plain, 0), "a program without LDS or barriers needs a workgroup");
const auto barrier = snapshot({0xbf8a0000, 0xbf810000});
check(AgcDriver::DriverDetail::ProgramUsesWorkgroup(barrier, 0), "an s_barrier did not need a workgroup");
const auto lds = snapshot({0xd8340000, 0x00000100, 0xbf810000});
check(AgcDriver::DriverDetail::ProgramUsesWorkgroup(lds, 0) && AgcDriver::DriverDetail::ProgramUsesWorkgroup(lds, 0), "an LDS write did not need a workgroup");
const auto entry = snapshot({0xbf8a0000, 0xbf810000, 0xbf800000, 0xbf810000});
check(!AgcDriver::DriverDetail::ProgramUsesWorkgroup(entry, 2) && AgcDriver::DriverDetail::ProgramUsesWorkgroup(entry, 0), "the workgroup check did not start at the program's entry");
}
void testWorkerFailure() {
std::array<std::uint32_t, 5> words{0xc0031500, 1, 1, 1, 0x41};
Packet packet{words.data(), static_cast<std::uint32_t>(words.size()), 0, {}};
@ -694,6 +709,7 @@ int main() {
check(!unterminated.empty() && bounded->code.size() == 64, "raw compute crossed inaccessible memory or missed its last instruction");
#endif
testProgramSnapshots();
testProgramWorkgroupUse();
testEvents();
testValidation();
testClearState();