Commit 7d023dac by Shahbaz Youssefi Committed by Angle LUCI CQ

Vulkan: SPIR-V Gen: Basic support for fragment shaders

Fragment shader built-ins are implemented in this change and direct SPIR-V generation for fragment shaders is enabled. Bug: angleproject:4889 Change-Id: I6f92a5585f242122a81c97a9b1aa2763009161a0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2951625 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent c2449441
...@@ -311,6 +311,7 @@ SpirvTypeData SPIRVBuilder::declareType(const SpirvType &type, const TSymbol *bl ...@@ -311,6 +311,7 @@ SpirvTypeData SPIRVBuilder::declareType(const SpirvType &type, const TSymbol *bl
// Declaring a matrix. Declare the column type first, then create a matrix out of it. // Declaring a matrix. Declare the column type first, then create a matrix out of it.
SpirvType columnType = type; SpirvType columnType = type;
columnType.primarySize = columnType.secondarySize;
columnType.secondarySize = 1; columnType.secondarySize = 1;
columnType.blockStorage = EbsUnspecified; columnType.blockStorage = EbsUnspecified;
...@@ -318,7 +319,7 @@ SpirvTypeData SPIRVBuilder::declareType(const SpirvType &type, const TSymbol *bl ...@@ -318,7 +319,7 @@ SpirvTypeData SPIRVBuilder::declareType(const SpirvType &type, const TSymbol *bl
typeId = getNewId({}); typeId = getNewId({});
spirv::WriteTypeMatrix(&mSpirvTypeAndConstantDecls, typeId, columnTypeId, spirv::WriteTypeMatrix(&mSpirvTypeAndConstantDecls, typeId, columnTypeId,
spirv::LiteralInteger(type.secondarySize)); spirv::LiteralInteger(type.primarySize));
} }
else if (type.primarySize > 1) else if (type.primarySize > 1)
{ {
...@@ -1276,8 +1277,7 @@ uint32_t SPIRVBuilder::calculateBaseAlignmentAndSize(const SpirvType &type, ...@@ -1276,8 +1277,7 @@ uint32_t SPIRVBuilder::calculateBaseAlignmentAndSize(const SpirvType &type,
// Here, we always calculate the base alignment and size for column-major matrices. If a // Here, we always calculate the base alignment and size for column-major matrices. If a
// row-major matrix is used in a block, the columns and rows are simply swapped before // row-major matrix is used in a block, the columns and rows are simply swapped before
// looking up the base alignment and size. // looking up the base alignment and size.
//
// TODO: verify that ANGLE's primary size is 3 in the example above.
vectorType.primarySize = vectorType.secondarySize; vectorType.primarySize = vectorType.secondarySize;
vectorType.secondarySize = 1; vectorType.secondarySize = 1;
...@@ -1537,6 +1537,10 @@ void SPIRVBuilder::generateExecutionModes(spirv::Blob *blob) ...@@ -1537,6 +1537,10 @@ void SPIRVBuilder::generateExecutionModes(spirv::Blob *blob)
{ {
switch (mShaderType) switch (mShaderType)
{ {
case gl::ShaderType::Fragment:
spirv::WriteExecutionMode(blob, mEntryPointId, spv::ExecutionModeOriginUpperLeft, {});
break;
case gl::ShaderType::Compute: case gl::ShaderType::Compute:
{ {
const sh::WorkGroupSize &localSize = mCompiler->getComputeShaderLocalSize(); const sh::WorkGroupSize &localSize = mCompiler->getComputeShaderLocalSize();
......
...@@ -77,8 +77,9 @@ struct AccessChain ...@@ -77,8 +77,9 @@ struct AccessChain
// dynamicComponent will contain the id of the index. // dynamicComponent will contain the id of the index.
spirv::IdRef dynamicComponent; spirv::IdRef dynamicComponent;
// Type of expression before swizzle is applied, after swizzle is applied and after dynamic // Type of base expression, before swizzle is applied, after swizzle is applied and after
// component is applied. // dynamic component is applied.
spirv::IdRef baseTypeId;
spirv::IdRef preSwizzleTypeId; spirv::IdRef preSwizzleTypeId;
spirv::IdRef postSwizzleTypeId; spirv::IdRef postSwizzleTypeId;
spirv::IdRef postDynamicComponentTypeId; spirv::IdRef postDynamicComponentTypeId;
...@@ -205,6 +206,9 @@ class OutputSPIRVTraverser : public TIntermTraverser ...@@ -205,6 +206,9 @@ class OutputSPIRVTraverser : public TIntermTraverser
spirv::IdRef createConstant(const TType &type, spirv::IdRef createConstant(const TType &type,
TBasicType expectedBasicType, TBasicType expectedBasicType,
const TConstantUnion *constUnion); const TConstantUnion *constUnion);
spirv::IdRef createComplexConstant(const TType &type,
spirv::IdRef typeId,
const spirv::IdRefList &parameters);
spirv::IdRef createConstructor(TIntermAggregate *node, spirv::IdRef typeId); spirv::IdRef createConstructor(TIntermAggregate *node, spirv::IdRef typeId);
spirv::IdRef createArrayOrStructConstructor(TIntermAggregate *node, spirv::IdRef createArrayOrStructConstructor(TIntermAggregate *node,
spirv::IdRef typeId, spirv::IdRef typeId,
...@@ -315,6 +319,10 @@ spv::StorageClass GetStorageClass(const TType &type) ...@@ -315,6 +319,10 @@ spv::StorageClass GetStorageClass(const TType &type)
case EvqVertexID: case EvqVertexID:
case EvqInstanceID: case EvqInstanceID:
case EvqFragCoord:
case EvqFrontFacing:
case EvqPointCoord:
case EvqHelperInvocation:
case EvqNumWorkGroups: case EvqNumWorkGroups:
case EvqWorkGroupID: case EvqWorkGroupID:
case EvqLocalInvocationID: case EvqLocalInvocationID:
...@@ -322,6 +330,9 @@ spv::StorageClass GetStorageClass(const TType &type) ...@@ -322,6 +330,9 @@ spv::StorageClass GetStorageClass(const TType &type)
case EvqLocalInvocationIndex: case EvqLocalInvocationIndex:
return spv::StorageClassInput; return spv::StorageClassInput;
case EvqFragDepth:
return spv::StorageClassOutput;
default: default:
// TODO: http://anglebug.com/4889 // TODO: http://anglebug.com/4889
UNIMPLEMENTED(); UNIMPLEMENTED();
...@@ -363,55 +374,67 @@ spirv::IdRef OutputSPIRVTraverser::getSymbolIdAndStorageClass(const TSymbol *sym ...@@ -363,55 +374,67 @@ spirv::IdRef OutputSPIRVTraverser::getSymbolIdAndStorageClass(const TSymbol *sym
// This must be an implicitly defined variable, define it now. // This must be an implicitly defined variable, define it now.
const char *name = nullptr; const char *name = nullptr;
spv::BuiltIn builtInDecoration = spv::BuiltInMax; spv::BuiltIn builtInDecoration = spv::BuiltInMax;
SpirvType spirvType;
switch (type.getQualifier()) switch (type.getQualifier())
{ {
case EvqVertexID: case EvqVertexID:
name = "gl_VertexIndex"; name = "gl_VertexIndex";
builtInDecoration = spv::BuiltInVertexIndex; builtInDecoration = spv::BuiltInVertexIndex;
spirvType.type = EbtInt;
break; break;
case EvqInstanceID: case EvqInstanceID:
name = "gl_InstanceIndex"; name = "gl_InstanceIndex";
builtInDecoration = spv::BuiltInInstanceIndex; builtInDecoration = spv::BuiltInInstanceIndex;
spirvType.type = EbtInt;
break; break;
// Fragment shader built-ins
case EvqFragCoord:
name = "gl_FragCoord";
builtInDecoration = spv::BuiltInFragCoord;
break;
case EvqFrontFacing:
name = "gl_FrontFacing";
builtInDecoration = spv::BuiltInFrontFacing;
break;
case EvqPointCoord:
name = "gl_PointCoord";
builtInDecoration = spv::BuiltInPointCoord;
break;
case EvqFragDepth:
name = "gl_FragDepth";
builtInDecoration = spv::BuiltInFragDepth;
break;
case EvqHelperInvocation:
name = "gl_HelperInvocation";
builtInDecoration = spv::BuiltInHelperInvocation;
break;
// Compute shader built-ins
case EvqNumWorkGroups: case EvqNumWorkGroups:
name = "gl_NumWorkGroups"; name = "gl_NumWorkGroups";
builtInDecoration = spv::BuiltInNumWorkgroups; builtInDecoration = spv::BuiltInNumWorkgroups;
spirvType.type = EbtUInt;
spirvType.primarySize = 3;
break; break;
case EvqWorkGroupID: case EvqWorkGroupID:
name = "gl_WorkGroupID"; name = "gl_WorkGroupID";
builtInDecoration = spv::BuiltInWorkgroupId; builtInDecoration = spv::BuiltInWorkgroupId;
spirvType.type = EbtUInt;
spirvType.primarySize = 3;
break; break;
case EvqLocalInvocationID: case EvqLocalInvocationID:
name = "gl_LocalInvocationID"; name = "gl_LocalInvocationID";
builtInDecoration = spv::BuiltInLocalInvocationId; builtInDecoration = spv::BuiltInLocalInvocationId;
spirvType.type = EbtUInt;
spirvType.primarySize = 3;
break; break;
case EvqGlobalInvocationID: case EvqGlobalInvocationID:
name = "gl_GlobalInvocationID"; name = "gl_GlobalInvocationID";
builtInDecoration = spv::BuiltInGlobalInvocationId; builtInDecoration = spv::BuiltInGlobalInvocationId;
spirvType.type = EbtUInt;
spirvType.primarySize = 3;
break; break;
case EvqLocalInvocationIndex: case EvqLocalInvocationIndex:
name = "gl_LocalInvocationIndex"; name = "gl_LocalInvocationIndex";
builtInDecoration = spv::BuiltInLocalInvocationIndex; builtInDecoration = spv::BuiltInLocalInvocationIndex;
spirvType.type = EbtUInt;
break; break;
default: default:
// TODO: more built-ins. http://anglebug.com/4889 // TODO: more built-ins. http://anglebug.com/4889
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
const spirv::IdRef typeId = mBuilder.getSpirvTypeData(spirvType, nullptr).id; const spirv::IdRef typeId = mBuilder.getTypeData(type, EbsUnspecified).id;
const spirv::IdRef varId = mBuilder.declareVariable( const spirv::IdRef varId = mBuilder.declareVariable(
typeId, *storageClass, mBuilder.getDecorations(type), nullptr, name); typeId, *storageClass, mBuilder.getDecorations(type), nullptr, name);
...@@ -434,6 +457,7 @@ void OutputSPIRVTraverser::nodeDataInitLValue(NodeData *data, ...@@ -434,6 +457,7 @@ void OutputSPIRVTraverser::nodeDataInitLValue(NodeData *data,
// Initialize the access chain as an lvalue. Useful when an access chain is resolved, but needs // Initialize the access chain as an lvalue. Useful when an access chain is resolved, but needs
// to be replaced by a reference to a temporary variable holding the result. // to be replaced by a reference to a temporary variable holding the result.
data->baseId = baseId; data->baseId = baseId;
data->accessChain.baseTypeId = typeId;
data->accessChain.preSwizzleTypeId = typeId; data->accessChain.preSwizzleTypeId = typeId;
data->accessChain.storageClass = storageClass; data->accessChain.storageClass = storageClass;
data->accessChain.baseBlockStorage = blockStorage; data->accessChain.baseBlockStorage = blockStorage;
...@@ -448,6 +472,7 @@ void OutputSPIRVTraverser::nodeDataInitRValue(NodeData *data, ...@@ -448,6 +472,7 @@ void OutputSPIRVTraverser::nodeDataInitRValue(NodeData *data,
// Initialize the access chain as an rvalue. Useful when an access chain is resolved, and needs // Initialize the access chain as an rvalue. Useful when an access chain is resolved, and needs
// to be replaced by a reference to it. // to be replaced by a reference to it.
data->baseId = baseId; data->baseId = baseId;
data->accessChain.baseTypeId = typeId;
data->accessChain.preSwizzleTypeId = typeId; data->accessChain.preSwizzleTypeId = typeId;
} }
...@@ -627,9 +652,9 @@ spirv::IdRef OutputSPIRVTraverser::accessChainLoad(NodeData *data, ...@@ -627,9 +652,9 @@ spirv::IdRef OutputSPIRVTraverser::accessChainLoad(NodeData *data,
else else
{ {
// Create a temp variable to hold the rvalue so an access chain can be made on it. // Create a temp variable to hold the rvalue so an access chain can be made on it.
const spirv::IdRef tempVar = mBuilder.declareVariable( const spirv::IdRef tempVar =
accessChain.preSwizzleTypeId, spv::StorageClassFunction, decorations, nullptr, mBuilder.declareVariable(accessChain.baseTypeId, spv::StorageClassFunction,
"indexable"); decorations, nullptr, "indexable");
// Write the rvalue into the temp variable // Write the rvalue into the temp variable
spirv::WriteStore(mBuilder.getSpirvCurrentFunctionBlock(), tempVar, loadResult, spirv::WriteStore(mBuilder.getSpirvCurrentFunctionBlock(), tempVar, loadResult,
...@@ -895,7 +920,7 @@ spirv::IdRef OutputSPIRVTraverser::createConstant(const TType &type, ...@@ -895,7 +920,7 @@ spirv::IdRef OutputSPIRVTraverser::createConstant(const TType &type,
// If this is a composite, create a composite constant from the components. // If this is a composite, create a composite constant from the components.
if (type.getBasicType() == EbtStruct || componentIds.size() > 1) if (type.getBasicType() == EbtStruct || componentIds.size() > 1)
{ {
return mBuilder.getCompositeConstant(typeId, componentIds); return createComplexConstant(type, typeId, componentIds);
} }
// Otherwise return the sole component. // Otherwise return the sole component.
...@@ -903,6 +928,35 @@ spirv::IdRef OutputSPIRVTraverser::createConstant(const TType &type, ...@@ -903,6 +928,35 @@ spirv::IdRef OutputSPIRVTraverser::createConstant(const TType &type,
return componentIds[0]; return componentIds[0];
} }
spirv::IdRef OutputSPIRVTraverser::createComplexConstant(const TType &type,
spirv::IdRef typeId,
const spirv::IdRefList &parameters)
{
if (type.isMatrix() && !type.isArray())
{
// Matrices are constructed from its columns.
spirv::IdRefList columnIds;
SpirvType columnType = mBuilder.getSpirvType(type, EbsUnspecified);
columnType.primarySize = columnType.secondarySize;
columnType.secondarySize = 1;
const spirv::IdRef columnTypeId = mBuilder.getSpirvTypeData(columnType, nullptr).id;
for (int columnIndex = 0; columnIndex < type.getCols(); ++columnIndex)
{
auto columnParametersStart = parameters.begin() + columnIndex * type.getRows();
spirv::IdRefList columnParameters(columnParametersStart,
columnParametersStart + type.getRows());
columnIds.push_back(mBuilder.getCompositeConstant(columnTypeId, columnParameters));
}
return mBuilder.getCompositeConstant(typeId, columnIds);
}
return mBuilder.getCompositeConstant(typeId, parameters);
}
spirv::IdRef OutputSPIRVTraverser::createConstructor(TIntermAggregate *node, spirv::IdRef typeId) spirv::IdRef OutputSPIRVTraverser::createConstructor(TIntermAggregate *node, spirv::IdRef typeId)
{ {
const TType &type = node->getType(); const TType &type = node->getType();
...@@ -943,6 +997,12 @@ spirv::IdRef OutputSPIRVTraverser::createConstructor(TIntermAggregate *node, spi ...@@ -943,6 +997,12 @@ spirv::IdRef OutputSPIRVTraverser::createConstructor(TIntermAggregate *node, spi
// Additionally, array and structs are constructed by OpCompositeConstruct followed by ids of // Additionally, array and structs are constructed by OpCompositeConstruct followed by ids of
// each parameter which must enumerate every individual element / field. // each parameter which must enumerate every individual element / field.
// In some cases, constructors with constant value are not folded. That is handled here.
if (node->hasConstantValue())
{
return createComplexConstant(node->getType(), typeId, parameters);
}
if (type.isArray() || type.getStruct() != nullptr) if (type.isArray() || type.getStruct() != nullptr)
{ {
return createArrayOrStructConstructor(node, typeId, parameters); return createArrayOrStructConstructor(node, typeId, parameters);
...@@ -1061,6 +1121,7 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromScalar( ...@@ -1061,6 +1121,7 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromScalar(
spirv::IdRefList columnIds; spirv::IdRefList columnIds;
SpirvType columnType = mBuilder.getSpirvType(type, EbsUnspecified); SpirvType columnType = mBuilder.getSpirvType(type, EbsUnspecified);
columnType.primarySize = columnType.secondarySize;
columnType.secondarySize = 1; columnType.secondarySize = 1;
const spirv::IdRef columnTypeId = mBuilder.getSpirvTypeData(columnType, nullptr).id; const spirv::IdRef columnTypeId = mBuilder.getSpirvTypeData(columnType, nullptr).id;
...@@ -1108,6 +1169,7 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromVectors( ...@@ -1108,6 +1169,7 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromVectors(
spirv::IdRefList columnIds; spirv::IdRefList columnIds;
SpirvType columnType = mBuilder.getSpirvType(type, EbsUnspecified); SpirvType columnType = mBuilder.getSpirvType(type, EbsUnspecified);
columnType.primarySize = columnType.secondarySize;
columnType.secondarySize = 1; columnType.secondarySize = 1;
const spirv::IdRef columnTypeId = mBuilder.getSpirvTypeData(columnType, nullptr).id; const spirv::IdRef columnTypeId = mBuilder.getSpirvTypeData(columnType, nullptr).id;
...@@ -1166,6 +1228,7 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromMatrix( ...@@ -1166,6 +1228,7 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromMatrix(
spirv::IdRefList columnIds; spirv::IdRefList columnIds;
SpirvType columnType = mBuilder.getSpirvType(type, EbsUnspecified); SpirvType columnType = mBuilder.getSpirvType(type, EbsUnspecified);
columnType.primarySize = columnType.secondarySize;
columnType.secondarySize = 1; columnType.secondarySize = 1;
const spirv::IdRef columnTypeId = mBuilder.getSpirvTypeData(columnType, nullptr).id; const spirv::IdRef columnTypeId = mBuilder.getSpirvTypeData(columnType, nullptr).id;
...@@ -1639,7 +1702,10 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I ...@@ -1639,7 +1702,10 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I
const bool isFloat = basicType == EbtFloat || basicType == EbtDouble; const bool isFloat = basicType == EbtFloat || basicType == EbtDouble;
const bool isUnsigned = basicType == EbtUInt; const bool isUnsigned = basicType == EbtUInt;
const bool isBool = basicType == EbtBool; const bool isBool = basicType == EbtBool;
const bool operateOnColumns = firstOperandType.isMatrix(); // Whether the operation needs to be applied column by column.
TIntermBinary *asBinary = node->getAsBinaryNode();
bool operateOnColumns = asBinary && (asBinary->getLeft()->getType().isMatrix() ||
asBinary->getRight()->getType().isMatrix());
// Whether the operands need to be swapped in the (binary) instruction // Whether the operands need to be swapped in the (binary) instruction
bool binarySwapOperands = false; bool binarySwapOperands = false;
// Whether the scalar operand needs to be extended to match the other operand which is a vector // Whether the scalar operand needs to be extended to match the other operand which is a vector
...@@ -1717,6 +1783,8 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I ...@@ -1717,6 +1783,8 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I
case EOpEqual: case EOpEqual:
case EOpEqualComponentWise: case EOpEqualComponentWise:
// TODO: handle vector, matrix and other complex comparisons. EOpEqual must use OpAll
// to reduce to a bool. http://anglebug.com/4889.
if (isFloat) if (isFloat)
writeBinaryOp = spirv::WriteFOrdEqual; writeBinaryOp = spirv::WriteFOrdEqual;
else if (isBool) else if (isBool)
...@@ -1726,6 +1794,8 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I ...@@ -1726,6 +1794,8 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I
break; break;
case EOpNotEqual: case EOpNotEqual:
case EOpNotEqualComponentWise: case EOpNotEqualComponentWise:
// TODO: handle vector, matrix and other complex comparisons. EOpNotEqual must use
// OpAny to reduce to a bool. http://anglebug.com/4889.
if (isFloat) if (isFloat)
writeBinaryOp = spirv::WriteFUnordNotEqual; writeBinaryOp = spirv::WriteFUnordNotEqual;
else if (isBool) else if (isBool)
...@@ -1783,18 +1853,23 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I ...@@ -1783,18 +1853,23 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I
break; break;
case EOpVectorTimesMatrix: case EOpVectorTimesMatrix:
case EOpVectorTimesMatrixAssign: case EOpVectorTimesMatrixAssign:
writeBinaryOp = spirv::WriteVectorTimesMatrix; writeBinaryOp = spirv::WriteVectorTimesMatrix;
operateOnColumns = false;
break; break;
case EOpMatrixTimesVector: case EOpMatrixTimesVector:
writeBinaryOp = spirv::WriteMatrixTimesVector; writeBinaryOp = spirv::WriteMatrixTimesVector;
operateOnColumns = false;
break; break;
case EOpMatrixTimesScalar: case EOpMatrixTimesScalar:
case EOpMatrixTimesScalarAssign: case EOpMatrixTimesScalarAssign:
writeBinaryOp = spirv::WriteMatrixTimesScalar; writeBinaryOp = spirv::WriteMatrixTimesScalar;
binarySwapOperands = asBinary->getRight()->getType().isMatrix();
operateOnColumns = false;
break; break;
case EOpMatrixTimesMatrix: case EOpMatrixTimesMatrix:
case EOpMatrixTimesMatrixAssign: case EOpMatrixTimesMatrixAssign:
writeBinaryOp = spirv::WriteMatrixTimesMatrix; writeBinaryOp = spirv::WriteMatrixTimesMatrix;
operateOnColumns = false;
break; break;
case EOpLogicalOr: case EOpLogicalOr:
...@@ -2232,9 +2307,15 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I ...@@ -2232,9 +2307,15 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I
const SpirvDecorations operandDecorations = mBuilder.getDecorations(firstOperandType); const SpirvDecorations operandDecorations = mBuilder.getDecorations(firstOperandType);
SpirvType columnType = mBuilder.getSpirvType(firstOperandType, EbsUnspecified); SpirvType columnType = mBuilder.getSpirvType(firstOperandType, EbsUnspecified);
columnType.primarySize = columnType.secondarySize;
columnType.secondarySize = 1; columnType.secondarySize = 1;
const spirv::IdRef columnTypeId = mBuilder.getSpirvTypeData(columnType, nullptr).id; const spirv::IdRef columnTypeId = mBuilder.getSpirvTypeData(columnType, nullptr).id;
if (binarySwapOperands)
{
std::swap(parameters[0], parameters[1]);
}
// Extract and apply the operator to each column. // Extract and apply the operator to each column.
for (int columnIndex = 0; columnIndex < firstOperandType.getCols(); ++columnIndex) for (int columnIndex = 0; columnIndex < firstOperandType.getCols(); ++columnIndex)
{ {
...@@ -2304,13 +2385,6 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I ...@@ -2304,13 +2385,6 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I
// Write the operation that combines the left and right values. // Write the operation that combines the left and right values.
writeBinaryOp(mBuilder.getSpirvCurrentFunctionBlock(), resultTypeId, result, parameters[0], writeBinaryOp(mBuilder.getSpirvCurrentFunctionBlock(), resultTypeId, result, parameters[0],
parameters[1]); parameters[1]);
// If it's an assignment, store the calculated value.
if (IsAssignment(node->getOp()))
{
ASSERT(mNodeData.size() >= 2);
accessChainStore(&mNodeData[mNodeData.size() - 2], result);
}
} }
else if (writeTernaryOp) else if (writeTernaryOp)
{ {
...@@ -2342,6 +2416,14 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I ...@@ -2342,6 +2416,14 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I
spirv::LiteralExtInstInteger(extendedInst), parameters); spirv::LiteralExtInstInteger(extendedInst), parameters);
} }
// If it's an assignment, store the calculated value.
if (IsAssignment(node->getOp()))
{
ASSERT(mNodeData.size() >= 2);
ASSERT(parameters.size() == 2);
accessChainStore(&mNodeData[mNodeData.size() - 2], result);
}
return result; return result;
} }
...@@ -3108,8 +3190,9 @@ void OutputSPIRVTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node ...@@ -3108,8 +3190,9 @@ void OutputSPIRVTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node
bool OutputSPIRVTraverser::visitAggregate(Visit visit, TIntermAggregate *node) bool OutputSPIRVTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{ {
// Constants are expected to be folded. // Constants are expected to be folded. However, large constructors (such as arrays) are not
ASSERT(!node->hasConstantValue()); // folded and are handled here.
ASSERT(node->getOp() == EOpConstruct || !node->hasConstantValue());
if (visit == PreVisit) if (visit == PreVisit)
{ {
...@@ -3237,7 +3320,8 @@ bool OutputSPIRVTraverser::visitDeclaration(Visit visit, TIntermDeclaration *nod ...@@ -3237,7 +3320,8 @@ bool OutputSPIRVTraverser::visitDeclaration(Visit visit, TIntermDeclaration *nod
// makes sure their initialization is deferred to the beginning of main. // makes sure their initialization is deferred to the beginning of main.
TIntermTyped *initializer = assign->getRight(); TIntermTyped *initializer = assign->getRight();
initializeWithDeclaration = initializer->getAsConstantUnion() != nullptr; initializeWithDeclaration =
initializer->getAsConstantUnion() != nullptr || initializer->hasConstantValue();
if (initializeWithDeclaration) if (initializeWithDeclaration)
{ {
......
...@@ -1341,10 +1341,8 @@ bool TranslatorVulkan::translate(TIntermBlock *root, ...@@ -1341,10 +1341,8 @@ bool TranslatorVulkan::translate(TIntermBlock *root,
} }
#if defined(ANGLE_ENABLE_DIRECT_SPIRV_GENERATION) #if defined(ANGLE_ENABLE_DIRECT_SPIRV_GENERATION)
constexpr ShCompileOptions kUnsupportedTransformations = SH_CLAMP_POINT_SIZE;
if ((compileOptions & SH_GENERATE_SPIRV_DIRECTLY) != 0 && if ((compileOptions & SH_GENERATE_SPIRV_DIRECTLY) != 0 &&
((getShaderType() == GL_VERTEX_SHADER && (getShaderType() == GL_VERTEX_SHADER || getShaderType() == GL_FRAGMENT_SHADER ||
(compileOptions & kUnsupportedTransformations) == 0) ||
getShaderType() == GL_COMPUTE_SHADER)) getShaderType() == GL_COMPUTE_SHADER))
{ {
// Declare the implicitly defined gl_PerVertex I/O blocks if not already. This will help // Declare the implicitly defined gl_PerVertex I/O blocks if not already. This will help
......
...@@ -99,7 +99,7 @@ TIntermTyped *GenerateMat2x2ArrayWithIndex(const Mat2x2EnumMap &matrix, TIntermS ...@@ -99,7 +99,7 @@ TIntermTyped *GenerateMat2x2ArrayWithIndex(const Mat2x2EnumMap &matrix, TIntermS
CreateMat2x2(matrix, vk::SurfaceRotation::FlippedRotated180Degrees), CreateMat2x2(matrix, vk::SurfaceRotation::FlippedRotated180Degrees),
CreateMat2x2(matrix, vk::SurfaceRotation::FlippedRotated270Degrees)}; CreateMat2x2(matrix, vk::SurfaceRotation::FlippedRotated270Degrees)};
TIntermTyped *array = TIntermAggregate::CreateConstructor(*typeMat2Array, &sequences); TIntermTyped *array = TIntermAggregate::CreateConstructor(*typeMat2Array, &sequences);
return new TIntermBinary(EOpIndexDirect, array, rotation); return new TIntermBinary(EOpIndexIndirect, array, rotation);
} }
using Vec2 = std::array<float, 2>; using Vec2 = std::array<float, 2>;
...@@ -156,7 +156,7 @@ TIntermTyped *CreateVec2ArrayWithIndex(Vec2EnumMap vec2Values, ...@@ -156,7 +156,7 @@ TIntermTyped *CreateVec2ArrayWithIndex(Vec2EnumMap vec2Values,
CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedRotated180Degrees), CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedRotated180Degrees),
CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedRotated270Degrees)}; CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedRotated270Degrees)};
TIntermTyped *vec2Array = TIntermAggregate::CreateConstructor(*typeVec2Array, &sequences); TIntermTyped *vec2Array = TIntermAggregate::CreateConstructor(*typeVec2Array, &sequences);
return new TIntermBinary(EOpIndexDirect, vec2Array, rotation); return new TIntermBinary(EOpIndexIndirect, vec2Array, rotation);
} }
// Returns [flipX*m0, flipY*m1], where [m0 m1] is the first column of kFragRotation matrix. // Returns [flipX*m0, flipY*m1], where [m0 m1] is the first column of kFragRotation matrix.
...@@ -229,7 +229,7 @@ TIntermTyped *CreateFloatArrayWithRotationIndex(const Vec2EnumMap &valuesEnumMap ...@@ -229,7 +229,7 @@ TIntermTyped *CreateFloatArrayWithRotationIndex(const Vec2EnumMap &valuesEnumMap
scale)}; scale)};
TIntermTyped *array = TIntermAggregate::CreateConstructor(*typeFloat8, &sequences); TIntermTyped *array = TIntermAggregate::CreateConstructor(*typeFloat8, &sequences);
return new TIntermBinary(EOpIndexDirect, array, rotation); return new TIntermBinary(EOpIndexIndirect, array, rotation);
} }
const TType *MakeSpecConst(const TType &type, vk::SpecializationConstantId id) const TType *MakeSpecConst(const TType &type, vk::SpecializationConstantId id)
......
...@@ -41,6 +41,13 @@ ...@@ -41,6 +41,13 @@
// Mac // Mac
6025 MAC AMD OPENGL : IndexBufferOffsetTestES3.UseAsUBOThenUpdateThenUInt8Index/ES3_OpenGL = SKIP 6025 MAC AMD OPENGL : IndexBufferOffsetTestES3.UseAsUBOThenUpdateThenUInt8Index/ES3_OpenGL = SKIP
6025 MAC AMD OPENGL : IndexBufferOffsetTestES3.UseAsUBOThenUpdateThenUInt8IndexSmallUpdates/ES3_OpenGL = SKIP 6025 MAC AMD OPENGL : IndexBufferOffsetTestES3.UseAsUBOThenUpdateThenUInt8IndexSmallUpdates/ES3_OpenGL = SKIP
6096 MAC METAL : GLSLTest_ES3.InitGlobalComplexConstant/ES3_Metal = SKIP
// D3D
6091 WIN D3D11 : GLSLTest_ES3.InitGlobalComplexConstant/* = SKIP
// Android
6095 ANDROID GLES : GLSLTest_ES3.InitGlobalComplexConstant/ES3_OpenGLES = SKIP
// Pixel 4 expectations. // Pixel 4 expectations.
5981 PIXEL4ORXL GLES : BlitFramebufferTest.BlitSRGBToRGBOversizedDestArea/* = SKIP 5981 PIXEL4ORXL GLES : BlitFramebufferTest.BlitSRGBToRGBOversizedDestArea/* = SKIP
......
...@@ -11007,6 +11007,73 @@ void main() ...@@ -11007,6 +11007,73 @@ void main()
glDeleteShader(shader); glDeleteShader(shader);
} }
// Test that initializing global variables with complex constants work
TEST_P(GLSLTest_ES3, InitGlobalComplexConstant)
{
constexpr char kFS[] = R"(#version 300 es
precision highp float;
out vec4 color;
struct T
{
float f;
};
struct S
{
vec4 v;
mat3x4 m[2];
T t;
};
S s = S(
vec4(0, 1, 2, 3),
mat3x4[2](
mat3x4(
vec4(4, 5, 6, 7),
vec4(8, 9, 10, 11),
vec4(12, 13, 14, 15)
),
mat3x4(
vec4(16, 17, 18, 19),
vec4(20, 21, 22, 23),
vec4(24, 25, 26, 27)
)
),
T(28.0)
);
void main()
{
vec4 result = vec4(0, 1, 0, 1);
if (s.v != vec4(0, 1, 2, 3))
result = vec4(1, 0, 0, 0);
for (int index = 0; index < 2; ++index)
{
for (int column = 0; column < 3; ++column)
{
int expect = index * 12 + column * 4 + 4;
if (s.m[index][column] != vec4(expect, expect + 1, expect + 2, expect + 3))
result = vec4(float(index + 1) / 2.0, 0, float(column + 1) / 3.0, 1);
}
}
if (s.t.f != 28.0)
result = vec4(0, 0, 1, 0);
color = result;
})";
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
} // anonymous namespace } // anonymous namespace
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(GLSLTest); ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(GLSLTest);
......
...@@ -656,7 +656,7 @@ TEST_P(LineLoopIndirectTest, UseAsUBOThenUpdateThenUShortIndexIndirectBuffer) ...@@ -656,7 +656,7 @@ TEST_P(LineLoopIndirectTest, UseAsUBOThenUpdateThenUShortIndexIndirectBuffer)
} }
ANGLE_INSTANTIATE_TEST_ES2(LineLoopTest); ANGLE_INSTANTIATE_TEST_ES2(LineLoopTest);
ANGLE_INSTANTIATE_TEST_ES3(LineLoopTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(LineLoopTestES3, WithDirectSPIRVGeneration(ES3_VULKAN()));
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LineLoopPrimitiveRestartTest); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LineLoopPrimitiveRestartTest);
ANGLE_INSTANTIATE_TEST_ES3_AND( ANGLE_INSTANTIATE_TEST_ES3_AND(
......
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