93 lines
3.8 KiB
C++
93 lines
3.8 KiB
C++
#ifndef CORE_SHADER_RECOMPILER_BDAABI_HPP
|
|
#define CORE_SHADER_RECOMPILER_BDAABI_HPP
|
|
|
|
#include <bit>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <type_traits>
|
|
|
|
namespace ShaderRecompiler::BdaAbi {
|
|
|
|
inline constexpr std::uint32_t Version = 1;
|
|
inline constexpr std::uint32_t Read = 1;
|
|
inline constexpr std::uint32_t Write = 2;
|
|
|
|
struct Header {
|
|
std::uint32_t version;
|
|
std::uint32_t count;
|
|
std::uint32_t entryBytes;
|
|
std::uint32_t reserved;
|
|
};
|
|
|
|
struct Range {
|
|
std::uint64_t begin;
|
|
std::uint64_t end;
|
|
std::uint64_t deviceAddress;
|
|
std::uint32_t permissions;
|
|
std::uint32_t reserved;
|
|
};
|
|
|
|
enum class FaultState : std::uint32_t { Empty, Writing, Ready };
|
|
enum class FaultReason : std::uint32_t { Unmapped = 1, Permission, Overflow, InvalidTable, InvalidRectangle, LoopLimit, Unaligned, InvalidDescriptor };
|
|
|
|
struct Fault {
|
|
FaultState state;
|
|
FaultReason reason;
|
|
std::uint64_t address;
|
|
std::uint32_t bytes;
|
|
std::uint32_t stage;
|
|
std::uint32_t instruction;
|
|
std::uint32_t reserved;
|
|
};
|
|
|
|
static_assert(std::is_standard_layout_v<Header> && std::is_trivially_copyable_v<Header> && sizeof(Header) == 16);
|
|
static_assert(std::is_standard_layout_v<Range> && std::is_trivially_copyable_v<Range> && sizeof(Range) == 32);
|
|
static_assert(offsetof(Range, deviceAddress) == 16 && offsetof(Range, permissions) == 24);
|
|
static_assert(std::is_standard_layout_v<Fault> && std::is_trivially_copyable_v<Fault> && sizeof(Fault) == 32);
|
|
static_assert(offsetof(Fault, address) == 8 && offsetof(Fault, instruction) == 24);
|
|
|
|
inline constexpr std::uint32_t WrittenPageShift = 12;
|
|
inline constexpr std::uint32_t WrittenChunkShift = 17;
|
|
inline constexpr std::uint32_t WrittenChunkPages = 1u << (WrittenChunkShift - WrittenPageShift);
|
|
inline constexpr std::uint32_t WrittenPageSlots = 2048;
|
|
inline constexpr std::uint32_t WrittenPageProbes = 8;
|
|
inline constexpr std::uint64_t WrittenAddressLimit = std::uint64_t{0xffffffffu} << WrittenChunkShift;
|
|
inline constexpr std::uint32_t WrittenOverflowWord = sizeof(Fault) / sizeof(std::uint32_t);
|
|
inline constexpr std::uint32_t WrittenCountWord = WrittenOverflowWord + 1;
|
|
inline constexpr std::uint32_t WrittenSlotsWord = WrittenCountWord + 1;
|
|
inline constexpr std::uint32_t WrittenListWord = WrittenSlotsWord + 2 * WrittenPageSlots;
|
|
inline constexpr std::size_t FaultBufferBytes = (WrittenListWord + WrittenPageSlots) * sizeof(std::uint32_t);
|
|
static_assert((WrittenPageSlots & (WrittenPageSlots - 1)) == 0);
|
|
static_assert(WrittenChunkPages == 32);
|
|
|
|
inline constexpr std::uint32_t WrittenChunkKey(std::uint64_t address) {
|
|
return static_cast<std::uint32_t>(address >> WrittenChunkShift) + 1u;
|
|
}
|
|
|
|
template<typename TMark>
|
|
bool ForEachWrittenRange(const std::uint32_t* words, TMark&& mark) {
|
|
const auto count = words[WrittenCountWord];
|
|
if (count > WrittenPageSlots) return false;
|
|
for (std::uint32_t claim = 0; claim < count; ++claim) {
|
|
const auto slot = words[WrittenListWord + claim];
|
|
if (slot >= WrittenPageSlots || words[WrittenSlotsWord + 2 * slot] == 0) return false;
|
|
}
|
|
for (std::uint32_t claim = 0; claim < count; ++claim) {
|
|
const auto slot = words[WrittenListWord + claim];
|
|
const auto key = words[WrittenSlotsWord + 2 * slot];
|
|
auto mask = words[WrittenSlotsWord + 2 * slot + 1];
|
|
const auto base = static_cast<std::uint64_t>(key - 1u) << WrittenChunkShift;
|
|
while (mask != 0) {
|
|
const auto first = static_cast<std::uint32_t>(std::countr_zero(mask));
|
|
const auto pages = static_cast<std::uint32_t>(std::countr_one(mask >> first));
|
|
mark(base + (static_cast<std::uint64_t>(first) << WrittenPageShift), static_cast<std::size_t>(pages) << WrittenPageShift);
|
|
mask = pages + first >= 32u ? 0u : mask & ~((1u << (first + pages)) - 1u);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|