mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 00:12:40 +00:00
graphics: add RDNA2 FLAT BDA buffer cache and faults
This commit is contained in:
1 parent
8072718462
commit
e738535294
37 files changed
+1002
-684
No files matched your search
@@ -295,7 +295,7 @@ void TestInvariantIndirectImageMaterialization() {
|
||||
const auto same_snapshot = [](const ResourceSnapshot &lhs,
|
||||
const ResourceSnapshot &rhs) {
|
||||
return lhs.buffers == rhs.buffers && lhs.images == rhs.images &&
|
||||
lhs.samplers == rhs.samplers && lhs.addresses == rhs.addresses &&
|
||||
lhs.samplers == rhs.samplers &&
|
||||
lhs.flattened_srt == rhs.flattened_srt &&
|
||||
lhs.user_data == rhs.user_data &&
|
||||
lhs.indirect_images.empty() == rhs.indirect_images.empty();
|
||||
@@ -848,7 +848,7 @@ void TestSrtFlatteningAndRuntimeMemoization() {
|
||||
Check(fixture.program.srt_reads.size() == 1,
|
||||
"shared typed scalar read did not receive one flat SRT slot");
|
||||
Check(fixture.program.info.buffers.size() == 1 &&
|
||||
fixture.program.info.addresses.empty(),
|
||||
!fixture.program.info.uses_dma,
|
||||
"planning-only scalar reads leaked into resource topology");
|
||||
Check(fixture.program.memory_info[0].planning_only,
|
||||
"canonical runtime scalar read was not marked planning-only");
|
||||
@@ -910,7 +910,7 @@ void TestDynamicSrtReadRemainsExplicit() {
|
||||
|
||||
Check(fixture.program.srt_reads.empty() &&
|
||||
fixture.program.dynamic_reads.size() == 1 &&
|
||||
fixture.program.info.addresses.size() == 1,
|
||||
fixture.program.info.uses_dma,
|
||||
"dynamic scalar read was incorrectly flattened or lost");
|
||||
std::array<uint32_t, 3> user_data{0x1000u, 0u, 4u};
|
||||
TestMemory memory;
|
||||
@@ -932,11 +932,13 @@ void TestDynamicSrtReadRemainsExplicit() {
|
||||
FindBinding(fixture.program.bindings,
|
||||
DescriptorBindingKind::FlattenedSrt) == nullptr &&
|
||||
FindBinding(fixture.program.bindings,
|
||||
DescriptorBindingKind::AddressMemory) != nullptr,
|
||||
DescriptorBindingKind::BdaPagetable) != nullptr &&
|
||||
FindBinding(fixture.program.bindings,
|
||||
DescriptorBindingKind::FaultBuffer) != nullptr,
|
||||
"dynamic scalar read received the wrong resource bindings");
|
||||
Check(fixture.program.bindings.memory_offset_dword ==
|
||||
fixture.program.bindings.user_data_registers.size() &&
|
||||
fixture.program.bindings.memory_offset_count == 2u &&
|
||||
fixture.program.bindings.memory_offset_count == 1u &&
|
||||
fixture.program.bindings.ShaderDataDwords() ==
|
||||
fixture.program.bindings.memory_offset_dword + 1u,
|
||||
"unified memory-offset layout is inconsistent");
|
||||
@@ -1029,7 +1031,7 @@ void TestInvariantLoopPhi() {
|
||||
"loop-invariant descriptor phi was not evaluated through typed SSA");
|
||||
}
|
||||
|
||||
void TestAddressMaterializationAndSpecialization() {
|
||||
void TestDmaAddressMaterialization() {
|
||||
Fixture fixture;
|
||||
const auto based =
|
||||
fixture.Address(fixture.UserData(0), fixture.UserData(1), 4);
|
||||
@@ -1050,29 +1052,19 @@ void TestAddressMaterializationAndSpecialization() {
|
||||
fixture.AddMemory(flat, 8));
|
||||
fixture.PlanAndTrack();
|
||||
|
||||
Check(fixture.program.info.addresses.size() == 2 &&
|
||||
!fixture.program.info.addresses[0].unbased &&
|
||||
fixture.program.info.addresses[0].min_offset == -8 &&
|
||||
fixture.program.info.addresses[1].unbased,
|
||||
"typed based and unbased addresses were classified incorrectly");
|
||||
Check(fixture.program.info.uses_dma,
|
||||
"typed address operations did not enable DMA");
|
||||
std::array<uint32_t, 2> user_data{0x2008u, 0u};
|
||||
SrtRuntime runtime{.user_data = user_data, .flat_memory_base = 0x9000u};
|
||||
SrtRuntime runtime{.user_data = user_data};
|
||||
ResourceSnapshot snapshot;
|
||||
std::string error;
|
||||
Check(MaterializeResources(fixture.program, runtime, snapshot, &error),
|
||||
"address resources did not materialize");
|
||||
Check(snapshot.addresses.size() == 2 &&
|
||||
snapshot.addresses[0].guest_base == 0x2008u &&
|
||||
snapshot.addresses[0].binding_base == 0x2000u &&
|
||||
snapshot.addresses[1].binding_base == 0x9000u,
|
||||
"materialized address windows are incorrect");
|
||||
Check(SpecializeResources(fixture.program, snapshot, &error) &&
|
||||
fixture.program.info.addresses[0].specialized_base == 8u &&
|
||||
fixture.program.info.addresses[1].specialized_base == 0x9000u,
|
||||
"typed address specialization was not applied");
|
||||
"DMA shader resources did not materialize");
|
||||
Check(SpecializeResources(fixture.program, snapshot, &error),
|
||||
"DMA shader resources were not specialized");
|
||||
}
|
||||
|
||||
void TestExecMaskedFlatAddressProvenance() {
|
||||
void TestDynamicFlatAddressesUseDma() {
|
||||
Fixture fixture;
|
||||
const auto low_root = fixture.UserData(0);
|
||||
const auto high_root = fixture.UserData(1);
|
||||
@@ -1092,18 +1084,14 @@ void TestExecMaskedFlatAddressProvenance() {
|
||||
fixture.AddMemory(flat, 0xa4));
|
||||
fixture.PlanAndTrack();
|
||||
|
||||
Check(fixture.program.info.addresses.size() == 1 &&
|
||||
!fixture.program.info.addresses[0].unbased,
|
||||
"exec-masked FLAT address lost its active user-data root");
|
||||
Check(fixture.program.info.uses_dma,
|
||||
"exec-masked FLAT address did not enable DMA");
|
||||
std::array<uint32_t, 3> user_data{0x23456780u, 1u, 1u};
|
||||
SrtRuntime runtime{.user_data = user_data};
|
||||
ResourceSnapshot snapshot;
|
||||
std::string error;
|
||||
Check(MaterializeResources(fixture.program, runtime, snapshot, &error) &&
|
||||
snapshot.addresses.size() == 1 &&
|
||||
snapshot.addresses[0].guest_base == 0x0000000123456780ull &&
|
||||
snapshot.addresses[0].binding_base == 0x0000000123450000ull,
|
||||
"exec-masked FLAT address materialized the wrong user-data root");
|
||||
Check(MaterializeResources(fixture.program, runtime, snapshot, &error),
|
||||
"exec-masked FLAT shader resources did not materialize");
|
||||
|
||||
Fixture mismatch;
|
||||
const auto mismatch_active = mismatch.Emit(ValueOpcode::INotEqual32,
|
||||
@@ -1122,9 +1110,8 @@ void TestExecMaskedFlatAddressProvenance() {
|
||||
{mismatch_address, mismatch_low, mismatch_high, other_active},
|
||||
mismatch.AddMemory(flat, 0xa4));
|
||||
mismatch.PlanAndTrack();
|
||||
Check(mismatch.program.info.addresses.size() == 1 &&
|
||||
mismatch.program.info.addresses[0].unbased,
|
||||
"FLAT address used a select arm guarded by a different active mask");
|
||||
Check(mismatch.program.info.uses_dma,
|
||||
"dynamic FLAT address did not enable DMA");
|
||||
}
|
||||
|
||||
void TestBufferSwizzleSpecialization() {
|
||||
@@ -1393,8 +1380,8 @@ int main() {
|
||||
Run("phi validation", TestPhiValidation);
|
||||
Run("runtime-rooted loop", TestLoopCycleEnteredThroughRuntimeValue);
|
||||
Run("invariant loop phi", TestInvariantLoopPhi);
|
||||
Run("address materialization", TestAddressMaterializationAndSpecialization);
|
||||
Run("exec-masked FLAT address", TestExecMaskedFlatAddressProvenance);
|
||||
Run("DMA address materialization", TestDmaAddressMaterialization);
|
||||
Run("dynamic FLAT address", TestDynamicFlatAddressesUseDma);
|
||||
Run("buffer swizzle specialization", TestBufferSwizzleSpecialization);
|
||||
Run("shader info and bindings", TestShaderInfoAndBindingLayout);
|
||||
Run("graphics push constants", TestGraphicsPushConstantLayout);
|
||||
|
||||
@@ -919,6 +919,11 @@ void CheckLeastRecentlyUsedCacheOrdering() {
|
||||
std::printf("[host] %-32s ok\n", "LeastRecentlyUsedCache");
|
||||
}
|
||||
|
||||
struct BdaMapping {
|
||||
uint64_t guest_base = 0;
|
||||
u32 backing_offset = 0;
|
||||
};
|
||||
|
||||
struct TestCase {
|
||||
const char *name = "";
|
||||
std::vector<u32> code;
|
||||
@@ -959,15 +964,15 @@ struct TestCase {
|
||||
bool compile_only = false;
|
||||
size_t storage_buffer_range_dwords = 0;
|
||||
std::vector<u32> storage_buffer_offsets;
|
||||
std::vector<u32> address_memory_offsets;
|
||||
std::vector<BdaMapping> bda_mappings;
|
||||
bool expand_shader_data_storage = false;
|
||||
bool expected_force_point_sampler = false;
|
||||
std::optional<uint64_t> flat_memory_base;
|
||||
std::vector<u32> gds_initial;
|
||||
std::vector<u32> expected_gds;
|
||||
std::vector<std::pair<std::string, size_t>> decoded_counts;
|
||||
std::vector<std::pair<std::string, size_t>> ir_counts;
|
||||
u32 expected_storage_mip_descriptors = 0;
|
||||
std::string expected_compile_error;
|
||||
};
|
||||
|
||||
struct GraphicsCase {
|
||||
@@ -1168,7 +1173,6 @@ CompiledShader CompileCase(const TestCase &test) {
|
||||
options.user_data = user_data.data();
|
||||
options.read_memory = ReadTestMemory;
|
||||
options.read_memory_data = const_cast<std::vector<u32> *>(&test.initial);
|
||||
options.flat_memory_base = test.flat_memory_base;
|
||||
options.scratch_dwords = test.compute_info.scratch_size_dwords;
|
||||
if (test.has_compute_info) {
|
||||
options.wave_size = test.compute_info.wave_size;
|
||||
@@ -1177,8 +1181,14 @@ CompiledShader CompileCase(const TestCase &test) {
|
||||
ShaderRecompiler::CompileResult result;
|
||||
std::string error;
|
||||
if (!ShaderRecompiler::TryRecompile(test.code, options, result, &error)) {
|
||||
if (!test.expected_compile_error.empty() &&
|
||||
error.find(test.expected_compile_error) != std::string::npos) {
|
||||
return {};
|
||||
}
|
||||
Fail(test.name, "decode/IR", error.c_str());
|
||||
}
|
||||
Require(test.name, "decode/IR", test.expected_compile_error.empty(),
|
||||
"shader unexpectedly compiled despite the required rejection");
|
||||
for (const auto &[text, expected] : test.decoded_counts) {
|
||||
const auto actual = CountText(result.decoded_dump, text);
|
||||
Require(test.name, "decoded RDNA2", actual == expected,
|
||||
@@ -1267,17 +1277,6 @@ CompiledShader CompileCase(const TestCase &test) {
|
||||
packed_user_data[result.program.bindings.memory_offset_dword + i / 4u] |=
|
||||
offset << ((i % 4u) * 8u);
|
||||
}
|
||||
for (u32 i = 0; i < result.program.info.addresses.size(); i++) {
|
||||
u32 offset = 0;
|
||||
if (i < test.address_memory_offsets.size()) {
|
||||
offset = test.address_memory_offsets[i];
|
||||
}
|
||||
Require(test.name, "shader data", offset < 256,
|
||||
"address-memory offset is not representable");
|
||||
const auto index = buffer_count + i;
|
||||
packed_user_data[result.program.bindings.memory_offset_dword +
|
||||
index / 4u] |= offset << ((index % 4u) * 8u);
|
||||
}
|
||||
return {std::move(result.spirv), std::move(result.program),
|
||||
std::move(result.resources.flattened_srt),
|
||||
std::move(packed_user_data)};
|
||||
@@ -1469,6 +1468,7 @@ public:
|
||||
struct Buffer {
|
||||
vk::Buffer buffer = nullptr;
|
||||
vk::DeviceMemory memory = nullptr;
|
||||
vk::DeviceAddress device_address = 0;
|
||||
vk::DeviceSize size = 0;
|
||||
bool coherent = false;
|
||||
};
|
||||
@@ -3157,7 +3157,7 @@ public:
|
||||
"chunked host copy lost bytes across its scratch boundary");
|
||||
|
||||
constexpr uint64_t index_offset = 0x180000;
|
||||
constexpr uint64_t index_page = BufferCache::CACHING_PAGE_SIZE;
|
||||
constexpr uint64_t index_page = BufferCache::CACHING_PAGESIZE;
|
||||
constexpr uint64_t index_span = 3 * index_page;
|
||||
const uint64_t index_begin = base + index_offset;
|
||||
Require(name, "registered-range empty lookup",
|
||||
@@ -3386,7 +3386,7 @@ public:
|
||||
"Buffer ownership");
|
||||
|
||||
constexpr uint64_t starvation_offset = 0x100000;
|
||||
constexpr uint64_t starvation_stride = 2 * BufferCache::CACHING_PAGE_SIZE;
|
||||
constexpr uint64_t starvation_stride = 2 * BufferCache::CACHING_PAGESIZE;
|
||||
constexpr uint32_t starvation_count = 33;
|
||||
constexpr uint32_t starvation_value = 0x31415926u;
|
||||
BufferCacheTestAccess::SetGarbageCollectionThresholds(
|
||||
@@ -3443,7 +3443,7 @@ public:
|
||||
constexpr uint64_t lookup_only_offset = 0x218000;
|
||||
constexpr uint64_t obtained_offset = 0x220000;
|
||||
constexpr uint64_t residency_size =
|
||||
2 * BufferCache::CACHING_PAGE_SIZE;
|
||||
2 * BufferCache::CACHING_PAGESIZE;
|
||||
BufferCacheTestAccess::SetGarbageCollectionThresholds(
|
||||
cache, std::numeric_limits<uint64_t>::max(),
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
@@ -4199,7 +4199,7 @@ public:
|
||||
const uint64_t mip_guest_size = mip_total.size + 256;
|
||||
Require(name, "formatted mip fixture",
|
||||
mip_sizes[0].offset == 0 &&
|
||||
mip_prefix_size > BufferCache::CACHING_PAGE_SIZE &&
|
||||
mip_prefix_size > BufferCache::CACHING_PAGESIZE &&
|
||||
mip_prefix_size < mip_guest_size &&
|
||||
mip_guest_size % sizeof(uint32_t) == 0,
|
||||
"single-mip fixture did not expose a cache-sized fitting backing "
|
||||
@@ -8946,7 +8946,7 @@ public:
|
||||
|
||||
Buffer CreateStorageBuffer(const char *shader_name,
|
||||
const std::vector<u32> &initial,
|
||||
size_t dword_count) {
|
||||
size_t dword_count, bool device_address = false) {
|
||||
Buffer ret;
|
||||
ret.size = static_cast<vk::DeviceSize>(std::max<size_t>(dword_count, 1u) *
|
||||
sizeof(u32));
|
||||
@@ -8955,6 +8955,9 @@ public:
|
||||
buffer_info.sType = vk::StructureType::eBufferCreateInfo;
|
||||
buffer_info.size = ret.size;
|
||||
buffer_info.usage = vk::BufferUsageFlagBits::eStorageBuffer;
|
||||
if (device_address) {
|
||||
buffer_info.usage |= vk::BufferUsageFlagBits::eShaderDeviceAddress;
|
||||
}
|
||||
buffer_info.sharingMode = vk::SharingMode::eExclusive;
|
||||
RequireVk(shader_name, "dispatch",
|
||||
m_device.createBuffer(&buffer_info, nullptr, &ret.buffer),
|
||||
@@ -8979,12 +8982,26 @@ public:
|
||||
alloc.sType = vk::StructureType::eMemoryAllocateInfo;
|
||||
alloc.allocationSize = req.size;
|
||||
alloc.memoryTypeIndex = memory_type;
|
||||
vk::MemoryAllocateFlagsInfo flags{};
|
||||
if (device_address) {
|
||||
flags.sType = vk::StructureType::eMemoryAllocateFlagsInfo;
|
||||
flags.flags = vk::MemoryAllocateFlagBits::eDeviceAddress;
|
||||
alloc.pNext = &flags;
|
||||
}
|
||||
RequireVk(shader_name, "dispatch",
|
||||
m_device.allocateMemory(&alloc, nullptr, &ret.memory),
|
||||
"vkAllocateMemory");
|
||||
RequireVk(shader_name, "dispatch",
|
||||
m_device.bindBufferMemory(ret.buffer, ret.memory, 0),
|
||||
"vkBindBufferMemory");
|
||||
if (device_address) {
|
||||
vk::BufferDeviceAddressInfo address_info{};
|
||||
address_info.sType = vk::StructureType::eBufferDeviceAddressInfo;
|
||||
address_info.buffer = ret.buffer;
|
||||
ret.device_address = m_device.getBufferAddress(address_info);
|
||||
Require(shader_name, "dispatch", ret.device_address != 0,
|
||||
"storage buffer has no device address");
|
||||
}
|
||||
|
||||
std::vector<u32> contents(dword_count, 0);
|
||||
for (size_t i = 0; i < initial.size() && i < contents.size(); i++) {
|
||||
@@ -9366,7 +9383,9 @@ public:
|
||||
pool_sizes.push_back({type, count});
|
||||
};
|
||||
add_pool_size(vk::DescriptorType::eStorageBuffer,
|
||||
Count(Kind::Buffers) + Count(Kind::AddressMemory) +
|
||||
Count(Kind::Buffers) +
|
||||
(Binding(Kind::BdaPagetable) != nullptr ? 1u : 0u) +
|
||||
(Binding(Kind::FaultBuffer) != nullptr ? 1u : 0u) +
|
||||
Count(Kind::Gds) +
|
||||
(Binding(Kind::FlattenedSrt) != nullptr ? 1u : 0u) +
|
||||
(Binding(Kind::UserData) != nullptr ? 1u : 0u));
|
||||
@@ -9411,7 +9430,6 @@ public:
|
||||
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
std::vector<vk::DescriptorBufferInfo> buffer_infos;
|
||||
std::vector<vk::DescriptorBufferInfo> address_memory_infos;
|
||||
std::vector<vk::DescriptorImageInfo> sampled_infos;
|
||||
std::vector<vk::DescriptorImageInfo> storage_infos;
|
||||
std::vector<vk::DescriptorImageInfo> storage_uint_infos;
|
||||
@@ -9422,6 +9440,33 @@ public:
|
||||
vk::DescriptorBufferInfo flattened_info{};
|
||||
vk::DescriptorBufferInfo user_data_info{};
|
||||
vk::DescriptorBufferInfo gds_info{};
|
||||
vk::DescriptorBufferInfo bda_pagetable_info{};
|
||||
vk::DescriptorBufferInfo fault_buffer_info{};
|
||||
|
||||
const bool uses_bda = Binding(Kind::BdaPagetable) != nullptr;
|
||||
Require(test.name, "dispatch",
|
||||
uses_bda == (Binding(Kind::FaultBuffer) != nullptr),
|
||||
"BDA page table and fault buffer must be bound together");
|
||||
if (uses_bda) {
|
||||
EnsureBdaBuffers(test.name);
|
||||
bda_pagetable_info = {m_bda_pagetable_buffer.buffer, 0,
|
||||
m_bda_pagetable_buffer.size};
|
||||
fault_buffer_info = {m_fault_buffer.buffer, 0, m_fault_buffer.size};
|
||||
const std::array special_buffers{
|
||||
std::pair{Kind::BdaPagetable, &bda_pagetable_info},
|
||||
std::pair{Kind::FaultBuffer, &fault_buffer_info},
|
||||
};
|
||||
for (const auto &[kind, info] : special_buffers) {
|
||||
vk::WriteDescriptorSet write{};
|
||||
write.sType = vk::StructureType::eWriteDescriptorSet;
|
||||
write.dstSet = descriptor_set;
|
||||
write.dstBinding = Native(kind);
|
||||
write.descriptorCount = 1;
|
||||
write.descriptorType = vk::DescriptorType::eStorageBuffer;
|
||||
write.pBufferInfo = info;
|
||||
writes.push_back(write);
|
||||
}
|
||||
}
|
||||
|
||||
const auto *buffers = Binding(Kind::Buffers);
|
||||
if (buffers != nullptr) {
|
||||
@@ -9450,21 +9495,6 @@ public:
|
||||
write.pBufferInfo = buffer_infos.data();
|
||||
writes.push_back(write);
|
||||
}
|
||||
if (const auto *address = Binding(Kind::AddressMemory);
|
||||
address != nullptr) {
|
||||
address_memory_infos.resize(address->resources.size());
|
||||
for (auto &info : address_memory_infos) {
|
||||
info = {buffer.buffer, 0, buffer.size};
|
||||
}
|
||||
vk::WriteDescriptorSet write{};
|
||||
write.sType = vk::StructureType::eWriteDescriptorSet;
|
||||
write.dstSet = descriptor_set;
|
||||
write.dstBinding = Native(Kind::AddressMemory);
|
||||
write.descriptorCount = static_cast<u32>(address_memory_infos.size());
|
||||
write.descriptorType = vk::DescriptorType::eStorageBuffer;
|
||||
write.pBufferInfo = address_memory_infos.data();
|
||||
writes.push_back(write);
|
||||
}
|
||||
if (const auto *flattened = Binding(Kind::FlattenedSrt);
|
||||
flattened != nullptr) {
|
||||
flattened_buffer = CreateStorageBuffer(test.name, compiled.flattened_srt,
|
||||
@@ -9590,6 +9620,52 @@ public:
|
||||
}
|
||||
|
||||
vk::CommandBuffer cmd = BeginCommands(test.name, "dispatch");
|
||||
if (uses_bda) {
|
||||
Require(test.name, "dispatch", buffer.device_address != 0,
|
||||
"BDA test backing has no device address");
|
||||
Require(test.name, "dispatch", !test.bda_mappings.empty(),
|
||||
"BDA test has no explicit guest mapping");
|
||||
cmd.fillBuffer(m_bda_pagetable_buffer.buffer, 0,
|
||||
m_bda_pagetable_buffer.size, 0);
|
||||
cmd.fillBuffer(m_fault_buffer.buffer, 0, m_fault_buffer.size, 0);
|
||||
for (const auto &[guest_base, backing] : test.bda_mappings) {
|
||||
const auto page_offset = guest_base &
|
||||
(BufferCache::CACHING_PAGESIZE - 1);
|
||||
Require(test.name, "dispatch",
|
||||
backing >= page_offset && backing < buffer.size,
|
||||
"BDA test mapping begins outside its backing buffer");
|
||||
const auto bytes = page_offset + buffer.size - backing;
|
||||
const auto pages =
|
||||
(bytes + BufferCache::CACHING_PAGESIZE - 1) /
|
||||
BufferCache::CACHING_PAGESIZE;
|
||||
auto address = buffer.device_address + backing - page_offset;
|
||||
auto page = guest_base >> BufferCache::CACHING_PAGEBITS;
|
||||
for (uint64_t mapped = 0; mapped < pages; mapped++) {
|
||||
cmd.updateBuffer(m_bda_pagetable_buffer.buffer,
|
||||
(page + mapped) * sizeof(vk::DeviceAddress),
|
||||
sizeof(address), &address);
|
||||
address += BufferCache::CACHING_PAGESIZE;
|
||||
}
|
||||
}
|
||||
std::array<vk::BufferMemoryBarrier, 2> barriers{};
|
||||
barriers[0].sType = vk::StructureType::eBufferMemoryBarrier;
|
||||
barriers[0].srcAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||
barriers[0].dstAccessMask = vk::AccessFlagBits::eShaderRead;
|
||||
barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barriers[0].buffer = m_bda_pagetable_buffer.buffer;
|
||||
barriers[0].offset = 0;
|
||||
barriers[0].size = m_bda_pagetable_buffer.size;
|
||||
barriers[1] = barriers[0];
|
||||
barriers[1].dstAccessMask = vk::AccessFlagBits::eShaderRead |
|
||||
vk::AccessFlagBits::eShaderWrite;
|
||||
barriers[1].buffer = m_fault_buffer.buffer;
|
||||
barriers[1].size = m_fault_buffer.size;
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::PipelineStageFlagBits::eComputeShader, {}, 0,
|
||||
nullptr, static_cast<u32>(barriers.size()),
|
||||
barriers.data(), 0, nullptr);
|
||||
}
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline);
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipeline_layout, 0,
|
||||
1, &descriptor_set, 0, nullptr);
|
||||
@@ -10951,6 +11027,7 @@ private:
|
||||
allocator_info.device = m_device;
|
||||
allocator_info.pVulkanFunctions = &functions;
|
||||
allocator_info.vulkanApiVersion = VK_API_VERSION_1_3;
|
||||
allocator_info.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
|
||||
RequireVk("VulkanHarness", "runtime context",
|
||||
static_cast<vk::Result>(vmaCreateAllocator(
|
||||
&allocator_info, &m_runtime_context.allocator)),
|
||||
@@ -11001,13 +11078,18 @@ private:
|
||||
if ((queues[i].queueFlags &
|
||||
(vk::QueueFlagBits::eCompute | vk::QueueFlagBits::eGraphics)) ==
|
||||
(vk::QueueFlagBits::eCompute | vk::QueueFlagBits::eGraphics)) {
|
||||
vk::PhysicalDeviceVulkan12Features features12{};
|
||||
features12.sType = vk::StructureType::ePhysicalDeviceVulkan12Features;
|
||||
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR barycentric{};
|
||||
barycentric.sType = vk::StructureType::ePhysicalDeviceFragmentShaderBarycentricFeaturesKHR;
|
||||
barycentric.pNext = &features12;
|
||||
vk::PhysicalDeviceFeatures2 features{};
|
||||
features.sType = vk::StructureType::ePhysicalDeviceFeatures2;
|
||||
features.pNext = &barycentric;
|
||||
physical.getFeatures2(&features);
|
||||
if (barycentric.fragmentShaderBarycentric != true) {
|
||||
if (barycentric.fragmentShaderBarycentric != true ||
|
||||
features.features.shaderInt64 != true ||
|
||||
features12.bufferDeviceAddress != true) {
|
||||
continue;
|
||||
}
|
||||
m_physical_device = physical;
|
||||
@@ -11051,6 +11133,11 @@ private:
|
||||
Require("VulkanHarness", "dispatch",
|
||||
available_features.sampleRateShading == true,
|
||||
"sample-rate shading is not supported");
|
||||
Require("VulkanHarness", "dispatch", available_features.shaderInt64 == true,
|
||||
"shaderInt64 is not supported");
|
||||
Require("VulkanHarness", "dispatch",
|
||||
available_features12.bufferDeviceAddress == true,
|
||||
"bufferDeviceAddress is not supported");
|
||||
|
||||
float priority = 1.0f;
|
||||
vk::DeviceQueueCreateInfo queue_info{};
|
||||
@@ -11067,6 +11154,7 @@ private:
|
||||
device_features12.sType =
|
||||
vk::StructureType::ePhysicalDeviceVulkan12Features;
|
||||
device_features12.timelineSemaphore = true;
|
||||
device_features12.bufferDeviceAddress = true;
|
||||
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR barycentric{};
|
||||
barycentric.sType = vk::StructureType::ePhysicalDeviceFragmentShaderBarycentricFeaturesKHR;
|
||||
barycentric.pNext = &device_features12;
|
||||
@@ -11081,6 +11169,7 @@ private:
|
||||
vk::PhysicalDeviceFeatures device_features{};
|
||||
device_features.shaderStorageImageWriteWithoutFormat = true;
|
||||
device_features.sampleRateShading = true;
|
||||
device_features.shaderInt64 = true;
|
||||
device_info.pEnabledFeatures = &device_features;
|
||||
constexpr const char *device_extensions[] = {
|
||||
VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
|
||||
@@ -11105,6 +11194,8 @@ private:
|
||||
void Destroy() {
|
||||
if (m_device != nullptr) {
|
||||
RequireVulkanSuccess(m_device.waitIdle(), "vkDeviceWaitIdle");
|
||||
DestroyBuffer(&m_fault_buffer);
|
||||
DestroyBuffer(&m_bda_pagetable_buffer);
|
||||
if (m_runtime_context.allocator != nullptr) {
|
||||
m_renderer.reset();
|
||||
vmaDestroyAllocator(m_runtime_context.allocator);
|
||||
@@ -11276,6 +11367,53 @@ private:
|
||||
image->layout = final_layout;
|
||||
}
|
||||
|
||||
Buffer CreateDeviceBuffer(const char *shader_name, vk::DeviceSize size,
|
||||
vk::BufferUsageFlags usage) {
|
||||
Buffer ret;
|
||||
ret.size = size;
|
||||
vk::BufferCreateInfo buffer_info{};
|
||||
buffer_info.sType = vk::StructureType::eBufferCreateInfo;
|
||||
buffer_info.size = size;
|
||||
buffer_info.usage = usage;
|
||||
buffer_info.sharingMode = vk::SharingMode::eExclusive;
|
||||
RequireVk(shader_name, "dispatch",
|
||||
m_device.createBuffer(&buffer_info, nullptr, &ret.buffer),
|
||||
"vkCreateBuffer");
|
||||
|
||||
vk::MemoryRequirements requirements{};
|
||||
m_device.getBufferMemoryRequirements(ret.buffer, &requirements);
|
||||
u32 memory_type = 0;
|
||||
Require(shader_name, "dispatch",
|
||||
FindMemoryType(requirements.memoryTypeBits,
|
||||
vk::MemoryPropertyFlagBits::eDeviceLocal,
|
||||
&memory_type) ||
|
||||
FindMemoryType(requirements.memoryTypeBits, {}, &memory_type),
|
||||
"no memory type for BDA support buffer");
|
||||
vk::MemoryAllocateInfo allocation{};
|
||||
allocation.sType = vk::StructureType::eMemoryAllocateInfo;
|
||||
allocation.allocationSize = requirements.size;
|
||||
allocation.memoryTypeIndex = memory_type;
|
||||
RequireVk(shader_name, "dispatch",
|
||||
m_device.allocateMemory(&allocation, nullptr, &ret.memory),
|
||||
"vkAllocateMemory");
|
||||
RequireVk(shader_name, "dispatch",
|
||||
m_device.bindBufferMemory(ret.buffer, ret.memory, 0),
|
||||
"vkBindBufferMemory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EnsureBdaBuffers(const char *shader_name) {
|
||||
if (m_bda_pagetable_buffer.buffer != nullptr) {
|
||||
return;
|
||||
}
|
||||
const auto usage = vk::BufferUsageFlagBits::eStorageBuffer |
|
||||
vk::BufferUsageFlagBits::eTransferDst;
|
||||
m_bda_pagetable_buffer =
|
||||
CreateDeviceBuffer(shader_name, BufferCache::BDA_PAGETABLE_SIZE, usage);
|
||||
m_fault_buffer = CreateDeviceBuffer(
|
||||
shader_name, BufferCache::CACHING_NUMPAGES / 8, usage);
|
||||
}
|
||||
|
||||
Buffer CreateHostBuffer(const char *shader_name, vk::DeviceSize size,
|
||||
vk::BufferUsageFlags usage,
|
||||
const std::vector<u32> &contents) {
|
||||
@@ -11349,6 +11487,8 @@ private:
|
||||
vk::CommandPool m_command_pool = nullptr;
|
||||
u32 m_queue_family = 0;
|
||||
vk::PhysicalDeviceMemoryProperties m_memory_properties{};
|
||||
Buffer m_bda_pagetable_buffer;
|
||||
Buffer m_fault_buffer;
|
||||
GraphicContext m_runtime_context{};
|
||||
std::unique_ptr<RenderContext> m_renderer;
|
||||
};
|
||||
@@ -11392,6 +11532,10 @@ void CompareGraphicsWords(const GraphicsCase &test,
|
||||
|
||||
void RunCase(VulkanHarness *vulkan, const TestCase &test) {
|
||||
auto compiled = CompileCase(test);
|
||||
if (!test.expected_compile_error.empty()) {
|
||||
std::printf("[compute] %-32s ok\n", test.name);
|
||||
return;
|
||||
}
|
||||
if (test.image_descriptor_swizzle != DstSel(4, 5, 6, 7)) {
|
||||
Require(test.name, "resource specialization",
|
||||
!compiled.program.info.images.empty() &&
|
||||
@@ -11410,15 +11554,15 @@ void RunCase(VulkanHarness *vulkan, const TestCase &test) {
|
||||
std::printf("[compute] %-32s ok\n", test.name);
|
||||
return;
|
||||
}
|
||||
const auto dwords = std::max<size_t>(
|
||||
{test.initial.size(), test.expected.size(), static_cast<size_t>(1)});
|
||||
auto buffer = vulkan->CreateStorageBuffer(test.name, test.initial, dwords);
|
||||
|
||||
using Kind = ShaderRecompiler::IR::DescriptorBindingKind;
|
||||
auto Has = [&](Kind kind) {
|
||||
return ShaderRecompiler::IR::FindBinding(compiled.program.bindings, kind) !=
|
||||
nullptr;
|
||||
};
|
||||
const auto dwords = std::max<size_t>(
|
||||
{test.initial.size(), test.expected.size(), static_cast<size_t>(1)});
|
||||
auto buffer = vulkan->CreateStorageBuffer(
|
||||
test.name, test.initial, dwords, Has(Kind::BdaPagetable));
|
||||
VulkanHarness::Image sampled_image;
|
||||
VulkanHarness::Image storage_image;
|
||||
VulkanHarness::Image storage_image_uint;
|
||||
@@ -17341,16 +17485,16 @@ TestCase FlatLoadVariants() {
|
||||
O::FLAT_LOAD_USHORT, O::FLAT_LOAD_SSHORT, O::FLAT_LOAD_DWORD,
|
||||
O::FLAT_LOAD_DWORDX2, O::FLAT_LOAD_DWORDX3,
|
||||
O::FLAT_LOAD_DWORDX4, O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
|
||||
test.flat_memory_base = 0;
|
||||
test.address_memory_offsets = {static_cast<u32>(byte_offset)};
|
||||
test.bda_mappings = {{0, static_cast<u32>(byte_offset)}};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase FlatSubdwordLoadsApplyByteOffset() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
constexpr size_t byte_offset = 3;
|
||||
std::vector<u32> code;
|
||||
AppendVMovU32(&code, 20, 0);
|
||||
AppendVMovU32(&code, 20, static_cast<u32>(byte_offset));
|
||||
AppendVMovU32(&code, 21, 0);
|
||||
code.push_back(EncodeFlat0(0x08, 0, 0));
|
||||
code.push_back(EncodeFlat1(0, 0x7d, 0, 20));
|
||||
@@ -17360,7 +17504,6 @@ TestCase FlatSubdwordLoadsApplyByteOffset() {
|
||||
AppendStoreVgpr(&code, 1, 1);
|
||||
AppendEnd(&code);
|
||||
|
||||
constexpr size_t byte_offset = 3;
|
||||
constexpr u32 guest_word = 0x80ff7f01u;
|
||||
std::vector<u32> host_memory(
|
||||
(byte_offset + sizeof(guest_word) + sizeof(u32) - 1u) / sizeof(u32));
|
||||
@@ -17372,8 +17515,7 @@ TestCase FlatSubdwordLoadsApplyByteOffset() {
|
||||
test.code = std::move(code);
|
||||
test.initial = std::move(host_memory);
|
||||
test.expected = {0x01u, 0x0000ff7fu};
|
||||
test.flat_memory_base = 0;
|
||||
test.address_memory_offsets = {static_cast<u32>(byte_offset)};
|
||||
test.bda_mappings = {{0, 0}};
|
||||
test.opcodes = {O::V_MOV_B32, O::FLAT_LOAD_UBYTE, O::FLAT_LOAD_USHORT,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
return test;
|
||||
@@ -17457,8 +17599,7 @@ TestCase FlatVirtualAddressRebasesGuestAllocation() {
|
||||
test.code = std::move(code);
|
||||
test.initial = {0xfeedfaceu, 0xcafebabeu, 0, 0x12345678u};
|
||||
test.expected = {0x12345678u, 0x12345678u, 0};
|
||||
test.flat_memory_base = GuestBase;
|
||||
test.address_memory_offsets = {8, 8, 8};
|
||||
test.bda_mappings = {{GuestBase, 8}};
|
||||
test.opcodes = {O::V_MOV_B32, O::FLAT_LOAD_DWORD, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
return test;
|
||||
@@ -17480,10 +17621,9 @@ TestCase GlobalSignedImmediateRebasesBeforeSaddr() {
|
||||
TestCase test;
|
||||
test.name = "GlobalSignedImmediateRebasesBeforeSaddr";
|
||||
test.code = std::move(code);
|
||||
test.initial = {0xfeedfaceu, 0xcafebabeu, 0x11111111u, 0x22222222u,
|
||||
0x12345678u};
|
||||
test.initial = {0xfeedfaceu, 0xcafebabeu, 0x11111111u, 0x12345678u};
|
||||
test.expected = {0x12345678u};
|
||||
test.address_memory_offsets = {8};
|
||||
test.bda_mappings = {{GuestBase, 8}};
|
||||
test.opcodes = {O::S_MOV_B32, O::V_MOV_B32, O::FLAT_LOAD_DWORD,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
return test;
|
||||
@@ -17517,7 +17657,7 @@ TestCase FlatSegmentIgnoresSaddrAndMasksOffsetMsb() {
|
||||
test.expected = {0x11111111u, 0x11111111u};
|
||||
test.opcodes = {O::S_MOV_B32, O::V_MOV_B32, O::FLAT_LOAD_DWORD,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.flat_memory_base = 0;
|
||||
test.bda_mappings = {{0, 0}};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -17596,7 +17736,8 @@ TestCase FlatStoreVariants() {
|
||||
{O::V_MOV_B32, O::FLAT_STORE_BYTE, O::FLAT_STORE_SHORT,
|
||||
O::FLAT_STORE_DWORD, O::FLAT_STORE_DWORDX2,
|
||||
O::FLAT_STORE_DWORDX3, O::FLAT_STORE_DWORDX4, O::S_ENDPGM}};
|
||||
test.flat_memory_base = 0;
|
||||
test.expected_compile_error =
|
||||
"writable FLAT/GLOBAL addresses require GPU ownership tracking";
|
||||
return test;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,12 +73,7 @@ UnbasedFlatProgram() {
|
||||
program.srt_plan_complete = true;
|
||||
program.resource_tracking_complete = true;
|
||||
AddValueBlock(program);
|
||||
AddressResource address;
|
||||
address.source = UINT32_MAX;
|
||||
address.first_use_pc = 0x80;
|
||||
address.kind = ResourceKind::Flat;
|
||||
address.unbased = true;
|
||||
program.info.addresses.push_back(address);
|
||||
program.info.uses_dma = true;
|
||||
return std::make_shared<const Program>(std::move(program));
|
||||
}
|
||||
|
||||
@@ -102,7 +97,7 @@ void TestMappedSrtUsesDirectReaderByDefault() {
|
||||
"cache rematerialization did not use the direct reader by default");
|
||||
}
|
||||
|
||||
void TestUnbasedFlatCacheHitFailsClosed() {
|
||||
void TestUnbasedFlatCacheHitMaterializes() {
|
||||
using namespace Libs::Graphics;
|
||||
auto cached_program = UnbasedFlatProgram();
|
||||
auto prior_program = std::make_shared<const ShaderRecompiler::IR::Program>();
|
||||
@@ -110,12 +105,9 @@ void TestUnbasedFlatCacheHitFailsClosed() {
|
||||
std::make_shared<const ShaderRecompiler::IR::ResourceSnapshot>();
|
||||
ShaderStageRuntime stage{prior_program, prior_resources};
|
||||
std::string error;
|
||||
Check(!ShaderMaterializeStageRuntime(cached_program, {}, 0, stage, &error) &&
|
||||
error.find("requires runtime guest-address translation") !=
|
||||
std::string::npos,
|
||||
"unbased FLAT cache hit did not fail without a runtime translator");
|
||||
Check(stage.program == prior_program && stage.resources == prior_resources,
|
||||
"unbased FLAT cache rejection replaced the prior stage snapshot");
|
||||
Check(ShaderMaterializeStageRuntime(cached_program, {}, 0, stage, &error), error.c_str());
|
||||
Check(stage.program == cached_program && stage.resources != prior_resources,
|
||||
"unbased FLAT cache hit did not publish its BDA stage snapshot");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -130,7 +122,7 @@ void DbgExit(int) { std::abort(); }
|
||||
|
||||
int main() {
|
||||
TestMappedSrtUsesDirectReaderByDefault();
|
||||
TestUnbasedFlatCacheHitFailsClosed();
|
||||
TestUnbasedFlatCacheHitMaterializes();
|
||||
std::puts("ShaderStageRuntimeTests: all cases passed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
+48
-61
@@ -4319,14 +4319,14 @@ void TestNewShaderRecompilerScalarMemoryBindingDomains() {
|
||||
error.c_str());
|
||||
const auto *address_binding = ShaderRecompiler::IR::FindBinding(
|
||||
raw.program.bindings,
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::AddressMemory);
|
||||
Check(raw.program.info.addresses.size() == 1u &&
|
||||
raw.program.info.addresses[0].kind ==
|
||||
ShaderRecompiler::IR::ResourceKind::ScalarAddress &&
|
||||
raw.program.info.addresses[0].read &&
|
||||
!raw.program.info.addresses[0].written &&
|
||||
raw.program.info.buffers.empty() && address_binding != nullptr &&
|
||||
address_binding->resources == std::vector<uint32_t>{0u} &&
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::BdaPagetable);
|
||||
const auto *fault_binding = ShaderRecompiler::IR::FindBinding(
|
||||
raw.program.bindings,
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::FaultBuffer);
|
||||
Check(raw.program.info.uses_dma && raw.program.info.buffers.empty() &&
|
||||
address_binding != nullptr && fault_binding != nullptr &&
|
||||
address_binding->resources.empty() &&
|
||||
fault_binding->resources.empty() &&
|
||||
ShaderRecompiler::IR::FindBinding(
|
||||
raw.program.bindings,
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::Buffers) ==
|
||||
@@ -4335,17 +4335,12 @@ void TestNewShaderRecompilerScalarMemoryBindingDomains() {
|
||||
raw.program.bindings,
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::FlattenedSrt) ==
|
||||
nullptr &&
|
||||
raw.program.bindings.memory_offset_count == 1u,
|
||||
"raw scalar load did not use only the address-memory domain");
|
||||
raw.program.bindings.memory_offset_count == 0u,
|
||||
"raw scalar load did not use only the DMA domain");
|
||||
Check(count_live_memory_ops(
|
||||
raw.program, ShaderRecompiler::IR::ValueOpcode::LoadAddressU32,
|
||||
ShaderRecompiler::IR::ResourceKind::ScalarAddress) == 1u,
|
||||
"raw scalar load did not remain a live typed address operation");
|
||||
Check(raw.resources.addresses.size() == 1u &&
|
||||
raw.resources.addresses[0].guest_base == 0x1000u &&
|
||||
raw.resources.addresses[0].binding_base == 0x1000u &&
|
||||
raw.program.info.addresses[0].specialized_base == 0u,
|
||||
"raw scalar address specialization was incorrect");
|
||||
Check(SpirvContainsOpcode(raw.spirv, 199),
|
||||
"raw scalar SOFFSET alignment was not emitted");
|
||||
CheckSpirvBinaryValidates(raw.spirv);
|
||||
@@ -4377,12 +4372,12 @@ void TestNewShaderRecompilerScalarMemoryBindingDomains() {
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::Buffers);
|
||||
Check(buffer.program.info.buffers.size() == 1u &&
|
||||
buffer.program.info.buffers[0].scalar &&
|
||||
buffer.program.info.addresses.empty() &&
|
||||
!buffer.program.info.uses_dma &&
|
||||
buffer_binding != nullptr &&
|
||||
buffer_binding->resources == std::vector<uint32_t>{0u} &&
|
||||
ShaderRecompiler::IR::FindBinding(
|
||||
buffer.program.bindings,
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::AddressMemory) ==
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::BdaPagetable) ==
|
||||
nullptr &&
|
||||
ShaderRecompiler::IR::FindBinding(
|
||||
buffer.program.bindings,
|
||||
@@ -6201,7 +6196,6 @@ void TestNewShaderRecompilerFlatOldBackedTranslation() {
|
||||
|
||||
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||
options.dump_ir = true;
|
||||
options.flat_memory_base = 0;
|
||||
|
||||
ShaderRecompiler::CompileResult result;
|
||||
std::string error;
|
||||
@@ -6224,23 +6218,32 @@ void TestNewShaderRecompilerFlatOldBackedTranslation() {
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerUnbasedFlatRequiresTranslator() {
|
||||
void TestNewShaderRecompilerUnbasedFlatUsesBda() {
|
||||
const uint32_t shader[] = {
|
||||
EncodeFlat0(0x0c, 0, 0),
|
||||
EncodeFlat1(0, 0x7d, 0, 1),
|
||||
EncodeFlat0(0x1c, 0, 0),
|
||||
EncodeFlat1(0, 0x7d, 0, 2),
|
||||
0xbf810000u,
|
||||
EncodeExp0(0x00, 0x1),
|
||||
EncodeExp1(0, 0, 0, 0),
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
|
||||
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||
auto options = MakeCompileOptions(ShaderType::Pixel);
|
||||
|
||||
ShaderRecompiler::CompileResult result;
|
||||
std::string error;
|
||||
Check(!ShaderRecompiler::TryRecompile(shader, options, result, &error) &&
|
||||
Common::ContainsStr(error,
|
||||
"requires runtime guest-address translation"),
|
||||
"unbased FLAT compiled without an explicit translator");
|
||||
Check(ShaderRecompiler::TryRecompile(shader, options, result, &error),
|
||||
error.c_str());
|
||||
Check(result.program.info.uses_dma &&
|
||||
ShaderRecompiler::IR::FindBinding(
|
||||
result.program.bindings,
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::BdaPagetable) !=
|
||||
nullptr &&
|
||||
ShaderRecompiler::IR::FindBinding(
|
||||
result.program.bindings,
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::FaultBuffer) !=
|
||||
nullptr,
|
||||
"unbased FLAT did not compile through BDA");
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerFlatSignedLoadTranslation() {
|
||||
@@ -6256,7 +6259,6 @@ void TestNewShaderRecompilerFlatSignedLoadTranslation() {
|
||||
|
||||
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||
options.dump_ir = true;
|
||||
options.flat_memory_base = 0;
|
||||
|
||||
ShaderRecompiler::CompileResult result;
|
||||
std::string error;
|
||||
@@ -6311,7 +6313,6 @@ void TestNewShaderRecompilerFlatStoreTranslation() {
|
||||
|
||||
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||
options.dump_ir = true;
|
||||
options.flat_memory_base = 0;
|
||||
|
||||
ShaderRecompiler::CompileResult result;
|
||||
std::string error;
|
||||
@@ -11966,49 +11967,40 @@ void TestNewShaderRecompilerUnsupportedMemoryDecode() {
|
||||
"MTBUF", "opcode=0x08");
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerFlatUserPointerProvenance() {
|
||||
void TestNewShaderRecompilerFlatUserPointerUsesDma() {
|
||||
const uint32_t shader[] = {
|
||||
EncodeVop2(0x25, 0, 0, 2), // v_add_nc_u32 v0, s0, v2
|
||||
EncodeVop1(0x01, 1, 1), // v_mov_b32 v1, s1
|
||||
EncodeFlat0(0x1c, 0, 0),
|
||||
EncodeFlat1(0, 0x7d, 3, 0), // flat_store_dword v3, v[0:1]
|
||||
0xbf810000u,
|
||||
EncodeFlat0(0x0c, 0, 0),
|
||||
EncodeFlat1(3, 0x7d, 0, 0), // flat_load_dword v3, v[0:1]
|
||||
EncodeExp0(0x00, 0x1),
|
||||
EncodeExp1(3, 0, 0, 0),
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
const uint32_t user_data[] = {0x34567000u, 0x00000012u};
|
||||
|
||||
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||
auto options = MakeCompileOptions(ShaderType::Pixel);
|
||||
options.user_data = user_data;
|
||||
options.user_data_count = static_cast<uint32_t>(std::size(user_data));
|
||||
options.flat_memory_base = 0;
|
||||
|
||||
ShaderRecompiler::CompileResult result;
|
||||
std::string error;
|
||||
const bool compiled =
|
||||
ShaderRecompiler::TryRecompile(shader, options, result, &error);
|
||||
Check(compiled, error.c_str());
|
||||
Check(result.program.info.addresses.size() == 1 &&
|
||||
!result.program.info.addresses[0].unbased &&
|
||||
result.program.info.addresses[0].source <
|
||||
result.program.descriptor_sources.size(),
|
||||
"FLAT user pointer provenance was not attached");
|
||||
Check(result.resources.addresses.size() == 1 &&
|
||||
result.resources.addresses[0].guest_base == 0x0000001234567000ull &&
|
||||
result.resources.addresses[0].binding_base ==
|
||||
0x0000001234560000ull &&
|
||||
result.program.info.addresses[0].specialized_base ==
|
||||
0x0000001234560000ull,
|
||||
"FLAT user pointer did not materialize its guest base");
|
||||
Check(result.program.info.uses_dma,
|
||||
"FLAT user pointer did not enable DMA");
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerFlatAddressProvenanceBoundaries() {
|
||||
void TestNewShaderRecompilerFlatAddressDomainsUseDma() {
|
||||
const uint32_t segmented_shader[] = {
|
||||
EncodeVop2(0x25, 0, 0, 2),
|
||||
EncodeVop1(0x01, 1, 1),
|
||||
EncodeFlat0(0x1c, 2, 0),
|
||||
EncodeFlat1(0, 0x7d, 3, 0), // global_store_dword v3, v[0:1]
|
||||
EncodeFlat0(0x0c, 2, 0),
|
||||
EncodeFlat1(3, 0x7d, 0, 0), // global_load_dword v3, v[0:1]
|
||||
EncodeFlat0(0x1c, 1, 0),
|
||||
EncodeFlat1(0, 0x7d, 4, 0), // scratch_store_dword v4, v[0:1]
|
||||
EncodeFlat1(0, 0x7d, 3, 0), // scratch_store_dword v3, v[0:1]
|
||||
0xbf810000u,
|
||||
};
|
||||
const uint32_t user_data[] = {0x34567000u, 0u, 0x1000u};
|
||||
@@ -12016,19 +12008,14 @@ void TestNewShaderRecompilerFlatAddressProvenanceBoundaries() {
|
||||
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||
options.user_data = user_data;
|
||||
options.user_data_count = static_cast<uint32_t>(std::size(user_data));
|
||||
options.flat_memory_base = 0;
|
||||
options.scratch_dwords = 1;
|
||||
ShaderRecompiler::CompileResult result;
|
||||
std::string error;
|
||||
const bool compiled =
|
||||
ShaderRecompiler::TryRecompile(segmented_shader, options, result, &error);
|
||||
Check(compiled, error.c_str());
|
||||
Check(result.program.info.addresses.size() == 1 &&
|
||||
result.program.info.addresses[0].kind ==
|
||||
ShaderRecompiler::IR::ResourceKind::Global &&
|
||||
result.program.info.addresses[0].unbased &&
|
||||
result.program.info.addresses[0].source == UINT32_MAX,
|
||||
"GLOBAL null-SADDR did not remain an unbased guest address");
|
||||
Check(result.program.info.uses_dma,
|
||||
"GLOBAL null-SADDR did not enable DMA");
|
||||
Check(Common::ContainsStr(result.ir_dump, "GetScratchResource") &&
|
||||
result.program.scratch_dwords == 1,
|
||||
"SCRATCH incorrectly entered guest address tracking");
|
||||
@@ -12324,9 +12311,9 @@ int main() {
|
||||
TestNewShaderRecompilerRejectsDppOn64BitCompares();
|
||||
TestNewShaderRecompilerIrLookupMissFailsExplicitly();
|
||||
TestPsInputCountRegisterDecode();
|
||||
TestNewShaderRecompilerUnbasedFlatRequiresTranslator();
|
||||
TestNewShaderRecompilerFlatUserPointerProvenance();
|
||||
TestNewShaderRecompilerFlatAddressProvenanceBoundaries();
|
||||
TestNewShaderRecompilerUnbasedFlatUsesBda();
|
||||
TestNewShaderRecompilerFlatUserPointerUsesDma();
|
||||
TestNewShaderRecompilerFlatAddressDomainsUseDma();
|
||||
TestNewShaderRecompilerCfgStraightLine();
|
||||
TestNewShaderRecompilerCfgIfElse();
|
||||
TestNewShaderRecompilerCfgConsecutiveNativePhis();
|
||||
|
||||
Reference in new issue
Block a user