Vulkan: Output SPIR-V ids from compiler

In this change, the shader interface variables are given SPIR-V ids by
the compiler before SPIR-V generation.  Those ids are made available
through the ShaderVariable interface.

The transformer does not yet rely on this information.  A follow up
change will rework the backend's name->info map and the transformer to
directly use ids instead of names.

Bug: angleproject:7220
Change-Id: Ic0a62681d4bcf3ed171c39c3ecd83e438ea068c8
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4600609
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Roman Lavrov <romanl@google.com>
Reviewed-by: Yuxin Hu <yuxinhu@google.com>
This commit is contained in:
Shahbaz Youssefi
2023-06-06 11:52:08 -04:00
committed by Angle LUCI CQ
parent acdf872299
commit 10380f4ba4
15 changed files with 273 additions and 56 deletions

View File

@@ -26,7 +26,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 334 #define ANGLE_SH_VERSION 335
enum ShShaderSpec enum ShShaderSpec
{ {
@@ -1027,10 +1027,15 @@ enum ReservedIds
// Pre-rotation and Z-correction support // Pre-rotation and Z-correction support
kIdTransformPositionFunction, kIdTransformPositionFunction,
kIdOutputPerVertexVar,
// Transform feedback support // Transform feedback support
kIdXfbEmulationGetOffsetsFunction, kIdXfbEmulationGetOffsetsFunction,
kIdXfbEmulationCaptureFunction, kIdXfbEmulationCaptureFunction,
kIdXfbEmulationBufferVarZero,
kIdXfbEmulationBufferVarOne,
kIdXfbEmulationBufferVarTwo,
kIdXfbEmulationBufferVarThree,
// Multisampling support // Multisampling support
kIdSampleID, kIdSampleID,
@@ -1039,12 +1044,14 @@ enum ReservedIds
// ANGLE internal shader variables, which are not produced as ShaderVariables. // ANGLE internal shader variables, which are not produced as ShaderVariables.
// kIdShaderVariablesBegin marks the beginning of these ids. variableId -> info maps in the // kIdShaderVariablesBegin marks the beginning of these ids. variableId -> info maps in the
// backend can use |variableId - kIdShaderVariablesBegin| as key into a flat array. // backend can use |variableId - kIdShaderVariablesBegin| as key into a flat array.
//
// Note that for blocks, only the block id is in this section as that is the id used in the
// variableId -> info maps.
kIdShaderVariablesBegin, kIdShaderVariablesBegin,
// gl_PerVertex // gl_PerVertex
kIdInputPerVertexBlock = kIdShaderVariablesBegin, kIdInputPerVertexBlock = kIdShaderVariablesBegin,
kIdOutputPerVertexBlock, kIdOutputPerVertexBlock,
kIdOutputPerVertexVar,
// The driver and default uniform blocks // The driver and default uniform blocks
kIdDriverUniformsBlock, kIdDriverUniformsBlock,
kIdDefaultUniformsBlock, kIdDefaultUniformsBlock,
@@ -1055,10 +1062,6 @@ enum ReservedIds
kIdXfbEmulationBufferBlockOne, kIdXfbEmulationBufferBlockOne,
kIdXfbEmulationBufferBlockTwo, kIdXfbEmulationBufferBlockTwo,
kIdXfbEmulationBufferBlockThree, kIdXfbEmulationBufferBlockThree,
kIdXfbEmulationBufferVarZero,
kIdXfbEmulationBufferVarOne,
kIdXfbEmulationBufferVarTwo,
kIdXfbEmulationBufferVarThree,
// Additional varying added to hold untransformed gl_Position for transform feedback capture // Additional varying added to hold untransformed gl_Position for transform feedback capture
kIdXfbExtensionPosition, kIdXfbExtensionPosition,

View File

@@ -240,6 +240,11 @@ struct ShaderVariable
// If the variable is a sampler that has ever been statically used with texelFetch // If the variable is a sampler that has ever been statically used with texelFetch
bool texelFetchStaticUse; bool texelFetchStaticUse;
// Id of the variable in the shader. Currently used by the SPIR-V output to communicate the
// SPIR-V id of the variable. This value is only set for variables that the SPIR-V transformer
// needs to know about, i.e. active variables, excluding non-zero array elements etc.
uint32_t id;
protected: protected:
bool isSameVariableAtLinkTime(const ShaderVariable &other, bool isSameVariableAtLinkTime(const ShaderVariable &other,
bool matchPrecision, bool matchPrecision,
@@ -296,6 +301,9 @@ struct InterfaceBlock
bool isReadOnly; bool isReadOnly;
BlockType blockType; BlockType blockType;
std::vector<ShaderVariable> fields; std::vector<ShaderVariable> fields;
// Id of the interface block in the shader. Similar to |ShaderVariable::id|.
uint32_t id;
}; };
struct WorkGroupSize struct WorkGroupSize

View File

@@ -97,6 +97,7 @@ void WriteShaderVar(gl::BinaryOutputStream *stream, const sh::ShaderVariable &va
stream->writeBool(var.isPatch); stream->writeBool(var.isPatch);
stream->writeBool(var.texelFetchStaticUse); stream->writeBool(var.texelFetchStaticUse);
stream->writeInt(var.getFlattenedOffsetInParentArrays()); stream->writeInt(var.getFlattenedOffsetInParentArrays());
stream->writeInt(var.id);
} }
void LoadShaderVar(gl::BinaryInputStream *stream, sh::ShaderVariable *var) void LoadShaderVar(gl::BinaryInputStream *stream, sh::ShaderVariable *var)
@@ -134,6 +135,7 @@ void LoadShaderVar(gl::BinaryInputStream *stream, sh::ShaderVariable *var)
var->isPatch = stream->readBool(); var->isPatch = stream->readBool();
var->texelFetchStaticUse = stream->readBool(); var->texelFetchStaticUse = stream->readBool();
var->setParentArrayIndex(stream->readInt<int>()); var->setParentArrayIndex(stream->readInt<int>());
var->id = stream->readInt<uint32_t>();
} }
void WriteShInterfaceBlock(gl::BinaryOutputStream *stream, const sh::InterfaceBlock &block) void WriteShInterfaceBlock(gl::BinaryOutputStream *stream, const sh::InterfaceBlock &block)
@@ -148,6 +150,7 @@ void WriteShInterfaceBlock(gl::BinaryOutputStream *stream, const sh::InterfaceBl
stream->writeBool(block.staticUse); stream->writeBool(block.staticUse);
stream->writeBool(block.active); stream->writeBool(block.active);
stream->writeEnum(block.blockType); stream->writeEnum(block.blockType);
stream->writeInt(block.id);
stream->writeInt<size_t>(block.fields.size()); stream->writeInt<size_t>(block.fields.size());
for (const sh::ShaderVariable &shaderVariable : block.fields) for (const sh::ShaderVariable &shaderVariable : block.fields)
@@ -168,6 +171,7 @@ void LoadShInterfaceBlock(gl::BinaryInputStream *stream, sh::InterfaceBlock *blo
block->staticUse = stream->readBool(); block->staticUse = stream->readBool();
block->active = stream->readBool(); block->active = stream->readBool();
block->blockType = stream->readEnum<sh::BlockType>(); block->blockType = stream->readEnum<sh::BlockType>();
block->id = stream->readInt<uint32_t>();
block->fields.resize(stream->readInt<size_t>()); block->fields.resize(stream->readInt<size_t>());
for (sh::ShaderVariable &variable : block->fields) for (sh::ShaderVariable &variable : block->fields)

View File

@@ -508,12 +508,13 @@ SPIRVBuilder::SPIRVBuilder(TCompiler *compiler,
const ShCompileOptions &compileOptions, const ShCompileOptions &compileOptions,
ShHashFunction64 hashFunction, ShHashFunction64 hashFunction,
NameMap &nameMap, NameMap &nameMap,
const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap) const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap,
uint32_t firstUnusedSpirvId)
: mCompiler(compiler), : mCompiler(compiler),
mCompileOptions(compileOptions), mCompileOptions(compileOptions),
mShaderType(gl::FromGLenum<gl::ShaderType>(compiler->getShaderType())), mShaderType(gl::FromGLenum<gl::ShaderType>(compiler->getShaderType())),
mUniqueToSpirvIdMap(uniqueToSpirvIdMap), mUniqueToSpirvIdMap(uniqueToSpirvIdMap),
mNextAvailableId(vk::spirv::kIdFirstUnreserved), mNextAvailableId(firstUnusedSpirvId),
mHashFunction(hashFunction), mHashFunction(hashFunction),
mNameMap(nameMap), mNameMap(nameMap),
mNextUnusedBinding(0), mNextUnusedBinding(0),

View File

@@ -309,7 +309,8 @@ class SPIRVBuilder : angle::NonCopyable
const ShCompileOptions &compileOptions, const ShCompileOptions &compileOptions,
ShHashFunction64 hashFunction, ShHashFunction64 hashFunction,
NameMap &nameMap, NameMap &nameMap,
const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap); const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap,
uint32_t firstUnusedSpirvId);
spirv::IdRef getNewId(const SpirvDecorations &decorations); spirv::IdRef getNewId(const SpirvDecorations &decorations);
spirv::IdRef getReservedOrNewId(TSymbolUniqueId uniqueId, const SpirvDecorations &decorations); spirv::IdRef getReservedOrNewId(TSymbolUniqueId uniqueId, const SpirvDecorations &decorations);

View File

@@ -181,7 +181,8 @@ class OutputSPIRVTraverser : public TIntermTraverser
public: public:
OutputSPIRVTraverser(TCompiler *compiler, OutputSPIRVTraverser(TCompiler *compiler,
const ShCompileOptions &compileOptions, const ShCompileOptions &compileOptions,
const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap); const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap,
uint32_t firstUnusedSpirvId);
~OutputSPIRVTraverser() override; ~OutputSPIRVTraverser() override;
spirv::Blob getSpirv(); spirv::Blob getSpirv();
@@ -499,7 +500,8 @@ spv::StorageClass GetStorageClass(const TType &type, GLenum shaderType)
OutputSPIRVTraverser::OutputSPIRVTraverser(TCompiler *compiler, OutputSPIRVTraverser::OutputSPIRVTraverser(TCompiler *compiler,
const ShCompileOptions &compileOptions, const ShCompileOptions &compileOptions,
const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap) const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap,
uint32_t firstUnusedSpirvId)
: TIntermTraverser(true, true, true, &compiler->getSymbolTable()), : TIntermTraverser(true, true, true, &compiler->getSymbolTable()),
mCompiler(compiler), mCompiler(compiler),
mCompileOptions(compileOptions), mCompileOptions(compileOptions),
@@ -507,7 +509,8 @@ OutputSPIRVTraverser::OutputSPIRVTraverser(TCompiler *compiler,
compileOptions, compileOptions,
compiler->getHashFunction(), compiler->getHashFunction(),
compiler->getNameMap(), compiler->getNameMap(),
uniqueToSpirvIdMap) uniqueToSpirvIdMap,
firstUnusedSpirvId)
{} {}
OutputSPIRVTraverser::~OutputSPIRVTraverser() OutputSPIRVTraverser::~OutputSPIRVTraverser()
@@ -6462,7 +6465,8 @@ spirv::Blob OutputSPIRVTraverser::getSpirv()
bool OutputSPIRV(TCompiler *compiler, bool OutputSPIRV(TCompiler *compiler,
TIntermBlock *root, TIntermBlock *root,
const ShCompileOptions &compileOptions, const ShCompileOptions &compileOptions,
const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap) const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap,
uint32_t firstUnusedSpirvId)
{ {
// Find the list of nodes that require NoContraction (as a result of |precise|). // Find the list of nodes that require NoContraction (as a result of |precise|).
if (compiler->hasAnyPreciseType()) if (compiler->hasAnyPreciseType())
@@ -6471,7 +6475,8 @@ bool OutputSPIRV(TCompiler *compiler,
} }
// Traverse the tree and generate SPIR-V instructions // Traverse the tree and generate SPIR-V instructions
OutputSPIRVTraverser traverser(compiler, compileOptions, uniqueToSpirvIdMap); OutputSPIRVTraverser traverser(compiler, compileOptions, uniqueToSpirvIdMap,
firstUnusedSpirvId);
root->traverse(&traverser); root->traverse(&traverser);
// Generate the final SPIR-V and store in the sink // Generate the final SPIR-V and store in the sink

View File

@@ -16,7 +16,8 @@ namespace sh
bool OutputSPIRV(TCompiler *compiler, bool OutputSPIRV(TCompiler *compiler,
TIntermBlock *root, TIntermBlock *root,
const ShCompileOptions &compileOptions, const ShCompileOptions &compileOptions,
const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap); const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap,
uint32_t firstUnusedSpirvId);
} // namespace sh } // namespace sh
#endif // COMPILER_TRANSLATOR_OUTPUTSPIRV_H_ #endif // COMPILER_TRANSLATOR_OUTPUTSPIRV_H_

View File

@@ -55,6 +55,7 @@ ShaderVariable::ShaderVariable(GLenum typeIn)
isShaderIOBlock(false), isShaderIOBlock(false),
isPatch(false), isPatch(false),
texelFetchStaticUse(false), texelFetchStaticUse(false),
id(0),
flattenedOffsetInParentArrays(-1) flattenedOffsetInParentArrays(-1)
{} {}
@@ -94,6 +95,7 @@ ShaderVariable::ShaderVariable(const ShaderVariable &other)
isShaderIOBlock(other.isShaderIOBlock), isShaderIOBlock(other.isShaderIOBlock),
isPatch(other.isPatch), isPatch(other.isPatch),
texelFetchStaticUse(other.texelFetchStaticUse), texelFetchStaticUse(other.texelFetchStaticUse),
id(other.id),
flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays) flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays)
{} {}
@@ -127,13 +129,14 @@ ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
isShaderIOBlock = other.isShaderIOBlock; isShaderIOBlock = other.isShaderIOBlock;
isPatch = other.isPatch; isPatch = other.isPatch;
texelFetchStaticUse = other.texelFetchStaticUse; texelFetchStaticUse = other.texelFetchStaticUse;
id = other.id;
return *this; return *this;
} }
bool ShaderVariable::operator==(const ShaderVariable &other) const bool ShaderVariable::operator==(const ShaderVariable &other) const
{ {
if (type != other.type || precision != other.precision || name != other.name || if (id != other.id || type != other.type || precision != other.precision ||
mappedName != other.mappedName || arraySizes != other.arraySizes || name != other.name || mappedName != other.mappedName || arraySizes != other.arraySizes ||
staticUse != other.staticUse || active != other.active || staticUse != other.staticUse || active != other.active ||
fields.size() != other.fields.size() || structOrBlockName != other.structOrBlockName || fields.size() != other.fields.size() || structOrBlockName != other.structOrBlockName ||
mappedStructOrBlockName != other.mappedStructOrBlockName || mappedStructOrBlockName != other.mappedStructOrBlockName ||
@@ -485,7 +488,8 @@ InterfaceBlock::InterfaceBlock()
staticUse(false), staticUse(false),
active(false), active(false),
isReadOnly(false), isReadOnly(false),
blockType(BlockType::BLOCK_UNIFORM) blockType(BlockType::BLOCK_UNIFORM),
id(0)
{} {}
InterfaceBlock::~InterfaceBlock() {} InterfaceBlock::~InterfaceBlock() {}
@@ -502,7 +506,8 @@ InterfaceBlock::InterfaceBlock(const InterfaceBlock &other)
active(other.active), active(other.active),
isReadOnly(other.isReadOnly), isReadOnly(other.isReadOnly),
blockType(other.blockType), blockType(other.blockType),
fields(other.fields) fields(other.fields),
id(other.id)
{} {}
InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other) InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other)
@@ -518,6 +523,7 @@ InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other)
active = other.active; active = other.active;
isReadOnly = other.isReadOnly; isReadOnly = other.isReadOnly;
blockType = other.blockType; blockType = other.blockType;
id = other.id;
fields = other.fields; fields = other.fields;
return *this; return *this;
} }
@@ -534,10 +540,10 @@ std::string InterfaceBlock::fieldMappedPrefix() const
bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const
{ {
if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize || if (id != other.id || name != other.name || mappedName != other.mappedName ||
layout != other.layout || isRowMajorLayout != other.isRowMajorLayout || arraySize != other.arraySize || layout != other.layout ||
binding != other.binding || blockType != other.blockType || isRowMajorLayout != other.isRowMajorLayout || binding != other.binding ||
fields.size() != other.fields.size()) blockType != other.blockType || fields.size() != other.fields.size())
{ {
return false; return false;
} }

View File

@@ -162,8 +162,8 @@ bool DeclareDefaultUniforms(TranslatorVulkan *compiler,
root, symbolTable, uniformList, EvqUniform, layoutQualifier, TMemoryQualifier::Create(), 0, root, symbolTable, uniformList, EvqUniform, layoutQualifier, TMemoryQualifier::Create(), 0,
ImmutableString(kDefaultUniformNames[shaderType]), ImmutableString("")); ImmutableString(kDefaultUniformNames[shaderType]), ImmutableString(""));
compiler->assignReservedSpirvId(uniformBlock->getType().getInterfaceBlock()->uniqueId(), compiler->assignSpirvId(uniformBlock->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdDefaultUniformsBlock); vk::spirv::kIdDefaultUniformsBlock);
// Create a map from the uniform variables to new variables that reference the fields of the // Create a map from the uniform variables to new variables that reference the fields of the
// block. // block.
@@ -382,8 +382,8 @@ TIntermSequence *GetMainSequence(TIntermBlock *root)
ivec4Type, true); ivec4Type, true);
getOffsetsFunction->addParameter(stridesVar); getOffsetsFunction->addParameter(stridesVar);
compiler->assignReservedSpirvId(getOffsetsFunction->uniqueId(), compiler->assignSpirvId(getOffsetsFunction->uniqueId(),
vk::spirv::kIdXfbEmulationGetOffsetsFunction); vk::spirv::kIdXfbEmulationGetOffsetsFunction);
TIntermFunctionDefinition *functionDef = TIntermFunctionDefinition *functionDef =
CreateInternalFunctionDefinitionNode(*getOffsetsFunction, body); CreateInternalFunctionDefinitionNode(*getOffsetsFunction, body);
@@ -407,8 +407,8 @@ TIntermSequence *GetMainSequence(TIntermBlock *root)
TFunction *xfbCaptureFunction = new TFunction(symbolTable, ImmutableString("ANGLECaptureXfb"), TFunction *xfbCaptureFunction = new TFunction(symbolTable, ImmutableString("ANGLECaptureXfb"),
SymbolType::AngleInternal, voidType, false); SymbolType::AngleInternal, voidType, false);
compiler->assignReservedSpirvId(xfbCaptureFunction->uniqueId(), compiler->assignSpirvId(xfbCaptureFunction->uniqueId(),
vk::spirv::kIdXfbEmulationCaptureFunction); vk::spirv::kIdXfbEmulationCaptureFunction);
// Insert the function declaration before main(). // Insert the function declaration before main().
root->insertChildNodes(mainIndex, root->insertChildNodes(mainIndex,
@@ -489,10 +489,10 @@ TIntermSequence *GetMainSequence(TIntermBlock *root)
static_assert(vk::spirv::kIdXfbEmulationBufferVarThree == static_assert(vk::spirv::kIdXfbEmulationBufferVarThree ==
vk::spirv::kIdXfbEmulationBufferVarZero + 3); vk::spirv::kIdXfbEmulationBufferVarZero + 3);
compiler->assignReservedSpirvId(xfbBuffer->getType().getInterfaceBlock()->uniqueId(), compiler->assignSpirvId(xfbBuffer->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdXfbEmulationBufferBlockZero + bufferIndex); vk::spirv::kIdXfbEmulationBufferBlockZero + bufferIndex);
compiler->assignReservedSpirvId(xfbBuffer->uniqueId(), compiler->assignSpirvId(xfbBuffer->uniqueId(),
vk::spirv::kIdXfbEmulationBufferVarZero + bufferIndex); vk::spirv::kIdXfbEmulationBufferVarZero + bufferIndex);
} }
return compiler->validateAST(root); return compiler->validateAST(root);
@@ -530,7 +530,7 @@ TIntermSequence *GetMainSequence(TIntermBlock *root)
new TVariable(symbolTable, ImmutableString(vk::kXfbExtensionPositionOutName), vec4Type, new TVariable(symbolTable, ImmutableString(vk::kXfbExtensionPositionOutName), vec4Type,
SymbolType::AngleInternal); SymbolType::AngleInternal);
compiler->assignReservedSpirvId(varyingVar->uniqueId(), vk::spirv::kIdXfbExtensionPosition); compiler->assignSpirvId(varyingVar->uniqueId(), vk::spirv::kIdXfbExtensionPosition);
TIntermDeclaration *varyingDecl = new TIntermDeclaration(); TIntermDeclaration *varyingDecl = new TIntermDeclaration();
varyingDecl->appendDeclarator(new TIntermSymbol(varyingVar)); varyingDecl->appendDeclarator(new TIntermSymbol(varyingVar));
@@ -625,8 +625,8 @@ TIntermSequence *GetMainSequence(TIntermBlock *root)
SymbolType::AngleInternal, vec4Type, true); SymbolType::AngleInternal, vec4Type, true);
transformPositionFunction->addParameter(positionVar); transformPositionFunction->addParameter(positionVar);
compiler->assignReservedSpirvId(transformPositionFunction->uniqueId(), compiler->assignSpirvId(transformPositionFunction->uniqueId(),
vk::spirv::kIdTransformPositionFunction); vk::spirv::kIdTransformPositionFunction);
TIntermFunctionDefinition *functionDef = TIntermFunctionDefinition *functionDef =
CreateInternalFunctionDefinitionNode(*transformPositionFunction, body); CreateInternalFunctionDefinitionNode(*transformPositionFunction, body);
@@ -670,10 +670,86 @@ bool HasFramebufferFetch(const TExtensionBehavior &extBehavior,
(compileOptions.pls.type == ShPixelLocalStorageType::FramebufferFetch && (compileOptions.pls.type == ShPixelLocalStorageType::FramebufferFetch &&
IsExtensionEnabled(extBehavior, TExtension::ANGLE_shader_pixel_local_storage)); IsExtensionEnabled(extBehavior, TExtension::ANGLE_shader_pixel_local_storage));
} }
template <typename Variable>
Variable *FindShaderVariable(std::vector<Variable> *vars, const ImmutableString &name)
{
for (Variable &var : *vars)
{
if (name == var.name)
{
return &var;
}
}
UNREACHABLE();
return nullptr;
}
ShaderVariable *FindIOBlockShaderVariable(std::vector<ShaderVariable> *vars,
const ImmutableString &name)
{
for (ShaderVariable &var : *vars)
{
if (name == var.structOrBlockName)
{
return &var;
}
}
UNREACHABLE();
return nullptr;
}
ShaderVariable *FindUniformFieldShaderVariable(std::vector<ShaderVariable> *vars,
const ImmutableString &name,
const char *prefix)
{
for (ShaderVariable &var : *vars)
{
// The name of the sampler is derived from the uniform name + fields
// that reach the uniform, concatenated with '_' per RewriteStructSamplers.
std::string varName = prefix;
varName += '_';
varName += var.name;
if (name == varName)
{
return &var;
}
ShaderVariable *field = FindUniformFieldShaderVariable(&var.fields, name, varName.c_str());
if (field != nullptr)
{
return field;
}
}
return nullptr;
}
ShaderVariable *FindUniformShaderVariable(std::vector<ShaderVariable> *vars,
const ImmutableString &name)
{
for (ShaderVariable &var : *vars)
{
if (name == var.name)
{
return &var;
}
// Note: samplers in structs are moved out. Such samplers will be found in the fields of
// the struct uniform.
ShaderVariable *field = FindUniformFieldShaderVariable(&var.fields, name, var.name.c_str());
if (field != nullptr)
{
return field;
}
}
UNREACHABLE();
return nullptr;
}
} // anonymous namespace } // anonymous namespace
TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec) TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec)
: TCompiler(type, spec, SH_SPIRV_VULKAN_OUTPUT) : TCompiler(type, spec, SH_SPIRV_VULKAN_OUTPUT), mFirstUnusedSpirvId(0)
{} {}
bool TranslatorVulkan::translateImpl(TIntermBlock *root, bool TranslatorVulkan::translateImpl(TIntermBlock *root,
@@ -808,7 +884,7 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
driverUniforms->addGraphicsDriverUniformsToShader(root, &getSymbolTable()); driverUniforms->addGraphicsDriverUniformsToShader(root, &getSymbolTable());
} }
assignReservedSpirvId( assignSpirvId(
driverUniforms->getDriverUniformsVariable()->getType().getInterfaceBlock()->uniqueId(), driverUniforms->getDriverUniformsVariable()->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdDriverUniformsBlock); vk::spirv::kIdDriverUniformsBlock);
@@ -830,8 +906,8 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
{ {
return false; return false;
} }
assignReservedSpirvId(atomicCounters->getType().getInterfaceBlock()->uniqueId(), assignSpirvId(atomicCounters->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdAtomicCounterBlock); vk::spirv::kIdAtomicCounterBlock);
} }
else if (getShaderVersion() >= 310) else if (getShaderVersion() >= 310)
{ {
@@ -1182,16 +1258,20 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
if (inputPerVertex) if (inputPerVertex)
{ {
assignReservedSpirvId(inputPerVertex->getType().getInterfaceBlock()->uniqueId(), assignSpirvId(inputPerVertex->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdInputPerVertexBlock); vk::spirv::kIdInputPerVertexBlock);
} }
if (outputPerVertex) if (outputPerVertex)
{ {
assignReservedSpirvId(outputPerVertex->getType().getInterfaceBlock()->uniqueId(), assignSpirvId(outputPerVertex->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdOutputPerVertexBlock); vk::spirv::kIdOutputPerVertexBlock);
assignReservedSpirvId(outputPerVertex->uniqueId(), vk::spirv::kIdOutputPerVertexVar); assignSpirvId(outputPerVertex->uniqueId(), vk::spirv::kIdOutputPerVertexVar);
} }
// Now that all transformations are done, assign SPIR-V ids to whatever shader variable is still
// present in the shader in some form. This should be the last thing done in this function.
assignSpirvIds(root);
return true; return true;
} }
@@ -1200,6 +1280,7 @@ bool TranslatorVulkan::translate(TIntermBlock *root,
PerformanceDiagnostics *perfDiagnostics) PerformanceDiagnostics *perfDiagnostics)
{ {
mUniqueToSpirvIdMap.clear(); mUniqueToSpirvIdMap.clear();
mFirstUnusedSpirvId = 0;
SpecConst specConst(&getSymbolTable(), compileOptions, getShaderType()); SpecConst specConst(&getSymbolTable(), compileOptions, getShaderType());
@@ -1215,7 +1296,7 @@ bool TranslatorVulkan::translate(TIntermBlock *root,
return false; return false;
} }
return OutputSPIRV(this, root, compileOptions, mUniqueToSpirvIdMap); return OutputSPIRV(this, root, compileOptions, mUniqueToSpirvIdMap, mFirstUnusedSpirvId);
} }
bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll() bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
@@ -1224,9 +1305,109 @@ bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
return false; return false;
} }
void TranslatorVulkan::assignReservedSpirvId(TSymbolUniqueId uniqueId, uint32_t spirvId) void TranslatorVulkan::assignSpirvId(TSymbolUniqueId uniqueId, uint32_t spirvId)
{ {
ASSERT(mUniqueToSpirvIdMap.find(uniqueId.get()) == mUniqueToSpirvIdMap.end()); ASSERT(mUniqueToSpirvIdMap.find(uniqueId.get()) == mUniqueToSpirvIdMap.end());
mUniqueToSpirvIdMap[uniqueId.get()] = spirvId; mUniqueToSpirvIdMap[uniqueId.get()] = spirvId;
} }
void TranslatorVulkan::assignSpirvIds(TIntermBlock *root)
{
// Match the declarations with collected variables and assign a new id to each, starting from
// the first unreserved id. This makes sure that the reserved ids for internal variables and
// ids for shader variables form a minimal contiguous range. The Vulkan backend takes advantage
// of this fact for optimal hashing.
mFirstUnusedSpirvId = vk::spirv::kIdFirstUnreserved;
for (TIntermNode *node : *root->getSequence())
{
TIntermDeclaration *decl = node->getAsDeclarationNode();
if (decl == nullptr)
{
continue;
}
TIntermSymbol *symbol = decl->getSequence()->front()->getAsSymbolNode();
if (symbol == nullptr)
{
continue;
}
const TType &type = symbol->getType();
const TQualifier qualifier = type.getQualifier();
// Skip internal symbols, which already have a reserved id.
const TSymbolUniqueId uniqueId =
type.isInterfaceBlock() ? type.getInterfaceBlock()->uniqueId() : symbol->uniqueId();
if (mUniqueToSpirvIdMap.find(uniqueId.get()) != mUniqueToSpirvIdMap.end())
{
continue;
}
uint32_t *variableId = nullptr;
if (type.isInterfaceBlock())
{
if (IsVaryingIn(qualifier))
{
ShaderVariable *varying =
FindIOBlockShaderVariable(&mInputVaryings, type.getInterfaceBlock()->name());
variableId = &varying->id;
}
else if (IsVaryingOut(qualifier))
{
ShaderVariable *varying =
FindIOBlockShaderVariable(&mOutputVaryings, type.getInterfaceBlock()->name());
variableId = &varying->id;
}
else
{
InterfaceBlock *block =
FindShaderVariable(&mInterfaceBlocks, type.getInterfaceBlock()->name());
variableId = &block->id;
}
}
else if (qualifier == EvqUniform)
{
ShaderVariable *uniform = FindUniformShaderVariable(&mUniforms, symbol->getName());
variableId = &uniform->id;
}
else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
{
ShaderVariable *attribute = FindShaderVariable(&mAttributes, symbol->getName());
variableId = &attribute->id;
}
else if (IsShaderIn(qualifier))
{
ShaderVariable *varying = FindShaderVariable(&mInputVaryings, symbol->getName());
variableId = &varying->id;
}
else if (qualifier == EvqFragmentOut)
{
// webgl_FragColor, webgl_FragData, webgl_SecondaryFragColor and webgl_SecondaryFragData
// are recorded with their original names (starting with gl_)
ImmutableString name(symbol->getName());
if (angle::BeginsWith(name.data(), "webgl_"))
{
name = ImmutableString(name.data() + 3, name.length() - 3);
}
ShaderVariable *output = FindShaderVariable(&mOutputVariables, name);
variableId = &output->id;
}
else if (IsShaderOut(qualifier))
{
ShaderVariable *varying = FindShaderVariable(&mOutputVaryings, symbol->getName());
variableId = &varying->id;
}
if (variableId == nullptr)
{
continue;
}
ASSERT(variableId != nullptr);
assignSpirvId(uniqueId, mFirstUnusedSpirvId);
*variableId = mFirstUnusedSpirvId++;
}
}
} // namespace sh } // namespace sh

View File

@@ -26,7 +26,7 @@ class TranslatorVulkan final : public TCompiler
public: public:
TranslatorVulkan(sh::GLenum type, ShShaderSpec spec); TranslatorVulkan(sh::GLenum type, ShShaderSpec spec);
void assignReservedSpirvId(TSymbolUniqueId uniqueId, uint32_t spirvId); void assignSpirvId(TSymbolUniqueId uniqueId, uint32_t spirvId);
protected: protected:
[[nodiscard]] bool translate(TIntermBlock *root, [[nodiscard]] bool translate(TIntermBlock *root,
@@ -39,10 +39,12 @@ class TranslatorVulkan final : public TCompiler
PerformanceDiagnostics *perfDiagnostics, PerformanceDiagnostics *perfDiagnostics,
SpecConst *specConst, SpecConst *specConst,
DriverUniform *driverUniforms); DriverUniform *driverUniforms);
void assignSpirvIds(TIntermBlock *root);
// A map from TSymbolUniqueId::mId to SPIR-V reserved ids. Used by the SPIR-V generator to // A map from TSymbolUniqueId::mId to SPIR-V reserved ids. Used by the SPIR-V generator to
// quickly know when to use a reserved id and not have to resort to name matching. // quickly know when to use a reserved id and not have to resort to name matching.
angle::HashMap<int, uint32_t> mUniqueToSpirvIdMap; angle::HashMap<int, uint32_t> mUniqueToSpirvIdMap;
uint32_t mFirstUnusedSpirvId;
}; };
} // namespace sh } // namespace sh

View File

@@ -57,11 +57,11 @@ class EmulateFragColorDataTraverser : public TIntermTraverser
name = "webgl_FragData"; name = "webgl_FragData";
break; break;
case EvqSecondaryFragColorEXT: case EvqSecondaryFragColorEXT:
name = "webgl_SecondaryFragColor"; name = "webgl_SecondaryFragColorEXT";
index = 1; index = 1;
break; break;
case EvqSecondaryFragDataEXT: case EvqSecondaryFragDataEXT:
name = "webgl_SecondaryFragData"; name = "webgl_SecondaryFragDataEXT";
index = 1; index = 1;
break; break;
default: default:

View File

@@ -452,6 +452,7 @@ class FlattenUniformVisitor : public sh::VariableNameVisitor
linkedUniform.staticUse = mMarkStaticUse; linkedUniform.staticUse = mMarkStaticUse;
linkedUniform.outerArraySizes = arraySizes; linkedUniform.outerArraySizes = arraySizes;
linkedUniform.texelFetchStaticUse = variable.texelFetchStaticUse; linkedUniform.texelFetchStaticUse = variable.texelFetchStaticUse;
linkedUniform.id = variable.id;
linkedUniform.imageUnitFormat = variable.imageUnitFormat; linkedUniform.imageUnitFormat = variable.imageUnitFormat;
linkedUniform.isFragmentInOut = variable.isFragmentInOut; linkedUniform.isFragmentInOut = variable.isFragmentInOut;
if (variable.hasParentArrayIndex()) if (variable.hasParentArrayIndex())
@@ -1421,6 +1422,7 @@ void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSizeFunc &getBlock
firstFieldArraySize, blockBinding); firstFieldArraySize, blockBinding);
block.memberIndexes = blockIndexes; block.memberIndexes = blockIndexes;
block.setActive(shaderType, interfaceBlock.active); block.setActive(shaderType, interfaceBlock.active);
block.id = interfaceBlock.id;
// Since all block elements in an array share the same active interface blocks, they // Since all block elements in an array share the same active interface blocks, they
// will all be active once any block member is used. So, since interfaceBlock.name[0] // will all be active once any block member is used. So, since interfaceBlock.name[0]

View File

@@ -126,7 +126,7 @@ int ShaderVariableBuffer::numActiveVariables() const
return static_cast<int>(memberIndexes.size()); return static_cast<int>(memberIndexes.size());
} }
InterfaceBlock::InterfaceBlock() : isArray(false), isReadOnly(false), arrayElement(0) {} InterfaceBlock::InterfaceBlock() : isArray(false), isReadOnly(false), arrayElement(0), id(0) {}
InterfaceBlock::InterfaceBlock(const std::string &nameIn, InterfaceBlock::InterfaceBlock(const std::string &nameIn,
const std::string &mappedNameIn, const std::string &mappedNameIn,
@@ -140,7 +140,8 @@ InterfaceBlock::InterfaceBlock(const std::string &nameIn,
isArray(isArrayIn), isArray(isArrayIn),
isReadOnly(isReadOnlyIn), isReadOnly(isReadOnlyIn),
arrayElement(arrayElementIn), arrayElement(arrayElementIn),
firstFieldArraySize(firstFieldArraySizeIn) firstFieldArraySize(firstFieldArraySizeIn),
id(0)
{ {
binding = bindingIn; binding = bindingIn;
} }

View File

@@ -138,6 +138,8 @@ struct InterfaceBlock : public ShaderVariableBuffer
bool isReadOnly; bool isReadOnly;
unsigned int arrayElement; unsigned int arrayElement;
unsigned int firstFieldArraySize; unsigned int firstFieldArraySize;
// The ID of the block, coming from sh::InterfaceBlock::id
uint32_t id;
}; };
} // namespace gl } // namespace gl

View File

@@ -350,14 +350,14 @@ void AssignSecondaryOutputLocations(const gl::ProgramExecutable &programExecutab
if (outputVar.name == "gl_SecondaryFragColorEXT") if (outputVar.name == "gl_SecondaryFragColorEXT")
{ {
AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment, AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment,
ShaderVariableType::SecondaryOutput, "webgl_SecondaryFragColor", 0, ShaderVariableType::SecondaryOutput, "webgl_SecondaryFragColorEXT",
ShaderInterfaceVariableInfo::kInvalid, 0, 0); 0, ShaderInterfaceVariableInfo::kInvalid, 0, 0);
} }
else if (outputVar.name == "gl_SecondaryFragDataEXT") else if (outputVar.name == "gl_SecondaryFragDataEXT")
{ {
AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment, AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment,
ShaderVariableType::SecondaryOutput, "webgl_SecondaryFragData", 0, ShaderVariableType::SecondaryOutput, "webgl_SecondaryFragDataEXT",
ShaderInterfaceVariableInfo::kInvalid, 0, 0); 0, ShaderInterfaceVariableInfo::kInvalid, 0, 0);
} }
} }
} }