mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-17 20:52:36 +01:00
Updated spirv-cross.
This commit is contained in:
250
3rdparty/spirv-cross/spirv_cross.cpp
vendored
250
3rdparty/spirv-cross/spirv_cross.cpp
vendored
@@ -181,6 +181,30 @@ bool Compiler::block_is_pure(const SPIRBlock &block)
|
||||
// This is a global side effect of the function.
|
||||
return false;
|
||||
|
||||
case OpExtInst:
|
||||
{
|
||||
uint32_t extension_set = ops[2];
|
||||
if (get<SPIRExtension>(extension_set).ext == SPIRExtension::GLSL)
|
||||
{
|
||||
auto op_450 = static_cast<GLSLstd450>(ops[3]);
|
||||
switch (op_450)
|
||||
{
|
||||
case GLSLstd450Modf:
|
||||
case GLSLstd450Frexp:
|
||||
{
|
||||
auto &type = expression_type(ops[5]);
|
||||
if (type.storage != StorageClassFunction)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -716,6 +740,15 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t
|
||||
break;
|
||||
}
|
||||
|
||||
case GLSLstd450Modf:
|
||||
case GLSLstd450Fract:
|
||||
{
|
||||
auto *var = compiler.maybe_get<SPIRVariable>(args[5]);
|
||||
if (var && storage_class_is_interface(var->storage))
|
||||
variables.insert(args[5]);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1729,10 +1762,22 @@ size_t Compiler::get_declared_struct_size(const SPIRType &type) const
|
||||
if (type.member_types.empty())
|
||||
SPIRV_CROSS_THROW("Declared struct in block cannot be empty.");
|
||||
|
||||
uint32_t last = uint32_t(type.member_types.size() - 1);
|
||||
size_t offset = type_struct_member_offset(type, last);
|
||||
size_t size = get_declared_struct_member_size(type, last);
|
||||
return offset + size;
|
||||
// Offsets can be declared out of order, so we need to deduce the actual size
|
||||
// based on last member instead.
|
||||
uint32_t member_index = 0;
|
||||
size_t highest_offset = 0;
|
||||
for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
|
||||
{
|
||||
size_t offset = type_struct_member_offset(type, i);
|
||||
if (offset > highest_offset)
|
||||
{
|
||||
highest_offset = offset;
|
||||
member_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
size_t size = get_declared_struct_member_size(type, member_index);
|
||||
return highest_offset + size;
|
||||
}
|
||||
|
||||
size_t Compiler::get_declared_struct_size_runtime_array(const SPIRType &type, size_t array_size) const
|
||||
@@ -3278,6 +3323,33 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3
|
||||
for (uint32_t i = 4; i < length; i++)
|
||||
notify_variable_access(args[i], current_block->self);
|
||||
notify_variable_access(args[1], current_block->self);
|
||||
|
||||
uint32_t extension_set = args[2];
|
||||
if (compiler.get<SPIRExtension>(extension_set).ext == SPIRExtension::GLSL)
|
||||
{
|
||||
auto op_450 = static_cast<GLSLstd450>(args[3]);
|
||||
switch (op_450)
|
||||
{
|
||||
case GLSLstd450Modf:
|
||||
case GLSLstd450Frexp:
|
||||
{
|
||||
uint32_t ptr = args[5];
|
||||
auto *var = compiler.maybe_get_backing_variable(ptr);
|
||||
if (var)
|
||||
{
|
||||
accessed_variables_to_block[var->self].insert(current_block->self);
|
||||
if (var->self == ptr)
|
||||
complete_write_variables_to_block[var->self].insert(current_block->self);
|
||||
else
|
||||
partial_write_variables_to_block[var->self].insert(current_block->self);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4677,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)
|
||||
|
||||
19
3rdparty/spirv-cross/spirv_cross.hpp
vendored
19
3rdparty/spirv-cross/spirv_cross.hpp
vendored
@@ -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,
|
||||
|
||||
@@ -327,8 +327,8 @@ public:
|
||||
|
||||
void reserve(size_t count) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
if ((count > std::numeric_limits<size_t>::max() / sizeof(T)) ||
|
||||
(count > std::numeric_limits<size_t>::max() / 2))
|
||||
if ((count > (std::numeric_limits<size_t>::max)() / sizeof(T)) ||
|
||||
(count > (std::numeric_limits<size_t>::max)() / 2))
|
||||
{
|
||||
// Only way this should ever happen is with garbage input, terminate.
|
||||
std::terminate();
|
||||
|
||||
38
3rdparty/spirv-cross/spirv_glsl.cpp
vendored
38
3rdparty/spirv-cross/spirv_glsl.cpp
vendored
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
2
3rdparty/spirv-cross/spirv_glsl.hpp
vendored
2
3rdparty/spirv-cross/spirv_glsl.hpp
vendored
@@ -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();
|
||||
|
||||
42
3rdparty/spirv-cross/spirv_msl.cpp
vendored
42
3rdparty/spirv-cross/spirv_msl.cpp
vendored
@@ -1710,6 +1710,16 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
|
||||
added_arg_ids.insert(stage_in_var_id);
|
||||
break;
|
||||
}
|
||||
|
||||
case GLSLstd450Modf:
|
||||
case GLSLstd450Frexp:
|
||||
{
|
||||
uint32_t base_id = ops[5];
|
||||
if (global_var_ids.find(base_id) != global_var_ids.end())
|
||||
added_arg_ids.insert(base_id);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2251,7 +2261,7 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, comp);
|
||||
mark_location_as_used_by_shader(locn, get<SPIRType>(type_id), storage);
|
||||
}
|
||||
else if (is_builtin && is_tessellation_shader() && inputs_by_builtin.count(builtin))
|
||||
else if (is_builtin && is_tessellation_shader() && storage == StorageClassInput && inputs_by_builtin.count(builtin))
|
||||
{
|
||||
uint32_t locn = inputs_by_builtin[builtin].location;
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
||||
@@ -2416,7 +2426,7 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, comp);
|
||||
mark_location_as_used_by_shader(locn, *usable_type, storage);
|
||||
}
|
||||
else if (is_builtin && is_tessellation_shader() && inputs_by_builtin.count(builtin))
|
||||
else if (is_builtin && is_tessellation_shader() && storage == StorageClassInput && inputs_by_builtin.count(builtin))
|
||||
{
|
||||
uint32_t locn = inputs_by_builtin[builtin].location + i;
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
||||
@@ -2589,7 +2599,7 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
||||
mark_location_as_used_by_shader(locn, *usable_type, storage);
|
||||
}
|
||||
else if (is_builtin && is_tessellation_shader() && inputs_by_builtin.count(builtin))
|
||||
else if (is_builtin && is_tessellation_shader() && storage == StorageClassInput && inputs_by_builtin.count(builtin))
|
||||
{
|
||||
uint32_t locn = inputs_by_builtin[builtin].location + i;
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
||||
@@ -2780,7 +2790,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
||||
mark_location_as_used_by_shader(locn, get<SPIRType>(mbr_type_id), storage);
|
||||
}
|
||||
else if (is_builtin && is_tessellation_shader() && inputs_by_builtin.count(builtin))
|
||||
else if (is_builtin && is_tessellation_shader() && storage == StorageClassInput && inputs_by_builtin.count(builtin))
|
||||
{
|
||||
uint32_t locn = 0;
|
||||
auto builtin_itr = inputs_by_builtin.find(builtin);
|
||||
@@ -4171,11 +4181,7 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in
|
||||
set_decoration(type_id, DecorationArrayStride, array_stride);
|
||||
|
||||
// Remove packed_ for vectors of size 1, 2 and 4.
|
||||
if (has_extended_decoration(ib_type.self, SPIRVCrossDecorationPhysicalTypePacked))
|
||||
SPIRV_CROSS_THROW("Unable to remove packed decoration as entire struct must be fully packed. Do not mix "
|
||||
"scalar and std140 layout rules.");
|
||||
else
|
||||
unset_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
||||
unset_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
||||
}
|
||||
else if (is_matrix(mbr_type))
|
||||
{
|
||||
@@ -4202,11 +4208,7 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in
|
||||
set_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypeID, type_id);
|
||||
|
||||
// Remove packed_ for vectors of size 1, 2 and 4.
|
||||
if (has_extended_decoration(ib_type.self, SPIRVCrossDecorationPhysicalTypePacked))
|
||||
SPIRV_CROSS_THROW("Unable to remove packed decoration as entire struct must be fully packed. Do not mix "
|
||||
"scalar and std140 layout rules.");
|
||||
else
|
||||
unset_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
||||
unset_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
||||
}
|
||||
else
|
||||
SPIRV_CROSS_THROW("Found a buffer packing case which we cannot represent in MSL.");
|
||||
@@ -9171,8 +9173,16 @@ void CompilerMSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||
case GLSLstd450Frexp:
|
||||
{
|
||||
// Special case. If the variable is a scalar access chain, we cannot use it directly. We have to emit a temporary.
|
||||
// Another special case is if the variable is in a storage class which is not thread.
|
||||
auto *ptr = maybe_get<SPIRExpression>(args[1]);
|
||||
if (ptr && ptr->access_chain && is_scalar(expression_type(args[1])))
|
||||
auto &type = expression_type(args[1]);
|
||||
|
||||
bool is_thread_storage = storage_class_array_is_thread(type.storage);
|
||||
if (type.storage == StorageClassOutput && capture_output_to_buffer)
|
||||
is_thread_storage = false;
|
||||
|
||||
if (!is_thread_storage ||
|
||||
(ptr && ptr->access_chain && is_scalar(expression_type(args[1]))))
|
||||
{
|
||||
register_call_out_argument(args[1]);
|
||||
forced_temporaries.insert(id);
|
||||
@@ -9183,7 +9193,7 @@ void CompilerMSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||
if (!tmp_id)
|
||||
tmp_id = ir.increase_bound_by(1);
|
||||
|
||||
uint32_t tmp_type_id = get_pointee_type_id(ptr->expression_type);
|
||||
uint32_t tmp_type_id = get_pointee_type_id(expression_type_id(args[1]));
|
||||
emit_uninitialized_temporary_expression(tmp_type_id, tmp_id);
|
||||
emit_binary_func_op(result_type, id, args[0], tmp_id, eop == GLSLstd450Modf ? "modf" : "frexp");
|
||||
statement(to_expression(args[1]), " = ", to_expression(tmp_id), ";");
|
||||
|
||||
43
3rdparty/spirv-cross/spirv_parser.cpp
vendored
43
3rdparty/spirv-cross/spirv_parser.cpp
vendored
@@ -961,6 +961,49 @@ void Parser::parse(const Instruction &instruction)
|
||||
current_block->false_block = ops[2];
|
||||
|
||||
current_block->terminator = SPIRBlock::Select;
|
||||
|
||||
if (current_block->true_block == current_block->false_block)
|
||||
{
|
||||
// Bogus conditional, translate to a direct branch.
|
||||
// Avoids some ugly edge cases later when analyzing CFGs.
|
||||
|
||||
// There are some super jank cases where the merge block is different from the true/false,
|
||||
// and later branches can "break" out of the selection construct this way.
|
||||
// This is complete nonsense, but CTS hits this case.
|
||||
// In this scenario, we should see the selection construct as more of a Switch with one default case.
|
||||
// The problem here is that this breaks any attempt to break out of outer switch statements,
|
||||
// but it's theoretically solvable if this ever comes up using the ladder breaking system ...
|
||||
|
||||
if (current_block->true_block != current_block->next_block &&
|
||||
current_block->merge == SPIRBlock::MergeSelection)
|
||||
{
|
||||
uint32_t ids = ir.increase_bound_by(2);
|
||||
|
||||
SPIRType type;
|
||||
type.basetype = SPIRType::Int;
|
||||
type.width = 32;
|
||||
set<SPIRType>(ids, type);
|
||||
auto &c = set<SPIRConstant>(ids + 1, ids);
|
||||
|
||||
current_block->condition = c.self;
|
||||
current_block->default_block = current_block->true_block;
|
||||
current_block->terminator = SPIRBlock::MultiSelect;
|
||||
ir.block_meta[current_block->next_block] &= ~ParsedIR::BLOCK_META_SELECTION_MERGE_BIT;
|
||||
ir.block_meta[current_block->next_block] |= ParsedIR::BLOCK_META_MULTISELECT_MERGE_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ir.block_meta[current_block->next_block] &= ~ParsedIR::BLOCK_META_SELECTION_MERGE_BIT;
|
||||
current_block->next_block = current_block->true_block;
|
||||
current_block->condition = 0;
|
||||
current_block->true_block = 0;
|
||||
current_block->false_block = 0;
|
||||
current_block->merge_block = 0;
|
||||
current_block->merge = SPIRBlock::MergeNone;
|
||||
current_block->terminator = SPIRBlock::Direct;
|
||||
}
|
||||
}
|
||||
|
||||
current_block = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user