GLSL: Deal with buffer_reference_align.

This is somewhat awkward to support, but the best effort we can do here
is to analyze various Load/Store opcodes and deduce the ideal overall
alignment based on this. This is not a 100% perfect solution, but should
be correct for any reasonable use case.

Also fix various nitpicks with BDA support while I'm at it.
This commit is contained in:
Hans-Kristian Arntzen 2021-11-07 15:43:57 +01:00
parent 1adc53b107
commit f1b411c9e8
30 changed files with 511 additions and 48 deletions

View File

@ -3,7 +3,7 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer Block;
layout(buffer_reference, std430) buffer Block
layout(buffer_reference, buffer_reference_align = 4, std430) buffer Block
{
float v;
};

View File

@ -0,0 +1,28 @@
#version 450
#extension GL_EXT_buffer_reference : require
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer Bar;
layout(buffer_reference) buffer Foo;
layout(buffer_reference, buffer_reference_align = 8, std430) buffer Bar
{
uint a;
uint b;
Foo foo;
};
layout(buffer_reference, std430) buffer Foo
{
uint v;
};
layout(push_constant, std430) uniform Push
{
Bar bar;
} _13;
void main()
{
uint _24 = atomicAdd(_13.bar.b, 1u);
}

View File

@ -0,0 +1,28 @@
#version 450
#extension GL_EXT_buffer_reference : require
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer Bar;
layout(buffer_reference) buffer Foo;
layout(buffer_reference, buffer_reference_align = 8, std430) buffer Bar
{
uint a;
uint b;
Foo foo;
};
layout(buffer_reference, std430) buffer Foo
{
uint v;
};
layout(push_constant, std430) uniform Push
{
Bar bar;
} _15;
void main()
{
uint _31 = atomicAdd(_15.bar.a, _15.bar.b);
}

View File

@ -4,7 +4,7 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer PtrInt;
layout(buffer_reference, std430) buffer PtrInt
layout(buffer_reference, buffer_reference_align = 4, std430) buffer PtrInt
{
int value;
};

View File

@ -4,7 +4,7 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer PtrInt;
layout(buffer_reference, std430) buffer PtrInt
layout(buffer_reference, buffer_reference_align = 16, std430) buffer PtrInt
{
int value;
};

View File

@ -4,12 +4,12 @@ layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer PtrUint;
layout(buffer_reference) buffer PtrInt;
layout(buffer_reference, std430) buffer PtrUint
layout(buffer_reference, buffer_reference_align = 4, std430) buffer PtrUint
{
uint value;
};
layout(buffer_reference, std430) buffer PtrInt
layout(buffer_reference, buffer_reference_align = 16, std430) buffer PtrInt
{
int value;
};

View File

@ -5,17 +5,17 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer RO;
layout(buffer_reference) buffer RW;
layout(buffer_reference) buffer WO;
layout(buffer_reference, std430) readonly buffer RO
layout(buffer_reference, buffer_reference_align = 16, std430) readonly buffer RO
{
vec4 v[];
};
layout(buffer_reference, std430) restrict buffer RW
layout(buffer_reference, buffer_reference_align = 16, std430) restrict buffer RW
{
vec4 v[];
};
layout(buffer_reference, std430) coherent writeonly buffer WO
layout(buffer_reference, buffer_reference_align = 16, std430) coherent writeonly buffer WO
{
vec4 v[];
};

View File

@ -4,7 +4,7 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer Node;
layout(buffer_reference, std430) buffer Node
layout(buffer_reference, buffer_reference_align = 16, std430) buffer Node
{
layout(offset = 0) int value;
layout(offset = 16) Node next;

View File

@ -5,17 +5,17 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer Alias;
layout(buffer_reference) buffer _6;
layout(buffer_reference) buffer _7;
layout(buffer_reference, std430) readonly buffer Alias
layout(buffer_reference, buffer_reference_align = 16, std430) readonly buffer Alias
{
vec4 v[];
};
layout(buffer_reference, std430) restrict buffer _6
layout(buffer_reference, buffer_reference_align = 16, std430) restrict buffer _6
{
vec4 v[];
};
layout(buffer_reference, std430) coherent writeonly buffer _7
layout(buffer_reference, buffer_reference_align = 16, std430) coherent writeonly buffer _7
{
vec4 v[];
};

View File

@ -0,0 +1,19 @@
#version 450
#extension GL_EXT_buffer_reference : require
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference, buffer_reference_align = 8) buffer uvec4Pointer
{
uvec4 value;
};
layout(push_constant, std430) uniform Push
{
uvec4Pointer ptr;
} _4;
void main()
{
_4.ptr.value = uvec4(1u, 2u, 3u, 4u);
}

View File

@ -0,0 +1,13 @@
#version 450
#extension GL_EXT_buffer_reference : require
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer uvec4Pointer
{
uvec4 value;
};
void main()
{
}

View File

@ -3,7 +3,7 @@
#extension GL_EXT_buffer_reference : require
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer uintPointer
layout(buffer_reference, buffer_reference_align = 4) buffer uintPointer
{
uint value;
};

View File

@ -3,7 +3,7 @@
#extension GL_EXT_buffer_reference : require
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer uint0_Pointer
layout(buffer_reference, buffer_reference_align = 4) buffer uint0_Pointer
{
uint value[];
};

View File

@ -3,7 +3,7 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer Block;
layout(buffer_reference, std430) buffer Block
layout(buffer_reference, buffer_reference_align = 4, std430) buffer Block
{
float v;
};

View File

@ -0,0 +1,28 @@
#version 450
#extension GL_EXT_buffer_reference : require
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer Bar;
layout(buffer_reference) buffer Foo;
layout(buffer_reference, buffer_reference_align = 8, std430) buffer Bar
{
uint a;
uint b;
Foo foo;
};
layout(buffer_reference, std430) buffer Foo
{
uint v;
};
layout(push_constant, std430) uniform Push
{
Bar bar;
} _13;
void main()
{
uint _24 = atomicAdd(_13.bar.b, 1u);
}

View File

@ -0,0 +1,29 @@
#version 450
#extension GL_EXT_buffer_reference : require
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer Bar;
layout(buffer_reference) buffer Foo;
layout(buffer_reference, buffer_reference_align = 8, std430) buffer Bar
{
uint a;
uint b;
Foo foo;
};
layout(buffer_reference, std430) buffer Foo
{
uint v;
};
layout(push_constant, std430) uniform Push
{
Bar bar;
} _15;
void main()
{
uint v = _15.bar.b;
uint _31 = atomicAdd(_15.bar.a, v);
}

View File

@ -4,7 +4,7 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer PtrInt;
layout(buffer_reference, std430) buffer PtrInt
layout(buffer_reference, buffer_reference_align = 4, std430) buffer PtrInt
{
int value;
};

View File

@ -4,7 +4,7 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer PtrInt;
layout(buffer_reference, std430) buffer PtrInt
layout(buffer_reference, buffer_reference_align = 16, std430) buffer PtrInt
{
int value;
};

View File

@ -4,12 +4,12 @@ layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer PtrUint;
layout(buffer_reference) buffer PtrInt;
layout(buffer_reference, std430) buffer PtrUint
layout(buffer_reference, buffer_reference_align = 4, std430) buffer PtrUint
{
uint value;
};
layout(buffer_reference, std430) buffer PtrInt
layout(buffer_reference, buffer_reference_align = 16, std430) buffer PtrInt
{
int value;
};

View File

@ -5,17 +5,17 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer RO;
layout(buffer_reference) buffer RW;
layout(buffer_reference) buffer WO;
layout(buffer_reference, std430) readonly buffer RO
layout(buffer_reference, buffer_reference_align = 16, std430) readonly buffer RO
{
vec4 v[];
};
layout(buffer_reference, std430) restrict buffer RW
layout(buffer_reference, buffer_reference_align = 16, std430) restrict buffer RW
{
vec4 v[];
};
layout(buffer_reference, std430) coherent writeonly buffer WO
layout(buffer_reference, buffer_reference_align = 16, std430) coherent writeonly buffer WO
{
vec4 v[];
};

View File

@ -4,7 +4,7 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(buffer_reference) buffer Node;
layout(buffer_reference, std430) buffer Node
layout(buffer_reference, buffer_reference_align = 16, std430) buffer Node
{
layout(offset = 0) int value;
layout(offset = 16) Node next;

View File

@ -0,0 +1,44 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 10
; Bound: 25
; Schema: 0
OpCapability Shader
OpCapability PhysicalStorageBufferAddresses
OpExtension "SPV_EXT_physical_storage_buffer"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 450
OpSourceExtension "GL_EXT_buffer_reference"
OpName %main "main"
OpName %Push "Push"
OpMemberName %Push 0 "ptr"
OpName %_ ""
OpMemberDecorate %Push 0 Offset 0
OpDecorate %Push Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%v4uint = OpTypeVector %uint 4
%_ptr_PhysicalStorageBuffer_uintPtr = OpTypePointer PhysicalStorageBuffer %v4uint
%Push = OpTypeStruct %_ptr_PhysicalStorageBuffer_uintPtr
%_ptr_PushConstant_Push = OpTypePointer PushConstant %Push
%_ = OpVariable %_ptr_PushConstant_Push PushConstant
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_PushConstant__ptr_PhysicalStorageBuffer_uintPtr = OpTypePointer PushConstant %_ptr_PhysicalStorageBuffer_uintPtr
%uint_1 = OpConstant %uint 1
%uint_2 = OpConstant %uint 2
%uint_3 = OpConstant %uint 3
%uint_4 = OpConstant %uint 4
%22 = OpConstantComposite %v4uint %uint_1 %uint_2 %uint_3 %uint_4
%_ptr_PhysicalStorageBuffer_v4uint = OpTypePointer PhysicalStorageBuffer %v4uint
%main = OpFunction %void None %3
%5 = OpLabel
%16 = OpAccessChain %_ptr_PushConstant__ptr_PhysicalStorageBuffer_uintPtr %_ %int_0
%17 = OpLoad %_ptr_PhysicalStorageBuffer_uintPtr %16
OpStore %17 %22 Aligned 8
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,44 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 10
; Bound: 25
; Schema: 0
OpCapability Shader
OpCapability PhysicalStorageBufferAddresses
OpExtension "SPV_EXT_physical_storage_buffer"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 450
OpSourceExtension "GL_EXT_buffer_reference"
OpName %main "main"
OpName %Push "Push"
OpMemberName %Push 0 "ptr"
OpName %_ ""
OpMemberDecorate %Push 0 Offset 0
OpDecorate %Push Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%v4uint = OpTypeVector %uint 4
%_ptr_PhysicalStorageBuffer_uintPtr = OpTypePointer PhysicalStorageBuffer %v4uint
%Push = OpTypeStruct %_ptr_PhysicalStorageBuffer_uintPtr
%_ptr_PushConstant_Push = OpTypePointer PushConstant %Push
%_ = OpVariable %_ptr_PushConstant_Push PushConstant
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_PushConstant__ptr_PhysicalStorageBuffer_uintPtr = OpTypePointer PushConstant %_ptr_PhysicalStorageBuffer_uintPtr
%uint_1 = OpConstant %uint 1
%uint_2 = OpConstant %uint 2
%uint_3 = OpConstant %uint 3
%uint_4 = OpConstant %uint 4
%22 = OpConstantComposite %v4uint %uint_1 %uint_2 %uint_3 %uint_4
%_ptr_PhysicalStorageBuffer_v4uint = OpTypePointer PhysicalStorageBuffer %v4uint
%main = OpFunction %void None %3
%5 = OpLabel
;%16 = OpAccessChain %_ptr_PushConstant__ptr_PhysicalStorageBuffer_uintPtr %_ %int_0
;%17 = OpLoad %_ptr_PhysicalStorageBuffer_uintPtr %16
; OpStore %17 %22 Aligned 8
OpReturn
OpFunctionEnd

View File

@ -2,7 +2,7 @@
#extension GL_EXT_buffer_reference : require
layout(local_size_x = 1) in;
layout(buffer_reference) buffer Block
layout(buffer_reference, buffer_reference_align = 4) buffer Block
{
float v;
};

View File

@ -0,0 +1,24 @@
#version 450
#extension GL_EXT_buffer_reference : require
layout(buffer_reference) buffer Foo
{
uint v;
};
layout(buffer_reference, buffer_reference_align = 8) buffer Bar
{
uint a;
uint b;
Foo foo;
};
layout(push_constant) uniform Push
{
Bar bar;
};
void main()
{
atomicAdd(bar.b, 1u);
}

View File

@ -0,0 +1,25 @@
#version 450
#extension GL_EXT_buffer_reference : require
layout(buffer_reference) buffer Foo
{
uint v;
};
layout(buffer_reference, buffer_reference_align = 8) buffer Bar
{
uint a;
uint b;
Foo foo;
};
layout(push_constant) uniform Push
{
Bar bar;
};
void main()
{
uint v = bar.b;
atomicAdd(bar.a, v);
}

View File

@ -4749,31 +4749,181 @@ Compiler::PhysicalStorageBufferPointerHandler::PhysicalStorageBufferPointerHandl
{
}
bool Compiler::PhysicalStorageBufferPointerHandler::handle(Op op, const uint32_t *args, uint32_t)
Compiler::PhysicalBlockMeta *Compiler::PhysicalStorageBufferPointerHandler::find_block_meta(uint32_t id) const
{
if (op == OpConvertUToPtr || op == OpBitcast)
auto chain_itr = access_chain_to_physical_block.find(id);
if (chain_itr != access_chain_to_physical_block.end())
return chain_itr->second;
else
return nullptr;
}
void Compiler::PhysicalStorageBufferPointerHandler::mark_aligned_access(uint32_t id, const uint32_t *args, uint32_t length)
{
uint32_t mask = *args;
args++;
length--;
if (length && (mask & MemoryAccessVolatileMask) != 0)
{
auto &type = compiler.get<SPIRType>(args[0]);
if (type.storage == StorageClassPhysicalStorageBufferEXT && type.pointer && type.pointer_depth == 1)
args++;
length--;
}
if (length && (mask & MemoryAccessAlignedMask) != 0)
{
uint32_t alignment = *args;
auto *meta = find_block_meta(id);
// This makes the assumption that the application does not rely on insane edge cases like:
// Bind buffer with ADDR = 8, use block offset of 8 bytes, load/store with 16 byte alignment.
// If we emit the buffer with alignment = 16 here, the first element at offset = 0 should
// actually have alignment of 8 bytes, but this is too theoretical and awkward to support.
// We could potentially keep track of any offset in the access chain, but it's
// practically impossible for high level compilers to emit code like that,
// so deducing overall alignment requirement based on maximum observed Alignment value is probably fine.
if (meta && alignment > meta->alignment)
meta->alignment = alignment;
}
}
bool Compiler::PhysicalStorageBufferPointerHandler::type_is_bda_block_entry(uint32_t type_id) const
{
auto &type = compiler.get<SPIRType>(type_id);
return type.storage == StorageClassPhysicalStorageBufferEXT && type.pointer &&
type.pointer_depth == 1 && !compiler.type_is_array_of_pointers(type);
}
uint32_t Compiler::PhysicalStorageBufferPointerHandler::get_minimum_scalar_alignment(const SPIRType &type) const
{
if (type.storage == spv::StorageClassPhysicalStorageBufferEXT)
return 8;
else if (type.basetype == SPIRType::Struct)
{
uint32_t alignment = 0;
for (auto &member_type : type.member_types)
{
// If we need to cast to a pointer type which is not a block, we might need to synthesize ourselves
// a block type which wraps this POD type.
if (type.basetype != SPIRType::Struct)
types.insert(args[0]);
uint32_t member_align = get_minimum_scalar_alignment(compiler.get<SPIRType>(member_type));
if (member_align > alignment)
alignment = member_align;
}
return alignment;
}
else
return type.width / 8;
}
void Compiler::PhysicalStorageBufferPointerHandler::setup_meta_chain(uint32_t type_id, uint32_t var_id)
{
if (type_is_bda_block_entry(type_id))
{
auto &meta = physical_block_type_meta[type_id];
access_chain_to_physical_block[var_id] = &meta;
auto &type = compiler.get<SPIRType>(type_id);
if (type.basetype != SPIRType::Struct)
non_block_types.insert(type_id);
if (meta.alignment == 0)
meta.alignment = get_minimum_scalar_alignment(compiler.get_pointee_type(type));
}
}
bool Compiler::PhysicalStorageBufferPointerHandler::handle(Op op, const uint32_t *args, uint32_t length)
{
// When a BDA pointer comes to life, we need to keep a mapping of SSA ID -> type ID for the pointer type.
// For every load and store, we'll need to be able to look up the type ID being accessed and mark any alignment
// requirements.
switch (op)
{
case OpConvertUToPtr:
case OpBitcast:
case OpCompositeExtract:
// Extract can begin a new chain if we had a struct or array of pointers as input.
// We don't begin chains before we have a pure scalar pointer.
setup_meta_chain(args[0], args[1]);
break;
case OpAccessChain:
case OpInBoundsAccessChain:
case OpPtrAccessChain:
case OpCopyObject:
{
auto itr = access_chain_to_physical_block.find(args[2]);
if (itr != access_chain_to_physical_block.end())
access_chain_to_physical_block[args[1]] = itr->second;
break;
}
case OpLoad:
{
setup_meta_chain(args[0], args[1]);
if (length >= 4)
mark_aligned_access(args[2], args + 3, length - 3);
break;
}
case OpStore:
{
if (length >= 3)
mark_aligned_access(args[0], args + 2, length - 2);
break;
}
default:
break;
}
return true;
}
uint32_t Compiler::PhysicalStorageBufferPointerHandler::get_base_non_block_type_id(uint32_t type_id) const
{
auto *type = &compiler.get<SPIRType>(type_id);
while (type->pointer &&
type->storage == StorageClassPhysicalStorageBufferEXT &&
!type_is_bda_block_entry(type_id))
{
type_id = type->parent_type;
type = &compiler.get<SPIRType>(type_id);
}
assert(type_is_bda_block_entry(type_id));
return type_id;
}
void Compiler::PhysicalStorageBufferPointerHandler::analyze_non_block_types_from_block(const SPIRType &type)
{
for (auto &member : type.member_types)
{
auto &subtype = compiler.get<SPIRType>(member);
if (subtype.basetype != SPIRType::Struct && subtype.pointer &&
subtype.storage == spv::StorageClassPhysicalStorageBufferEXT)
{
non_block_types.insert(get_base_non_block_type_id(member));
}
else if (subtype.basetype == SPIRType::Struct && !subtype.pointer)
analyze_non_block_types_from_block(subtype);
}
}
void Compiler::analyze_non_block_pointer_types()
{
PhysicalStorageBufferPointerHandler handler(*this);
traverse_all_reachable_opcodes(get<SPIRFunction>(ir.default_entry_point), handler);
physical_storage_non_block_pointer_types.reserve(handler.types.size());
for (auto type : handler.types)
// Analyze any block declaration we have to make. It might contain
// physical pointers to POD types which we never used, and thus never added to the list.
// We'll need to add those pointer types to the set of types we declare.
ir.for_each_typed_id<SPIRType>([&](uint32_t, SPIRType &type) {
if (has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock))
handler.analyze_non_block_types_from_block(type);
});
physical_storage_non_block_pointer_types.reserve(handler.non_block_types.size());
for (auto type : handler.non_block_types)
physical_storage_non_block_pointer_types.push_back(type);
sort(begin(physical_storage_non_block_pointer_types), end(physical_storage_non_block_pointer_types));
physical_storage_type_to_alignment = move(handler.physical_block_type_meta);
}
bool Compiler::InterlockedResourceAccessPrepassHandler::handle(Op op, const uint32_t *, uint32_t)

View File

@ -1010,15 +1010,32 @@ protected:
uint32_t write_count = 0;
};
struct PhysicalBlockMeta
{
uint32_t alignment = 0;
};
struct PhysicalStorageBufferPointerHandler : OpcodeHandler
{
explicit PhysicalStorageBufferPointerHandler(Compiler &compiler_);
bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
std::unordered_set<uint32_t> types;
std::unordered_set<uint32_t> non_block_types;
std::unordered_map<uint32_t, PhysicalBlockMeta> physical_block_type_meta;
std::unordered_map<uint32_t, PhysicalBlockMeta *> access_chain_to_physical_block;
void mark_aligned_access(uint32_t id, const uint32_t *args, uint32_t length);
PhysicalBlockMeta *find_block_meta(uint32_t id) const;
bool type_is_bda_block_entry(uint32_t type_id) const;
void setup_meta_chain(uint32_t type_id, uint32_t var_id);
uint32_t get_minimum_scalar_alignment(const SPIRType &type) const;
void analyze_non_block_types_from_block(const SPIRType &type);
uint32_t get_base_non_block_type_id(uint32_t type_id) const;
};
void analyze_non_block_pointer_types();
SmallVector<uint32_t> physical_storage_non_block_pointer_types;
std::unordered_map<uint32_t, PhysicalBlockMeta> physical_storage_type_to_alignment;
void analyze_variable_scope(SPIRFunction &function, AnalyzeVariableScopeAccessHandler &handler);
void find_function_local_luts(SPIRFunction &function, const AnalyzeVariableScopeAccessHandler &handler,

View File

@ -2171,8 +2171,9 @@ void CompilerGLSL::emit_buffer_block_legacy(const SPIRVariable &var)
statement("");
}
void CompilerGLSL::emit_buffer_reference_block(SPIRType &type, bool forward_declaration)
void CompilerGLSL::emit_buffer_reference_block(uint32_t type_id, bool forward_declaration)
{
auto &type = get<SPIRType>(type_id);
string buffer_name;
if (forward_declaration)
@ -2215,8 +2216,19 @@ void CompilerGLSL::emit_buffer_reference_block(SPIRType &type, bool forward_decl
if (!forward_declaration)
{
auto itr = physical_storage_type_to_alignment.find(type_id);
uint32_t alignment = 0;
if (itr != physical_storage_type_to_alignment.end())
alignment = itr->second.alignment;
if (type.basetype == SPIRType::Struct)
{
SmallVector<std::string> attributes;
attributes.push_back("buffer_reference");
if (alignment)
attributes.push_back(join("buffer_reference_align = ", alignment));
attributes.push_back(buffer_to_packing_standard(type, true));
auto flags = ir.get_buffer_block_type_flags(type);
string decorations;
if (flags.get(DecorationRestrict))
@ -2227,9 +2239,11 @@ void CompilerGLSL::emit_buffer_reference_block(SPIRType &type, bool forward_decl
decorations += " writeonly";
if (flags.get(DecorationNonWritable))
decorations += " readonly";
statement("layout(buffer_reference, ", buffer_to_packing_standard(type, true),
")", decorations, " buffer ", buffer_name);
statement("layout(", merge(attributes), ")", decorations, " buffer ", buffer_name);
}
else if (alignment)
statement("layout(buffer_reference, buffer_reference_align = ", alignment, ") buffer ", buffer_name);
else
statement("layout(buffer_reference) buffer ", buffer_name);
@ -3447,28 +3461,28 @@ void CompilerGLSL::emit_resources()
{
for (auto type : physical_storage_non_block_pointer_types)
{
emit_buffer_reference_block(get<SPIRType>(type), false);
emit_buffer_reference_block(type, false);
}
// Output buffer reference blocks.
// Do this in two stages, one with forward declaration,
// and one without. Buffer reference blocks can reference themselves
// to support things like linked lists.
ir.for_each_typed_id<SPIRType>([&](uint32_t, SPIRType &type) {
bool has_block_flags = has_decoration(type.self, DecorationBlock);
if (has_block_flags && type.pointer && type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
if (type.basetype == SPIRType::Struct && type.pointer &&
type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
type.storage == StorageClassPhysicalStorageBufferEXT)
{
emit_buffer_reference_block(type, true);
emit_buffer_reference_block(self, true);
}
});
ir.for_each_typed_id<SPIRType>([&](uint32_t, SPIRType &type) {
bool has_block_flags = has_decoration(type.self, DecorationBlock);
if (has_block_flags && type.pointer && type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
if (type.basetype == SPIRType::Struct &&
type.pointer && type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
type.storage == StorageClassPhysicalStorageBufferEXT)
{
emit_buffer_reference_block(type, false);
emit_buffer_reference_block(self, false);
}
});
}

View File

@ -592,7 +592,7 @@ protected:
void emit_resources();
void emit_extension_workarounds(spv::ExecutionModel model);
void emit_buffer_block_native(const SPIRVariable &var);
void emit_buffer_reference_block(SPIRType &type, bool forward_declaration);
void emit_buffer_reference_block(uint32_t type_id, bool forward_declaration);
void emit_buffer_block_legacy(const SPIRVariable &var);
void emit_buffer_block_flattened(const SPIRVariable &type);
void fixup_implicit_builtin_block_names();