mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
shader: emulate DS_ORDERED_COUNT as a GDS atomic (#1117)
* feat(shader): emulate DS_ORDERED_COUNT as a GDS atomic * fix(shader): issue one ordered-count atomic per wave * shader: correct ordered-count addressing and wave results Use the M0 base and pixel packer offset for the GDS counter. Broadcast the previous value to every lane and preserve the counter when EXEC is empty. Add GPU regressions for add/exchange with full, partial, and empty EXEC in wave32 and wave64. The targeted DS and buffer atomic suite passes 63 cases. --------- Co-authored-by: nmzik <Nmzik@mail.ru>
This commit is contained in:
@@ -32243,6 +32243,66 @@ TestCase DsAppendUsesEncodedGdsSelector() {
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase DsOrderedCountAddressAndExec(u32 wave_size, bool pixel_counter) {
|
||||
using O = ShaderOpcode;
|
||||
TestCase test;
|
||||
test.name = pixel_counter
|
||||
? (wave_size == 64 ? "DsOrderedCountPixelAddressWave64"
|
||||
: "DsOrderedCountPixelAddressWave32")
|
||||
: (wave_size == 64 ? "DsOrderedCountAddressAndExecWave64"
|
||||
: "DsOrderedCountAddressAndExecWave32");
|
||||
auto &code = test.code;
|
||||
// Both the base and OFFSET0 are aligned independently; M0's low bits are
|
||||
// a wave index, or a pixel packer ID, rather than a byte address or size.
|
||||
AppendSMovLiteral(&code, 124, 0x01030003u);
|
||||
code.push_back(EncodeSop1(0x04, 10, 126)); // Save the full EXEC mask.
|
||||
code.push_back(EncodeVop2(0x25, 2, InlineU32(1), 0)); // ADDR value = lane + 1.
|
||||
AppendVMovU32(&code, 9, 99); // DATA0 must not supply the count.
|
||||
const u32 selected_lane = wave_size == 64 ? 47u : 7u;
|
||||
const std::array<uint64_t, 3> masks = {
|
||||
wave_size == 64 ? UINT64_MAX : uint64_t{UINT32_MAX},
|
||||
uint64_t{1} << selected_lane, 0};
|
||||
u32 counter = 1000;
|
||||
for (bool exchange : {false, true}) {
|
||||
for (size_t mode = 0; mode < masks.size(); ++mode) {
|
||||
AppendVMovU32(&code, 3, 0xdeadbeefu);
|
||||
AppendSMovLiteral(&code, 126, static_cast<u32>(masks[mode]));
|
||||
AppendSMovLiteral(&code, 127, static_cast<u32>(masks[mode] >> 32u));
|
||||
const u32 release_done = exchange && mode == 2 ? 3u : 0u;
|
||||
const u32 offset1 = release_done | (pixel_counter ? 4u : 0u) |
|
||||
(exchange ? 0x10u : 0u);
|
||||
code.push_back(EncodeDs0(0x3f, (offset1 << 8u) | 7u, true));
|
||||
code.push_back(EncodeDs1(3, 9, 2));
|
||||
code.push_back(EncodeSopp(0x0c, 0)); // Wait for the returned GDS value.
|
||||
code.push_back(EncodeSop1(0x04, 126, 10)); // Restore EXEC before reading all lanes.
|
||||
AppendStoreVgprAtLaneDwordOffset(&code, 3, 0,
|
||||
static_cast<u32>(test.expected.size()));
|
||||
test.expected.insert(test.expected.end(), wave_size, counter);
|
||||
if (mode != 2) {
|
||||
const u32 value = mode == 0 ? 1u : selected_lane + 1u;
|
||||
counter = exchange ? value : counter + value;
|
||||
}
|
||||
}
|
||||
}
|
||||
AppendEnd(&code);
|
||||
test.initial.assign(test.expected.size(), 0xdeadbeefu);
|
||||
const u32 counter_address = pixel_counter ? 0x110u : 0x104u;
|
||||
test.gds_initial.assign(0x120u / sizeof(u32), 100);
|
||||
test.gds_initial[counter_address / sizeof(u32)] = 1000;
|
||||
test.expected_gds = test.gds_initial;
|
||||
test.expected_gds[counter_address / sizeof(u32)] = counter;
|
||||
test.compute_info.threads_num[0] = wave_size;
|
||||
test.compute_info.threads_num[1] = 1;
|
||||
test.compute_info.threads_num[2] = 1;
|
||||
test.compute_info.thread_ids_num = 1;
|
||||
test.compute_info.wave_size = wave_size;
|
||||
test.has_compute_info = true;
|
||||
test.opcodes = {O::S_MOV_B32, O::S_MOV_B64, O::V_ADD_NC_U32, O::V_MOV_B32,
|
||||
O::DS_ORDERED_COUNT, O::S_WAITCNT, O::V_LSHLREV_B32,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase DsAppendConsumeGdsRegionBounds() {
|
||||
using O = ShaderOpcode;
|
||||
struct Access {
|
||||
@@ -35538,6 +35598,10 @@ std::vector<TestCase> MakeCases() {
|
||||
cases.push_back(DsAppendAllocatesAcrossWaves(32));
|
||||
cases.push_back(DsAppendAllocatesAcrossWaves(64));
|
||||
AddCase(DsAppendUsesEncodedGdsSelector);
|
||||
for (u32 wave_size : {32, 64}) {
|
||||
cases.push_back(DsOrderedCountAddressAndExec(wave_size, false));
|
||||
cases.push_back(DsOrderedCountAddressAndExec(wave_size, true));
|
||||
}
|
||||
AddCase(DsAppendConsumeGdsRegionBounds);
|
||||
AddCase(DsGdsSubdwordAndAtomicWrites);
|
||||
AddCase(DsReadWrite2Variants);
|
||||
@@ -41059,6 +41123,14 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--ds-ordered-count-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
for (u32 wave_size : {32, 64}) {
|
||||
RunCase(&vulkan, DsOrderedCountAddressAndExec(wave_size, false));
|
||||
RunCase(&vulkan, DsOrderedCountAddressAndExec(wave_size, true));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--ds-atomics-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
for (const auto &test : MakeCases()) {
|
||||
|
||||
Reference in New Issue
Block a user