Be careful about who gets to be the alias master, and don't alias types
when we have packed types in play.
This commit is contained in:
Hans-Kristian Arntzen 2018-03-05 16:27:04 +01:00
Родитель c9516fa917
Коммит 294259e2f1
4 изменённых файлов: 83 добавлений и 2 удалений

Просмотреть файл

@ -188,7 +188,12 @@ string Compiler::to_name(uint32_t id, bool allow_alias) const
// as that can be overridden by the reflection APIs after parse.
auto &type = get<SPIRType>(id);
if (type.type_alias)
return to_name(type.type_alias);
{
// If the alias master has been specially packed, we will have emitted a clean variant as well,
// so skip the name aliasing here.
if (!has_decoration(type.type_alias, DecorationCPacked))
return to_name(type.type_alias);
}
}
if (meta[id].decoration.alias.empty())
@ -802,6 +807,71 @@ static bool is_valid_spirv_version(uint32_t version)
}
}
bool Compiler::type_is_block_like(const SPIRType &type) const
{
if (type.basetype != SPIRType::Struct)
return false;
if (has_decoration(type.self, DecorationBlock) ||
has_decoration(type.self, DecorationBufferBlock))
{
return true;
}
// Block-like types may have Offset decorations.
for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
if (has_member_decoration(type.self, i, DecorationOffset))
return true;
return false;
}
void Compiler::fixup_type_alias()
{
// Due to how some backends work, the "master" type of type_alias must be a block-like type if it exists.
// FIXME: Multiple alias types which are both block-like will be awkward, for now, it's best to just drop the type
// alias if the slave type is a block type.
for (auto &id : ids)
{
if (id.get_type() != TypeType)
continue;
auto &type = id.get<SPIRType>();
if (type.type_alias && type_is_block_like(type))
{
// Become the master.
for (auto &other_id : ids)
{
if (other_id.get_type() != TypeType)
continue;
if (other_id.get_id() == type.self)
continue;
auto &other_type = other_id.get<SPIRType>();
if (other_type.type_alias == type.type_alias)
other_type.type_alias = type.self;
}
get<SPIRType>(type.type_alias).type_alias = id.get_id();
type.type_alias = 0;
}
}
for (auto &id : ids)
{
if (id.get_type() != TypeType)
continue;
auto &type = id.get<SPIRType>();
if (type.type_alias && type_is_block_like(type))
{
// This is not allowed, drop the type_alias.
type.type_alias = 0;
}
}
}
void Compiler::parse()
{
auto len = spirv.size();
@ -853,6 +923,8 @@ void Compiler::parse()
}
}
}
fixup_type_alias();
}
void Compiler::flatten_interface_block(uint32_t id)

Просмотреть файл

@ -824,6 +824,9 @@ private:
// Used only to implement the old deprecated get_entry_point() interface.
const SPIREntryPoint &get_first_entry_point(const std::string &name) const;
SPIREntryPoint &get_first_entry_point(const std::string &name);
void fixup_type_alias();
bool type_is_block_like(const SPIRType &type) const;
};
}

Просмотреть файл

@ -612,7 +612,8 @@ void CompilerGLSL::emit_struct(SPIRType &type)
// with just different offsets, matrix layouts, etc ...
// Type-punning with these types is legal, which complicates things
// when we are storing struct and array types in an SSBO for example.
if (type.type_alias != 0)
// If the type master is packed however, we can no longer assume that the struct declaration will be redundant.
if (type.type_alias != 0 && !has_decoration(type.type_alias, DecorationCPacked))
return;
// Don't declare empty structs in GLSL, this is not allowed.

Просмотреть файл

@ -438,6 +438,11 @@ void CompilerMSL::mark_as_packable(SPIRType &type)
uint32_t mbr_type_id = type.member_types[mbr_idx];
auto &mbr_type = get<SPIRType>(mbr_type_id);
mark_as_packable(mbr_type);
if (mbr_type.type_alias)
{
auto &mbr_type_alias = get<SPIRType>(mbr_type.type_alias);
mark_as_packable(mbr_type_alias);
}
}
}
}