shader: add support for const buffer indirect addressing
This commit is contained in:
parent
cd07a43724
commit
52895fab67
|
@ -124,25 +124,56 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
|
||||||
|
|
||||||
Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size,
|
Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size,
|
||||||
const IR::Value& binding, const IR::Value& offset) {
|
const IR::Value& binding, const IR::Value& offset) {
|
||||||
if (!binding.IsImmediate()) {
|
std::array<Id, 2> indexes;
|
||||||
throw NotImplementedException("Constant buffer indexing");
|
|
||||||
}
|
|
||||||
const Id cbuf{ctx.cbufs[binding.U32()].*member_ptr};
|
|
||||||
const Id uniform_type{ctx.uniform_types.*member_ptr};
|
const Id uniform_type{ctx.uniform_types.*member_ptr};
|
||||||
if (!offset.IsImmediate()) {
|
if (offset.IsImmediate()) {
|
||||||
|
// Hardware been proved to read the aligned offset (e.g. LDC.U32 at 6 will read offset 4)
|
||||||
|
const Id imm_offset{ctx.Const(offset.U32() / element_size)};
|
||||||
|
indexes = {ctx.u32_zero_value, imm_offset};
|
||||||
|
} else {
|
||||||
Id index{ctx.Def(offset)};
|
Id index{ctx.Def(offset)};
|
||||||
if (element_size > 1) {
|
if (element_size > 1) {
|
||||||
const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))};
|
const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))};
|
||||||
const Id shift{ctx.Const(log2_element_size)};
|
const Id shift{ctx.Const(log2_element_size)};
|
||||||
index = ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), shift);
|
index = ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), shift);
|
||||||
}
|
}
|
||||||
const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, index)};
|
indexes = {ctx.u32_zero_value, index};
|
||||||
return ctx.OpLoad(result_type, access_chain);
|
}
|
||||||
|
|
||||||
|
if (binding.IsImmediate()) {
|
||||||
|
const Id cbuf{ctx.cbufs[binding.U32()].*member_ptr};
|
||||||
|
const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, indexes)};
|
||||||
|
return ctx.OpLoad(result_type, access_chain);
|
||||||
|
} else {
|
||||||
|
const Id index{ctx.Def(binding)};
|
||||||
|
const Id ptr{ctx.TypePointer(spv::StorageClass::Function, result_type)};
|
||||||
|
const Id value{ctx.AddLocalVariable(ptr, spv::StorageClass::Function)};
|
||||||
|
const Id merge_label = ctx.OpLabel();
|
||||||
|
|
||||||
|
std::array<Id, Info::MAX_CBUFS> buf_labels;
|
||||||
|
std::array<Sirit::Literal, Info::MAX_CBUFS> buf_literals;
|
||||||
|
for (u32 i = 0; i < Info::MAX_CBUFS; i++) {
|
||||||
|
buf_labels[i] = ctx.OpLabel();
|
||||||
|
buf_literals[i] = Sirit::Literal{i};
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone);
|
||||||
|
ctx.OpSwitch(index, buf_labels[0], buf_literals, buf_labels);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < Info::MAX_CBUFS; i++) {
|
||||||
|
ctx.AddLabel(buf_labels[i]);
|
||||||
|
const Id cbuf{ctx.cbufs[i].*member_ptr};
|
||||||
|
const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, indexes)};
|
||||||
|
const Id result = ctx.OpLoad(result_type, access_chain);
|
||||||
|
ctx.OpStore(value, result);
|
||||||
|
ctx.OpBranch(merge_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.AddLabel(merge_label);
|
||||||
|
|
||||||
|
return ctx.OpLoad(result_type, value);
|
||||||
}
|
}
|
||||||
// Hardware been proved to read the aligned offset (e.g. LDC.U32 at 6 will read offset 4)
|
|
||||||
const Id imm_offset{ctx.Const(offset.U32() / element_size)};
|
|
||||||
const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, imm_offset)};
|
|
||||||
return ctx.OpLoad(result_type, access_chain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||||
|
|
|
@ -29,6 +29,20 @@ void AddConstantBufferDescriptor(Info& info, u32 index, u32 count) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddRegisterIndexedLdc(Info& info) {
|
||||||
|
// The shader can use any possible constant buffer
|
||||||
|
info.constant_buffer_mask = (1 << Info::MAX_CBUFS) - 1;
|
||||||
|
|
||||||
|
auto& cbufs{info.constant_buffer_descriptors};
|
||||||
|
cbufs.clear();
|
||||||
|
for (u32 i = 0; i < Info::MAX_CBUFS; i++) {
|
||||||
|
cbufs.push_back(ConstantBufferDescriptor{.index = i, .count = 1});
|
||||||
|
|
||||||
|
// The shader can use any possible access size
|
||||||
|
info.constant_buffer_used_sizes[i] = 0x10'000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GetPatch(Info& info, IR::Patch patch) {
|
void GetPatch(Info& info, IR::Patch patch) {
|
||||||
if (!IR::IsGeneric(patch)) {
|
if (!IR::IsGeneric(patch)) {
|
||||||
throw NotImplementedException("Reading non-generic patch {}", patch);
|
throw NotImplementedException("Reading non-generic patch {}", patch);
|
||||||
|
@ -463,10 +477,12 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
||||||
case IR::Opcode::GetCbufU32x2: {
|
case IR::Opcode::GetCbufU32x2: {
|
||||||
const IR::Value index{inst.Arg(0)};
|
const IR::Value index{inst.Arg(0)};
|
||||||
const IR::Value offset{inst.Arg(1)};
|
const IR::Value offset{inst.Arg(1)};
|
||||||
if (!index.IsImmediate()) {
|
if (index.IsImmediate()) {
|
||||||
throw NotImplementedException("Constant buffer with non-immediate index");
|
AddConstantBufferDescriptor(info, index.U32(), 1);
|
||||||
|
} else {
|
||||||
|
AddRegisterIndexedLdc(info);
|
||||||
}
|
}
|
||||||
AddConstantBufferDescriptor(info, index.U32(), 1);
|
|
||||||
u32 element_size{};
|
u32 element_size{};
|
||||||
switch (inst.GetOpcode()) {
|
switch (inst.GetOpcode()) {
|
||||||
case IR::Opcode::GetCbufU8:
|
case IR::Opcode::GetCbufU8:
|
||||||
|
@ -494,11 +510,14 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
u32& size{info.constant_buffer_used_sizes[index.U32()]};
|
|
||||||
if (offset.IsImmediate()) {
|
if (index.IsImmediate()) {
|
||||||
size = Common::AlignUp(std::max(size, offset.U32() + element_size), 16u);
|
u32& size{info.constant_buffer_used_sizes[index.U32()]};
|
||||||
} else {
|
if (offset.IsImmediate()) {
|
||||||
size = 0x10'000;
|
size = Common::AlignUp(std::max(size, offset.U32() + element_size), 16u);
|
||||||
|
} else {
|
||||||
|
size = 0x10'000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue