AnyPS5/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp

96 lines
5.0 KiB
C++

#include "BdaTests.hpp"
#include "prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp"
#include <array>
#include <cstring>
#include <limits>
namespace {
using namespace AgcDriver::Graphics;
using Role = ShaderRecompiler::DescriptorRole;
template<typename TAction>
void reject(TAction action, const char* reason) {
try { action(); }
catch (const std::runtime_error& error) {
Require(std::string(error.what()).find(reason) != std::string::npos, std::string("unexpected BDA test error: ") + error.what());
return;
}
throw std::runtime_error(std::string("expected BDA rejection: ") + reason);
}
ShaderRecompiler::DescriptorBinding binding(Role role, std::uint32_t slot) {
return {ShaderRecompiler::DescriptorKind::StorageBuffer, role, 0, slot, 1, {}, false};
}
}
void RunBdaResourceTests(const Context& context, const BdaTestAccess& access) {
alignas(64) std::array<std::uint32_t, 16> guest{};
guest[0] = 123;
const auto address = reinterpret_cast<std::uintptr_t>(guest.data());
GuestBufferMemory memory(context);
memory.AddWritable(address, sizeof(guest));
memory.AddWritable(address + 16, 16);
memory.Upload(true);
const auto first = memory.Descriptor(address, sizeof(guest));
const auto alias = memory.Descriptor(address + 16, 16);
Require(first.buffer == alias.buffer && alias.offset == 16, "aliased guest buffers have different owners");
const auto ranges = memory.AddressRanges();
Require(ranges.size() == 1 && ranges[0].begin == address && ranges[0].end == address + sizeof(guest), "incorrect BDA range bounds");
Require(ranges[0].deviceAddress != 0 && ranges[0].permissions == ShaderRecompiler::BdaAbi::Read, "incorrect BDA address or permissions");
std::uint32_t changed = 321;
std::memcpy(access.bytes(alias.buffer).data() + alias.offset, &changed, sizeof(changed));
memory.WriteBack();
Require(guest[4] == changed, "aliased GPU write was not published");
reject([&] { memory.WriteBack(); }, "cannot be committed twice");
reject([&] { memory.AddWritable(address, sizeof(guest)); }, "frozen");
GuestBufferMemory overflow(context);
const std::array<std::byte, 8> source{};
reject([&] { overflow.AddSnapshot({std::numeric_limits<std::uint64_t>::max() - 3, source}); }, "overflow");
const std::array<GuestMemorySnapshot, 1> snapshots{{{0x7fff12340000ULL, source}}};
ShaderRecompiler::RecompileResult shader;
shader.bindings = {binding(Role::BdaPagetable, 4), binding(Role::FaultBuffer, 5)};
CompiledShader compiled{ShaderRecompiler::ShaderStage::Compute, &shader, 0};
reject([&] { ShaderResources resources(context, compiled, snapshots); }, "ABI version");
shader.bdaAbiVersion = ShaderRecompiler::BdaAbi::Version;
auto disabled = context;
disabled.bufferDeviceAddress = false;
reject([&] { ShaderResources resources(disabled, compiled, snapshots); }, "not enabled");
{
ShaderResources resources(context, compiled, snapshots);
const auto table = access.bytes(access.descriptor(4).buffer);
ShaderRecompiler::BdaAbi::Header header{};
ShaderRecompiler::BdaAbi::Range range{};
std::memcpy(&header, table.data(), sizeof(header));
Require(header.version == ShaderRecompiler::BdaAbi::Version && header.count == 1 && header.entryBytes == sizeof(range), "BDA header layout mismatch");
std::memcpy(&range, table.data() + sizeof(header), sizeof(range));
Require(range.begin == snapshots[0].address && range.end == range.begin + source.size(), "64-bit guest address was truncated");
const auto fault = access.bytes(access.descriptor(5).buffer);
for (const auto byte : fault) Require(byte == std::byte{}, "fault buffer was not initialized");
resources.WriteBack();
}
{
auto writable = binding(Role::GuestBuffers, 6);
writable.guestDescriptor = {static_cast<std::uint32_t>(address), static_cast<std::uint32_t>(address >> 32) & 0xffffu, sizeof(guest), 0x31000000u};
shader.bindings.push_back(writable);
ShaderResources resources(context, compiled);
changed = 999;
std::memcpy(access.bytes(access.descriptor(6).buffer).data(), &changed, sizeof(changed));
const ShaderRecompiler::BdaAbi::Fault report{ShaderRecompiler::BdaAbi::FaultState::Ready, ShaderRecompiler::BdaAbi::FaultReason::Unmapped, 0x7fff99880000ULL, 4, 0, 0x44, 0};
std::memcpy(access.bytes(access.descriptor(5).buffer).data(), &report, sizeof(report));
reject([&] { resources.WriteBack(); }, "BDA access failed");
Require(guest[0] == 123, "failed GPU command published writes");
}
{
auto aligned = context;
aligned.limits.minStorageBufferOffsetAlignment = 16;
GuestBufferMemory unaligned(aligned);
unaligned.AddWritable(address, sizeof(guest));
unaligned.Upload(true);
reject([&] { unaligned.Descriptor(address + 4, 4); }, "offset alignment");
reject([&] { unaligned.Descriptor(address + sizeof(guest), 4); }, "exceeds its GPU owner");
}
}