Resolve GPU-selected raw buffer descriptors through shared RDNA2 addressing

Co-authored-by: Bipin <87369440+bipinkrish@users.noreply.github.com>
This commit is contained in:
nmzik
2026-09-21 14:07:52 +04:00
parent cfb8f7b246
commit b2a80a3a96
6 changed files with 253 additions and 58 deletions
+80
View File
@@ -22529,6 +22529,75 @@ TestCase BufferLoadDwordx4ZeroesOnlyOutOfBoundsTail() {
return test;
}
TestCase BufferLoadsGpuSelectedDescriptors() {
using O = ShaderOpcode;
constexpr uint64_t GuestBase = 0x0000000110000000ull;
struct DescriptorCase {
u32 stride, records, mode, soffset;
bool swizzle, bound;
std::array<u32, 6> expected;
};
const DescriptorCase cases[] = {
{24, 2, 0, 0, false, true, {7, 8, 9, 10, 11, 12}},
{12, 2, 0, 0, false, true, {4, 5, 6, 0, 0, 0}},
{12, 2, 1, 0, false, true, {4, 5, 6, 7, 8, 9}},
{12, 1, 2, 0, false, true, {4, 5, 6, 7, 8, 9}},
{12, 0, 2, 0, false, true, {}},
// OOB3 checks offset + soffset, independently of index * stride.
{12, 20, 3, 4, false, true, {5, 6, 7, 8, 0, 0}},
{12, 2, 0, 0, false, false, {}},
// RDNA2 swizzling uses four-byte elements; soffset is added afterward.
{12, 2, 0, 4, true, true, {3, 11, 19, 0, 0, 0}},
{12, 8, 3, 4, true, true, {3, 11, 19, 0, 0, 0}},
{12, 4, 3, 4, true, true, {}},
};
TestCase test;
test.name = "BufferLoadsGpuSelectedDescriptors";
test.initial.resize(2048);
for (u32 i = 0; i < std::size(cases); ++i) {
const auto &input = cases[i];
const u32 data_offset = 4096 + i * 128;
// 120-byte table entries with a descriptor at byte 8, as in PPSA04677.
const std::array<u32, 4> descriptor{
static_cast<u32>(GuestBase + data_offset),
(input.stride << 16u) | (input.swizzle ? 1u << 31u : 0u) | 1u,
input.records, (input.bound ? 0x5204u : 0x204u) | (input.mode << 28u)};
std::copy(descriptor.begin(), descriptor.end(), test.initial.begin() + 130 + i * 30);
for (u32 word = 0; word < 32; ++word) {
test.initial[data_offset / 4 + word] = i * 100 + word + 1;
}
// Reverse the table order through a GPU load and readfirstlane, not host constants.
const u32 selected = static_cast<u32>(std::size(cases)) - 1 - i;
test.initial[64 + i] = selected;
AppendVMovU32(&test.code, 30, (64 + i) * 4);
AppendBufferLoadDword(&test.code, 0, 30);
test.code.push_back(EncodeVop1(0x02, 20, Vgpr(0)));
test.code.push_back(EncodeSop2(0x26, 20, 20, 255)); // s_mul_i32 s20, s20, 120
test.code.push_back(120);
test.code.push_back(EncodeSmem0(0x0a, 8, 0));
test.code.push_back(EncodeSmem1(520, 20));
AppendSMovLiteral(&test.code, 22, cases[selected].soffset);
AppendVMovU32(&test.code, 21, 1);
test.code.push_back(EncodeMubuf0(0x0e, 0, true, false));
test.code.push_back(EncodeMubuf1(0, 2, 21, 22));
test.code.push_back(EncodeMubuf0(0x0d, 16, true, false));
test.code.push_back(EncodeMubuf1(4, 2, 21, 22));
for (u32 component = 0; component < 6; ++component) {
AppendStoreVgpr(&test.code, component, i * 6 + component);
const u32 expected = cases[selected].expected[component];
test.expected.push_back(expected == 0 ? 0 : selected * 100 + expected);
}
}
AppendEnd(&test.code);
test.bda_mappings = {{GuestBase, 0}};
test.opcodes = {O::V_MOV_B32, O::S_MOV_B32, O::BUFFER_LOAD_DWORD,
O::V_READFIRSTLANE_B32, O::S_MUL_I32, O::S_BUFFER_LOAD_DWORDX4,
O::BUFFER_LOAD_DWORDX4, O::BUFFER_LOAD_DWORDX2,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.required_spirv = {"OpConvertUToPtr", "PhysicalStorageBuffer"};
return test;
}
TestCase BufferStoreDwordx4DropsOnlyOutOfBoundsTail() {
using O = ShaderOpcode;
@@ -27572,6 +27641,7 @@ std::vector<TestCase> MakeCases() {
AddCase(BufferLoadDwordx3SnapshotsOverlappingAddress);
AddCase(BufferLoadDwordx4SnapshotsOverlappingAddress);
AddCase(BufferLoadDwordx4ZeroesOnlyOutOfBoundsTail);
AddCase(BufferLoadsGpuSelectedDescriptors);
AddCase(BufferStoreDwordx4DropsOnlyOutOfBoundsTail);
AddCase(BufferLoadFormatXyzwRejectsPartialRecord);
AddCase(BufferStoreFormatXyzwDropsPartialRecord);
@@ -32298,6 +32368,16 @@ int main(int argc, char **argv) {
return 0;
}
#endif
if (argc == 2 && std::strcmp(argv[1], "--indirect-buffer-only") == 0) {
VulkanHarness vulkan;
RunCase(&vulkan, BufferLoadsGpuSelectedDescriptors());
RunCase(&vulkan, BufferLoadDwordx4SnapshotsOverlappingAddress());
RunCase(&vulkan, BufferLoadDwordx4ZeroesOnlyOutOfBoundsTail());
RunCase(&vulkan, BufferLoadDwordIdxenUsesDescriptorStride());
RunCase(&vulkan, BufferStoreFormatXAddTidUsesLaneIndex());
RunCase(&vulkan, FlatVirtualAddressRebasesGuestAllocation());
return 0;
}
if (argc == 2 && std::strcmp(argv[1], "--wave64-only") == 0) {
VulkanHarness vulkan;
RunCase(&vulkan, Wave32VccMasksPreserveOtherHalf());