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:
parent
1adc53b107
commit
f1b411c9e8
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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[];
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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[];
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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[];
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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[];
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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
|
@ -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;
|
||||
};
|
||||
|
24
shaders/vulkan/comp/buffer-reference-atomic.nocompat.vk.comp
Normal file
24
shaders/vulkan/comp/buffer-reference-atomic.nocompat.vk.comp
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
170
spirv_cross.cpp
170
spirv_cross.cpp
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user