shader: align address-memory buffer bindings

This commit is contained in:
nmzik
2026-08-21 02:29:23 +02:00
parent 61dd8a3031
commit d0a4c908a1
12 changed files with 152 additions and 51 deletions
@@ -109,8 +109,9 @@ bool ValidateNativeProgram(const IR::Program& program, std::string* error) {
}
}
const auto has_user_storage = present[static_cast<size_t>(Kind::UserData)];
if (program.bindings.buffer_offset_dword != program.bindings.user_data_registers.size() ||
program.bindings.buffer_offset_count != program.info.buffers.size() ||
if (program.bindings.memory_offset_dword != program.bindings.user_data_registers.size() ||
program.bindings.memory_offset_count !=
program.info.buffers.size() + program.info.addresses.size() ||
(!has_user_storage &&
program.bindings.push_constant_size != program.bindings.ShaderDataDwords() * 4u) ||
(has_user_storage && program.bindings.push_constant_size != 0) ||
@@ -333,7 +333,8 @@ struct EmitterState {
uint32_t wave_size = 64;
bool per_invocation_masks = false;
uint32_t storage_buffer_variable = 0;
std::array<uint32_t, IR::ShaderInfo::MaxBuffers> storage_buffer_offsets {};
std::array<uint32_t, IR::ShaderInfo::MaxBuffers + IR::ShaderInfo::MaxAddresses>
memory_byte_offsets {};
uint32_t address_memory_variable = 0;
uint32_t gds_variable = 0;
uint32_t gds_length = 0;
@@ -713,7 +714,7 @@ uint32_t StorageBufferPackedStride(const EmitterState& state, const IR::MemoryIn
Prospero::BufferFormat StorageBufferFormat(const EmitterState& state, const IR::MemoryInfo& mem);
void EmitStorageBufferOffsets(EmitterState& state);
void EmitMemoryOffsets(EmitterState& state);
uint32_t LdsDwordCount(const EmitterState& state);
@@ -135,6 +135,22 @@ uint32_t AddressByteAddress(ValueEmitContext& ctx, const IR::Inst& inst, const I
return Select(state, TypeU32(state), valid, relative, ConstantU32(state, UINT32_MAX));
}
uint32_t AddAddressMemoryOffset(ValueEmitContext& ctx, const IR::MemoryInfo& mem,
uint32_t address) {
auto& state = ctx.state;
const auto binding =
ResourceForDescriptor(state, IR::DescriptorBindingKind::AddressMemory, mem.resource);
const auto offset =
state.memory_byte_offsets[state.program.info.buffers.size() + binding.array_index];
const auto corrected = Binary(state, OpIAdd, TypeU32(state), address, offset);
const auto not_invalid =
Binary(state, OpINotEqual, TypeBool(state), address, ConstantU32(state, UINT32_MAX));
const auto no_overflow =
Binary(state, OpUGreaterThanEqual, TypeBool(state), corrected, address);
return Select(state, TypeU32(state), AndCondition(state, not_invalid, no_overflow), corrected,
ConstantU32(state, UINT32_MAX));
}
uint32_t ByteAddress(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem) {
if (mem.kind == IR::ResourceKind::Buffer) {
return BufferByteAddress(ctx, inst, mem, ctx.Arg(inst, 1), ctx.Arg(inst, 2),
@@ -147,7 +163,11 @@ uint32_t ByteAddress(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Memo
return Binary(ctx.state, OpIAdd, TypeU32(ctx.state), ctx.Arg(inst, 0),
ConstantU32(ctx.state, mem.offset));
}
return AddressByteAddress(ctx, inst, mem, ctx.Arg(inst, 1), ctx.Arg(inst, 2));
const auto address = AddressByteAddress(ctx, inst, mem, ctx.Arg(inst, 1), ctx.Arg(inst, 2));
if (mem.kind == IR::ResourceKind::Scratch) {
return address;
}
return AddAddressMemoryOffset(ctx, mem, address);
}
uint32_t DwordIndex(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem) {
@@ -52,14 +52,14 @@ Prospero::BufferFormat StorageBufferFormat(const EmitterState& state, const IR::
return state.program.info.buffers[mem.resource].descriptor_format;
}
void EmitStorageBufferOffsets(EmitterState& state) {
for (uint32_t i = 0; i < state.program.bindings.buffer_offset_count; i++) {
void EmitMemoryOffsets(EmitterState& state) {
for (uint32_t i = 0; i < state.program.bindings.memory_offset_count; i++) {
const auto word =
EmitShaderDataDwordLoad(state, state.program.bindings.buffer_offset_dword + i / 4u);
const auto shift = ConstantU32(state, (i % 4u) * 8u + 2u);
state.storage_buffer_offsets[i] = EmitBinaryU32(
EmitShaderDataDwordLoad(state, state.program.bindings.memory_offset_dword + i / 4u);
const auto shift = ConstantU32(state, (i % 4u) * 8u);
state.memory_byte_offsets[i] = EmitBinaryU32(
state, OpBitwiseAnd, EmitBinaryU32(state, OpShiftRightLogical, word, shift),
ConstantU32(state, 0x3fu));
ConstantU32(state, 0xffu));
}
}
@@ -135,7 +135,9 @@ MemoryResourceAccess PrepareMemoryResourceAccess(EmitterState& state, const IR::
state.builder.AddFunction({OpAccessChain, TypeStorageBufferPointer(state),
access.object_pointer, state.storage_buffer_variable,
ConstantU32(state, binding.array_index)});
access.index_offset = state.storage_buffer_offsets[binding.array_index];
access.index_offset = EmitBinaryU32(state, OpShiftRightLogical,
state.memory_byte_offsets[binding.array_index],
ConstantU32(state, 2u));
access.add_index_offset = true;
break;
}
@@ -620,7 +620,7 @@ bool EmitValueProgram(EmitterState& state, const IR::ValueProgram& program, std:
state.builder.AddFunction(
{OpStore, state.pixel_valid_mask_variable, ConstantU32(state, 1)});
}
EmitStorageBufferOffsets(state);
EmitMemoryOffsets(state);
if (program.blocks.empty()) {
EmitReturn(ctx);
} else if (state.program.dispatcher_fallback) {
+3 -3
View File
@@ -423,13 +423,13 @@ struct BindingLayout {
uint32_t descriptor_set = 0;
uint32_t push_constant_offset = 0;
uint32_t push_constant_size = 0;
uint32_t buffer_offset_dword = 0;
uint32_t buffer_offset_count = 0;
uint32_t memory_offset_dword = 0;
uint32_t memory_offset_count = 0;
std::vector<uint32_t> user_data_registers;
std::vector<DescriptorBinding> descriptors;
[[nodiscard]] uint32_t ShaderDataDwords() const {
return buffer_offset_dword + (buffer_offset_count + 3u) / 4u;
return memory_offset_dword + (memory_offset_count + 3u) / 4u;
}
bool operator==(const BindingLayout& other) const = default;
@@ -130,8 +130,9 @@ bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std
}
return false;
}
next.buffer_offset_dword = static_cast<uint32_t>(next.user_data_registers.size());
next.buffer_offset_count = static_cast<uint32_t>(program.info.buffers.size());
next.memory_offset_dword = static_cast<uint32_t>(next.user_data_registers.size());
next.memory_offset_count =
static_cast<uint32_t>(program.info.buffers.size() + program.info.addresses.size());
if (!program.info.buffers.empty()) {
std::vector<uint32_t> resources(program.info.buffers.size());
+2 -2
View File
@@ -1059,8 +1059,8 @@ static void ShaderAppendNativeSpecialization(std::vector<uint32_t>&
ids.push_back(program.bindings.descriptor_set);
ids.push_back(program.bindings.push_constant_offset);
ids.push_back(program.bindings.push_constant_size);
ids.push_back(program.bindings.buffer_offset_dword);
ids.push_back(program.bindings.buffer_offset_count);
ids.push_back(program.bindings.memory_offset_dword);
ids.push_back(program.bindings.memory_offset_count);
ids.push_back(static_cast<uint32_t>(program.bindings.user_data_registers.size()));
ids.insert(ids.end(), program.bindings.user_data_registers.begin(),
program.bindings.user_data_registers.end());