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

View File

@@ -240,6 +240,11 @@ struct ShaderVariable
// If the variable is a sampler that has ever been statically used with texelFetch
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:
bool isSameVariableAtLinkTime(const ShaderVariable &other,
bool matchPrecision,
@@ -296,6 +301,9 @@ struct InterfaceBlock
bool isReadOnly;
BlockType blockType;
std::vector<ShaderVariable> fields;
// Id of the interface block in the shader. Similar to |ShaderVariable::id|.
uint32_t id;
};
struct WorkGroupSize

View File

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

View File

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

View File

@@ -309,7 +309,8 @@ class SPIRVBuilder : angle::NonCopyable
const ShCompileOptions &compileOptions,
ShHashFunction64 hashFunction,
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 getReservedOrNewId(TSymbolUniqueId uniqueId, const SpirvDecorations &decorations);

View File

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

View File

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

View File

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

View File

@@ -162,8 +162,8 @@ bool DeclareDefaultUniforms(TranslatorVulkan *compiler,
root, symbolTable, uniformList, EvqUniform, layoutQualifier, TMemoryQualifier::Create(), 0,
ImmutableString(kDefaultUniformNames[shaderType]), ImmutableString(""));
compiler->assignReservedSpirvId(uniformBlock->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdDefaultUniformsBlock);
compiler->assignSpirvId(uniformBlock->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdDefaultUniformsBlock);
// Create a map from the uniform variables to new variables that reference the fields of the
// block.
@@ -382,8 +382,8 @@ TIntermSequence *GetMainSequence(TIntermBlock *root)
ivec4Type, true);
getOffsetsFunction->addParameter(stridesVar);
compiler->assignReservedSpirvId(getOffsetsFunction->uniqueId(),
vk::spirv::kIdXfbEmulationGetOffsetsFunction);
compiler->assignSpirvId(getOffsetsFunction->uniqueId(),
vk::spirv::kIdXfbEmulationGetOffsetsFunction);
TIntermFunctionDefinition *functionDef =
CreateInternalFunctionDefinitionNode(*getOffsetsFunction, body);
@@ -407,8 +407,8 @@ TIntermSequence *GetMainSequence(TIntermBlock *root)
TFunction *xfbCaptureFunction = new TFunction(symbolTable, ImmutableString("ANGLECaptureXfb"),
SymbolType::AngleInternal, voidType, false);
compiler->assignReservedSpirvId(xfbCaptureFunction->uniqueId(),
vk::spirv::kIdXfbEmulationCaptureFunction);
compiler->assignSpirvId(xfbCaptureFunction->uniqueId(),
vk::spirv::kIdXfbEmulationCaptureFunction);
// Insert the function declaration before main().
root->insertChildNodes(mainIndex,
@@ -489,10 +489,10 @@ TIntermSequence *GetMainSequence(TIntermBlock *root)
static_assert(vk::spirv::kIdXfbEmulationBufferVarThree ==
vk::spirv::kIdXfbEmulationBufferVarZero + 3);
compiler->assignReservedSpirvId(xfbBuffer->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdXfbEmulationBufferBlockZero + bufferIndex);
compiler->assignReservedSpirvId(xfbBuffer->uniqueId(),
vk::spirv::kIdXfbEmulationBufferVarZero + bufferIndex);
compiler->assignSpirvId(xfbBuffer->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdXfbEmulationBufferBlockZero + bufferIndex);
compiler->assignSpirvId(xfbBuffer->uniqueId(),
vk::spirv::kIdXfbEmulationBufferVarZero + bufferIndex);
}
return compiler->validateAST(root);
@@ -530,7 +530,7 @@ TIntermSequence *GetMainSequence(TIntermBlock *root)
new TVariable(symbolTable, ImmutableString(vk::kXfbExtensionPositionOutName), vec4Type,
SymbolType::AngleInternal);
compiler->assignReservedSpirvId(varyingVar->uniqueId(), vk::spirv::kIdXfbExtensionPosition);
compiler->assignSpirvId(varyingVar->uniqueId(), vk::spirv::kIdXfbExtensionPosition);
TIntermDeclaration *varyingDecl = new TIntermDeclaration();
varyingDecl->appendDeclarator(new TIntermSymbol(varyingVar));
@@ -625,8 +625,8 @@ TIntermSequence *GetMainSequence(TIntermBlock *root)
SymbolType::AngleInternal, vec4Type, true);
transformPositionFunction->addParameter(positionVar);
compiler->assignReservedSpirvId(transformPositionFunction->uniqueId(),
vk::spirv::kIdTransformPositionFunction);
compiler->assignSpirvId(transformPositionFunction->uniqueId(),
vk::spirv::kIdTransformPositionFunction);
TIntermFunctionDefinition *functionDef =
CreateInternalFunctionDefinitionNode(*transformPositionFunction, body);
@@ -670,10 +670,86 @@ bool HasFramebufferFetch(const TExtensionBehavior &extBehavior,
(compileOptions.pls.type == ShPixelLocalStorageType::FramebufferFetch &&
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
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,
@@ -808,7 +884,7 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
driverUniforms->addGraphicsDriverUniformsToShader(root, &getSymbolTable());
}
assignReservedSpirvId(
assignSpirvId(
driverUniforms->getDriverUniformsVariable()->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdDriverUniformsBlock);
@@ -830,8 +906,8 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
{
return false;
}
assignReservedSpirvId(atomicCounters->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdAtomicCounterBlock);
assignSpirvId(atomicCounters->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdAtomicCounterBlock);
}
else if (getShaderVersion() >= 310)
{
@@ -1182,16 +1258,20 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
if (inputPerVertex)
{
assignReservedSpirvId(inputPerVertex->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdInputPerVertexBlock);
assignSpirvId(inputPerVertex->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdInputPerVertexBlock);
}
if (outputPerVertex)
{
assignReservedSpirvId(outputPerVertex->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdOutputPerVertexBlock);
assignReservedSpirvId(outputPerVertex->uniqueId(), vk::spirv::kIdOutputPerVertexVar);
assignSpirvId(outputPerVertex->getType().getInterfaceBlock()->uniqueId(),
vk::spirv::kIdOutputPerVertexBlock);
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;
}
@@ -1200,6 +1280,7 @@ bool TranslatorVulkan::translate(TIntermBlock *root,
PerformanceDiagnostics *perfDiagnostics)
{
mUniqueToSpirvIdMap.clear();
mFirstUnusedSpirvId = 0;
SpecConst specConst(&getSymbolTable(), compileOptions, getShaderType());
@@ -1215,7 +1296,7 @@ bool TranslatorVulkan::translate(TIntermBlock *root,
return false;
}
return OutputSPIRV(this, root, compileOptions, mUniqueToSpirvIdMap);
return OutputSPIRV(this, root, compileOptions, mUniqueToSpirvIdMap, mFirstUnusedSpirvId);
}
bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
@@ -1224,9 +1305,109 @@ bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
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());
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

View File

@@ -26,7 +26,7 @@ class TranslatorVulkan final : public TCompiler
public:
TranslatorVulkan(sh::GLenum type, ShShaderSpec spec);
void assignReservedSpirvId(TSymbolUniqueId uniqueId, uint32_t spirvId);
void assignSpirvId(TSymbolUniqueId uniqueId, uint32_t spirvId);
protected:
[[nodiscard]] bool translate(TIntermBlock *root,
@@ -39,10 +39,12 @@ class TranslatorVulkan final : public TCompiler
PerformanceDiagnostics *perfDiagnostics,
SpecConst *specConst,
DriverUniform *driverUniforms);
void assignSpirvIds(TIntermBlock *root);
// 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.
angle::HashMap<int, uint32_t> mUniqueToSpirvIdMap;
uint32_t mFirstUnusedSpirvId;
};
} // namespace sh

View File

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

View File

@@ -452,6 +452,7 @@ class FlattenUniformVisitor : public sh::VariableNameVisitor
linkedUniform.staticUse = mMarkStaticUse;
linkedUniform.outerArraySizes = arraySizes;
linkedUniform.texelFetchStaticUse = variable.texelFetchStaticUse;
linkedUniform.id = variable.id;
linkedUniform.imageUnitFormat = variable.imageUnitFormat;
linkedUniform.isFragmentInOut = variable.isFragmentInOut;
if (variable.hasParentArrayIndex())
@@ -1421,6 +1422,7 @@ void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSizeFunc &getBlock
firstFieldArraySize, blockBinding);
block.memberIndexes = blockIndexes;
block.setActive(shaderType, interfaceBlock.active);
block.id = interfaceBlock.id;
// 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]

View File

@@ -126,7 +126,7 @@ int ShaderVariableBuffer::numActiveVariables() const
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,
const std::string &mappedNameIn,
@@ -140,7 +140,8 @@ InterfaceBlock::InterfaceBlock(const std::string &nameIn,
isArray(isArrayIn),
isReadOnly(isReadOnlyIn),
arrayElement(arrayElementIn),
firstFieldArraySize(firstFieldArraySizeIn)
firstFieldArraySize(firstFieldArraySizeIn),
id(0)
{
binding = bindingIn;
}

View File

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

View File

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