mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-03 14:09:33 +03:00
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:
committed by
Angle LUCI CQ
parent
acdf872299
commit
10380f4ba4
@@ -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,
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user