Commit 3b0fcf6a by Shahbaz Youssefi Committed by Angle LUCI CQ

Vulkan: SPIR-V Gen: Support type casts in constructors

GLSL basic, vector and matrix constructors can convert between types. This was already done for constants used in constructors. This change implements the cast for non-constant expressions. Bug: angleproject:4889 Change-Id: I0a8c1a6e97ffced0d1652032a41fb87c70be16ca Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2999022Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 0fa2e7f9
...@@ -362,6 +362,23 @@ SpirvTypeData SPIRVBuilder::declareType(const SpirvType &type, const TSymbol *bl ...@@ -362,6 +362,23 @@ SpirvTypeData SPIRVBuilder::declareType(const SpirvType &type, const TSymbol *bl
spirv::LiteralInteger(0)); spirv::LiteralInteger(0));
break; break;
case EbtBool: case EbtBool:
// TODO: In SPIR-V, it's invalid to have a bool type in an interface block. An AST
// transformation should be written to rewrite the blocks to use a uint type with
// appropriate casts where used. Need to handle:
//
// - Store: cast the rhs of assignment
// - Non-array load: cast the expression
// - Array load (for example to use in a struct constructor): reconstruct the array
// with elements cast.
// - Pass to function as out parameter: Use
// MonomorphizeUnsupportedFunctionsInVulkanGLSL to avoid it, as there's no easy
// way to handle such function calls inside if conditions and such.
//
// It might be simplest to do this for bools in structs as well, to avoid having to
// convert between an old and new struct type if the struct is used both inside and
// outside an interface block.
//
// http://anglebug.com/4889.
spirv::WriteTypeBool(&mSpirvTypeAndConstantDecls, typeId); spirv::WriteTypeBool(&mSpirvTypeAndConstantDecls, typeId);
break; break;
default: default:
...@@ -836,6 +853,41 @@ spirv::IdRef SPIRVBuilder::getFloatConstant(float value) ...@@ -836,6 +853,41 @@ spirv::IdRef SPIRVBuilder::getFloatConstant(float value)
return getBasicConstantHelper(asUint.u, EbtFloat, &mFloatConstants); return getBasicConstantHelper(asUint.u, EbtFloat, &mFloatConstants);
} }
spirv::IdRef SPIRVBuilder::getVectorConstantHelper(spirv::IdRef valueId, TBasicType type, int size)
{
if (size == 1)
{
return valueId;
}
SpirvType vecType;
vecType.type = type;
vecType.primarySize = static_cast<uint8_t>(size);
const spirv::IdRef typeId = getSpirvTypeData(vecType, nullptr).id;
const spirv::IdRefList valueIds(size, valueId);
return getCompositeConstant(typeId, valueIds);
}
spirv::IdRef SPIRVBuilder::getUvecConstant(uint32_t value, int size)
{
const spirv::IdRef valueId = getUintConstant(value);
return getVectorConstantHelper(valueId, EbtUInt, size);
}
spirv::IdRef SPIRVBuilder::getIvecConstant(int32_t value, int size)
{
const spirv::IdRef valueId = getIntConstant(value);
return getVectorConstantHelper(valueId, EbtInt, size);
}
spirv::IdRef SPIRVBuilder::getVecConstant(float value, int size)
{
const spirv::IdRef valueId = getFloatConstant(value);
return getVectorConstantHelper(valueId, EbtFloat, size);
}
spirv::IdRef SPIRVBuilder::getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values) spirv::IdRef SPIRVBuilder::getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values)
{ {
SpirvIdAndIdList key{typeId, values}; SpirvIdAndIdList key{typeId, values};
......
...@@ -323,6 +323,9 @@ class SPIRVBuilder : angle::NonCopyable ...@@ -323,6 +323,9 @@ class SPIRVBuilder : angle::NonCopyable
spirv::IdRef getUintConstant(uint32_t value); spirv::IdRef getUintConstant(uint32_t value);
spirv::IdRef getIntConstant(int32_t value); spirv::IdRef getIntConstant(int32_t value);
spirv::IdRef getFloatConstant(float value); spirv::IdRef getFloatConstant(float value);
spirv::IdRef getUvecConstant(uint32_t value, int size);
spirv::IdRef getIvecConstant(int32_t value, int size);
spirv::IdRef getVecConstant(float value, int size);
spirv::IdRef getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values); spirv::IdRef getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values);
// Helpers to start and end a function. // Helpers to start and end a function.
...@@ -381,6 +384,7 @@ class SPIRVBuilder : angle::NonCopyable ...@@ -381,6 +384,7 @@ class SPIRVBuilder : angle::NonCopyable
spirv::IdRef getBasicConstantHelper(uint32_t value, spirv::IdRef getBasicConstantHelper(uint32_t value,
TBasicType type, TBasicType type,
angle::HashMap<uint32_t, spirv::IdRef> *constants); angle::HashMap<uint32_t, spirv::IdRef> *constants);
spirv::IdRef getVectorConstantHelper(spirv::IdRef valueId, TBasicType type, int size);
uint32_t nextUnusedBinding(); uint32_t nextUnusedBinding();
uint32_t nextUnusedInputLocation(uint32_t consumedCount); uint32_t nextUnusedInputLocation(uint32_t consumedCount);
......
...@@ -216,9 +216,12 @@ class OutputSPIRVTraverser : public TIntermTraverser ...@@ -216,9 +216,12 @@ class OutputSPIRVTraverser : public TIntermTraverser
spirv::IdRef createConstructorVectorFromScalar(const TType &type, spirv::IdRef createConstructorVectorFromScalar(const TType &type,
spirv::IdRef typeId, spirv::IdRef typeId,
const spirv::IdRefList &parameters); const spirv::IdRefList &parameters);
spirv::IdRef createConstructorVectorFromNonScalar(TIntermAggregate *node, spirv::IdRef createConstructorVectorFromMatrix(TIntermAggregate *node,
spirv::IdRef typeId, spirv::IdRef typeId,
const spirv::IdRefList &parameters); const spirv::IdRefList &parameters);
spirv::IdRef createConstructorVectorFromScalarsAndVectors(TIntermAggregate *node,
spirv::IdRef typeId,
const spirv::IdRefList &parameters);
spirv::IdRef createConstructorMatrixFromScalar(TIntermAggregate *node, spirv::IdRef createConstructorMatrixFromScalar(TIntermAggregate *node,
spirv::IdRef typeId, spirv::IdRef typeId,
const spirv::IdRefList &parameters); const spirv::IdRefList &parameters);
...@@ -244,6 +247,21 @@ class OutputSPIRVTraverser : public TIntermTraverser ...@@ -244,6 +247,21 @@ class OutputSPIRVTraverser : public TIntermTraverser
spirv::IdRef createFunctionCall(TIntermAggregate *node, spirv::IdRef resultTypeId); spirv::IdRef createFunctionCall(TIntermAggregate *node, spirv::IdRef resultTypeId);
// Cast between types. There are two kinds of casts:
//
// - A constructor can cast between basic types, for example vec4(someInt).
// - Assignments, constructors, function calls etc may copy an array or struct between different
// block storages or invariance (which due to their decorations generate different SPIR-V
// types). For example:
//
// layout(std140) uniform U { invariant Struct s; } u; ... Struct s2 = u.s;
//
// TODO: implement casts due to block storage and invariance differences.
// http://anglebug.com/4889
spirv::IdRef castBasicType(spirv::IdRef value,
const TType &valueType,
TBasicType expectedBasicType);
TCompiler *mCompiler; TCompiler *mCompiler;
ShCompileOptions mCompileOptions; ShCompileOptions mCompileOptions;
...@@ -1009,24 +1027,28 @@ spirv::IdRef OutputSPIRVTraverser::createConstructor(TIntermAggregate *node, spi ...@@ -1009,24 +1027,28 @@ spirv::IdRef OutputSPIRVTraverser::createConstructor(TIntermAggregate *node, spi
if (type.isScalar()) if (type.isScalar())
{ {
// TODO: handle casting. http://anglebug.com/4889. return castBasicType(parameters[0], arg0Type, type.getBasicType());
return parameters[0];
} }
if (type.isVector()) if (type.isVector())
{ {
if (arguments.size() == 1 && arg0Type.isScalar()) if (arguments.size() == 1 && arg0Type.isScalar())
{ {
parameters[0] = castBasicType(parameters[0], arg0Type, type.getBasicType());
return createConstructorVectorFromScalar(node->getType(), typeId, parameters); return createConstructorVectorFromScalar(node->getType(), typeId, parameters);
} }
if (arguments.size() == 1 && arg0Type.isMatrix())
return createConstructorVectorFromNonScalar(node, typeId, parameters); {
return createConstructorVectorFromMatrix(node, typeId, parameters);
}
return createConstructorVectorFromScalarsAndVectors(node, typeId, parameters);
} }
ASSERT(type.isMatrix()); ASSERT(type.isMatrix());
if (arg0Type.isScalar()) if (arg0Type.isScalar())
{ {
parameters[0] = castBasicType(parameters[0], arg0Type, type.getBasicType());
return createConstructorMatrixFromScalar(node, typeId, parameters); return createConstructorMatrixFromScalar(node, typeId, parameters);
} }
if (arg0Type.isMatrix()) if (arg0Type.isMatrix())
...@@ -1062,16 +1084,51 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorVectorFromScalar( ...@@ -1062,16 +1084,51 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorVectorFromScalar(
return result; return result;
} }
spirv::IdRef OutputSPIRVTraverser::createConstructorVectorFromNonScalar( spirv::IdRef OutputSPIRVTraverser::createConstructorVectorFromMatrix(
TIntermAggregate *node, TIntermAggregate *node,
spirv::IdRef typeId, spirv::IdRef typeId,
const spirv::IdRefList &parameters) const spirv::IdRefList &parameters)
{ {
// vecN(v1.zy, v2.x) translates to OpCompositeConstruct %vecN %v1.z %v1.y %v2.x
// vecN(m) translates to OpCompositeConstruct %vecN %m[0][0] %m[0][1] ... // vecN(m) translates to OpCompositeConstruct %vecN %m[0][0] %m[0][1] ...
spirv::IdRefList extractedComponents; spirv::IdRefList extractedComponents;
extractComponents(node, node->getType().getNominalSize(), parameters, &extractedComponents); extractComponents(node, node->getType().getNominalSize(), parameters, &extractedComponents);
// Construct the vector with the basic type of the argument, and cast it at end if needed.
ASSERT(parameters.size() == 1);
const TType &arg0Type = node->getChildNode(0)->getAsTyped()->getType();
const TBasicType expectedBasicType = node->getType().getBasicType();
spirv::IdRef argumentTypeId = typeId;
TType arg0TypeAsVector(arg0Type);
arg0TypeAsVector.setPrimarySize(static_cast<unsigned char>(node->getType().getNominalSize()));
arg0TypeAsVector.setSecondarySize(1);
if (arg0Type.getBasicType() != expectedBasicType)
{
argumentTypeId = mBuilder.getTypeData(arg0TypeAsVector, EbsUnspecified).id;
}
spirv::IdRef result = mBuilder.getNewId(mBuilder.getDecorations(node->getType()));
spirv::WriteCompositeConstruct(mBuilder.getSpirvCurrentFunctionBlock(), argumentTypeId, result,
extractedComponents);
if (arg0Type.getBasicType() != expectedBasicType)
{
result = castBasicType(result, arg0TypeAsVector, expectedBasicType);
}
return result;
}
spirv::IdRef OutputSPIRVTraverser::createConstructorVectorFromScalarsAndVectors(
TIntermAggregate *node,
spirv::IdRef typeId,
const spirv::IdRefList &parameters)
{
// vecN(v1.zy, v2.x) translates to OpCompositeConstruct %vecN %v1.z %v1.y %v2.x
spirv::IdRefList extractedComponents;
extractComponents(node, node->getType().getNominalSize(), parameters, &extractedComponents);
const spirv::IdRef result = mBuilder.getNewId(mBuilder.getDecorations(node->getType())); const spirv::IdRef result = mBuilder.getNewId(mBuilder.getDecorations(node->getType()));
spirv::WriteCompositeConstruct(mBuilder.getSpirvCurrentFunctionBlock(), typeId, result, spirv::WriteCompositeConstruct(mBuilder.getSpirvCurrentFunctionBlock(), typeId, result,
extractedComponents); extractedComponents);
...@@ -1091,8 +1148,7 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromScalar( ...@@ -1091,8 +1148,7 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromScalar(
// ... // ...
// %m = OpCompositeConstruct %matNxM %c0 %c1 %c2 ... // %m = OpCompositeConstruct %matNxM %c0 %c1 %c2 ...
const TType &type = node->getType(); const TType &type = node->getType();
// TODO: handle casting. http://anglebug.com/4889.
const spirv::IdRef scalarId = parameters[0]; const spirv::IdRef scalarId = parameters[0];
spirv::IdRef zeroId; spirv::IdRef zeroId;
...@@ -1129,8 +1185,11 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromScalar( ...@@ -1129,8 +1185,11 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromScalar(
columnIds.push_back(mBuilder.getNewId(decorations)); columnIds.push_back(mBuilder.getNewId(decorations));
// Place the scalar at the correct index (diagonal of the matrix, i.e. row == col). // Place the scalar at the correct index (diagonal of the matrix, i.e. row == col).
componentIds[columnIndex] = scalarId; if (columnIndex < type.getRows())
if (columnIndex > 0) {
componentIds[columnIndex] = scalarId;
}
if (columnIndex > 0 && columnIndex <= type.getRows())
{ {
componentIds[columnIndex - 1] = zeroId; componentIds[columnIndex - 1] = zeroId;
} }
...@@ -1220,8 +1279,6 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromMatrix( ...@@ -1220,8 +1279,6 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromMatrix(
SpirvDecorations decorations = mBuilder.getDecorations(type); SpirvDecorations decorations = mBuilder.getDecorations(type);
// TODO: handle casting. http://anglebug.com/4889.
ASSERT(parameters.size() == 1); ASSERT(parameters.size() == 1);
spirv::IdRefList columnIds; spirv::IdRefList columnIds;
...@@ -1361,9 +1418,8 @@ void OutputSPIRVTraverser::extractComponents(TIntermAggregate *node, ...@@ -1361,9 +1418,8 @@ void OutputSPIRVTraverser::extractComponents(TIntermAggregate *node,
// more components than necessary) and extracts the first componentCount components. // more components than necessary) and extracts the first componentCount components.
const TIntermSequence &arguments = *node->getSequence(); const TIntermSequence &arguments = *node->getSequence();
SpirvDecorations decorations = mBuilder.getDecorations(node->getType()); const SpirvDecorations decorations = mBuilder.getDecorations(node->getType());
const TBasicType expectedBasicType = node->getType().getBasicType();
// TODO: handle casting. http://anglebug.com/4889.
ASSERT(arguments.size() == parameters.size()); ASSERT(arguments.size() == parameters.size());
...@@ -1371,22 +1427,34 @@ void OutputSPIRVTraverser::extractComponents(TIntermAggregate *node, ...@@ -1371,22 +1427,34 @@ void OutputSPIRVTraverser::extractComponents(TIntermAggregate *node,
argumentIndex < arguments.size() && extractedComponentsOut->size() < componentCount; argumentIndex < arguments.size() && extractedComponentsOut->size() < componentCount;
++argumentIndex) ++argumentIndex)
{ {
const TType &argumentType = arguments[argumentIndex]->getAsTyped()->getType(); TIntermNode *argument = arguments[argumentIndex];
const TType &argumentType = argument->getAsTyped()->getType();
const spirv::IdRef parameterId = parameters[argumentIndex]; const spirv::IdRef parameterId = parameters[argumentIndex];
if (argumentType.isScalar()) if (argumentType.isScalar())
{ {
// For scalar parameters, there's nothing to do. // For scalar parameters, there's nothing to do other than a potential cast.
extractedComponentsOut->push_back(parameterId); const spirv::IdRef castParameterId =
argument->getAsConstantUnion()
? parameterId
: castBasicType(parameterId, argumentType, expectedBasicType);
extractedComponentsOut->push_back(castParameterId);
continue; continue;
} }
if (argumentType.isVector()) if (argumentType.isVector())
{ {
SpirvType componentType = mBuilder.getSpirvType(argumentType, EbsUnspecified); SpirvType componentType = mBuilder.getSpirvType(argumentType, EbsUnspecified);
componentType.type = expectedBasicType;
componentType.primarySize = 1; componentType.primarySize = 1;
const spirv::IdRef componentTypeId = const spirv::IdRef componentTypeId =
mBuilder.getSpirvTypeData(componentType, nullptr).id; mBuilder.getSpirvTypeData(componentType, nullptr).id;
// Cast the whole vector parameter in one go.
const spirv::IdRef castParameterId =
argument->getAsConstantUnion()
? parameterId
: castBasicType(parameterId, argumentType, expectedBasicType);
// For vector parameters, take components out of the vector one by one. // For vector parameters, take components out of the vector one by one.
for (int componentIndex = 0; componentIndex < argumentType.getNominalSize() && for (int componentIndex = 0; componentIndex < argumentType.getNominalSize() &&
extractedComponentsOut->size() < componentCount; extractedComponentsOut->size() < componentCount;
...@@ -1394,7 +1462,7 @@ void OutputSPIRVTraverser::extractComponents(TIntermAggregate *node, ...@@ -1394,7 +1462,7 @@ void OutputSPIRVTraverser::extractComponents(TIntermAggregate *node,
{ {
const spirv::IdRef componentId = mBuilder.getNewId(decorations); const spirv::IdRef componentId = mBuilder.getNewId(decorations);
spirv::WriteCompositeExtract(mBuilder.getSpirvCurrentFunctionBlock(), spirv::WriteCompositeExtract(mBuilder.getSpirvCurrentFunctionBlock(),
componentTypeId, componentId, parameterId, componentTypeId, componentId, castParameterId,
{spirv::LiteralInteger(componentIndex)}); {spirv::LiteralInteger(componentIndex)});
extractedComponentsOut->push_back(componentId); extractedComponentsOut->push_back(componentId);
...@@ -1410,7 +1478,8 @@ void OutputSPIRVTraverser::extractComponents(TIntermAggregate *node, ...@@ -1410,7 +1478,8 @@ void OutputSPIRVTraverser::extractComponents(TIntermAggregate *node,
const spirv::IdRef componentTypeId = mBuilder.getSpirvTypeData(componentType, nullptr).id; const spirv::IdRef componentTypeId = mBuilder.getSpirvTypeData(componentType, nullptr).id;
// For matrix parameters, take components out of the matrix one by one in column-major // For matrix parameters, take components out of the matrix one by one in column-major
// order. // order. No cast is done here; it would only be required for vector constructors with
// matrix parameters, in which case the resulting vector is cast in the end.
for (int columnIndex = 0; columnIndex < argumentType.getCols() && for (int columnIndex = 0; columnIndex < argumentType.getCols() &&
extractedComponentsOut->size() < componentCount; extractedComponentsOut->size() < componentCount;
++columnIndex) ++columnIndex)
...@@ -1547,20 +1616,17 @@ spirv::IdRef OutputSPIRVTraverser::createFunctionCall(TIntermAggregate *node, ...@@ -1547,20 +1616,17 @@ spirv::IdRef OutputSPIRVTraverser::createFunctionCall(TIntermAggregate *node,
spirv::IdRef paramValue; spirv::IdRef paramValue;
SpirvDecorations decorations = mBuilder.getDecorations(paramType); SpirvDecorations decorations = mBuilder.getDecorations(paramType);
if (IsOpaqueType(paramType.getBasicType()) || paramQualifier == EvqConst) if (paramQualifier == EvqConst)
{ {
// The following parameters are passed as rvalue: // |const| parameters are passed as rvalue.
//
// - Opaque uniforms,
// - const parameters,
paramValue = accessChainLoad(&param, decorations); paramValue = accessChainLoad(&param, decorations);
} }
else if (IsAccessChainUnindexedLValue(param) && else if (IsAccessChainUnindexedLValue(param) &&
(mCompileOptions & SH_GENERATE_SPIRV_WORKAROUNDS) == 0) (IsOpaqueType(paramType.getBasicType()) ||
(param.accessChain.storageClass == spv::StorageClassFunction &&
(mCompileOptions & SH_GENERATE_SPIRV_WORKAROUNDS) == 0)))
{ {
// The following parameters are passed directly: // Unindexed lvalues are passed directly.
//
// - unindexed lvalues.
// //
// This optimization is not applied on buggy drivers. http://anglebug.com/6110. // This optimization is not applied on buggy drivers. http://anglebug.com/6110.
paramValue = param.baseId; paramValue = param.baseId;
...@@ -3355,6 +3421,122 @@ spirv::IdRef OutputSPIRVTraverser::createImageTextureBuiltIn(TIntermOperator *no ...@@ -3355,6 +3421,122 @@ spirv::IdRef OutputSPIRVTraverser::createImageTextureBuiltIn(TIntermOperator *no
return result; return result;
} }
spirv::IdRef OutputSPIRVTraverser::castBasicType(spirv::IdRef value,
const TType &valueType,
TBasicType expectedBasicType)
{
if (valueType.getBasicType() == expectedBasicType)
{
return value;
}
SpirvType valueSpirvType = mBuilder.getSpirvType(valueType, EbsUnspecified);
valueSpirvType.type = expectedBasicType;
const spirv::IdRef castTypeId = mBuilder.getSpirvTypeData(valueSpirvType, nullptr).id;
const spirv::IdRef castValue = mBuilder.getNewId(mBuilder.getDecorations(valueType));
// Write the instruction that casts between types. Different instructions are used based on the
// types being converted.
//
// - int/uint <-> float: OpConvert*To*
// - int <-> uint: OpBitcast
// - bool --> int/uint/float: OpSelect with 0 and 1
// - int/uint --> bool: OPINotEqual 0
// - float --> bool: OpFUnordNotEqual 0
WriteUnaryOp writeUnaryOp = nullptr;
WriteBinaryOp writeBinaryOp = nullptr;
WriteTernaryOp writeTernaryOp = nullptr;
spirv::IdRef zero;
spirv::IdRef one;
switch (valueType.getBasicType())
{
case EbtFloat:
switch (expectedBasicType)
{
case EbtInt:
writeUnaryOp = spirv::WriteConvertFToS;
break;
case EbtUInt:
writeUnaryOp = spirv::WriteConvertFToU;
break;
case EbtBool:
zero = mBuilder.getVecConstant(0, valueType.getNominalSize());
writeBinaryOp = spirv::WriteFUnordNotEqual;
break;
default:
UNREACHABLE();
}
break;
case EbtInt:
case EbtUInt:
switch (expectedBasicType)
{
case EbtFloat:
writeUnaryOp = valueType.getBasicType() == EbtInt ? spirv::WriteConvertSToF
: spirv::WriteConvertUToF;
break;
case EbtInt:
case EbtUInt:
writeUnaryOp = spirv::WriteBitcast;
break;
case EbtBool:
zero = mBuilder.getUvecConstant(0, valueType.getNominalSize());
writeBinaryOp = spirv::WriteINotEqual;
break;
default:
UNREACHABLE();
}
break;
case EbtBool:
writeTernaryOp = spirv::WriteSelect;
switch (expectedBasicType)
{
case EbtFloat:
zero = mBuilder.getVecConstant(0, valueType.getNominalSize());
one = mBuilder.getVecConstant(1, valueType.getNominalSize());
break;
case EbtInt:
zero = mBuilder.getIvecConstant(0, valueType.getNominalSize());
one = mBuilder.getIvecConstant(1, valueType.getNominalSize());
break;
case EbtUInt:
zero = mBuilder.getUvecConstant(0, valueType.getNominalSize());
one = mBuilder.getUvecConstant(1, valueType.getNominalSize());
break;
default:
UNREACHABLE();
}
break;
default:
// TODO: support desktop GLSL. http://anglebug.com/4889.
UNIMPLEMENTED();
}
if (writeUnaryOp)
{
writeUnaryOp(mBuilder.getSpirvCurrentFunctionBlock(), castTypeId, castValue, value);
}
else if (writeBinaryOp)
{
writeBinaryOp(mBuilder.getSpirvCurrentFunctionBlock(), castTypeId, castValue, value, zero);
}
else
{
ASSERT(writeTernaryOp);
writeTernaryOp(mBuilder.getSpirvCurrentFunctionBlock(), castTypeId, castValue, value, one,
zero);
}
return castValue;
}
void OutputSPIRVTraverser::visitSymbol(TIntermSymbol *node) void OutputSPIRVTraverser::visitSymbol(TIntermSymbol *node)
{ {
// Constants are expected to be folded. // Constants are expected to be folded.
...@@ -4225,7 +4407,10 @@ void OutputSPIRVTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node ...@@ -4225,7 +4407,10 @@ void OutputSPIRVTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node
// with the Function storage class. // with the Function storage class.
if (paramType.getQualifier() != EvqConst) if (paramType.getQualifier() != EvqConst)
{ {
paramId = mBuilder.getTypePointerId(paramId, spv::StorageClassFunction); const spv::StorageClass storageClass = IsOpaqueType(paramType.getBasicType())
? spv::StorageClassUniformConstant
: spv::StorageClassFunction;
paramId = mBuilder.getTypePointerId(paramId, storageClass);
} }
ids.parameterTypeIds.push_back(paramId); ids.parameterTypeIds.push_back(paramId);
......
...@@ -3376,7 +3376,9 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferTest_ES3); ...@@ -3376,7 +3376,9 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferTest_ES3);
ANGLE_INSTANTIATE_TEST_ES3_AND(FramebufferTest_ES3, ANGLE_INSTANTIATE_TEST_ES3_AND(FramebufferTest_ES3,
WithEmulatedPrerotation(ES3_VULKAN(), 90), WithEmulatedPrerotation(ES3_VULKAN(), 90),
WithEmulatedPrerotation(ES3_VULKAN(), 180), WithEmulatedPrerotation(ES3_VULKAN(), 180),
WithEmulatedPrerotation(ES3_VULKAN(), 270)); WithEmulatedPrerotation(ES3_VULKAN(), 270),
WithDirectSPIRVGeneration(WithEmulatedPrerotation(ES3_VULKAN(),
90)));
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferTest_ES31); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferTest_ES31);
ANGLE_INSTANTIATE_TEST_ES31(FramebufferTest_ES31); ANGLE_INSTANTIATE_TEST_ES31(FramebufferTest_ES31);
...@@ -2585,6 +2585,83 @@ TEST_P(GLSLTest_ES3, AmbiguousFunctionCall2x2) ...@@ -2585,6 +2585,83 @@ TEST_P(GLSLTest_ES3, AmbiguousFunctionCall2x2)
EXPECT_NE(0u, program); EXPECT_NE(0u, program);
} }
// Test that constructing matrices from non-float types works.
TEST_P(GLSLTest_ES3, ConstructMatrixFromNonFloat)
{
constexpr char kFS[] = R"(#version 300 es
precision highp float;
out vec4 color;
uniform int i;
uniform uint u;
void main()
{
bool b = i > 10;
mat3x2 mi = mat3x2(i);
mat4 mu = mat4(u);
mat2x4 mb = mat2x4(b);
mat3x2 m = mat3x2(ivec2(i), uvec2(u), bvec2(b));
color = vec4(mi[0][0] == float(i) ? 1 : 0,
mu[2][2] == float(u) ? 1 : 0,
mb[1][1] == float(b) ? 1 : 0,
m[0][1] == float(i) && m[1][0] == float(u) && m[2][0] == float(b) ? 1 : 0);
})";
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
glUseProgram(program);
GLint iloc = glGetUniformLocation(program, "i");
GLint uloc = glGetUniformLocation(program, "u");
ASSERT_NE(iloc, -1);
ASSERT_NE(uloc, -1);
glUniform1i(iloc, -123);
glUniform1ui(uloc, 456);
drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
}
// Test that constructing non-float vectors from matrix types works.
TEST_P(GLSLTest_ES3, ConstructNonFloatVectorFromMatrix)
{
constexpr char kFS[] = R"(#version 300 es
precision highp float;
out vec4 color;
uniform float f;
void main()
{
mat4 m = mat4(f);
ivec3 vi = ivec3(m);
uvec2 vu = uvec2(m);
bvec4 vb = bvec4(m);
color = vec4(vi.x == int(f) ? 1 : 0,
vu.x == uint(f) ? 1 : 0,
vb.x == bool(f) ? 1 : 0,
1);
})";
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
glUseProgram(program);
GLint floc = glGetUniformLocation(program, "f");
ASSERT_NE(floc, -1);
glUniform1f(floc, 123);
drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
}
// Test that an user-defined function with a large number of float4 parameters doesn't fail due to // Test that an user-defined function with a large number of float4 parameters doesn't fail due to
// the function name being too long. // the function name being too long.
TEST_P(GLSLTest_ES3, LargeNumberOfFloat4Parameters) TEST_P(GLSLTest_ES3, LargeNumberOfFloat4Parameters)
......
...@@ -9468,7 +9468,8 @@ ANGLE_INSTANTIATE_TEST_ES2(TextureCubeTest); ...@@ -9468,7 +9468,8 @@ ANGLE_INSTANTIATE_TEST_ES2(TextureCubeTest);
ANGLE_INSTANTIATE_TEST_ES2(Texture2DTestWithDrawScale); ANGLE_INSTANTIATE_TEST_ES2(Texture2DTestWithDrawScale);
ANGLE_INSTANTIATE_TEST_ES2(Sampler2DAsFunctionParameterTest); ANGLE_INSTANTIATE_TEST_ES2(Sampler2DAsFunctionParameterTest);
ANGLE_INSTANTIATE_TEST_ES2(SamplerArrayTest); ANGLE_INSTANTIATE_TEST_ES2(SamplerArrayTest);
ANGLE_INSTANTIATE_TEST_ES2(SamplerArrayAsFunctionParameterTest); ANGLE_INSTANTIATE_TEST_ES2_AND(SamplerArrayAsFunctionParameterTest,
WithDirectSPIRVGeneration(ES2_VULKAN()));
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DTestES3); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DTestES3);
ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DTestES3, WithAllocateNonZeroMemory(ES3_VULKAN())); ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DTestES3, WithAllocateNonZeroMemory(ES3_VULKAN()));
...@@ -9501,7 +9502,8 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DArrayTestES3); ...@@ -9501,7 +9502,8 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DArrayTestES3);
ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DArrayTestES3, WithDirectSPIRVGeneration(ES3_VULKAN())); ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DArrayTestES3, WithDirectSPIRVGeneration(ES3_VULKAN()));
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TextureSizeTextureArrayTest); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TextureSizeTextureArrayTest);
ANGLE_INSTANTIATE_TEST_ES3(TextureSizeTextureArrayTest); ANGLE_INSTANTIATE_TEST_ES3_AND(TextureSizeTextureArrayTest,
WithDirectSPIRVGeneration(ES3_VULKAN()));
ANGLE_INSTANTIATE_TEST_ES2(SamplerInStructTest); ANGLE_INSTANTIATE_TEST_ES2(SamplerInStructTest);
ANGLE_INSTANTIATE_TEST_ES2(SamplerInStructAsFunctionParameterTest); ANGLE_INSTANTIATE_TEST_ES2(SamplerInStructAsFunctionParameterTest);
...@@ -9546,10 +9548,12 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TextureCubeIntegerEdgeTestES3); ...@@ -9546,10 +9548,12 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TextureCubeIntegerEdgeTestES3);
ANGLE_INSTANTIATE_TEST_ES3(TextureCubeIntegerEdgeTestES3); ANGLE_INSTANTIATE_TEST_ES3(TextureCubeIntegerEdgeTestES3);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DIntegerProjectiveOffsetTestES3); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DIntegerProjectiveOffsetTestES3);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DIntegerProjectiveOffsetTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DIntegerProjectiveOffsetTestES3,
WithDirectSPIRVGeneration(ES3_VULKAN()));
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DArrayIntegerTestES3); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DArrayIntegerTestES3);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DArrayIntegerTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DArrayIntegerTestES3,
WithDirectSPIRVGeneration(ES3_VULKAN()));
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture3DIntegerTestES3); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture3DIntegerTestES3);
ANGLE_INSTANTIATE_TEST_ES3(Texture3DIntegerTestES3); ANGLE_INSTANTIATE_TEST_ES3(Texture3DIntegerTestES3);
......
...@@ -168,6 +168,11 @@ struct CombinedPrintToStringParamName ...@@ -168,6 +168,11 @@ struct CombinedPrintToStringParamName
INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \ INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \
testing::PrintToStringParamName()) testing::PrintToStringParamName())
#define ANGLE_INSTANTIATE_TEST_ES2_AND(testName, ...) \
const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES2, __VA_ARGS__}; \
INSTANTIATE_TEST_SUITE_P(, testName, ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \
testing::PrintToStringParamName())
// Instantiate the test once for each GLES3 platform // Instantiate the test once for each GLES3 platform
#define ANGLE_INSTANTIATE_TEST_ES3(testName) \ #define ANGLE_INSTANTIATE_TEST_ES3(testName) \
const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES3}; \ const PlatformParameters testName##params[] = {ANGLE_ALL_TEST_PLATFORMS_ES3}; \
......
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