mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
shader: run non-amplifying NGG programs in mesh workgroups
This commit is contained in:
@@ -1137,7 +1137,8 @@ IR::Program TranslateProgram(const Decoder::Program& decoded, const CFG::Graph&
|
||||
}
|
||||
} else if (options.stage == ShaderType::Mesh) {
|
||||
const auto& mesh = options.input_info.vertex->mesh;
|
||||
EXIT_NOT_IMPLEMENTED(mesh.primitives_per_group == 0u || mesh.vertices_per_group > 64u ||
|
||||
EXIT_NOT_IMPLEMENTED(mesh.primitives_per_group == 0u || mesh.vertices_per_group > 0x1ffu ||
|
||||
mesh.primitives_per_group > 0x1ffu ||
|
||||
total_threads > 15u * options.wave_size);
|
||||
const auto u32 = [](uint32_t value) { return IR::U32(IR::Value(value)); };
|
||||
const auto draw = [&](uint32_t index) {
|
||||
@@ -1173,6 +1174,10 @@ IR::Program TranslateProgram(const Decoder::Program& decoded, const CFG::Graph&
|
||||
const auto wave_info = entry_ir.BitwiseOr(entry_ir.ShiftLeftLogical(wave, u32(24)),
|
||||
u32(((total_threads + options.wave_size - 1u) /
|
||||
options.wave_size) << 28u));
|
||||
entry_ir.SetScalarReg(
|
||||
static_cast<IR::ScalarReg>(2),
|
||||
entry_ir.BitwiseOr(entry_ir.ShiftLeftLogical(vertices, u32(12)),
|
||||
entry_ir.ShiftLeftLogical(primitives, u32(22))));
|
||||
entry_ir.SetScalarReg(
|
||||
static_cast<IR::ScalarReg>(3),
|
||||
entry_ir.BitwiseOr(wave_info, entry_ir.BitwiseOr(entry_ir.ShiftLeftLogical(
|
||||
|
||||
@@ -705,11 +705,14 @@ ShaderParams PrepareProgram(const HW::VertexShaderInfo& regs, const HW::Context&
|
||||
const auto& sh = context.GetShaderRegisters();
|
||||
const auto [data, hash] = ShaderGetMappedData(regs.es_regs.data_addr, "ShaderGetInputInfoVS():");
|
||||
const bool merged = (context.GetShaderStages() & 0x20u) != 0;
|
||||
// GS_EN controls amplification, not whether an NGG shader uses a workgroup.
|
||||
const bool native_ngg = !merged && data.type == Prospero::ShaderBinaryType::kGs &&
|
||||
regs.gs_regs.rsrc2.lds_size != 0;
|
||||
auto params = GetShaderParams(
|
||||
regs.es_regs.data_addr, hash,
|
||||
std::span<const uint32_t>(regs.gs_user_sgpr.value, regs.gs_regs.rsrc2.user_sgpr), data,
|
||||
merged ? 8u : 0u);
|
||||
if (!merged) {
|
||||
merged || native_ngg ? 8u : 0u);
|
||||
if (!merged && !native_ngg) {
|
||||
if (!ShaderGetStaticVertexInputInfo(regs.es_regs.data_addr, regs.gs_user_sgpr,
|
||||
regs.gs_regs.rsrc2.user_sgpr, sh, data, info)) {
|
||||
EXIT("failed to prepare vertex shader program\n");
|
||||
@@ -754,7 +757,7 @@ ShaderParams PrepareProgram(const HW::VertexShaderInfo& regs, const HW::Context&
|
||||
group.primitive_group_size != 1u || group.vertex_group_size != 1u ||
|
||||
user_vgpr.vgpr1 || user_vgpr.vgpr2 || user_vgpr.vgpr3 ||
|
||||
mesh.max_vertices != sh.m_vgtGsMaxVertOut);
|
||||
} else {
|
||||
} else if (merged) {
|
||||
EXIT_NOT_IMPLEMENTED(regs.gs_regs.rsrc1.gs_vgpr_component_count != 3u ||
|
||||
regs.gs_regs.rsrc2.es_vgpr_component_count != 3u);
|
||||
}
|
||||
@@ -763,7 +766,7 @@ ShaderParams PrepareProgram(const HW::VertexShaderInfo& regs, const HW::Context&
|
||||
user_config.GetPrimType() != Prospero::PrimitiveType::kTriFan &&
|
||||
user_config.GetPrimType() != Prospero::PrimitiveType::kTriStrip &&
|
||||
user_config.GetPrimType() != Prospero::PrimitiveType::kTriList) ||
|
||||
sh.m_vgtGsOutPrimType != 2u || sh.m_vgtGsMaxVertOut < 3u ||
|
||||
sh.m_vgtGsOutPrimType != 2u || (!native_ngg && sh.m_vgtGsMaxVertOut < 3u) ||
|
||||
group.vertex_group_size < mesh.InputPrimitiveSize() ||
|
||||
mesh.max_vertices == 0u) {
|
||||
EXIT("unsupported GS assembly: input=%u output=%u vertices=%u GE=%u/%u max_output=%u\n",
|
||||
@@ -771,14 +774,16 @@ ShaderParams PrepareProgram(const HW::VertexShaderInfo& regs, const HW::Context&
|
||||
group.primitive_group_size, group.vertex_group_size, mesh.max_vertices);
|
||||
}
|
||||
mesh.max_primitives = mesh.fast_launch ? mesh.max_vertices :
|
||||
native_ngg ? mesh.InputPrimitiveCount(mesh.max_vertices) :
|
||||
group.primitive_group_size * (sh.m_vgtGsMaxVertOut - 2u);
|
||||
mesh.primitives_per_group = std::min({static_cast<uint32_t>(group.primitive_group_size),
|
||||
mesh.InputPrimitiveCount(group.vertex_group_size),
|
||||
mesh.max_vertices / sh.m_vgtGsMaxVertOut});
|
||||
native_ngg ? mesh.max_primitives :
|
||||
mesh.max_vertices / sh.m_vgtGsMaxVertOut});
|
||||
EXIT_IF(mesh.primitives_per_group == 0u);
|
||||
mesh.vertices_per_group = mesh.InputVertexCount(mesh.primitives_per_group);
|
||||
mesh.threads_num[0] =
|
||||
((mesh.max_vertices + mesh.wave_size - 1u) / mesh.wave_size) * mesh.wave_size;
|
||||
const auto threads = native_ngg && !mesh.fast_launch ? mesh.vertices_per_group : mesh.max_vertices;
|
||||
mesh.threads_num[0] = ((threads + mesh.wave_size - 1u) / mesh.wave_size) * mesh.wave_size;
|
||||
mesh.threads_num[1] = mesh.threads_num[2] = 1u;
|
||||
return params;
|
||||
}
|
||||
|
||||
+67
-28
@@ -10615,6 +10615,32 @@ void TestMergedShaderUserDataSnapshot() {
|
||||
regs.gs_user_sgpr.value[HW::UserSgprInfo::SGPRS_MAX - 1]++;
|
||||
Check(full.user_data.back() == 0x10001000u + HW::UserSgprInfo::SGPRS_MAX - 1,
|
||||
"merged shader parameters borrowed mutable register storage");
|
||||
regs.gs_regs.rsrc2.lds_size = 64;
|
||||
regs.gs_regs.rsrc1.gs_vgpr_component_count = 1;
|
||||
context.SetGsMaxVertOut(0);
|
||||
for (const uint32_t wave_size : {32u, 64u}) {
|
||||
context.SetShaderStages(wave_size == 32 ? 0x00400000u : 0u);
|
||||
for (const uint16_t capacity : {64u, 128u, 256u}) {
|
||||
context.SetMaxOutputPerSubgroup(capacity);
|
||||
user_config.SetGeControl({capacity, capacity});
|
||||
ShaderVertexInputInfo input{};
|
||||
const auto params = PrepareProgram(regs, context, user_config, input);
|
||||
Check(input.logical_stage == ShaderType::Mesh && input.mesh.wave_size == wave_size &&
|
||||
input.mesh.lds_size_dwords == 8192 && input.mesh.max_vertices == capacity &&
|
||||
input.mesh.max_primitives == capacity / 3 &&
|
||||
input.mesh.primitives_per_group == capacity / 3 &&
|
||||
input.mesh.vertices_per_group == capacity / 3 * 3 &&
|
||||
input.mesh.threads_num[0] == capacity && params.back_code.empty() &&
|
||||
params.user_data_count == 8u + HW::UserSgprInfo::SGPRS_MAX &&
|
||||
params.user_data[0] == 0 && params.user_data[1] == 0 &&
|
||||
std::equal(std::begin(regs.gs_user_sgpr.value), std::end(regs.gs_user_sgpr.value),
|
||||
params.user_data.begin() + 8),
|
||||
"non-amplifying NGG shader lost its workgroup, GE bounds, or native user SGPRs");
|
||||
}
|
||||
}
|
||||
regs.gs_regs.rsrc2.lds_size = 0;
|
||||
regs.gs_regs.rsrc1.gs_vgpr_component_count = 3;
|
||||
context.SetShaderStages(0x20);
|
||||
context.SetMaxOutputPerSubgroup(256);
|
||||
context.SetGsMaxVertOut(8);
|
||||
user_config.SetPrimitiveType(Prospero::PrimitiveType::kTriFan);
|
||||
@@ -10872,7 +10898,7 @@ void TestMeshInputAssembly() {
|
||||
struct Case {
|
||||
Prospero::PrimitiveType topology;
|
||||
uint32_t capacity, count, group, lane, width, address_low, base_vertex;
|
||||
uint32_t wave_info, first, second, third, byte_offset, vertex_id;
|
||||
uint32_t wave_info, group_info, first, second, third, byte_offset, vertex_id;
|
||||
bool fetch;
|
||||
uint32_t wave_size = 64;
|
||||
bool fast_launch = false;
|
||||
@@ -10880,51 +10906,63 @@ void TestMeshInputAssembly() {
|
||||
};
|
||||
std::vector<Case> cases = {
|
||||
{Prospero::PrimitiveType::kTriList, 14, 177, 14, 2, 2, 0x1002, UINT32_MAX,
|
||||
0x40000309, 6, 7, 8, 340, 0xabcc, true},
|
||||
0x40000309, 0x00c09000, 6, 7, 8, 340, 0xabcc, true},
|
||||
{Prospero::PrimitiveType::kTriList, 14, 177, 14, 9, 2, 0x1002, 0,
|
||||
0x40000309, 27, 28, 29, 356, 0, false},
|
||||
0x40000309, 0x00c09000, 27, 28, 29, 356, 0, false},
|
||||
{Prospero::PrimitiveType::kTriList, 8, 180, 0, 64, 2, 0x1002, 0,
|
||||
0x41000000, 192, 193, 194, 128, 0, false},
|
||||
0x41000000, 0x00806000, 192, 193, 194, 128, 0, false},
|
||||
{Prospero::PrimitiveType::kTriList, 8, 180, 1, 1, 1, 0x1000, 5,
|
||||
0x40000206, 3, 4, 5, 4, 0xb0, true},
|
||||
0x40000206, 0x00806000, 3, 4, 5, 4, 0xb0, true},
|
||||
{Prospero::PrimitiveType::kTriList, 8, 180, 1, 1, 4, 0x1000, 5,
|
||||
0x40000206, 3, 4, 5, 28, 0xabcd0128, true},
|
||||
0x40000206, 0x00806000, 3, 4, 5, 28, 0xabcd0128, true},
|
||||
{Prospero::PrimitiveType::kTriStrip, 5, 8, 1, 1, 0, 0, 11,
|
||||
0x40000305, 1, 2, 3, 0, 15, false},
|
||||
0x40000305, 0x00c05000, 1, 2, 3, 0, 15, false},
|
||||
{Prospero::PrimitiveType::kTriStrip, 5, 8, 0, 1, 0, 0, 11,
|
||||
0x40000305, 2, 1, 3, 0, 12, false},
|
||||
0x40000305, 0x00c05000, 2, 1, 3, 0, 12, false},
|
||||
{Prospero::PrimitiveType::kTriFan, 32, 6, 0, 3, 2, 0x1002, 0,
|
||||
0x40000406, 0, 4, 5, 8, 0x0123, true},
|
||||
0x40000406, 0x01006000, 0, 4, 5, 8, 0x0123, true},
|
||||
{Prospero::PrimitiveType::kTriFan, 5, 8, 1, 0, 2, 0x1002, 0,
|
||||
0x40000305, 0, 1, 2, 0, 0xabcd, true},
|
||||
0x40000305, 0x00c05000, 0, 1, 2, 0, 0xabcd, true},
|
||||
{Prospero::PrimitiveType::kTriFan, 5, 8, 1, 1, 0, 0, 11,
|
||||
0x40000305, 0, 2, 3, 0, 15, false},
|
||||
0x40000305, 0x00c05000, 0, 2, 3, 0, 15, false},
|
||||
{Prospero::PrimitiveType::kTriFan, 5, 7, 1, 3, 2, 0x1002, 11,
|
||||
0x40000204, 0, 4, 5, 12, 0xabd8, true},
|
||||
0x40000204, 0x00804000, 0, 4, 5, 12, 0xabd8, true},
|
||||
{Prospero::PrimitiveType::kTriFan, 5, 7, 1, 4, 2, 0x1002, 0,
|
||||
0x40000204, 0, 5, 6, 16, 0, false},
|
||||
0x40000204, 0x00804000, 0, 5, 6, 16, 0, false},
|
||||
{Prospero::PrimitiveType::kTriFan, 5, 8, 1, 64, 4, 0x1000, 0,
|
||||
0x41000000, 0, 65, 66, 268, 0, false},
|
||||
0x41000000, 0x00c05000, 0, 65, 66, 268, 0, false},
|
||||
{Prospero::PrimitiveType::kLineList, 5, 17, 3, 0, 0, 0, 11,
|
||||
0x40000204, 0, 1, 0, 0, 23, false},
|
||||
0x40000204, 0x00804000, 0, 1, 0, 0, 23, false},
|
||||
{Prospero::PrimitiveType::kLineList, 6, 17, 2, 4, 2, 0x1002, 11,
|
||||
0x40000205, 8, 9, 0, 32, 0xabd8, true},
|
||||
0x40000205, 0x00805000, 8, 9, 0, 32, 0xabd8, true},
|
||||
{Prospero::PrimitiveType::kLineList, 6, 17, 2, 5, 2, 0x1002, 0,
|
||||
0x40000205, 10, 11, 0, 36, 0, false},
|
||||
0x40000205, 0x00805000, 10, 11, 0, 36, 0, false},
|
||||
{Prospero::PrimitiveType::kLineList, 8, 180, 1, 64, 4, 0x1000, 0,
|
||||
0x41000000, 128, 129, 0, 288, 0, false},
|
||||
0x41000000, 0x01008000, 128, 129, 0, 288, 0, false},
|
||||
{Prospero::PrimitiveType::kPointList, 12, 265, 22, 0, 2, 0x1002, 0,
|
||||
0x40000101, 0, 0, 0, 528, 0xabcd, true},
|
||||
0x40000101, 0x00401000, 0, 0, 0, 528, 0xabcd, true},
|
||||
{Prospero::PrimitiveType::kPointList, 12, 265, 22, 1, 2, 0x1002, 0,
|
||||
0x40000101, 1, 0, 0, 532, 0, false},
|
||||
0x40000101, 0x00401000, 1, 0, 0, 532, 0, false},
|
||||
{Prospero::PrimitiveType::kPointList, 1, 1, 0, 0, 0, 0, 11,
|
||||
0x40000101, 0, 0, 0, 0, 11, false},
|
||||
0x40000101, 0x00401000, 0, 0, 0, 0, 11, false},
|
||||
{Prospero::PrimitiveType::kPointList, 12, 265, 1, 1, 4, 0x1000, 5,
|
||||
0x40000c0c, 1, 0, 0, 52, 0xabcd0128, true},
|
||||
0x40000c0c, 0x0300c000, 1, 0, 0, 52, 0xabcd0128, true},
|
||||
{Prospero::PrimitiveType::kPointList, 12, 265, 1, 64, 4, 0x1000, 0,
|
||||
0x41000000, 64, 0, 0, 304, 0, false},
|
||||
0x41000000, 0x0300c000, 64, 0, 0, 304, 0, false},
|
||||
{Prospero::PrimitiveType::kTriStrip, 40, 40, 0, 32, 0, 0, 11,
|
||||
0x81000608, 32, 33, 34, 0, 43, false, 32},
|
||||
0x81000608, 0x09828000, 32, 33, 34, 0, 43, false, 32},
|
||||
{Prospero::PrimitiveType::kTriList, 64, 64, 0, 0, 0, 0, 11,
|
||||
0x1000153f, 0x0543f000, 0, 1, 2, 0, 11, false, 64, false, 64},
|
||||
{Prospero::PrimitiveType::kTriList, 128, 128, 0, 64, 0, 0, 11,
|
||||
0x2100003e, 0x0a87e000, 192, 193, 194, 0, 75, false, 64, false, 128},
|
||||
{Prospero::PrimitiveType::kTriList, 256, 256, 0, 192, 0, 0, 11,
|
||||
0x4300003f, 0x154ff000, 576, 577, 578, 0, 203, false, 64, false, 256},
|
||||
{Prospero::PrimitiveType::kTriList, 64, 64, 0, 32, 0, 0, 11,
|
||||
0x2100001f, 0x0543f000, 96, 97, 98, 0, 43, false, 32, false, 64},
|
||||
{Prospero::PrimitiveType::kTriList, 128, 128, 0, 32, 0, 0, 11,
|
||||
0x41000a20, 0x0a87e000, 96, 97, 98, 0, 43, false, 32, false, 128},
|
||||
{Prospero::PrimitiveType::kTriList, 256, 256, 0, 64, 0, 0, 11,
|
||||
0x82001520, 0x154ff000, 192, 193, 194, 0, 75, false, 32, false, 256},
|
||||
};
|
||||
for (const uint32_t wave_size : {32u, 64u}) {
|
||||
for (const uint32_t threads : {wave_size, 2u * wave_size}) {
|
||||
@@ -10935,7 +10973,7 @@ void TestMeshInputAssembly() {
|
||||
(lane < wave_size ? 0x101u : 0u);
|
||||
const uint32_t base_vertex = group == 11u ? UINT32_MAX : 11u;
|
||||
cases.push_back({Prospero::PrimitiveType::kPointList, 1, 12, group, lane, 0, 0,
|
||||
base_vertex, wave_info, 0, 0, 0, 0, group + base_vertex, false,
|
||||
base_vertex, wave_info, 0x00401000, 0, 0, 0, 0, group + base_vertex, false,
|
||||
wave_size, true, threads});
|
||||
}
|
||||
}
|
||||
@@ -10998,15 +11036,16 @@ void TestMeshInputAssembly() {
|
||||
ConstantPropagationPass(program.blocks);
|
||||
}
|
||||
std::array<uint32_t, 9> vgprs{};
|
||||
uint32_t sgpr3 = 0;
|
||||
std::array<uint32_t, 4> sgprs{};
|
||||
for (const auto &inst : *program.blocks.front()) {
|
||||
if (inst.GetOpcode() == ValueOpcode::SetVectorRegister) {
|
||||
vgprs[RegIndex(inst.Arg(0).VectorRegister())] = inst.Arg(1).Resolve().U32();
|
||||
} else if (inst.GetOpcode() == ValueOpcode::SetScalarRegister) {
|
||||
sgpr3 = inst.Arg(1).Resolve().U32();
|
||||
sgprs[RegIndex(inst.Arg(0).ScalarRegister())] = inst.Arg(1).Resolve().U32();
|
||||
}
|
||||
}
|
||||
Check(sgpr3 == test.wave_info && vgprs[0] == ((test.first << 2) | (test.second << 18)) &&
|
||||
Check(sgprs[2] == test.group_info && sgprs[3] == test.wave_info &&
|
||||
vgprs[0] == ((test.first << 2) | (test.second << 18)) &&
|
||||
vgprs[1] == test.third * 4 && vgprs[5] == test.vertex_id &&
|
||||
vgprs[test.fast_launch ? 6 : 8] == 9u,
|
||||
"mesh prolog changed input assembly, wave counts, vertex ID, or instance ID");
|
||||
|
||||
Reference in New Issue
Block a user