Vulkan: Remove reliance on names for gl_PerVertex-trimmer

Instead of passing in gl_Position etc built-in names and then find their
index by looking at OpMemberName instructions, this change has the
front-end create a bitset of active gl_PerVertex members.  The SPIR-V
transformer then directly uses this information to trim gl_PerVertex.

Bug: angleproject:7220
Change-Id: I5c3d56784801abb310d09d98d9c82c9e6e019de8
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4600608
Reviewed-by: Yuxin Hu <yuxinhu@google.com>
Reviewed-by: Roman Lavrov <romanl@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
Shahbaz Youssefi 2023-06-07 11:26:37 -04:00 коммит произвёл Angle LUCI CQ
Родитель a01a566c48
Коммит acdf872299
6 изменённых файлов: 310 добавлений и 162 удалений

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

@ -22,7 +22,6 @@ namespace gl
namespace
{
// true if varying x has a higher priority in packing than y
bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
{
@ -183,6 +182,53 @@ std::vector<unsigned int> StripVaryingArrayDimension(const sh::ShaderVariable *f
return frontVarying ? frontVarying->arraySizes : backVarying->arraySizes;
}
PerVertexMember GetPerVertexMember(const std::string &name)
{
if (name == "gl_Position")
{
return PerVertexMember::Position;
}
if (name == "gl_PointSize")
{
return PerVertexMember::PointSize;
}
if (name == "gl_ClipDistance")
{
return PerVertexMember::ClipDistance;
}
if (name == "gl_CullDistance")
{
return PerVertexMember::CullDistance;
}
return PerVertexMember::InvalidEnum;
}
void SetActivePerVertexMembers(const sh::ShaderVariable *var, PerVertexMemberBitSet *bitset)
{
ASSERT(var->isBuiltIn() && var->active);
// Only process gl_Position, gl_PointSize, gl_ClipDistance, gl_CullDistance and the fields of
// gl_in/out.
if (var->fields.empty())
{
PerVertexMember member = GetPerVertexMember(var->name);
// Skip gl_TessLevelInner/Outer etc.
if (member != PerVertexMember::InvalidEnum)
{
bitset->set(member);
}
return;
}
// This must be gl_out. Note that only `out gl_PerVertex` is processed; the input of the
// next stage is implicitly identically active.
ASSERT(var->name == "gl_out");
for (const sh::ShaderVariable &field : var->fields)
{
bitset->set(GetPerVertexMember(field.name));
}
}
} // anonymous namespace
// Implementation of VaryingInShaderRef
@ -289,10 +335,8 @@ void VaryingPacking::reset()
inactiveVaryingMappedNames.clear();
}
for (std::vector<std::string> &activeBuiltIns : mActiveOutputBuiltIns)
{
activeBuiltIns.clear();
}
std::fill(mOutputPerVertexActiveMembers.begin(), mOutputPerVertexActiveMembers.end(),
gl::PerVertexMemberBitSet{});
}
void VaryingPacking::clearRegisterMap()
@ -841,16 +885,9 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
const bool isActiveBuiltInInput = input && input->isBuiltIn() && input->active;
const bool isActiveBuiltInOutput = output && output->isBuiltIn() && output->active;
// Keep track of output builtins that are used by the shader, such as gl_Position,
// gl_PointSize etc.
if (isActiveBuiltInInput)
{
mActiveOutputBuiltIns[ref.frontShaderStage].push_back(input->name);
// Keep track of members of builtins, such as gl_out[].gl_Position, too.
for (sh::ShaderVariable field : input->fields)
{
mActiveOutputBuiltIns[ref.frontShaderStage].push_back(field.name);
}
SetActivePerVertexMembers(input, &mOutputPerVertexActiveMembers[frontShaderStage]);
}
// Only pack statically used varyings that have a matched input or output, plus special

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

@ -205,6 +205,27 @@ enum class PackMode
ANGLE_NON_CONFORMANT_D3D9,
};
enum class PerVertexMember
{
// The gl_Pervertex struct is defined as:
//
// out gl_PerVertex
// {
// vec4 gl_Position;
// float gl_PointSize;
// float gl_ClipDistance[];
// float gl_CullDistance[];
// };
Position,
PointSize,
ClipDistance,
CullDistance,
EnumCount,
InvalidEnum = EnumCount,
};
using PerVertexMemberBitSet = angle::PackedEnumBitSet<PerVertexMember, uint8_t>;
class VaryingPacking final : angle::NonCopyable
{
public:
@ -244,9 +265,9 @@ class VaryingPacking final : angle::NonCopyable
return mInactiveVaryingMappedNames;
}
const ShaderMap<std::vector<std::string>> &getActiveOutputBuiltInNames() const
const ShaderMap<PerVertexMemberBitSet> &getOutputPerVertexActiveMembers() const
{
return mActiveOutputBuiltIns;
return mOutputPerVertexActiveMembers;
}
void reset();
@ -294,7 +315,7 @@ class VaryingPacking final : angle::NonCopyable
std::vector<PackedVaryingRegister> mRegisterList;
std::vector<PackedVarying> mPackedVaryings;
ShaderMap<std::vector<std::string>> mInactiveVaryingMappedNames;
ShaderMap<std::vector<std::string>> mActiveOutputBuiltIns;
ShaderMap<PerVertexMemberBitSet> mOutputPerVertexActiveMembers;
};
class ProgramVaryingPacking final : angle::NonCopyable

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

@ -545,6 +545,8 @@ std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(ContextVk *contextVk,
gl::ShaderMap<ShaderInterfaceVariableInfoMap::VariableTypeToInfoMap> data;
gl::ShaderMap<ShaderInterfaceVariableInfoMap::NameToTypeAndIndexMap> nameToTypeAndIndexMap;
gl::ShaderMap<ShaderInterfaceVariableInfoMap::VariableTypeToIndexMap> indexedResourceMap;
gl::ShaderMap<gl::PerVertexMemberBitSet> inputPerVertexActiveMembers;
gl::ShaderMap<gl::PerVertexMemberBitSet> outputPerVertexActiveMembers;
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
@ -596,7 +598,24 @@ std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(ContextVk *contextVk,
}
}
mVariableInfoMap.load(data, nameToTypeAndIndexMap, indexedResourceMap);
outputPerVertexActiveMembers[gl::ShaderType::Vertex] =
gl::PerVertexMemberBitSet(stream->readInt<uint8_t>());
inputPerVertexActiveMembers[gl::ShaderType::TessControl] =
gl::PerVertexMemberBitSet(stream->readInt<uint8_t>());
outputPerVertexActiveMembers[gl::ShaderType::TessControl] =
gl::PerVertexMemberBitSet(stream->readInt<uint8_t>());
inputPerVertexActiveMembers[gl::ShaderType::TessEvaluation] =
gl::PerVertexMemberBitSet(stream->readInt<uint8_t>());
outputPerVertexActiveMembers[gl::ShaderType::TessEvaluation] =
gl::PerVertexMemberBitSet(stream->readInt<uint8_t>());
inputPerVertexActiveMembers[gl::ShaderType::Geometry] =
gl::PerVertexMemberBitSet(stream->readInt<uint8_t>());
outputPerVertexActiveMembers[gl::ShaderType::Geometry] =
gl::PerVertexMemberBitSet(stream->readInt<uint8_t>());
mVariableInfoMap.load(std::move(data), std::move(nameToTypeAndIndexMap),
std::move(indexedResourceMap), std::move(inputPerVertexActiveMembers),
std::move(outputPerVertexActiveMembers));
mOriginalShaderInfo.load(stream);
@ -662,6 +681,10 @@ void ProgramExecutableVk::save(ContextVk *contextVk,
&nameToTypeAndIndexMap = mVariableInfoMap.getNameToTypeAndIndexMap();
const gl::ShaderMap<ShaderInterfaceVariableInfoMap::VariableTypeToIndexMap>
&indexedResourceMap = mVariableInfoMap.getIndexedResourceMap();
const gl::ShaderMap<gl::PerVertexMemberBitSet> &inputPerVertexActiveMembers =
mVariableInfoMap.getInputPerVertexActiveMembers();
const gl::ShaderMap<gl::PerVertexMemberBitSet> &outputPerVertexActiveMembers =
mVariableInfoMap.getOutputPerVertexActiveMembers();
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
@ -715,6 +738,15 @@ void ProgramExecutableVk::save(ContextVk *contextVk,
}
}
// Store gl_PerVertex members only for stages that have it.
stream->writeInt(outputPerVertexActiveMembers[gl::ShaderType::Vertex].bits());
stream->writeInt(inputPerVertexActiveMembers[gl::ShaderType::TessControl].bits());
stream->writeInt(outputPerVertexActiveMembers[gl::ShaderType::TessControl].bits());
stream->writeInt(inputPerVertexActiveMembers[gl::ShaderType::TessEvaluation].bits());
stream->writeInt(outputPerVertexActiveMembers[gl::ShaderType::TessEvaluation].bits());
stream->writeInt(inputPerVertexActiveMembers[gl::ShaderType::Geometry].bits());
stream->writeInt(outputPerVertexActiveMembers[gl::ShaderType::Geometry].bits());
mOriginalShaderInfo.save(stream);
// Serializes the uniformLayout data of mDefaultUniformBlocks

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

@ -28,16 +28,24 @@ void ShaderInterfaceVariableInfoMap::clear()
}
mNameToTypeAndIndexMap[shaderType].clear();
}
std::fill(mInputPerVertexActiveMembers.begin(), mInputPerVertexActiveMembers.end(),
gl::PerVertexMemberBitSet{});
std::fill(mOutputPerVertexActiveMembers.begin(), mOutputPerVertexActiveMembers.end(),
gl::PerVertexMemberBitSet{});
}
void ShaderInterfaceVariableInfoMap::load(
const gl::ShaderMap<VariableTypeToInfoMap> &data,
const gl::ShaderMap<NameToTypeAndIndexMap> &nameToTypeAndIndexMap,
const gl::ShaderMap<VariableTypeToIndexMap> &indexedResourceIndexMap)
gl::ShaderMap<VariableTypeToInfoMap> &&data,
gl::ShaderMap<NameToTypeAndIndexMap> &&nameToTypeAndIndexMap,
gl::ShaderMap<VariableTypeToIndexMap> &&indexedResourceIndexMap,
gl::ShaderMap<gl::PerVertexMemberBitSet> &&inputPerVertexActiveMembers,
gl::ShaderMap<gl::PerVertexMemberBitSet> &&outputPerVertexActiveMembers)
{
mData = data;
mNameToTypeAndIndexMap = nameToTypeAndIndexMap;
mIndexedResourceIndexMap = indexedResourceIndexMap;
mData.swap(data);
mNameToTypeAndIndexMap.swap(nameToTypeAndIndexMap);
mIndexedResourceIndexMap.swap(indexedResourceIndexMap);
mInputPerVertexActiveMembers.swap(inputPerVertexActiveMembers);
mOutputPerVertexActiveMembers.swap(outputPerVertexActiveMembers);
}
void ShaderInterfaceVariableInfoMap::setActiveStages(gl::ShaderType shaderType,
@ -50,6 +58,28 @@ void ShaderInterfaceVariableInfoMap::setActiveStages(gl::ShaderType shaderType,
mData[shaderType][variableType][index].activeStages = activeStages;
}
void ShaderInterfaceVariableInfoMap::setInputPerVertexActiveMembers(
gl::ShaderType shaderType,
gl::PerVertexMemberBitSet activeMembers)
{
// Input gl_PerVertex is only meaningful for tessellation and geometry stages
ASSERT(shaderType == gl::ShaderType::TessControl ||
shaderType == gl::ShaderType::TessEvaluation || shaderType == gl::ShaderType::Geometry ||
activeMembers.none());
mInputPerVertexActiveMembers[shaderType] = activeMembers;
}
void ShaderInterfaceVariableInfoMap::setOutputPerVertexActiveMembers(
gl::ShaderType shaderType,
gl::PerVertexMemberBitSet activeMembers)
{
// Output gl_PerVertex is only meaningful for vertex, tessellation and geometry stages
ASSERT(shaderType == gl::ShaderType::Vertex || shaderType == gl::ShaderType::TessControl ||
shaderType == gl::ShaderType::TessEvaluation || shaderType == gl::ShaderType::Geometry ||
activeMembers.none());
mOutputPerVertexActiveMembers[shaderType] = activeMembers;
}
ShaderInterfaceVariableInfo &ShaderInterfaceVariableInfoMap::getMutable(
gl::ShaderType shaderType,
ShaderVariableType variableType,
@ -145,22 +175,4 @@ ShaderInterfaceVariableInfoMap::getAttributes() const
{
return mData[gl::ShaderType::Vertex][ShaderVariableType::Attribute];
}
const gl::ShaderMap<ShaderInterfaceVariableInfoMap::VariableTypeToInfoMap>
&ShaderInterfaceVariableInfoMap::getData() const
{
return mData;
}
const gl::ShaderMap<ShaderInterfaceVariableInfoMap::NameToTypeAndIndexMap>
&ShaderInterfaceVariableInfoMap::getNameToTypeAndIndexMap() const
{
return mNameToTypeAndIndexMap;
}
const gl::ShaderMap<ShaderInterfaceVariableInfoMap::VariableTypeToIndexMap>
&ShaderInterfaceVariableInfoMap::getIndexedResourceMap() const
{
return mIndexedResourceIndexMap;
}
} // namespace rx

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

@ -59,9 +59,11 @@ class ShaderInterfaceVariableInfoMap final : angle::NonCopyable
~ShaderInterfaceVariableInfoMap();
void clear();
void load(const gl::ShaderMap<VariableTypeToInfoMap> &data,
const gl::ShaderMap<NameToTypeAndIndexMap> &nameToTypeAndIndexMap,
const gl::ShaderMap<VariableTypeToIndexMap> &indexedResourceIndexMap);
void load(gl::ShaderMap<VariableTypeToInfoMap> &&data,
gl::ShaderMap<NameToTypeAndIndexMap> &&nameToTypeAndIndexMap,
gl::ShaderMap<VariableTypeToIndexMap> &&indexedResourceIndexMap,
gl::ShaderMap<gl::PerVertexMemberBitSet> &&inputPerVertexActiveMembers,
gl::ShaderMap<gl::PerVertexMemberBitSet> &&outputPerVertexActiveMembers);
ShaderInterfaceVariableInfo &add(gl::ShaderType shaderType,
ShaderVariableType variableType,
@ -77,6 +79,10 @@ class ShaderInterfaceVariableInfoMap final : angle::NonCopyable
ShaderVariableType variableType,
const std::string &variableName,
gl::ShaderBitSet activeStages);
void setInputPerVertexActiveMembers(gl::ShaderType shaderType,
gl::PerVertexMemberBitSet activeMembers);
void setOutputPerVertexActiveMembers(gl::ShaderType shaderType,
gl::PerVertexMemberBitSet activeMembers);
ShaderInterfaceVariableInfo &getMutable(gl::ShaderType shaderType,
ShaderVariableType variableType,
const std::string &variableName);
@ -110,14 +116,32 @@ class ShaderInterfaceVariableInfoMap final : angle::NonCopyable
uint32_t variableIndex);
const VariableInfoArray &getAttributes() const;
const gl::ShaderMap<VariableTypeToInfoMap> &getData() const;
const gl::ShaderMap<NameToTypeAndIndexMap> &getNameToTypeAndIndexMap() const;
const gl::ShaderMap<VariableTypeToIndexMap> &getIndexedResourceMap() const;
const gl::ShaderMap<VariableTypeToInfoMap> &getData() const { return mData; }
const gl::ShaderMap<NameToTypeAndIndexMap> &getNameToTypeAndIndexMap() const
{
return mNameToTypeAndIndexMap;
}
const gl::ShaderMap<VariableTypeToIndexMap> &getIndexedResourceMap() const
{
return mIndexedResourceIndexMap;
}
const gl::ShaderMap<gl::PerVertexMemberBitSet> &getInputPerVertexActiveMembers() const
{
return mInputPerVertexActiveMembers;
}
const gl::ShaderMap<gl::PerVertexMemberBitSet> &getOutputPerVertexActiveMembers() const
{
return mOutputPerVertexActiveMembers;
}
private:
gl::ShaderMap<VariableTypeToInfoMap> mData;
gl::ShaderMap<NameToTypeAndIndexMap> mNameToTypeAndIndexMap;
gl::ShaderMap<VariableTypeToIndexMap> mIndexedResourceIndexMap;
// Active members of `in gl_PerVertex` and `out gl_PerVertex`
gl::ShaderMap<gl::PerVertexMemberBitSet> mInputPerVertexActiveMembers;
gl::ShaderMap<gl::PerVertexMemberBitSet> mOutputPerVertexActiveMembers;
};
ANGLE_INLINE const ShaderInterfaceVariableInfo &

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

@ -482,35 +482,6 @@ void AssignVaryingLocations(const SpvSourceOptions &options,
ASSERT(info.location == ShaderInterfaceVariableInfo::kInvalid);
}
// Add an entry for active builtins varyings. This will allow inactive builtins, such as
// gl_PointSize, gl_ClipDistance etc to be removed.
const gl::ShaderMap<std::vector<std::string>> &activeOutputBuiltIns =
varyingPacking.getActiveOutputBuiltInNames();
for (const std::string &builtInName : activeOutputBuiltIns[shaderType])
{
ASSERT(gl::IsBuiltInName(builtInName));
ShaderInterfaceVariableInfo &info =
variableInfoMapOut->addOrGet(shaderType, ShaderVariableType::Varying, builtInName);
info.activeStages.set(shaderType);
info.varyingIsOutput = true;
}
// If an output builtin is active in the previous stage, assume it's active in the input of the
// current stage as well.
if (frontShaderType != gl::ShaderType::InvalidEnum)
{
for (const std::string &builtInName : activeOutputBuiltIns[frontShaderType])
{
ASSERT(gl::IsBuiltInName(builtInName));
ShaderInterfaceVariableInfo &info =
variableInfoMapOut->addOrGet(shaderType, ShaderVariableType::Varying, builtInName);
info.activeStages.set(shaderType);
info.varyingIsInput = true;
}
}
// Add an entry for gl_PerVertex, for use with transform feedback capture of built-ins.
ShaderInterfaceVariableInfo &info =
variableInfoMapOut->addOrGet(shaderType, ShaderVariableType::Varying, "gl_PerVertex");
@ -1195,17 +1166,13 @@ namespace
class SpirvIDDiscoverer final : angle::NonCopyable
{
public:
SpirvIDDiscoverer() : mOutputPerVertexMaxActiveMember(0), mInputPerVertexMaxActiveMember(0) {}
SpirvIDDiscoverer() {}
void init(size_t indexBound);
// Instructions:
void visitDecorate(spirv::IdRef id, spv::Decoration decoration);
void visitName(spirv::IdRef id, const spirv::LiteralString &name);
void visitMemberName(const ShaderInterfaceVariableInfo &info,
spirv::IdRef id,
spirv::LiteralInteger member,
const spirv::LiteralString &name);
void visitTypeArray(spirv::IdResult id, spirv::IdRef elementType, spirv::IdRef length);
void visitTypePointer(spirv::IdResult id, spv::StorageClass storageClass, spirv::IdRef typeId);
SpirvVariableType visitVariable(spirv::IdResultType typeId,
@ -1219,16 +1186,6 @@ class SpirvIDDiscoverer final : angle::NonCopyable
// Getters:
const spirv::LiteralString &getName(spirv::IdRef id) const { return mNamesById[id]; }
bool isIOBlock(spirv::IdRef id) const { return mIsIOBlockById[id]; }
bool isPerVertex(spirv::IdRef typeId) const
{
return typeId == ID::OutputPerVertexBlock || typeId == ID::InputPerVertexBlock;
}
uint32_t getPerVertexMaxActiveMember(spirv::IdRef typeId) const
{
ASSERT(isPerVertex(typeId));
return typeId == ID::OutputPerVertexBlock ? mOutputPerVertexMaxActiveMember
: mInputPerVertexMaxActiveMember;
}
private:
// Names associated with ids through OpName. The same name may be assigned to multiple ids, but
@ -1242,14 +1199,6 @@ class SpirvIDDiscoverer final : angle::NonCopyable
// identified by their instance name). To disambiguate them, the `OpDecorate %N Block`
// instruction is used which decorates I/O block types.
std::vector<bool> mIsIOBlockById;
// gl_PerVertex is unique in that it's the only builtin of struct type. This struct is pruned
// by removing trailing inactive members. We therefore need to keep track of which is the last
// active member. In the case of gl_PerVertex being used in an array, we need to keep track of
// the array's id. Note that intermediate stages, i.e. geometry and tessellation have two
// gl_PerVertex declarations, one for input and one for output.
uint32_t mOutputPerVertexMaxActiveMember;
uint32_t mInputPerVertexMaxActiveMember;
};
void SpirvIDDiscoverer::init(size_t indexBound)
@ -1278,24 +1227,6 @@ void SpirvIDDiscoverer::visitName(spirv::IdRef id, const spirv::LiteralString &n
mNamesById[id] = name;
}
void SpirvIDDiscoverer::visitMemberName(const ShaderInterfaceVariableInfo &info,
spirv::IdRef id,
spirv::LiteralInteger member,
const spirv::LiteralString &name)
{
// Use varyingIsInput and varyingIsOutput to know which gl_PerVertex the builtin is active in.
if (info.varyingIsOutput && id == ID::OutputPerVertexBlock &&
member > mOutputPerVertexMaxActiveMember)
{
mOutputPerVertexMaxActiveMember = member;
}
else if (info.varyingIsInput && id == ID::InputPerVertexBlock &&
member > mInputPerVertexMaxActiveMember)
{
mInputPerVertexMaxActiveMember = member;
}
}
void SpirvIDDiscoverer::visitTypeHelper(spirv::IdResult id, spirv::IdRef typeId)
{
// Every type id is declared only once.
@ -1373,27 +1304,121 @@ SpirvVariableType SpirvIDDiscoverer::visitVariable(spirv::IdResultType typeId,
}
// Helper class that trims input and output gl_PerVertex declarations to remove inactive builtins.
//
// gl_PerVertex is unique in that it's the only builtin of struct type. This struct is pruned
// by removing trailing inactive members. Note that intermediate stages, i.e. geometry and
// tessellation have two gl_PerVertex declarations, one for input and one for output.
class SpirvPerVertexTrimmer final : angle::NonCopyable
{
public:
SpirvPerVertexTrimmer() {}
SpirvPerVertexTrimmer(const SpvTransformOptions &options,
const ShaderInterfaceVariableInfoMap &variableInfoMap)
: mInputPerVertexMaxActiveMember{gl::PerVertexMember::Position},
mOutputPerVertexMaxActiveMember{gl::PerVertexMember::Position},
mInputPerVertexMaxActiveMemberIndex(0),
mOutputPerVertexMaxActiveMemberIndex(0)
{
const gl::PerVertexMemberBitSet inputPerVertexActiveMembers =
variableInfoMap.getInputPerVertexActiveMembers()[options.shaderType];
const gl::PerVertexMemberBitSet outputPerVertexActiveMembers =
variableInfoMap.getOutputPerVertexActiveMembers()[options.shaderType];
TransformationState transformMemberDecorate(const SpirvIDDiscoverer &ids,
spirv::IdRef typeId,
// Currently, this transformation does not trim inactive members in between two active
// members.
if (inputPerVertexActiveMembers.any())
{
mInputPerVertexMaxActiveMember = inputPerVertexActiveMembers.last();
}
if (outputPerVertexActiveMembers.any())
{
mOutputPerVertexMaxActiveMember = outputPerVertexActiveMembers.last();
}
}
void visitMemberDecorate(spirv::IdRef id,
spirv::LiteralInteger member,
spv::Decoration decoration,
const spirv::LiteralIntegerList &valueList);
TransformationState transformMemberDecorate(spirv::IdRef typeId,
spirv::LiteralInteger member,
spv::Decoration decoration);
TransformationState transformMemberName(const SpirvIDDiscoverer &ids,
spirv::IdRef id,
TransformationState transformMemberName(spirv::IdRef id,
spirv::LiteralInteger member,
const spirv::LiteralString &name);
TransformationState transformTypeStruct(const SpirvIDDiscoverer &ids,
spirv::IdResult id,
TransformationState transformTypeStruct(spirv::IdResult id,
spirv::IdRefList *memberList,
spirv::Blob *blobOut);
private:
bool isPerVertex(spirv::IdRef typeId) const
{
return typeId == ID::OutputPerVertexBlock || typeId == ID::InputPerVertexBlock;
}
uint32_t getPerVertexMaxActiveMember(spirv::IdRef typeId) const
{
ASSERT(isPerVertex(typeId));
return typeId == ID::OutputPerVertexBlock ? mOutputPerVertexMaxActiveMemberIndex
: mInputPerVertexMaxActiveMemberIndex;
}
gl::PerVertexMember mInputPerVertexMaxActiveMember;
gl::PerVertexMember mOutputPerVertexMaxActiveMember;
// If gl_ClipDistance and gl_CullDistance are not used, they are missing from gl_PerVertex. So
// the index of gl_CullDistance may not be the same as the value of
// gl::PerVertexMember::CullDistance.
//
// By looking at OpMemberDecorate %kIdInput/OutputPerVertexBlock <Index> BuiltIn <Member>, the
// <Index> corresponding to mInput/OutputPerVertexMaxActiveMember is discovered and kept in
// mInput/OutputPerVertexMaxActiveMemberIndex
uint32_t mInputPerVertexMaxActiveMemberIndex;
uint32_t mOutputPerVertexMaxActiveMemberIndex;
};
TransformationState SpirvPerVertexTrimmer::transformMemberDecorate(const SpirvIDDiscoverer &ids,
spirv::IdRef typeId,
void SpirvPerVertexTrimmer::visitMemberDecorate(spirv::IdRef id,
spirv::LiteralInteger member,
spv::Decoration decoration,
const spirv::LiteralIntegerList &valueList)
{
if (decoration != spv::DecorationBuiltIn || !isPerVertex(id))
{
return;
}
// Map spv::BuiltIn to gl::PerVertexMember.
ASSERT(!valueList.empty());
const uint32_t builtIn = valueList[0];
gl::PerVertexMember perVertexMember = gl::PerVertexMember::Position;
switch (builtIn)
{
case spv::BuiltInPosition:
perVertexMember = gl::PerVertexMember::Position;
break;
case spv::BuiltInPointSize:
perVertexMember = gl::PerVertexMember::PointSize;
break;
case spv::BuiltInClipDistance:
perVertexMember = gl::PerVertexMember::ClipDistance;
break;
case spv::BuiltInCullDistance:
perVertexMember = gl::PerVertexMember::CullDistance;
break;
default:
UNREACHABLE();
}
if (id == ID::OutputPerVertexBlock && perVertexMember == mOutputPerVertexMaxActiveMember)
{
mOutputPerVertexMaxActiveMemberIndex = member;
}
else if (id == ID::InputPerVertexBlock && perVertexMember == mInputPerVertexMaxActiveMember)
{
mInputPerVertexMaxActiveMemberIndex = member;
}
}
TransformationState SpirvPerVertexTrimmer::transformMemberDecorate(spirv::IdRef typeId,
spirv::LiteralInteger member,
spv::Decoration decoration)
{
@ -1402,7 +1427,7 @@ TransformationState SpirvPerVertexTrimmer::transformMemberDecorate(const SpirvID
// - OpMemberDecorate %gl_PerVertex N BuiltIn B
// - OpMemberDecorate %gl_PerVertex N Invariant
// - OpMemberDecorate %gl_PerVertex N RelaxedPrecision
if (!ids.isPerVertex(typeId) ||
if (!isPerVertex(typeId) ||
(decoration != spv::DecorationBuiltIn && decoration != spv::DecorationInvariant &&
decoration != spv::DecorationRelaxedPrecision))
{
@ -1410,32 +1435,30 @@ TransformationState SpirvPerVertexTrimmer::transformMemberDecorate(const SpirvID
}
// Drop stripped fields.
return member > ids.getPerVertexMaxActiveMember(typeId) ? TransformationState::Transformed
: TransformationState::Unchanged;
return member > getPerVertexMaxActiveMember(typeId) ? TransformationState::Transformed
: TransformationState::Unchanged;
}
TransformationState SpirvPerVertexTrimmer::transformMemberName(const SpirvIDDiscoverer &ids,
spirv::IdRef id,
TransformationState SpirvPerVertexTrimmer::transformMemberName(spirv::IdRef id,
spirv::LiteralInteger member,
const spirv::LiteralString &name)
{
// Remove the instruction if it's a stripped member of gl_PerVertex.
return ids.isPerVertex(id) && member > ids.getPerVertexMaxActiveMember(id)
return isPerVertex(id) && member > getPerVertexMaxActiveMember(id)
? TransformationState::Transformed
: TransformationState::Unchanged;
}
TransformationState SpirvPerVertexTrimmer::transformTypeStruct(const SpirvIDDiscoverer &ids,
spirv::IdResult id,
TransformationState SpirvPerVertexTrimmer::transformTypeStruct(spirv::IdResult id,
spirv::IdRefList *memberList,
spirv::Blob *blobOut)
{
if (!ids.isPerVertex(id))
if (!isPerVertex(id))
{
return TransformationState::Unchanged;
}
const uint32_t maxMembers = ids.getPerVertexMaxActiveMember(id);
const uint32_t maxMembers = getPerVertexMaxActiveMember(id);
// Change the definition of the gl_PerVertex struct by stripping unused fields at the end.
const uint32_t memberCount = maxMembers + 1;
@ -3053,6 +3076,7 @@ class SpirvTransformer final : public SpirvTransformerBase
mOptions(options),
mOverviewFlags(0),
mNonSemanticInstructions(isLastPass),
mPerVertexTrimmer(options, variableInfoMap),
mXfbCodeGenerator(options.isTransformFeedbackEmulated),
mPositionTransformer(options),
mMultisampleTransformer(options)
@ -3071,7 +3095,6 @@ class SpirvTransformer final : public SpirvTransformerBase
void visitDecorate(const uint32_t *instruction);
void visitName(const uint32_t *instruction);
void visitMemberDecorate(const uint32_t *instruction);
void visitMemberName(const uint32_t *instruction);
void visitTypeArray(const uint32_t *instruction);
void visitTypePointer(const uint32_t *instruction);
void visitTypeStruct(const uint32_t *instruction);
@ -3180,9 +3203,6 @@ void SpirvTransformer::resolveVariableIds()
case spv::OpMemberDecorate:
visitMemberDecorate(instruction);
break;
case spv::OpMemberName:
visitMemberName(instruction);
break;
case spv::OpTypeArray:
visitTypeArray(instruction);
break;
@ -3457,29 +3477,13 @@ void SpirvTransformer::visitMemberDecorate(const uint32_t *instruction)
spirv::IdRef typeId;
spirv::LiteralInteger member;
spv::Decoration decoration;
spirv::ParseMemberDecorate(instruction, &typeId, &member, &decoration, nullptr);
spirv::LiteralIntegerList valueList;
spirv::ParseMemberDecorate(instruction, &typeId, &member, &decoration, &valueList);
mPerVertexTrimmer.visitMemberDecorate(typeId, member, decoration, valueList);
mMultisampleTransformer.visitMemberDecorate(typeId, member, decoration);
}
void SpirvTransformer::visitMemberName(const uint32_t *instruction)
{
spirv::IdRef id;
spirv::LiteralInteger member;
spirv::LiteralString name;
spirv::ParseMemberName(instruction, &id, &member, &name);
if (!mVariableInfoMap.hasVariable(mOptions.shaderType, name))
{
return;
}
const ShaderInterfaceVariableInfo &info =
mVariableInfoMap.getVariableByName(mOptions.shaderType, name);
mIds.visitMemberName(info, id, member, name);
}
void SpirvTransformer::visitTypeArray(const uint32_t *instruction)
{
spirv::IdResult id;
@ -3715,7 +3719,7 @@ TransformationState SpirvTransformer::transformMemberDecorate(const uint32_t *in
spv::Decoration decoration;
spirv::ParseMemberDecorate(instruction, &typeId, &member, &decoration, nullptr);
return mPerVertexTrimmer.transformMemberDecorate(mIds, typeId, member, decoration);
return mPerVertexTrimmer.transformMemberDecorate(typeId, member, decoration);
}
TransformationState SpirvTransformer::transformCapability(const uint32_t *instruction)
@ -3750,7 +3754,7 @@ TransformationState SpirvTransformer::transformDebugInfo(const uint32_t *instruc
spirv::LiteralString name;
spirv::ParseMemberName(instruction, &id, &member, &name);
return mPerVertexTrimmer.transformMemberName(mIds, id, member, name);
return mPerVertexTrimmer.transformMemberName(id, member, name);
}
if (op == spv::OpName)
@ -3881,7 +3885,7 @@ TransformationState SpirvTransformer::transformTypeStruct(const uint32_t *instru
spirv::IdRefList memberList;
ParseTypeStruct(instruction, &id, &memberList);
return mPerVertexTrimmer.transformTypeStruct(mIds, id, &memberList, mSpirvBlobOut);
return mPerVertexTrimmer.transformTypeStruct(id, &memberList, mSpirvBlobOut);
}
TransformationState SpirvTransformer::transformReturn(const uint32_t *instruction)
@ -5080,11 +5084,29 @@ void SpvAssignLocations(const SpvSourceOptions &options,
{
AssignVaryingLocations(options, inputPacking, shaderType, frontShaderType,
programInterfaceInfo, variableInfoMapOut);
// Record active members of in gl_PerVertex.
if (shaderType != gl::ShaderType::Fragment &&
frontShaderType != gl::ShaderType::InvalidEnum)
{
// If an output builtin is active in the previous stage, assume it's active in the
// input of the current stage as well.
const gl::ShaderMap<gl::PerVertexMemberBitSet> &outputPerVertexActiveMembers =
inputPacking.getOutputPerVertexActiveMembers();
variableInfoMapOut->setInputPerVertexActiveMembers(
shaderType, outputPerVertexActiveMembers[frontShaderType]);
}
}
if (shaderType != gl::ShaderType::Fragment)
{
AssignVaryingLocations(options, outputPacking, shaderType, frontShaderType,
programInterfaceInfo, variableInfoMapOut);
// Record active members of out gl_PerVertex.
const gl::ShaderMap<gl::PerVertexMemberBitSet> &outputPerVertexActiveMembers =
outputPacking.getOutputPerVertexActiveMembers();
variableInfoMapOut->setOutputPerVertexActiveMembers(
shaderType, outputPerVertexActiveMembers[shaderType]);
}
// Assign qualifiers to all varyings captured by transform feedback