graphics: unify buffer bindings and depth target handling

This commit is contained in:
nmzik
2026-07-27 10:08:08 +02:00
parent f43567e12c
commit 142b3c20fa
17 changed files with 669 additions and 564 deletions
@@ -213,6 +213,8 @@ 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());
if (!program.info.buffers.empty()) {
std::vector<uint32_t> resources(program.info.buffers.size());
@@ -269,8 +271,8 @@ bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std
const auto available_push_dwords = (MaxPushConstantBytes - options.push_constant_offset) / 4u;
const auto push_limit = std::min(options.max_push_dwords, available_push_dwords);
if (next.user_data_registers.size() <= push_limit) {
next.push_constant_size = static_cast<uint32_t>(next.user_data_registers.size() * 4u);
if (next.ShaderDataDwords() <= push_limit) {
next.push_constant_size = next.ShaderDataDwords() * sizeof(uint32_t);
} else {
AddBinding(next, DescriptorBindingKind::UserData);
}
@@ -249,6 +249,12 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
auto cursor = values.begin();
next.buffers.assign(cursor, cursor + program.info.buffers.size());
cursor += program.info.buffers.size();
for (auto& descriptor: next.buffers) {
ShaderBufferResource buffer;
if (DecodeBufferDescriptor(descriptor, buffer) && buffer.Type() != 0) {
descriptor.dwords.fill(0);
}
}
next.images.assign(cursor, cursor + program.info.images.size());
cursor += program.info.images.size();
for (auto& descriptor: next.images) {
@@ -705,9 +705,15 @@ 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;
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;
}
bool operator==(const BindingLayout& other) const = default;
};
@@ -238,7 +238,7 @@ bool ValidateNativeProgram(const IR::Program& program, std::string* error) {
if (!program.srt.reads.empty()) {
Expect(Kind::FlattenedSrt);
}
if (!program.bindings.user_data_registers.empty() && program.bindings.push_constant_size == 0) {
if (program.bindings.ShaderDataDwords() != 0 && program.bindings.push_constant_size == 0) {
Expect(Kind::UserData);
}
@@ -263,8 +263,10 @@ bool ValidateNativeProgram(const IR::Program& program, std::string* error) {
}
}
const auto has_user_storage = present[static_cast<size_t>(Kind::UserData)];
if ((!has_user_storage &&
program.bindings.push_constant_size != program.bindings.user_data_registers.size() * 4u) ||
if (program.bindings.buffer_offset_dword != program.bindings.user_data_registers.size() ||
program.bindings.buffer_offset_count != program.info.buffers.size() ||
(!has_user_storage &&
program.bindings.push_constant_size != program.bindings.ShaderDataDwords() * 4u) ||
(has_user_storage && program.bindings.push_constant_size != 0) ||
!std::is_sorted(program.bindings.user_data_registers.begin(),
program.bindings.user_data_registers.end()) ||
@@ -408,10 +410,10 @@ bool ProgramRequiresExactSubgroupSize(const IR::Program& program) {
}
bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resources,
const ShaderVertexInputInfo* vertex_input_info,
const ShaderPixelInputInfo* pixel_input_info,
const ShaderComputeInputInfo* compute_input_info, std::vector<uint32_t>& spirv,
std::string* error) {
const ShaderVertexInputInfo* vertex_input_info,
const ShaderPixelInputInfo* pixel_input_info,
const ShaderComputeInputInfo* compute_input_info, std::vector<uint32_t>& spirv,
std::string* error) {
using namespace Emitter;
if (program.stage != ShaderType::Compute && program.stage != ShaderType::Vertex &&
@@ -134,7 +134,7 @@ bool UserDataDwordIndex(const EmitterState& state, IR::Register reg, uint32_t& d
return false;
}
uint32_t EmitVsharpDwordLoad(EmitterState& state, uint32_t dword_index) {
uint32_t EmitShaderDataDwordLoad(EmitterState& state, uint32_t dword_index) {
if (state.push_constant_variable != 0) {
const auto pointer = state.builder.AllocateId();
const auto value = state.builder.AllocateId();
@@ -172,7 +172,7 @@ uint32_t InitialRegisterValue(const EmitterState& state, IR::Register reg) {
uint32_t EmitInitialRegisterValue(EmitterState& state, IR::Register reg) {
uint32_t dword_index = 0;
if (UserDataDwordIndex(state, reg, dword_index)) {
return EmitVsharpDwordLoad(state, dword_index);
return EmitShaderDataDwordLoad(state, dword_index);
}
return ConstantU32(state, InitialRegisterValue(state, reg));
}
@@ -1064,6 +1064,7 @@ void EmitFunction(EmitterState& state, const IR::Program& program) {
EmitComputeInputRegisters(state);
EmitPixelInputRegisters(state);
EmitVertexInputRegisters(state);
EmitStorageBufferOffsets(state);
if (state.dispatcher_fallback) {
EmitDispatcherFunction(state, program);
state.builder.AddFunction({OpFunctionEnd});
@@ -355,6 +355,7 @@ struct EmitterState {
uint32_t storage_buffer_array_type = 0;
uint32_t ptr_storage_buffer_array = 0;
uint32_t storage_buffer_variable = 0;
std::array<uint32_t, IR::ShaderInfo::MaxBuffers> storage_buffer_offsets {};
uint32_t address_memory_array_type = 0;
uint32_t ptr_address_memory_array = 0;
uint32_t address_memory_variable = 0;
@@ -837,6 +838,8 @@ uint32_t EmitNotEqualZeroBool(EmitterState& state, uint32_t value);
uint32_t EmitSelectU32Value(EmitterState& state, uint32_t condition, uint32_t true_value,
uint32_t false_value);
uint32_t EmitShaderDataDwordLoad(EmitterState& state, uint32_t dword_index);
uint32_t EmitByteAddress(EmitterState& state, const IR::Instruction& inst, uint32_t first_src,
uint32_t src_count);
@@ -854,6 +857,8 @@ uint32_t EmitOptionalLogicalAndBool(EmitterState& state, uint32_t lhs, uint32_t
bool IsStorageBufferMemoryKind(IR::ResourceKind kind);
void EmitStorageBufferOffsets(EmitterState& state);
uint32_t EmitBufferAddressFromParts(EmitterState& state, const IR::Instruction& inst,
uint32_t index, uint32_t offset, uint32_t soffset);
@@ -210,6 +210,17 @@ bool IsStorageBufferMemoryKind(IR::ResourceKind kind) {
}
}
void EmitStorageBufferOffsets(EmitterState& state) {
for (uint32_t i = 0; i < state.program.bindings.buffer_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(
state, OpBitwiseAnd,
EmitBinaryU32(state, OpShiftRightLogical, word, shift), ConstantU32(state, 0x3fu));
}
}
uint32_t EmitBufferAddressFromParts(EmitterState& state, const IR::Instruction& inst,
uint32_t index, uint32_t offset, uint32_t soffset) {
const auto& mem = inst.memory;
@@ -398,6 +409,15 @@ StorageBufferBindingForMemory(EmitterState& state, const IR::MemoryInfo& mem, ui
return binding;
}
uint32_t EmitStorageBufferIndex(EmitterState& state, const IR::MemoryInfo& mem, uint32_t index,
uint32_t use_pc) {
if (IsFlatMemoryKind(mem.kind)) {
return index;
}
const auto binding = StorageBufferBindingForMemory(state, mem, use_pc);
return EmitAddU32(state, index, state.storage_buffer_offsets[binding.array_index]);
}
uint32_t EmitStorageBufferObjectPointer(EmitterState& state, const IR::MemoryInfo& mem,
uint32_t use_pc) {
if (IsFlatMemoryKind(mem.kind)) {
@@ -422,7 +442,8 @@ uint32_t EmitStorageBufferObjectPointer(EmitterState& state, const IR::MemoryInf
}
uint32_t EmitStorageBufferElementInBounds(EmitterState& state, const IR::MemoryInfo& mem,
uint32_t index, uint32_t use_pc) {
uint32_t index, uint32_t use_pc) {
index = EmitStorageBufferIndex(state, mem, index, use_pc);
const auto object = EmitStorageBufferObjectPointer(state, mem, use_pc);
const auto length = state.builder.AllocateId();
const auto in_bounds = state.builder.AllocateId();
@@ -432,7 +453,8 @@ uint32_t EmitStorageBufferElementInBounds(EmitterState& state, const IR::MemoryI
}
uint32_t EmitStorageBufferElementPointer(EmitterState& state, const IR::MemoryInfo& mem,
uint32_t index, uint32_t use_pc) {
uint32_t index, uint32_t use_pc) {
index = EmitStorageBufferIndex(state, mem, index, use_pc);
if (IsFlatMemoryKind(mem.kind)) {
if (state.address_memory_variable == 0) {
ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::AddressMemory,