Add support for new HLSL semantic/counter buffer decorations.

This commit is contained in:
Hans-Kristian Arntzen 2018-03-20 20:04:12 +01:00
parent 7f84537350
commit 215d3ca0a4
3 changed files with 129 additions and 2 deletions

View File

@ -1185,6 +1185,7 @@ struct Meta
{
std::string alias;
std::string qualified_alias;
std::string hlsl_semantic;
Bitset decoration_flags;
spv::BuiltIn builtin_type;
uint32_t location = 0;
@ -1212,6 +1213,11 @@ struct Meta
// is not a valid identifier in any high-level language.
std::string hlsl_magic_counter_buffer_name;
bool hlsl_magic_counter_buffer_candidate = false;
// For SPV_GOOGLE_hlsl_functionality1, this avoids the workaround.
bool hlsl_is_magic_counter_buffer = false;
// ID for the sibling counter buffer.
uint32_t hlsl_magic_counter_buffer = 0;
};
// A user callback that remaps the type of any variable.

View File

@ -1012,6 +1012,7 @@ void Compiler::set_name(uint32_t id, const std::string &name)
// glslang uses identifiers to pass along meaningful information
// about HLSL reflection.
// FIXME: This should be deprecated eventually.
auto &m = meta.at(id);
if (source.hlsl && name.size() >= 6 && name.find("@count") == name.size() - 6)
{
@ -1041,6 +1042,24 @@ const SPIRType &Compiler::get_type_from_variable(uint32_t id) const
return get<SPIRType>(get<SPIRVariable>(id).basetype);
}
void Compiler::set_member_decoration_string(uint32_t id, uint32_t index, spv::Decoration decoration,
const std::string &argument)
{
meta.at(id).members.resize(max(meta[id].members.size(), size_t(index) + 1));
auto &dec = meta.at(id).members[index];
dec.decoration_flags.set(decoration);
switch (decoration)
{
case DecorationHlslSemanticGOOGLE:
dec.hlsl_semantic = argument;
break;
default:
break;
}
}
void Compiler::set_member_decoration(uint32_t id, uint32_t index, Decoration decoration, uint32_t argument)
{
meta.at(id).members.resize(max(meta[id].members.size(), size_t(index) + 1));
@ -1206,6 +1225,26 @@ void Compiler::unset_member_decoration(uint32_t id, uint32_t index, Decoration d
dec.spec_id = 0;
break;
case DecorationHlslSemanticGOOGLE:
dec.hlsl_semantic.clear();
break;
default:
break;
}
}
void Compiler::set_decoration_string(uint32_t id, spv::Decoration decoration, const std::string &argument)
{
auto &dec = meta.at(id).decoration;
dec.decoration_flags.set(decoration);
switch (decoration)
{
case DecorationHlslSemanticGOOGLE:
dec.hlsl_semantic = argument;
break;
default:
break;
}
@ -1259,6 +1298,11 @@ void Compiler::set_decoration(uint32_t id, Decoration decoration, uint32_t argum
dec.index = argument;
break;
case DecorationHlslCounterBufferGOOGLE:
meta.at(id).hlsl_magic_counter_buffer = argument;
meta.at(argument).hlsl_is_magic_counter_buffer = true;
break;
default:
break;
}
@ -1304,6 +1348,24 @@ bool Compiler::has_decoration(uint32_t id, Decoration decoration) const
return get_decoration_bitset(id).get(decoration);
}
const string &Compiler::get_decoration_string(uint32_t id, spv::Decoration decoration) const
{
auto &dec = meta.at(id).decoration;
static const string empty;
if (!dec.decoration_flags.get(decoration))
return empty;
switch (decoration)
{
case DecorationHlslSemanticGOOGLE:
return dec.hlsl_semantic;
default:
return empty;
}
}
uint32_t Compiler::get_decoration(uint32_t id, Decoration decoration) const
{
auto &dec = meta.at(id).decoration;
@ -1371,6 +1433,21 @@ void Compiler::unset_decoration(uint32_t id, Decoration decoration)
dec.spec_id = 0;
break;
case DecorationHlslSemanticGOOGLE:
dec.hlsl_semantic.clear();
break;
case DecorationHlslCounterBufferGOOGLE:
{
auto &counter = meta.at(id).hlsl_magic_counter_buffer;
if (counter)
{
meta.at(counter).hlsl_is_magic_counter_buffer = false;
counter = 0;
}
break;
}
default:
break;
}
@ -1548,6 +1625,7 @@ void Compiler::parse(const Instruction &instruction)
}
case OpDecorate:
case OpDecorateId:
{
uint32_t id = ops[0];
@ -1563,6 +1641,14 @@ void Compiler::parse(const Instruction &instruction)
break;
}
case OpDecorateStringGOOGLE:
{
uint32_t id = ops[0];
auto decoration = static_cast<Decoration>(ops[1]);
set_decoration_string(id, decoration, extract_string(spirv, instruction.offset + 2));
break;
}
case OpMemberDecorate:
{
uint32_t id = ops[0];
@ -1575,6 +1661,15 @@ void Compiler::parse(const Instruction &instruction)
break;
}
case OpMemberDecorateStringGOOGLE:
{
uint32_t id = ops[0];
uint32_t member = ops[1];
auto decoration = static_cast<Decoration>(ops[2]);
set_member_decoration_string(id, member, decoration, extract_string(spirv, instruction.offset + 3));
break;
}
// Build up basic types.
case OpTypeVoid:
{
@ -4239,6 +4334,13 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_
bool Compiler::buffer_is_hlsl_counter_buffer(uint32_t id) const
{
// First, check for the proper decoration.
if (meta.at(id).hlsl_is_magic_counter_buffer)
return true;
// Check for legacy fallback method.
// FIXME: This should be deprecated eventually.
if (meta.at(id).hlsl_magic_counter_buffer_candidate)
{
auto *var = maybe_get<SPIRVariable>(id);
@ -4252,6 +4354,16 @@ bool Compiler::buffer_is_hlsl_counter_buffer(uint32_t id) const
bool Compiler::buffer_get_hlsl_counter_buffer(uint32_t id, uint32_t &counter_id) const
{
// First, check for the proper decoration.
if (meta[id].hlsl_magic_counter_buffer != 0)
{
counter_id = meta[id].hlsl_magic_counter_buffer;
return true;
}
// Check for legacy fallback method.
// FIXME: This should be deprecated eventually.
auto &name = get_name(id);
uint32_t id_bound = get_current_id_bound();
for (uint32_t i = 0; i < id_bound; i++)

View File

@ -136,6 +136,7 @@ public:
// Applies a decoration to an ID. Effectively injects OpDecorate.
void set_decoration(uint32_t id, spv::Decoration decoration, uint32_t argument = 0);
void set_decoration_string(uint32_t id, spv::Decoration decoration, const std::string &argument);
// Overrides the identifier OpName of an ID.
// Identifiers beginning with underscores or identifiers which contain double underscores
@ -157,6 +158,7 @@ public:
// If decoration doesn't exist or decoration is not recognized,
// 0 will be returned.
uint32_t get_decoration(uint32_t id, spv::Decoration decoration) const;
const std::string &get_decoration_string(uint32_t id, spv::Decoration decoration) const;
// Removes the decoration for a an ID.
void unset_decoration(uint32_t id, spv::Decoration decoration);
@ -185,6 +187,7 @@ public:
// Given an OpTypeStruct in ID, obtain the OpMemberDecoration for member number "index".
uint32_t get_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration) const;
const std::string &get_member_decoration_string(uint32_t id, uint32_t index, spv::Decoration decoration) const;
// Sets the member identifier for OpTypeStruct ID, member number "index".
void set_member_name(uint32_t id, uint32_t index, const std::string &name);
@ -206,6 +209,8 @@ public:
// Similar to set_decoration, but for struct members.
void set_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration, uint32_t argument = 0);
void set_member_decoration_string(uint32_t id, uint32_t index, spv::Decoration decoration,
const std::string &argument);
// Unsets a member decoration, similar to unset_decoration.
void unset_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration);
@ -441,14 +446,18 @@ public:
// which lets us link the two buffers together.
// Queries if a variable ID is a counter buffer which "belongs" to a regular buffer object.
// NOTE: This query is purely based on OpName identifiers as found in the SPIR-V module, and will
// If SPV_GOOGLE_hlsl_functionality1 is used, this can be used even with a stripped SPIR-V module.
// Otherwise, this query is purely based on OpName identifiers as found in the SPIR-V module, and will
// only return true if OpSource was reported HLSL.
// To rely on this functionality, ensure that the SPIR-V module is not stripped.
bool buffer_is_hlsl_counter_buffer(uint32_t id) const;
// Queries if a buffer object has a neighbor "counter" buffer.
// If so, the ID of that counter buffer will be returned in counter_id.
// NOTE: This query is purely based on OpName identifiers as found in the SPIR-V module, and will
// If SPV_GOOGLE_hlsl_functionality1 is used, this can be used even with a stripped SPIR-V module.
// Otherwise, this query is purely based on OpName identifiers as found in the SPIR-V module, and will
// only return true if OpSource was reported HLSL.
// To rely on this functionality, ensure that the SPIR-V module is not stripped.
bool buffer_get_hlsl_counter_buffer(uint32_t id, uint32_t &counter_id) const;