Add support for GL_ARB_enhanced_layouts.
This commit is contained in:
Родитель
1079e7930b
Коммит
5a89606f26
|
@ -101,7 +101,9 @@ struct BufferRange
|
||||||
enum BufferPackingStandard
|
enum BufferPackingStandard
|
||||||
{
|
{
|
||||||
BufferPackingStd140,
|
BufferPackingStd140,
|
||||||
BufferPackingStd430
|
BufferPackingStd430,
|
||||||
|
BufferPackingStd140EnhancedLayout,
|
||||||
|
BufferPackingStd430EnhancedLayout
|
||||||
};
|
};
|
||||||
|
|
||||||
class Compiler
|
class Compiler
|
||||||
|
|
115
spirv_glsl.cpp
115
spirv_glsl.cpp
|
@ -656,6 +656,11 @@ string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
|
||||||
if (dec.decoration_flags & (1ull << DecorationLocation))
|
if (dec.decoration_flags & (1ull << DecorationLocation))
|
||||||
attr.push_back(join("location = ", dec.location));
|
attr.push_back(join("location = ", dec.location));
|
||||||
|
|
||||||
|
// DecorationCPacked is set by layout_for_variable earlier to mark that we need to emit offset qualifiers.
|
||||||
|
// This is only done selectively in GLSL as needed.
|
||||||
|
if (has_decoration(type.self, DecorationCPacked) && (dec.decoration_flags & (1ull << DecorationOffset)) != 0)
|
||||||
|
attr.push_back(join("offset = ", dec.offset));
|
||||||
|
|
||||||
if (attr.empty())
|
if (attr.empty())
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
|
@ -814,7 +819,7 @@ uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, uint64_t f
|
||||||
}
|
}
|
||||||
|
|
||||||
// In std140, struct alignment is rounded up to 16.
|
// In std140, struct alignment is rounded up to 16.
|
||||||
if (packing == BufferPackingStd140)
|
if (packing == BufferPackingStd140 || packing == BufferPackingStd140EnhancedLayout)
|
||||||
alignment = max(alignment, 16u);
|
alignment = max(alignment, 16u);
|
||||||
|
|
||||||
return alignment;
|
return alignment;
|
||||||
|
@ -840,7 +845,9 @@ uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, uint64_t f
|
||||||
// vectors.
|
// vectors.
|
||||||
if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
|
if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
|
||||||
{
|
{
|
||||||
if (type.vecsize == 3)
|
if (packing == BufferPackingStd140 || packing == BufferPackingStd140EnhancedLayout)
|
||||||
|
return 4 * base_alignment;
|
||||||
|
else if (type.vecsize == 3)
|
||||||
return 4 * base_alignment;
|
return 4 * base_alignment;
|
||||||
else
|
else
|
||||||
return type.vecsize * base_alignment;
|
return type.vecsize * base_alignment;
|
||||||
|
@ -851,7 +858,9 @@ uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, uint64_t f
|
||||||
// Rule 7.
|
// Rule 7.
|
||||||
if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
|
if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
|
||||||
{
|
{
|
||||||
if (type.columns == 3)
|
if (packing == BufferPackingStd140 || packing == BufferPackingStd140EnhancedLayout)
|
||||||
|
return 4 * base_alignment;
|
||||||
|
else if (type.columns == 3)
|
||||||
return 4 * base_alignment;
|
return 4 * base_alignment;
|
||||||
else
|
else
|
||||||
return type.columns * base_alignment;
|
return type.columns * base_alignment;
|
||||||
|
@ -873,7 +882,7 @@ uint32_t CompilerGLSL::type_to_packed_array_stride(const SPIRType &type, uint64_
|
||||||
uint32_t alignment = type_to_packed_alignment(tmp, flags, packing);
|
uint32_t alignment = type_to_packed_alignment(tmp, flags, packing);
|
||||||
|
|
||||||
// Rule 4. In std140, array strides are padded out to the alignment of a vec4.
|
// Rule 4. In std140, array strides are padded out to the alignment of a vec4.
|
||||||
if (packing == BufferPackingStd140)
|
if (packing == BufferPackingStd140 || packing == BufferPackingStd140EnhancedLayout)
|
||||||
alignment = max(alignment, 16u);
|
alignment = max(alignment, 16u);
|
||||||
|
|
||||||
return (size + alignment - 1) & ~(alignment - 1);
|
return (size + alignment - 1) & ~(alignment - 1);
|
||||||
|
@ -918,7 +927,7 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, uint64_t flags,
|
||||||
|
|
||||||
if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
|
if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
|
||||||
{
|
{
|
||||||
if (packing == BufferPackingStd140)
|
if (packing == BufferPackingStd140 || packing == BufferPackingStd140EnhancedLayout)
|
||||||
size = type.columns * 4 * base_alignment;
|
size = type.columns * 4 * base_alignment;
|
||||||
else if (type.vecsize == 3)
|
else if (type.vecsize == 3)
|
||||||
size = type.columns * 4 * base_alignment;
|
size = type.columns * 4 * base_alignment;
|
||||||
|
@ -928,7 +937,7 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, uint64_t flags,
|
||||||
|
|
||||||
if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
|
if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
|
||||||
{
|
{
|
||||||
if (packing == BufferPackingStd140)
|
if (packing == BufferPackingStd140 || packing == BufferPackingStd140EnhancedLayout)
|
||||||
size = type.vecsize * 4 * base_alignment;
|
size = type.vecsize * 4 * base_alignment;
|
||||||
else if (type.columns == 3)
|
else if (type.columns == 3)
|
||||||
size = type.vecsize * 4 * base_alignment;
|
size = type.vecsize * 4 * base_alignment;
|
||||||
|
@ -975,9 +984,14 @@ bool CompilerGLSL::ssbo_is_packing_standard(const SPIRType &type, BufferPackingS
|
||||||
else
|
else
|
||||||
pad_alignment = 1;
|
pad_alignment = 1;
|
||||||
|
|
||||||
uint32_t actual_offset = type_struct_member_offset(type, i);
|
// We only care about offsets in std140, std430, for EnhancedLayout variants,
|
||||||
if (actual_offset != offset) // This cannot be the packing we're looking for.
|
// we have the flexibility to choose our own offsets.
|
||||||
return false;
|
if (packing == BufferPackingStd140 || packing == BufferPackingStd430)
|
||||||
|
{
|
||||||
|
uint32_t actual_offset = type_struct_member_offset(type, i);
|
||||||
|
if (actual_offset != offset) // This cannot be the packing we're looking for.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Verify array stride rules.
|
// Verify array stride rules.
|
||||||
if (!memb_type.array.empty() &&
|
if (!memb_type.array.empty() &&
|
||||||
|
@ -985,7 +999,22 @@ bool CompilerGLSL::ssbo_is_packing_standard(const SPIRType &type, BufferPackingS
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Verify that sub-structs also follow packing rules.
|
// Verify that sub-structs also follow packing rules.
|
||||||
if (!memb_type.member_types.empty() && !ssbo_is_packing_standard(memb_type, packing))
|
// We cannot use enhanced layouts on substructs, so they better be up to spec.
|
||||||
|
BufferPackingStandard substruct_packing;
|
||||||
|
switch (packing)
|
||||||
|
{
|
||||||
|
case BufferPackingStd140EnhancedLayout:
|
||||||
|
substruct_packing = BufferPackingStd140;
|
||||||
|
break;
|
||||||
|
case BufferPackingStd430EnhancedLayout:
|
||||||
|
substruct_packing = BufferPackingStd430;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
substruct_packing = packing;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memb_type.member_types.empty() && !ssbo_is_packing_standard(memb_type, substruct_packing))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Bump size.
|
// Bump size.
|
||||||
|
@ -1073,34 +1102,74 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
|
||||||
if (flags & (1ull << DecorationOffset))
|
if (flags & (1ull << DecorationOffset))
|
||||||
attr.push_back(join("offset = ", dec.offset));
|
attr.push_back(join("offset = ", dec.offset));
|
||||||
|
|
||||||
|
bool push_constant_block = options.vulkan_semantics && var.storage == StorageClassPushConstant;
|
||||||
|
bool ssbo_block = var.storage == StorageClassStorageBuffer ||
|
||||||
|
(var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBufferBlock)));
|
||||||
|
|
||||||
// Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
|
// Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
|
||||||
// If SPIR-V does not comply with either layout, we cannot really work around it.
|
// If SPIR-V does not comply with either layout, we cannot really work around it.
|
||||||
if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBlock)))
|
if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBlock)))
|
||||||
{
|
{
|
||||||
if (ssbo_is_packing_standard(type, BufferPackingStd140))
|
if (ssbo_is_packing_standard(type, BufferPackingStd140))
|
||||||
attr.push_back("std140");
|
attr.push_back("std140");
|
||||||
|
else if (ssbo_is_packing_standard(type, BufferPackingStd140EnhancedLayout))
|
||||||
|
{
|
||||||
|
// Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference,
|
||||||
|
// however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
|
||||||
|
// Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
|
||||||
|
if (options.es && !options.vulkan_semantics)
|
||||||
|
SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do not support GL_ARB_enhanced_layouts.");
|
||||||
|
if (!options.es && !options.vulkan_semantics && options.version < 440)
|
||||||
|
require_extension("GL_ARB_enhanced_layouts");
|
||||||
|
|
||||||
|
// This is a very last minute to check for this, but use this unused decoration to mark that we should emit
|
||||||
|
// explicit offsets for this block type.
|
||||||
|
// layout_for_variable() will be called before the actual buffer emit.
|
||||||
|
// The alternative is a full pass before codegen where we deduce this decoration,
|
||||||
|
// but then we are just doing the exact same work twice, and more complexity.
|
||||||
|
set_decoration(type.self, DecorationCPacked);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
SPIRV_CROSS_THROW("Uniform buffer cannot be expressed as std140. You can try flattening this block to "
|
{
|
||||||
"support a more flexible layout.");
|
SPIRV_CROSS_THROW(
|
||||||
|
"Uniform buffer cannot be expressed as std140, even with enhanced layouts. You can try flattening this block to "
|
||||||
|
"support a more flexible layout.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (var.storage == StorageClassStorageBuffer ||
|
else if (push_constant_block || ssbo_block)
|
||||||
(var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBufferBlock))))
|
|
||||||
{
|
{
|
||||||
if (ssbo_is_packing_standard(type, BufferPackingStd430))
|
if (ssbo_is_packing_standard(type, BufferPackingStd430))
|
||||||
attr.push_back("std430");
|
attr.push_back("std430");
|
||||||
else if (ssbo_is_packing_standard(type, BufferPackingStd140))
|
else if (ssbo_is_packing_standard(type, BufferPackingStd140))
|
||||||
attr.push_back("std140");
|
attr.push_back("std140");
|
||||||
else
|
else if (ssbo_is_packing_standard(type, BufferPackingStd140EnhancedLayout))
|
||||||
SPIRV_CROSS_THROW("Buffer block cannot be expressed as neither std430 nor std140.");
|
{
|
||||||
}
|
|
||||||
else if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
|
|
||||||
{
|
|
||||||
if (ssbo_is_packing_standard(type, BufferPackingStd430))
|
|
||||||
attr.push_back("std430");
|
|
||||||
else if (ssbo_is_packing_standard(type, BufferPackingStd140))
|
|
||||||
attr.push_back("std140");
|
attr.push_back("std140");
|
||||||
|
|
||||||
|
// Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference,
|
||||||
|
// however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
|
||||||
|
// Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
|
||||||
|
if (options.es && !options.vulkan_semantics)
|
||||||
|
SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do not support GL_ARB_enhanced_layouts.");
|
||||||
|
if (!options.es && !options.vulkan_semantics && options.version < 440)
|
||||||
|
require_extension("GL_ARB_enhanced_layouts");
|
||||||
|
|
||||||
|
set_decoration(type.self, DecorationCPacked);
|
||||||
|
}
|
||||||
|
else if (ssbo_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
|
||||||
|
{
|
||||||
|
attr.push_back("std430");
|
||||||
|
if (options.es && !options.vulkan_semantics)
|
||||||
|
SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do not support GL_ARB_enhanced_layouts.");
|
||||||
|
if (!options.es && !options.vulkan_semantics && options.version < 440)
|
||||||
|
require_extension("GL_ARB_enhanced_layouts");
|
||||||
|
|
||||||
|
set_decoration(type.self, DecorationCPacked);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140.");
|
{
|
||||||
|
SPIRV_CROSS_THROW("Buffer block cannot be expressed as neither std430 nor std140, even with enhanced layouts. You can try flattening this block to support a more flexible layout.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For images, the type itself adds a layout qualifer.
|
// For images, the type itself adds a layout qualifer.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче