Fix NVN buffer descriptor mapping (#363)
Select global-memory buffers by their constant-buffer index and descriptor offset, rather than their position in the descriptor list. Preserve balanced GLASM conditionals and correct 64-bit storage exchange types. Keep existing address-load and range-check code. Adapt Eden fe2591888d.
This commit is contained in:
parent
7b7dc386c8
commit
be889d661f
|
|
@ -31,11 +31,13 @@ void StorageOp(EmitContext& ctx, const IR::Value& binding, ScalarU32 offset,
|
|||
void GlobalStorageOp(EmitContext& ctx, Register address, bool pointer_based, std::string_view expr,
|
||||
std::string_view else_expr = {}) {
|
||||
const size_t num_buffers{ctx.info.storage_buffers_descriptors.size()};
|
||||
size_t num_used_buffers{};
|
||||
for (size_t index = 0; index < num_buffers; ++index) {
|
||||
if (!ctx.info.nvn_buffer_used[index]) {
|
||||
const auto& ssbo{ctx.info.storage_buffers_descriptors[index]};
|
||||
if (!IsUsedNvnStorageBufferDescriptor(ctx.info, ssbo)) {
|
||||
continue;
|
||||
}
|
||||
const auto& ssbo{ctx.info.storage_buffers_descriptors[index]};
|
||||
++num_used_buffers;
|
||||
const u64 ssbo_align_mask{~(ctx.profile.min_ssbo_alignment - 1U)};
|
||||
ctx.Add("LDC.U64 DC.x,c{}[{}];" // unaligned_ssbo_addr
|
||||
"AND.U64 DC.x,DC.x,{};" // ssbo_addr = unaligned_ssbo_addr & ssbo_align_mask
|
||||
|
|
@ -65,7 +67,6 @@ void GlobalStorageOp(EmitContext& ctx, Register address, bool pointer_based, std
|
|||
if (!else_expr.empty()) {
|
||||
ctx.Add("{}", else_expr);
|
||||
}
|
||||
const size_t num_used_buffers{ctx.info.nvn_buffer_used.count()};
|
||||
for (size_t index = 0; index < num_used_buffers; ++index) {
|
||||
ctx.Add("ENDIF;");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -628,7 +628,7 @@ std::string EmitContext::DefineGlobalMemoryFunctions() {
|
|||
std::string load_func_128{"uvec4 LoadGlobal128(uint64_t addr){"};
|
||||
const size_t num_buffers{info.storage_buffers_descriptors.size()};
|
||||
for (size_t index = 0; index < num_buffers; ++index) {
|
||||
if (!info.nvn_buffer_used[index]) {
|
||||
if (!IsUsedNvnStorageBufferDescriptor(info, info.storage_buffers_descriptors[index])) {
|
||||
continue;
|
||||
}
|
||||
define_body(write_func, index, "{0}[uint(addr-{1})>>2]=data;return;}}");
|
||||
|
|
|
|||
|
|
@ -70,7 +70,8 @@ Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value&
|
|||
Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id),
|
||||
Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) {
|
||||
if (!ctx.profile.support_descriptor_aliasing) {
|
||||
LOG_WARNING(Shader_SPIRV, "Descriptor aliasing not supported, this cannot be atomic.");
|
||||
LOG_WARNING(Shader_SPIRV,
|
||||
"Storage descriptor aliasing not supported, this cannot be atomic.");
|
||||
return ctx.ConstantNull(ctx.U64);
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +93,8 @@ Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value&
|
|||
Id StorageAtomicU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value,
|
||||
Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) {
|
||||
if (!ctx.profile.support_descriptor_aliasing) {
|
||||
LOG_WARNING(Shader_SPIRV, "Descriptor aliasing not supported, this cannot be atomic.");
|
||||
LOG_WARNING(Shader_SPIRV,
|
||||
"Storage descriptor aliasing not supported, this cannot be atomic.");
|
||||
return ctx.ConstantNull(ctx.U32[2]);
|
||||
}
|
||||
|
||||
|
|
@ -295,6 +297,11 @@ Id EmitStorageAtomicXor64(EmitContext& ctx, const IR::Value& binding, const IR::
|
|||
|
||||
Id EmitStorageAtomicExchange64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
if (!ctx.profile.support_descriptor_aliasing) {
|
||||
LOG_WARNING(Shader_SPIRV,
|
||||
"Storage descriptor aliasing not supported, this cannot be atomic.");
|
||||
return ctx.ConstantNull(ctx.U64);
|
||||
}
|
||||
if (ctx.profile.support_int64_atomics) {
|
||||
const Id pointer{StoragePointer(ctx, ctx.storage_types.U64, &StorageDefinitions::U64,
|
||||
binding, offset, sizeof(u64))};
|
||||
|
|
@ -305,7 +312,7 @@ Id EmitStorageAtomicExchange64(EmitContext& ctx, const IR::Value& binding, const
|
|||
const Id pointer{StoragePointer(ctx, ctx.storage_types.U32x2, &StorageDefinitions::U32x2,
|
||||
binding, offset, sizeof(u32[2]))};
|
||||
const Id original{ctx.OpBitcast(ctx.U64, ctx.OpLoad(ctx.U32[2], pointer))};
|
||||
ctx.OpStore(pointer, value);
|
||||
ctx.OpStore(pointer, ctx.OpBitcast(ctx.U32[2], value));
|
||||
return original;
|
||||
}
|
||||
|
||||
|
|
@ -351,6 +358,11 @@ Id EmitStorageAtomicXor32x2(EmitContext& ctx, const IR::Value& binding, const IR
|
|||
|
||||
Id EmitStorageAtomicExchange32x2(EmitContext& ctx, const IR::Value& binding,
|
||||
const IR::Value& offset, Id value) {
|
||||
if (!ctx.profile.support_descriptor_aliasing) {
|
||||
LOG_WARNING(Shader_SPIRV,
|
||||
"Storage descriptor aliasing not supported, this cannot be atomic.");
|
||||
return ctx.ConstantNull(ctx.U32[2]);
|
||||
}
|
||||
LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
|
||||
const Id pointer{StoragePointer(ctx, ctx.storage_types.U32x2, &StorageDefinitions::U32x2,
|
||||
binding, offset, sizeof(u32[2]))};
|
||||
|
|
|
|||
|
|
@ -941,7 +941,7 @@ void EmitContext::DefineGlobalMemoryFunctions(const Info& info) {
|
|||
AddLabel();
|
||||
const size_t num_buffers{info.storage_buffers_descriptors.size()};
|
||||
for (size_t index = 0; index < num_buffers; ++index) {
|
||||
if (!info.nvn_buffer_used[index]) {
|
||||
if (!IsUsedNvnStorageBufferDescriptor(info, info.storage_buffers_descriptors[index])) {
|
||||
continue;
|
||||
}
|
||||
const auto& ssbo{info.storage_buffers_descriptors[index]};
|
||||
|
|
|
|||
|
|
@ -89,43 +89,26 @@ void AddNVNStorageBuffers(IR::Program& program) {
|
|||
if (!program.info.uses_global_memory) {
|
||||
return;
|
||||
}
|
||||
const u32 driver_cbuf{0};
|
||||
const u32 descriptor_size{0x10};
|
||||
const u32 num_buffers{16};
|
||||
const u32 base{[&] {
|
||||
switch (program.stage) {
|
||||
case Stage::VertexA:
|
||||
case Stage::VertexB:
|
||||
return 0x110u;
|
||||
case Stage::TessellationControl:
|
||||
return 0x210u;
|
||||
case Stage::TessellationEval:
|
||||
return 0x310u;
|
||||
case Stage::Geometry:
|
||||
return 0x410u;
|
||||
case Stage::Fragment:
|
||||
return 0x510u;
|
||||
case Stage::Compute:
|
||||
return 0x310u;
|
||||
}
|
||||
throw InvalidArgument("Invalid stage {}", program.stage);
|
||||
}()};
|
||||
auto& descs{program.info.storage_buffers_descriptors};
|
||||
for (u32 index = 0; index < num_buffers; ++index) {
|
||||
if (!program.info.nvn_buffer_used[index]) {
|
||||
auto& info{program.info};
|
||||
auto& descs{info.storage_buffers_descriptors};
|
||||
for (size_t nvn_index = 0; nvn_index < info.nvn_buffer_used.size(); ++nvn_index) {
|
||||
if (!info.nvn_buffer_used[nvn_index]) {
|
||||
continue;
|
||||
}
|
||||
const u32 offset{base + index * descriptor_size};
|
||||
const auto it{std::ranges::find(descs, offset, &StorageBufferDescriptor::cbuf_offset)};
|
||||
const u32 offset{NvnStorageBufferOffset(info, nvn_index)};
|
||||
const auto it{std::ranges::find_if(descs, [offset](const StorageBufferDescriptor& desc) {
|
||||
return desc.cbuf_index == Info::NVN_STORAGE_BUFFER_CBUF_INDEX &&
|
||||
desc.cbuf_offset == offset;
|
||||
})};
|
||||
if (it != descs.end()) {
|
||||
it->is_written |= program.info.stores_global_memory;
|
||||
it->is_written |= info.stores_global_memory;
|
||||
continue;
|
||||
}
|
||||
descs.push_back({
|
||||
.cbuf_index = driver_cbuf,
|
||||
.cbuf_index = Info::NVN_STORAGE_BUFFER_CBUF_INDEX,
|
||||
.cbuf_offset = offset,
|
||||
.count = 1,
|
||||
.is_written = program.info.stores_global_memory,
|
||||
.is_written = info.stores_global_memory,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,8 +107,9 @@ void CheckCBufNVN(Info& info, IR::Inst& inst) {
|
|||
return;
|
||||
}
|
||||
const u32 offset{cbuf_offset.U32()};
|
||||
const u32 descriptor_size{0x10};
|
||||
const u32 upper_limit{info.nvn_buffer_base + descriptor_size * 16};
|
||||
const u32 descriptor_size{Info::NVN_STORAGE_BUFFER_DESCRIPTOR_SIZE};
|
||||
const u32 upper_limit{info.nvn_buffer_base +
|
||||
descriptor_size * static_cast<u32>(Info::NUM_NVN_STORAGE_BUFFERS)};
|
||||
if (offset >= info.nvn_buffer_base && offset < upper_limit) {
|
||||
const std::size_t nvn_index{(offset - info.nvn_buffer_base) / descriptor_size};
|
||||
info.nvn_buffer_used.set(nvn_index, true);
|
||||
|
|
@ -723,6 +724,7 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
|||
case IR::Opcode::StorageAtomicAnd64:
|
||||
case IR::Opcode::StorageAtomicOr64:
|
||||
case IR::Opcode::StorageAtomicXor64:
|
||||
case IR::Opcode::StorageAtomicExchange64:
|
||||
info.used_storage_buffer_types |= IR::Type::U64 | IR::Type::U32x2;
|
||||
info.uses_int64_bit_atomics = true;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -239,6 +239,9 @@ struct Info {
|
|||
static constexpr size_t MAX_INDIRECT_CBUFS{14};
|
||||
static constexpr size_t MAX_CBUFS{18};
|
||||
static constexpr size_t MAX_SSBOS{32};
|
||||
static constexpr size_t NUM_NVN_STORAGE_BUFFERS{16};
|
||||
static constexpr u32 NVN_STORAGE_BUFFER_DESCRIPTOR_SIZE{0x10};
|
||||
static constexpr u32 NVN_STORAGE_BUFFER_CBUF_INDEX{0};
|
||||
|
||||
bool uses_workgroup_id{};
|
||||
bool uses_local_invocation_id{};
|
||||
|
|
@ -319,7 +322,7 @@ struct Info {
|
|||
u32 constant_buffer_mask{};
|
||||
std::array<u32, MAX_CBUFS> constant_buffer_used_sizes{};
|
||||
u32 nvn_buffer_base{};
|
||||
std::bitset<16> nvn_buffer_used{};
|
||||
std::bitset<NUM_NVN_STORAGE_BUFFERS> nvn_buffer_used{};
|
||||
|
||||
bool requires_layer_emulation{};
|
||||
IR::Attribute emulated_layer{};
|
||||
|
|
@ -335,6 +338,25 @@ struct Info {
|
|||
ImageDescriptors image_descriptors;
|
||||
};
|
||||
|
||||
inline u32 NvnStorageBufferOffset(const Info& info, size_t nvn_index) {
|
||||
return info.nvn_buffer_base +
|
||||
static_cast<u32>(nvn_index) * Info::NVN_STORAGE_BUFFER_DESCRIPTOR_SIZE;
|
||||
}
|
||||
|
||||
inline bool IsUsedNvnStorageBufferDescriptor(const Info& info,
|
||||
const StorageBufferDescriptor& desc) {
|
||||
if (desc.cbuf_index != Info::NVN_STORAGE_BUFFER_CBUF_INDEX ||
|
||||
desc.cbuf_offset < info.nvn_buffer_base) {
|
||||
return false;
|
||||
}
|
||||
const u32 relative_offset{desc.cbuf_offset - info.nvn_buffer_base};
|
||||
if (relative_offset % Info::NVN_STORAGE_BUFFER_DESCRIPTOR_SIZE != 0) {
|
||||
return false;
|
||||
}
|
||||
const size_t nvn_index{relative_offset / Info::NVN_STORAGE_BUFFER_DESCRIPTOR_SIZE};
|
||||
return nvn_index < info.nvn_buffer_used.size() && info.nvn_buffer_used[nvn_index];
|
||||
}
|
||||
|
||||
template <typename Descriptors>
|
||||
u32 NumDescriptors(const Descriptors& descriptors) {
|
||||
u32 num{};
|
||||
|
|
|
|||
Loading…
Reference in New Issue