shader: support single and split NGG shaders for PPSA11142

This commit is contained in:
nmzik
2026-09-08 14:43:07 +04:00
parent 9d550fbffa
commit ef0155636a
6 changed files with 79 additions and 27 deletions
@@ -535,7 +535,7 @@ TranslateResult TranslateProgram(std::span<const uint32_t> code, const CompileOp
Decoder::Program decoded;
std::vector<uint32_t> joined_code;
if (options.stage == ShaderType::Mesh) {
if (!options.back_code.empty()) {
decoded = DecodeFusedProgram(code, options.back_code, joined_code);
} else {
Decoder::DecodeProgram(code, decoded);
@@ -1109,7 +1109,7 @@ IR::Program TranslateProgram(const Decoder::Program& decoded, const CFG::Graph&
: u32(0);
const auto vertex = entry_ir.IMul(local, step);
const auto first = entry_ir.IAdd(vertex, parity);
const auto second = mesh.InputPrimitiveSize() == 3u
const auto second = mesh.InputPrimitiveSize() >= 2u
? entry_ir.ISub(entry_ir.IAdd(vertex, u32(1)), parity)
: u32(0);
const auto third = mesh.InputPrimitiveSize() == 3u
+17 -13
View File
@@ -755,19 +755,9 @@ ShaderParams PrepareProgram(const HW::VertexShaderInfo& regs, const HW::Context&
}
return params;
}
EXIT_IF(regs.gs_regs.data_addr == 0);
const auto back = ShaderGetMappedData(regs.gs_regs.data_addr, "ShaderGetInputInfoGS():");
const auto back_params =
GetShaderParams(regs.gs_regs.data_addr, "ShaderRecompiler GS",
GetDeclaredShaderHash(regs.gs_regs.data_addr), {}, back);
params.back_code = back_params.code;
// Merged shaders receive the GS-back user-data pointer in s0:s1, followed
// by the ordinary user SGPRs at s8. Keep both in the runtime register snapshot.
// NGG user SGPRs start at s8; a separately compiled GS back half also receives
// its user-data pointer in s0:s1.
params.user_data.insert(params.user_data.begin(), 8u, 0u);
params.user_data[0] = static_cast<uint32_t>(regs.gs_regs.user_data_addr);
params.user_data[1] = static_cast<uint32_t>(regs.gs_regs.user_data_addr >> 32u);
const uint64_t hashes[] = {params.hash, back_params.hash};
params.hash = XXH3_64bits(hashes, sizeof(hashes));
info = {};
info.pa_cl_vs_out_cntl = sh.m_paClVsOutCntl;
auto& mesh = info.mesh;
@@ -776,11 +766,25 @@ ShaderParams PrepareProgram(const HW::VertexShaderInfo& regs, const HW::Context&
mesh.max_vertices = sh.m_geMaxOutputPerSubgroup;
mesh.provoking_vertex = context.GetModeControl().provoking_vtx_last ? 2u : 0u;
mesh.lds_size_dwords = static_cast<uint32_t>(regs.gs_regs.rsrc2.lds_size) * 128u;
mesh.scratch_size_dwords = std::max(data.scratch_size_dwords, back.scratch_size_dwords);
mesh.scratch_size_dwords = data.scratch_size_dwords;
if (data.type == Prospero::ShaderBinaryType::kGsFront) {
EXIT_IF(regs.gs_regs.data_addr == 0);
const auto back = ShaderGetMappedData(regs.gs_regs.data_addr, "ShaderGetInputInfoGS():");
const auto back_params =
GetShaderParams(regs.gs_regs.data_addr, "ShaderRecompiler GS",
GetDeclaredShaderHash(regs.gs_regs.data_addr), {}, back);
params.back_code = back_params.code;
params.user_data[0] = static_cast<uint32_t>(regs.gs_regs.user_data_addr);
params.user_data[1] = static_cast<uint32_t>(regs.gs_regs.user_data_addr >> 32u);
const uint64_t hashes[] = {params.hash, back_params.hash};
params.hash = XXH3_64bits(hashes, sizeof(hashes));
mesh.scratch_size_dwords = std::max(mesh.scratch_size_dwords, back.scratch_size_dwords);
}
EXIT_NOT_IMPLEMENTED(regs.gs_regs.rsrc1.gs_vgpr_component_count != 3u ||
regs.gs_regs.rsrc2.es_vgpr_component_count != 3u);
const auto& group = user_config.GetGeControl();
if ((user_config.GetPrimType() != Prospero::PrimitiveType::kPointList &&
user_config.GetPrimType() != Prospero::PrimitiveType::kLineList &&
user_config.GetPrimType() != Prospero::PrimitiveType::kTriStrip &&
user_config.GetPrimType() != Prospero::PrimitiveType::kTriList) ||
sh.m_vgtGsOutPrimType != 2u || sh.m_vgtGsMaxVertOut < 3u ||
+8 -2
View File
@@ -80,10 +80,15 @@ struct ShaderMeshInputInfo: ShaderWorkgroupInputInfo {
uint32_t provoking_vertex = 0;
[[nodiscard]] constexpr uint32_t InputPrimitiveSize() const {
return input_primitive == static_cast<uint32_t>(Prospero::PrimitiveType::kPointList) ? 1u : 3u;
switch (static_cast<Prospero::PrimitiveType>(input_primitive)) {
case Prospero::PrimitiveType::kPointList: return 1u;
case Prospero::PrimitiveType::kLineList: return 2u;
default: return 3u;
}
}
[[nodiscard]] constexpr uint32_t InputPrimitiveStep() const {
return input_primitive == static_cast<uint32_t>(Prospero::PrimitiveType::kTriList) ? 3u : 1u;
return input_primitive == static_cast<uint32_t>(Prospero::PrimitiveType::kTriStrip)
? 1u : InputPrimitiveSize();
}
[[nodiscard]] constexpr uint32_t InputPrimitiveCount(uint32_t vertices) const {
const auto size = InputPrimitiveSize();
@@ -257,6 +262,7 @@ struct Shader {
};
struct ShaderMappedData {
Prospero::ShaderBinaryType type {};
ShaderUserData* user_data = nullptr;
ShaderSemantic* input_semantics = nullptr;
uint32_t num_input_semantics = 0;
+1
View File
@@ -662,6 +662,7 @@ int KYTY_SYSV_ABI AgcCreateShader(Shader** dst, void* header, const volatile voi
LOGF("\t base = 0x%016" PRIx64 "\n", base);
ShaderMappedData map;
map.type = static_cast<Prospero::ShaderBinaryType>(h->type);
map.user_data = h->user_data;
map.input_semantics = h->input_semantics;
map.num_input_semantics = h->num_input_semantics;
+51 -10
View File
@@ -9117,6 +9117,8 @@ void TestMeshExportStorage() {
EncodeExp0(0x14, 0x1), EncodeExp1(0, 0, 0, 0), // primitive
EncodeSopp(0x01),
};
std::vector<uint32_t> monolithic(std::begin(front), std::begin(front) + 2);
monolithic.insert(monolithic.end(), std::begin(back), std::end(back));
ShaderVertexInputInfo input{};
input.pa_cl_vs_out_cntl = (1u << 21u) | (1u << 18u);
auto &mesh = input.mesh;
@@ -9136,16 +9138,23 @@ void TestMeshExportStorage() {
ShaderRecompiler::CompileOptions options{};
options.stage = ShaderType::Mesh;
options.input_info.vertex = &input;
options.back_code = back;
options.user_data = user_data;
for (const auto [subgroup_size, push_data_start] :
{std::pair{32u, PushData::MeshDrawDwordCount},
std::pair{64u, PushData::MeshDrawDwordCount},
std::pair{32u, PushData::DwordCount},
std::pair{64u, PushData::DwordCount}}) {
struct Case {
uint32_t subgroup_size, push_data_start;
bool split;
};
const Case cases[] = {
{32u, PushData::MeshDrawDwordCount, true}, {64u, PushData::MeshDrawDwordCount, true},
{32u, PushData::DwordCount, true}, {64u, PushData::DwordCount, true},
{32u, PushData::MeshDrawDwordCount, false}, {64u, PushData::MeshDrawDwordCount, false},
{32u, PushData::DwordCount, false}, {64u, PushData::DwordCount, false},
};
for (const auto [subgroup_size, push_data_start, split] : cases) {
mesh.host_subgroup_size = subgroup_size;
const auto result =
RecompileForTest(front, options, nullptr, nullptr, push_data_start);
options.back_code = split ? std::span{back} : std::span<const uint32_t>{};
const auto result = RecompileForTest(
split ? std::span{front} : std::span<const uint32_t>{monolithic},
options, nullptr, nullptr, push_data_start);
CheckSpirvBinaryValidates(result.spirv);
const auto &layout = result.program.bindings;
Check(layout.UsesPushData() == (push_data_start == PushData::MeshDrawDwordCount) &&
@@ -9232,9 +9241,13 @@ void TestMergedShaderUserDataSnapshot() {
const std::array<uint32_t, 4> front_data = {regs.gs_user_sgpr.value[0],
regs.gs_user_sgpr.value[1], regs.gs_user_sgpr.value[2], regs.gs_user_sgpr.value[3]};
ShaderMappedData mapped{};
mapped.type = Prospero::ShaderBinaryType::kGsFront;
mapped.code_size_bytes = sizeof(front);
mapped.scratch_size_dwords = 3;
ShaderMapUserData(regs.es_regs.data_addr, mapped);
mapped.type = Prospero::ShaderBinaryType::kGsBack;
mapped.code_size_bytes = sizeof(back);
mapped.scratch_size_dwords = 7;
ShaderMapUserData(regs.gs_regs.data_addr, mapped);
HW::Context context;
context.SetShaderStages(0x20);
@@ -9255,8 +9268,9 @@ void TestMergedShaderUserDataSnapshot() {
second.user_data[8] == front_data[0] + 1,
"merged shader parameters did not snapshot ordinary user SGPRs at s8");
Check(first.hash == second.hash &&
MakeStageStaticKey(first_input) == MakeStageStaticKey(second_input),
"a dynamic merged-shader user-data pointer changed shader identity");
MakeStageStaticKey(first_input) == MakeStageStaticKey(second_input) &&
first_input.mesh.scratch_size_dwords == 7,
"merged shader identity or maximum scratch size changed with dynamic user data");
CompileOptions options{};
options.stage = ShaderType::Mesh;
options.user_data_base = 0;
@@ -9281,6 +9295,25 @@ void TestMergedShaderUserDataSnapshot() {
std::equal(table.begin(), table.end(), back_descriptor.dwords.begin()),
"merged shader resource plan did not follow the current s0:s1 pointer and s8 data");
}
const uint32_t monolithic[] = {
EncodeMubuf0(0x1c), EncodeMubuf1(0, 2, 1), EncodeSopp(0x01),
};
regs.es_regs.data_addr = reinterpret_cast<uint64_t>(monolithic);
mapped.type = Prospero::ShaderBinaryType::kGs;
mapped.code_size_bytes = sizeof(monolithic);
mapped.scratch_size_dwords = 3;
ShaderMapUserData(regs.es_regs.data_addr, mapped);
for (const auto back_address : {regs.gs_regs.data_addr, uint64_t{0}}) {
regs.gs_regs.data_addr = back_address;
ShaderVertexInputInfo input{};
const auto params = PrepareProgram(regs, context, user_config, input);
Check(params.back_code.empty() && params.hash == XXH3_64bits(monolithic, sizeof(monolithic)) &&
input.mesh.scratch_size_dwords == 3 && params.user_data.size() == 12 &&
params.user_data[0] == 0 && params.user_data[1] == 0 &&
std::equal(second.user_data.begin() + 8, second.user_data.end(),
params.user_data.begin() + 8),
"monolithic NGG shader used stale GS-back state or lost its s8 user data");
}
}
void TestEmbeddedVertexFormatSwizzle() {
@@ -9418,6 +9451,14 @@ void TestMeshInputAssembly() {
0x40000305, 1, 2, 3, 0, 15, false},
{Prospero::PrimitiveType::kTriStrip, 5, 8, 0, 1, 0, 0, 11,
0x40000305, 2, 1, 3, 0, 12, false},
{Prospero::PrimitiveType::kLineList, 5, 17, 3, 0, 0, 0, 11,
0x40000204, 0, 1, 0, 0, 23, false},
{Prospero::PrimitiveType::kLineList, 6, 17, 2, 4, 2, 0x1002, 11,
0x40000205, 8, 9, 0, 32, 0xabd8, true},
{Prospero::PrimitiveType::kLineList, 6, 17, 2, 5, 2, 0x1002, 0,
0x40000205, 10, 11, 0, 36, 0, false},
{Prospero::PrimitiveType::kLineList, 8, 180, 1, 64, 4, 0x1000, 0,
0x41000000, 128, 129, 0, 288, 0, false},
{Prospero::PrimitiveType::kPointList, 12, 265, 22, 0, 2, 0x1002, 0,
0x40000101, 0, 0, 0, 528, 0xabcd, true},
{Prospero::PrimitiveType::kPointList, 12, 265, 22, 1, 2, 0x1002, 0,