mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
graphics: add RDNA2 FLAT BDA buffer cache and faults
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user