Commit 29227eef by Shahbaz Youssefi Committed by Angle LUCI CQ

Vulkan: SPIR-V Gen: Specialization constants

With specialization constant qualifier and ids set in the node types, the SPIR-V generation for these variables are trivially handled. This is in preparation for enabling line raster emulation as well as fragment shaders in general. Bug: angleproject:4889 Change-Id: Ie4d4e47b222ac66d1e0eee29f55ac09990313580 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2939337 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 166dd0c7
......@@ -846,7 +846,7 @@ spirv::IdRef SPIRVBuilder::declareVariable(spirv::IdRef typeId,
? &mSpirvCurrentFunctionBlocks.front().localVariables
: &mSpirvVariableDecls;
spirv::IdRef variableId = getNewId();
const spirv::IdRef variableId = getNewId();
const spirv::IdRef typePointerId = getTypePointerId(typeId, storageClass);
spirv::WriteVariable(spirvSection, typePointerId, variableId, storageClass, initializerId);
......@@ -860,6 +860,39 @@ spirv::IdRef SPIRVBuilder::declareVariable(spirv::IdRef typeId,
return variableId;
}
spirv::IdRef SPIRVBuilder::declareSpecConst(TBasicType type, int id, const char *name)
{
const spirv::IdRef specConstId = getNewId();
SpirvType spirvType;
spirvType.type = type;
const spirv::IdRef typeId = getSpirvTypeData(spirvType, "").id;
// Note: all spec constants are 0 initialized by the translator.
if (type == EbtBool)
{
spirv::WriteSpecConstantFalse(&mSpirvTypeAndConstantDecls, typeId, specConstId);
}
else
{
spirv::WriteSpecConstant(&mSpirvTypeAndConstantDecls, typeId, specConstId,
spirv::LiteralContextDependentNumber(0));
}
// Add the SpecId decoration
spirv::WriteDecorate(&mSpirvDecorations, specConstId, spv::DecorationSpecId,
{spirv::LiteralInteger(id)});
// Output debug information.
if (name)
{
spirv::WriteName(&mSpirvDebug, specConstId, name);
}
return specConstId;
}
void SPIRVBuilder::startConditional(size_t blockCount, bool isContinuable, bool isBreakable)
{
mConditionalStack.emplace_back();
......
......@@ -285,6 +285,8 @@ class SPIRVBuilder : angle::NonCopyable
spv::StorageClass storageClass,
spirv::IdRef *initializerId,
const char *name);
// Helper to declare specialization constants.
spirv::IdRef declareSpecConst(TBasicType type, int id, const char *name);
// Helpers for conditionals.
void startConditional(size_t blockCount, bool isContinuable, bool isBreakable);
......
......@@ -195,6 +195,7 @@ class OutputSPIRVTraverser : public TIntermTraverser
TLayoutBlockStorage blockStorage) const;
void nodeDataInitRValue(NodeData *data, spirv::IdRef baseId, spirv::IdRef typeId) const;
void declareSpecConst(TIntermDeclaration *decl);
spirv::IdRef createConstant(const TType &type,
TBasicType expectedBasicType,
const TConstantUnion *constUnion);
......@@ -782,6 +783,35 @@ spirv::IdRef OutputSPIRVTraverser::getAccessChainTypeId(NodeData *data)
return accessChain.preSwizzleTypeId;
}
void OutputSPIRVTraverser::declareSpecConst(TIntermDeclaration *decl)
{
const TIntermSequence &sequence = *decl->getSequence();
ASSERT(sequence.size() == 1);
TIntermBinary *assign = sequence.front()->getAsBinaryNode();
ASSERT(assign != nullptr && assign->getOp() == EOpInitialize);
TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
ASSERT(symbol != nullptr && symbol->getType().getQualifier() == EvqSpecConst);
TIntermConstantUnion *initializer = assign->getRight()->getAsConstantUnion();
ASSERT(initializer != nullptr);
const TType &type = symbol->getType();
const TVariable *variable = &symbol->variable();
// All spec consts in ANGLE are initialized to 0.
ASSERT(initializer->isZero(0));
const spirv::IdRef specConstId =
mBuilder.declareSpecConst(type.getBasicType(), type.getLayoutQualifier().location,
mBuilder.hashName(variable).data());
// Remember the id of the variable for future look up.
ASSERT(mSymbolIdMap.count(variable) == 0);
mSymbolIdMap[variable] = specConstId;
}
spirv::IdRef OutputSPIRVTraverser::createConstant(const TType &type,
TBasicType expectedBasicType,
const TConstantUnion *constUnion)
......@@ -1520,9 +1550,13 @@ void OutputSPIRVTraverser::visitSymbol(TIntermSymbol *node)
// The symbol is either:
//
// - A specialization constant
// - A variable (local, varying etc)
// - An interface block
// - A field of an unnamed interface block
//
// Specialization constants in SPIR-V are treated largely like constants, in which case make
// this behave like visitConstantUnion().
const TType &type = node->getType();
const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
......@@ -1546,8 +1580,9 @@ void OutputSPIRVTraverser::visitSymbol(TIntermSymbol *node)
const spirv::IdRef typeId = mBuilder.getTypeData(type, blockStorage).id;
// If the symbol is a const variable, such as a const function parameter, create an rvalue.
if (type.getQualifier() == EvqConst)
// If the symbol is a const variable, such as a const function parameter or specialization
// constant, create an rvalue.
if (type.getQualifier() == EvqConst || type.getQualifier() == EvqSpecConst)
{
ASSERT(mSymbolIdMap.count(symbol) > 0);
nodeDataInitRValue(&mNodeData.back(), mSymbolIdMap[symbol], typeId);
......@@ -1667,6 +1702,13 @@ bool OutputSPIRVTraverser::visitBinary(Visit visit, TIntermBinary *node)
return true;
}
// If this is a variable initialization node, defer any code generation to visitDeclaration.
if (node->getOp() == EOpInitialize)
{
ASSERT(getParentNode()->getAsDeclarationNode() != nullptr);
return true;
}
if (visit == InVisit)
{
// Left child visited. Take the entry it created as the current node's.
......@@ -1694,13 +1736,6 @@ bool OutputSPIRVTraverser::visitBinary(Visit visit, TIntermBinary *node)
return true;
}
// If this is a variable initialization node, defer any code generation to visitDeclaration.
if (node->getOp() == EOpInitialize)
{
ASSERT(getParentNode()->getAsDeclarationNode() != nullptr);
return true;
}
// There are at least two entries, one for the left node and one for the right one.
ASSERT(mNodeData.size() >= 2);
......@@ -2256,6 +2291,19 @@ bool OutputSPIRVTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
bool OutputSPIRVTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
{
const TIntermSequence &sequence = *node->getSequence();
// Enforced by ValidateASTOptions::validateMultiDeclarations.
ASSERT(sequence.size() == 1);
// Declare specialization constants especially; they don't require processing the left and right
// nodes, and they are like constant declarations with special instructions and decorations.
if (sequence.front()->getAsTyped()->getType().getQualifier() == EvqSpecConst)
{
declareSpecConst(node);
return false;
}
if (!mInGlobalScope && visit == PreVisit)
{
mNodeData.emplace_back();
......@@ -2268,11 +2316,6 @@ bool OutputSPIRVTraverser::visitDeclaration(Visit visit, TIntermDeclaration *nod
return true;
}
const TIntermSequence &sequence = *node->getSequence();
// Enforced by ValidateASTOptions::validateMultiDeclarations.
ASSERT(sequence.size() == 1);
TIntermSymbol *symbol = sequence.front()->getAsSymbolNode();
spirv::IdRef initializerId;
bool initializeWithDeclaration = false;
......
......@@ -200,6 +200,12 @@ constexpr const TType *GetBasic()
return Get<basicType, EbpUndefined, EvqGlobal, primarySize, secondarySize>();
}
template <TBasicType basicType, unsigned char primarySize = 1, unsigned char secondarySize = 1>
constexpr const TType *GetTemporary()
{
return Get<basicType, EbpUndefined, EvqTemporary, primarySize, secondarySize>();
}
template <TBasicType basicType,
TQualifier qualifier,
unsigned char primarySize = 1,
......
......@@ -309,7 +309,7 @@ ANGLE_NO_DISCARD bool AddBresenhamEmulationVS(TCompiler *compiler,
// Clamp position to subpixel grid.
// Do perspective divide (get normalized device coords)
// "vec2 ndc = gl_Position.xy / gl_Position.w"
const TType *vec2Type = StaticType::GetBasic<EbtFloat, 2>();
const TType *vec2Type = StaticType::GetTemporary<EbtFloat, 2>();
TIntermBinary *viewportRef = driverUniforms->getViewportRef();
TIntermSymbol *glPos = new TIntermSymbol(BuiltInVariable::gl_Position());
TIntermSwizzle *glPosXY = CreateSwizzle(glPos, 0, 1);
......@@ -657,7 +657,8 @@ ANGLE_NO_DISCARD bool AddBresenhamEmulationFS(TCompiler *compiler,
bool usesFragCoord)
{
TVariable *anglePosition = AddANGLEPositionVaryingDeclaration(root, symbolTable, EvqVaryingIn);
const TType *vec2Type = StaticType::GetBasic<EbtFloat, 2>();
const TType *vec2Type = StaticType::GetTemporary<EbtFloat, 2>();
TIntermBinary *viewportRef = driverUniforms->getViewportRef();
// vec2 p = ((ANGLEPosition * 0.5) + 0.5) * viewport.zw + viewport.xy
......
......@@ -148,7 +148,7 @@ bool Traverser::visitUnaryWithRotation(Visit visit, TIntermUnary *node)
// Multiply halfRotationMat by ANGLEUniforms.flipXY and store in a temporary variable
TIntermBinary *rotatedFlipXY = new TIntermBinary(EOpMul, flipXY, halfRotationMat);
const TType *vec2Type = StaticType::GetBasic<EbtFloat, 2>();
const TType *vec2Type = StaticType::GetTemporary<EbtFloat, 2>();
TIntermSymbol *tmpRotFlipXY = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec2Type));
TIntermSequence tmpDecl;
tmpDecl.push_back(CreateTempInitDeclarationNode(&tmpRotFlipXY->variable(), rotatedFlipXY));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment