|
|
@@ -411,6 +411,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& bin
|
|
|
DefineTextures(program.info, binding);
|
|
|
DefineImages(program.info, binding);
|
|
|
DefineAttributeMemAccess(program.info);
|
|
|
+ DefineGlobalMemoryFunctions(program.info);
|
|
|
DefineLabels(program);
|
|
|
}
|
|
|
|
|
|
@@ -762,6 +763,82 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void EmitContext::DefineGlobalMemoryFunctions(const Info& info) {
|
|
|
+ if (!info.uses_global_memory) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ using DefPtr = Id StorageDefinitions::*;
|
|
|
+ const Id zero{u32_zero_value};
|
|
|
+ const auto define_body{[&](DefPtr ssbo_member, Id addr, Id element_pointer, u32 shift,
|
|
|
+ auto&& callback) {
|
|
|
+ AddLabel();
|
|
|
+ const size_t num_buffers{info.storage_buffers_descriptors.size()};
|
|
|
+ for (size_t index = 0; index < num_buffers; ++index) {
|
|
|
+ const auto& ssbo{info.storage_buffers_descriptors[index]};
|
|
|
+ const Id ssbo_addr_cbuf_offset{Const(ssbo.cbuf_offset / 8)};
|
|
|
+ const Id ssbo_size_cbuf_offset{Const(ssbo.cbuf_offset / 4 + 2)};
|
|
|
+ const Id ssbo_addr_pointer{OpAccessChain(
|
|
|
+ uniform_types.U32x2, cbufs[ssbo.cbuf_index].U32x2, zero, ssbo_addr_cbuf_offset)};
|
|
|
+ const Id ssbo_size_pointer{OpAccessChain(uniform_types.U32, cbufs[ssbo.cbuf_index].U32,
|
|
|
+ zero, ssbo_size_cbuf_offset)};
|
|
|
+
|
|
|
+ const Id ssbo_addr{OpBitcast(U64, OpLoad(U32[2], ssbo_addr_pointer))};
|
|
|
+ const Id ssbo_size{OpUConvert(U64, OpLoad(U32[1], ssbo_size_pointer))};
|
|
|
+ const Id ssbo_end{OpIAdd(U64, ssbo_addr, ssbo_size)};
|
|
|
+ const Id cond{OpLogicalAnd(U1, OpUGreaterThanEqual(U1, addr, ssbo_addr),
|
|
|
+ OpULessThan(U1, addr, ssbo_end))};
|
|
|
+ const Id then_label{OpLabel()};
|
|
|
+ const Id else_label{OpLabel()};
|
|
|
+ OpSelectionMerge(else_label, spv::SelectionControlMask::MaskNone);
|
|
|
+ OpBranchConditional(cond, then_label, else_label);
|
|
|
+ AddLabel(then_label);
|
|
|
+ const Id ssbo_id{ssbos[index].*ssbo_member};
|
|
|
+ const Id ssbo_offset{OpUConvert(U32[1], OpISub(U64, addr, ssbo_addr))};
|
|
|
+ const Id ssbo_index{OpShiftRightLogical(U32[1], ssbo_offset, Const(shift))};
|
|
|
+ const Id ssbo_pointer{OpAccessChain(element_pointer, ssbo_id, zero, ssbo_index)};
|
|
|
+ callback(ssbo_pointer);
|
|
|
+ AddLabel(else_label);
|
|
|
+ }
|
|
|
+ }};
|
|
|
+ const auto define_load{[&](DefPtr ssbo_member, Id element_pointer, Id type, u32 shift) {
|
|
|
+ const Id function_type{TypeFunction(type, U64)};
|
|
|
+ const Id func_id{OpFunction(type, spv::FunctionControlMask::MaskNone, function_type)};
|
|
|
+ const Id addr{OpFunctionParameter(U64)};
|
|
|
+ define_body(ssbo_member, addr, element_pointer, shift,
|
|
|
+ [&](Id ssbo_pointer) { OpReturnValue(OpLoad(type, ssbo_pointer)); });
|
|
|
+ OpReturnValue(ConstantNull(type));
|
|
|
+ OpFunctionEnd();
|
|
|
+ return func_id;
|
|
|
+ }};
|
|
|
+ const auto define_write{[&](DefPtr ssbo_member, Id element_pointer, Id type, u32 shift) {
|
|
|
+ const Id function_type{TypeFunction(void_id, U64, type)};
|
|
|
+ const Id func_id{OpFunction(void_id, spv::FunctionControlMask::MaskNone, function_type)};
|
|
|
+ const Id addr{OpFunctionParameter(U64)};
|
|
|
+ const Id data{OpFunctionParameter(type)};
|
|
|
+ define_body(ssbo_member, addr, element_pointer, shift, [&](Id ssbo_pointer) {
|
|
|
+ OpStore(ssbo_pointer, data);
|
|
|
+ OpReturn();
|
|
|
+ });
|
|
|
+ OpReturn();
|
|
|
+ OpFunctionEnd();
|
|
|
+ return func_id;
|
|
|
+ }};
|
|
|
+ const auto define{
|
|
|
+ [&](DefPtr ssbo_member, const StorageTypeDefinition& type_def, Id type, size_t size) {
|
|
|
+ const Id element_type{type_def.element};
|
|
|
+ const u32 shift{static_cast<u32>(std::countr_zero(size))};
|
|
|
+ const Id load_func{define_load(ssbo_member, element_type, type, shift)};
|
|
|
+ const Id write_func{define_write(ssbo_member, element_type, type, shift)};
|
|
|
+ return std::make_pair(load_func, write_func);
|
|
|
+ }};
|
|
|
+ std::tie(load_global_func_u32, write_global_func_u32) =
|
|
|
+ define(&StorageDefinitions::U32, storage_types.U32, U32[1], sizeof(u32));
|
|
|
+ std::tie(load_global_func_u32x2, write_global_func_u32x2) =
|
|
|
+ define(&StorageDefinitions::U32x2, storage_types.U32x2, U32[2], sizeof(u32[2]));
|
|
|
+ std::tie(load_global_func_u32x4, write_global_func_u32x4) =
|
|
|
+ define(&StorageDefinitions::U32x4, storage_types.U32x4, U32[4], sizeof(u32[4]));
|
|
|
+}
|
|
|
+
|
|
|
void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
|
|
|
if (info.constant_buffer_descriptors.empty()) {
|
|
|
return;
|