зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
a01a566c48
Коммит
acdf872299
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче