зеркало из https://github.com/AvaloniaUI/angle.git
Vulkan: SPIR-V Gen: Assignment between mismatching SPIR-V types
In general, GLSL qualifiers translate to SPIR-V decorations on SPIR-V variables. In the case of blocks (struct or interface block), OpMemberDecorate is used, which due to its specification in SPIR-V, can only apply decorations to direct members of a block. This makes it impossible for example to decorate a nested member of a block through its variable id. As such, some decorations such as RowMajor and Invariant apply to members of a block given its _type_ id. Unfortunately SPIR-V requires ArrayStride to also be applied to a type directly, rather than a member of a block. This implies that some types, such as structs used in uniform/buffer interface block, or decorated with invariant or row_major, as well as arrays (of any type) used inside and outside interface blocks to produce different SPIR-V types from the same GLSL type. The SpirvTypeSpec data previously introduced specialize these types. It's necessary to "cast" between these types when needed. The translator handles casts at load/store boundary: - Upon load, the value is cast to the type with the default SpirvTypeSpec. - Upon store, the value is cast from the default to the store target SpirvTypeSpec. - All intermediate results use the default SpirvTypeSpec. Bug: angleproject:4889 Change-Id: I6fa28e518ec6b517ff163f44b6892859eb4b10fd Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3026145 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Родитель
5e579a1879
Коммит
9c6fb52c74
|
@ -1541,9 +1541,6 @@ void SPIRVBuilder::writeInterfaceVariableDecorations(const TType &type, spirv::I
|
||||||
const bool needsBlendIndex =
|
const bool needsBlendIndex =
|
||||||
type.getQualifier() == EvqFragmentOut && layoutQualifier.index >= 0;
|
type.getQualifier() == EvqFragmentOut && layoutQualifier.index >= 0;
|
||||||
|
|
||||||
// TODO: handle row-major matrixes. http://anglebug.com/4889.
|
|
||||||
// TODO: handle invariant (spv::DecorationInvariant).
|
|
||||||
|
|
||||||
// If the resource declaration requires set & binding, add the DescriptorSet and Binding
|
// If the resource declaration requires set & binding, add the DescriptorSet and Binding
|
||||||
// decorations.
|
// decorations.
|
||||||
if (needsSetBinding)
|
if (needsSetBinding)
|
||||||
|
|
|
@ -194,8 +194,8 @@ class OutputSPIRVTraverser : public TIntermTraverser
|
||||||
uint8_t componentCount) const;
|
uint8_t componentCount) const;
|
||||||
void accessChainPushDynamicComponent(NodeData *data, spirv::IdRef index, spirv::IdRef typeId);
|
void accessChainPushDynamicComponent(NodeData *data, spirv::IdRef index, spirv::IdRef typeId);
|
||||||
spirv::IdRef accessChainCollapse(NodeData *data);
|
spirv::IdRef accessChainCollapse(NodeData *data);
|
||||||
spirv::IdRef accessChainLoad(NodeData *data, const SpirvDecorations &decorations);
|
spirv::IdRef accessChainLoad(NodeData *data, const TType &valueType);
|
||||||
void accessChainStore(NodeData *data, spirv::IdRef value);
|
void accessChainStore(NodeData *data, spirv::IdRef value, const TType &valueType);
|
||||||
|
|
||||||
// Access chain helpers.
|
// Access chain helpers.
|
||||||
void makeAccessChainIdList(NodeData *data, spirv::IdRefList *idsOut);
|
void makeAccessChainIdList(NodeData *data, spirv::IdRefList *idsOut);
|
||||||
|
@ -261,16 +261,18 @@ class OutputSPIRVTraverser : public TIntermTraverser
|
||||||
//
|
//
|
||||||
// - A constructor can cast between basic types, for example vec4(someInt).
|
// - A constructor can cast between basic types, for example vec4(someInt).
|
||||||
// - Assignments, constructors, function calls etc may copy an array or struct between different
|
// - 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
|
// block storages, invariance etc (which due to their decorations generate different SPIR-V
|
||||||
// types). For example:
|
// types). For example:
|
||||||
//
|
//
|
||||||
// layout(std140) uniform U { invariant Struct s; } u; ... Struct s2 = u.s;
|
// 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,
|
spirv::IdRef castBasicType(spirv::IdRef value,
|
||||||
const TType &valueType,
|
const TType &valueType,
|
||||||
TBasicType expectedBasicType);
|
TBasicType expectedBasicType);
|
||||||
|
spirv::IdRef cast(spirv::IdRef value,
|
||||||
|
const TType &valueType,
|
||||||
|
const SpirvTypeSpec &valueTypeSpec,
|
||||||
|
const SpirvTypeSpec &expectedTypeSpec);
|
||||||
|
|
||||||
// Helper to reduce vector == and != with OpAll and OpAny respectively. If multiple ids are
|
// Helper to reduce vector == and != with OpAll and OpAny respectively. If multiple ids are
|
||||||
// given, either OpLogicalAnd or OpLogicalOr is used (if two operands) or a bool vector is
|
// given, either OpLogicalAnd or OpLogicalOr is used (if two operands) or a bool vector is
|
||||||
|
@ -686,9 +688,10 @@ spirv::IdRef OutputSPIRVTraverser::accessChainCollapse(NodeData *data)
|
||||||
return accessChain.accessChainId;
|
return accessChain.accessChainId;
|
||||||
}
|
}
|
||||||
|
|
||||||
spirv::IdRef OutputSPIRVTraverser::accessChainLoad(NodeData *data,
|
spirv::IdRef OutputSPIRVTraverser::accessChainLoad(NodeData *data, const TType &valueType)
|
||||||
const SpirvDecorations &decorations)
|
|
||||||
{
|
{
|
||||||
|
const SpirvDecorations &decorations = mBuilder.getDecorations(valueType);
|
||||||
|
|
||||||
// Loading through the access chain can generate different instructions based on whether it's an
|
// Loading through the access chain can generate different instructions based on whether it's an
|
||||||
// rvalue, the indices are literal, there's a swizzle etc.
|
// rvalue, the indices are literal, there's a swizzle etc.
|
||||||
//
|
//
|
||||||
|
@ -788,10 +791,15 @@ spirv::IdRef OutputSPIRVTraverser::accessChainLoad(NodeData *data,
|
||||||
loadResult = result;
|
loadResult = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadResult;
|
// Upon loading values, cast them to the default SPIR-V variant.
|
||||||
|
const spirv::IdRef castResult = cast(loadResult, valueType, accessChain.typeSpec, {});
|
||||||
|
|
||||||
|
return castResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutputSPIRVTraverser::accessChainStore(NodeData *data, spirv::IdRef value)
|
void OutputSPIRVTraverser::accessChainStore(NodeData *data,
|
||||||
|
spirv::IdRef value,
|
||||||
|
const TType &valueType)
|
||||||
{
|
{
|
||||||
// Storing through the access chain can generate different instructions based on whether the
|
// Storing through the access chain can generate different instructions based on whether the
|
||||||
// there's a swizzle.
|
// there's a swizzle.
|
||||||
|
@ -853,8 +861,12 @@ void OutputSPIRVTraverser::accessChainStore(NodeData *data, spirv::IdRef value)
|
||||||
value = result;
|
value = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store through the access chain.
|
// Store through the access chain. The values are always cast to the default SPIR-V type
|
||||||
spirv::WriteStore(mBuilder.getSpirvCurrentFunctionBlock(), accessChainId, value, nullptr);
|
// variant when loaded from memory and operated on as such. When storing, we need to cast the
|
||||||
|
// result to the variant specified by the access chain.
|
||||||
|
const spirv::IdRef castValue = cast(value, valueType, {}, accessChain.typeSpec);
|
||||||
|
|
||||||
|
spirv::WriteStore(mBuilder.getSpirvCurrentFunctionBlock(), accessChainId, castValue, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutputSPIRVTraverser::makeAccessChainIdList(NodeData *data, spirv::IdRefList *idsOut)
|
void OutputSPIRVTraverser::makeAccessChainIdList(NodeData *data, spirv::IdRefList *idsOut)
|
||||||
|
@ -1478,11 +1490,8 @@ spirv::IdRefList OutputSPIRVTraverser::loadAllParams(TIntermOperator *node)
|
||||||
// Take each parameter that is visited and evaluate it as rvalue
|
// Take each parameter that is visited and evaluate it as rvalue
|
||||||
NodeData ¶m = mNodeData[mNodeData.size() - parameterCount + paramIndex];
|
NodeData ¶m = mNodeData[mNodeData.size() - parameterCount + paramIndex];
|
||||||
|
|
||||||
const spirv::IdRef paramValue = accessChainLoad(
|
const spirv::IdRef paramValue =
|
||||||
¶m,
|
accessChainLoad(¶m, node->getChildNode(paramIndex)->getAsTyped()->getType());
|
||||||
mBuilder.getDecorations(node->getChildNode(paramIndex)->getAsTyped()->getType()));
|
|
||||||
|
|
||||||
// TODO: handle mismatching types. http://anglebug.com/6000
|
|
||||||
|
|
||||||
parameters.push_back(paramValue);
|
parameters.push_back(paramValue);
|
||||||
}
|
}
|
||||||
|
@ -1593,8 +1602,7 @@ void OutputSPIRVTraverser::startShortCircuit(TIntermBinary *node)
|
||||||
|
|
||||||
// Load |left| and replace the access chain with an rvalue that's the result.
|
// Load |left| and replace the access chain with an rvalue that's the result.
|
||||||
const spirv::IdRef typeId = getAccessChainTypeId(&mNodeData.back());
|
const spirv::IdRef typeId = getAccessChainTypeId(&mNodeData.back());
|
||||||
const spirv::IdRef left =
|
const spirv::IdRef left = accessChainLoad(&mNodeData.back(), node->getLeft()->getType());
|
||||||
accessChainLoad(&mNodeData.back(), mBuilder.getDecorations(node->getLeft()->getType()));
|
|
||||||
nodeDataInitRValue(&mNodeData.back(), left, typeId);
|
nodeDataInitRValue(&mNodeData.back(), left, typeId);
|
||||||
|
|
||||||
// Keep the id of the block |left| was evaluated in.
|
// Keep the id of the block |left| was evaluated in.
|
||||||
|
@ -1619,8 +1627,7 @@ void OutputSPIRVTraverser::startShortCircuit(TIntermBinary *node)
|
||||||
spirv::IdRef OutputSPIRVTraverser::endShortCircuit(TIntermBinary *node, spirv::IdRef *typeId)
|
spirv::IdRef OutputSPIRVTraverser::endShortCircuit(TIntermBinary *node, spirv::IdRef *typeId)
|
||||||
{
|
{
|
||||||
// Load the right hand side.
|
// Load the right hand side.
|
||||||
const spirv::IdRef right =
|
const spirv::IdRef right = accessChainLoad(&mNodeData.back(), node->getRight()->getType());
|
||||||
accessChainLoad(&mNodeData.back(), mBuilder.getDecorations(node->getRight()->getType()));
|
|
||||||
mNodeData.pop_back();
|
mNodeData.pop_back();
|
||||||
|
|
||||||
// Get the id of the block |right| is evaluated in.
|
// Get the id of the block |right| is evaluated in.
|
||||||
|
@ -1695,12 +1702,11 @@ spirv::IdRef OutputSPIRVTraverser::createFunctionCall(TIntermAggregate *node,
|
||||||
NodeData ¶m = mNodeData[mNodeData.size() - parameterCount + paramIndex];
|
NodeData ¶m = mNodeData[mNodeData.size() - parameterCount + paramIndex];
|
||||||
|
|
||||||
spirv::IdRef paramValue;
|
spirv::IdRef paramValue;
|
||||||
SpirvDecorations decorations = mBuilder.getDecorations(paramType);
|
|
||||||
|
|
||||||
if (paramQualifier == EvqConst)
|
if (paramQualifier == EvqConst)
|
||||||
{
|
{
|
||||||
// |const| parameters are passed as rvalue.
|
// |const| parameters are passed as rvalue.
|
||||||
paramValue = accessChainLoad(¶m, decorations);
|
paramValue = accessChainLoad(¶m, paramType);
|
||||||
}
|
}
|
||||||
else if (IsOpaqueType(paramType.getBasicType()))
|
else if (IsOpaqueType(paramType.getBasicType()))
|
||||||
{
|
{
|
||||||
|
@ -1725,15 +1731,13 @@ spirv::IdRef OutputSPIRVTraverser::createFunctionCall(TIntermAggregate *node,
|
||||||
tempVarTypeIds[paramIndex] = mBuilder.getTypeData(paramType, {}).id;
|
tempVarTypeIds[paramIndex] = mBuilder.getTypeData(paramType, {}).id;
|
||||||
tempVarIds[paramIndex] =
|
tempVarIds[paramIndex] =
|
||||||
mBuilder.declareVariable(tempVarTypeIds[paramIndex], spv::StorageClassFunction,
|
mBuilder.declareVariable(tempVarTypeIds[paramIndex], spv::StorageClassFunction,
|
||||||
decorations, nullptr, "param");
|
mBuilder.getDecorations(paramType), nullptr, "param");
|
||||||
|
|
||||||
// If it's an in or inout parameter, the temp variable needs to be initialized with the
|
// If it's an in or inout parameter, the temp variable needs to be initialized with the
|
||||||
// value of the parameter first.
|
// value of the parameter first.
|
||||||
//
|
|
||||||
// TODO: handle mismatching types. http://anglebug.com/6000
|
|
||||||
if (paramQualifier == EvqIn || paramQualifier == EvqInOut)
|
if (paramQualifier == EvqIn || paramQualifier == EvqInOut)
|
||||||
{
|
{
|
||||||
paramValue = accessChainLoad(¶m, decorations);
|
paramValue = accessChainLoad(¶m, paramType);
|
||||||
spirv::WriteStore(mBuilder.getSpirvCurrentFunctionBlock(), tempVarIds[paramIndex],
|
spirv::WriteStore(mBuilder.getSpirvCurrentFunctionBlock(), tempVarIds[paramIndex],
|
||||||
paramValue, nullptr);
|
paramValue, nullptr);
|
||||||
}
|
}
|
||||||
|
@ -1767,14 +1771,11 @@ spirv::IdRef OutputSPIRVTraverser::createFunctionCall(TIntermAggregate *node,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy from the temp variable to the parameter.
|
// Copy from the temp variable to the parameter.
|
||||||
//
|
|
||||||
// TODO: handle mismatching types. http://anglebug.com/6000
|
|
||||||
NodeData tempVarData;
|
NodeData tempVarData;
|
||||||
nodeDataInitLValue(&tempVarData, tempVarIds[paramIndex], tempVarTypeIds[paramIndex],
|
nodeDataInitLValue(&tempVarData, tempVarIds[paramIndex], tempVarTypeIds[paramIndex],
|
||||||
spv::StorageClassFunction, {});
|
spv::StorageClassFunction, {});
|
||||||
const spirv::IdRef tempVarValue =
|
const spirv::IdRef tempVarValue = accessChainLoad(&tempVarData, paramType);
|
||||||
accessChainLoad(&tempVarData, mBuilder.getDecorations(paramType));
|
accessChainStore(¶m, tempVarValue, function->getParam(paramIndex)->getType());
|
||||||
accessChainStore(¶m, tempVarValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -1888,7 +1889,7 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I
|
||||||
break;
|
break;
|
||||||
case EOpPositive:
|
case EOpPositive:
|
||||||
// This is a noop.
|
// This is a noop.
|
||||||
return accessChainLoad(&mNodeData.back(), mBuilder.getDecorations(firstOperandType));
|
return accessChainLoad(&mNodeData.back(), firstOperandType);
|
||||||
|
|
||||||
case EOpLogicalNot:
|
case EOpLogicalNot:
|
||||||
case EOpNotComponentWise:
|
case EOpNotComponentWise:
|
||||||
|
@ -2571,7 +2572,7 @@ spirv::IdRef OutputSPIRVTraverser::visitOperator(TIntermOperator *node, spirv::I
|
||||||
{
|
{
|
||||||
ASSERT(mNodeData.size() >= 2);
|
ASSERT(mNodeData.size() >= 2);
|
||||||
ASSERT(parameters.size() == 2);
|
ASSERT(parameters.size() == 2);
|
||||||
accessChainStore(&mNodeData[mNodeData.size() - 2], result);
|
accessChainStore(&mNodeData[mNodeData.size() - 2], result, firstOperandType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -2610,8 +2611,7 @@ spirv::IdRef OutputSPIRVTraverser::createIncrementDecrement(TIntermOperator *nod
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the operand.
|
// Load the operand.
|
||||||
spirv::IdRef value =
|
spirv::IdRef value = accessChainLoad(&mNodeData.back(), operandType);
|
||||||
accessChainLoad(&mNodeData.back(), mBuilder.getDecorations(operand->getType()));
|
|
||||||
|
|
||||||
spirv::IdRef result = mBuilder.getNewId(mBuilder.getDecorations(operandType));
|
spirv::IdRef result = mBuilder.getNewId(mBuilder.getDecorations(operandType));
|
||||||
const spirv::IdRef one = isFloat ? mBuilder.getFloatConstant(1) : mBuilder.getIntConstant(1);
|
const spirv::IdRef one = isFloat ? mBuilder.getFloatConstant(1) : mBuilder.getIntConstant(1);
|
||||||
|
@ -2619,7 +2619,7 @@ spirv::IdRef OutputSPIRVTraverser::createIncrementDecrement(TIntermOperator *nod
|
||||||
writeBinaryOp(mBuilder.getSpirvCurrentFunctionBlock(), resultTypeId, result, value, one);
|
writeBinaryOp(mBuilder.getSpirvCurrentFunctionBlock(), resultTypeId, result, value, one);
|
||||||
|
|
||||||
// The result is always written back.
|
// The result is always written back.
|
||||||
accessChainStore(&mNodeData.back(), result);
|
accessChainStore(&mNodeData.back(), result, operandType);
|
||||||
|
|
||||||
// Initialize the access chain with either the result or the value based on whether pre or
|
// Initialize the access chain with either the result or the value based on whether pre or
|
||||||
// post increment/decrement was used. The result is always an rvalue.
|
// post increment/decrement was used. The result is always an rvalue.
|
||||||
|
@ -2747,10 +2747,9 @@ spirv::IdRef OutputSPIRVTraverser::createAtomicBuiltIn(TIntermOperator *node,
|
||||||
pointerId = accessChainCollapse(&mNodeData[mNodeData.size() - parameterCount]);
|
pointerId = accessChainCollapse(&mNodeData[mNodeData.size() - parameterCount]);
|
||||||
for (size_t paramIndex = 1; paramIndex < parameterCount; ++paramIndex)
|
for (size_t paramIndex = 1; paramIndex < parameterCount; ++paramIndex)
|
||||||
{
|
{
|
||||||
NodeData ¶m = mNodeData[mNodeData.size() - parameterCount + paramIndex];
|
NodeData ¶m = mNodeData[mNodeData.size() - parameterCount + paramIndex];
|
||||||
const spirv::IdRef parameter = accessChainLoad(
|
const spirv::IdRef parameter =
|
||||||
¶m,
|
accessChainLoad(¶m, node->getChildNode(paramIndex)->getAsTyped()->getType());
|
||||||
mBuilder.getDecorations(node->getChildNode(paramIndex)->getAsTyped()->getType()));
|
|
||||||
|
|
||||||
// imageAtomic* built-ins have a few additional parameters right after the image. These are
|
// imageAtomic* built-ins have a few additional parameters right after the image. These are
|
||||||
// kept separately for use with OpImageTexelPointer.
|
// kept separately for use with OpImageTexelPointer.
|
||||||
|
@ -3736,6 +3735,111 @@ spirv::IdRef OutputSPIRVTraverser::castBasicType(spirv::IdRef value,
|
||||||
return castValue;
|
return castValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spirv::IdRef OutputSPIRVTraverser::cast(spirv::IdRef value,
|
||||||
|
const TType &valueType,
|
||||||
|
const SpirvTypeSpec &valueTypeSpec,
|
||||||
|
const SpirvTypeSpec &expectedTypeSpec)
|
||||||
|
{
|
||||||
|
// If there's no difference in type specialization, there's nothing to cast.
|
||||||
|
if (valueTypeSpec.blockStorage == expectedTypeSpec.blockStorage &&
|
||||||
|
valueTypeSpec.isInvariantBlock == expectedTypeSpec.isInvariantBlock &&
|
||||||
|
valueTypeSpec.isRowMajorQualifiedBlock == expectedTypeSpec.isRowMajorQualifiedBlock &&
|
||||||
|
valueTypeSpec.isRowMajorQualifiedArray == expectedTypeSpec.isRowMajorQualifiedArray)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, a value is loaded with the |valueType| GLSL type which is of a SPIR-V type
|
||||||
|
// specialized by |valueTypeSpec|. However, it's being assigned (for example through operator=,
|
||||||
|
// used in a constructor or passed as a function argument) where the same GLSL type is expected
|
||||||
|
// but with different SPIR-V type specialization (|expectedTypeSpec|). SPIR-V 1.4 has
|
||||||
|
// OpCopyLogical that does exactly that, but we generate SPIR-V 1.0 at the moment.
|
||||||
|
//
|
||||||
|
// The following code recursively copies the array elements or struct fields and then constructs
|
||||||
|
// the final result with the expected SPIR-V type.
|
||||||
|
|
||||||
|
// Interface blocks cannot be copied or passed as parameters in GLSL.
|
||||||
|
ASSERT(!valueType.isInterfaceBlock());
|
||||||
|
|
||||||
|
spirv::IdRefList constituents;
|
||||||
|
|
||||||
|
if (valueType.isArray())
|
||||||
|
{
|
||||||
|
// Find the SPIR-V type specialization for the element type.
|
||||||
|
SpirvTypeSpec valueElementTypeSpec = valueTypeSpec;
|
||||||
|
SpirvTypeSpec expectedElementTypeSpec = expectedTypeSpec;
|
||||||
|
|
||||||
|
const bool isElementBlock = valueType.getStruct() != nullptr;
|
||||||
|
const bool isElementArray = valueType.isArrayOfArrays();
|
||||||
|
|
||||||
|
valueElementTypeSpec.onArrayElementSelection(isElementBlock, isElementArray);
|
||||||
|
expectedElementTypeSpec.onArrayElementSelection(isElementBlock, isElementArray);
|
||||||
|
|
||||||
|
// Get the element type id.
|
||||||
|
TType elementType(valueType);
|
||||||
|
elementType.toArrayElementType();
|
||||||
|
|
||||||
|
const spirv::IdRef elementTypeId =
|
||||||
|
mBuilder.getTypeData(elementType, valueElementTypeSpec).id;
|
||||||
|
|
||||||
|
const SpirvDecorations elementDecorations = mBuilder.getDecorations(elementType);
|
||||||
|
|
||||||
|
// Extract each element of the array and cast it to the expected type.
|
||||||
|
for (unsigned int elementIndex = 0; elementIndex < valueType.getOutermostArraySize();
|
||||||
|
++elementIndex)
|
||||||
|
{
|
||||||
|
const spirv::IdRef elementId = mBuilder.getNewId(elementDecorations);
|
||||||
|
spirv::WriteCompositeExtract(mBuilder.getSpirvCurrentFunctionBlock(), elementTypeId,
|
||||||
|
elementId, value, {spirv::LiteralInteger(elementIndex)});
|
||||||
|
|
||||||
|
constituents.push_back(
|
||||||
|
cast(elementId, elementType, valueElementTypeSpec, expectedElementTypeSpec));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (valueType.getStruct() != nullptr)
|
||||||
|
{
|
||||||
|
uint32_t fieldIndex = 0;
|
||||||
|
|
||||||
|
// Extract each field of the struct and cast it to the expected type.
|
||||||
|
for (const TField *field : valueType.getStruct()->fields())
|
||||||
|
{
|
||||||
|
const TType &fieldType = *field->type();
|
||||||
|
|
||||||
|
// Find the SPIR-V type specialization for the field type.
|
||||||
|
SpirvTypeSpec valueFieldTypeSpec = valueTypeSpec;
|
||||||
|
SpirvTypeSpec expectedFieldTypeSpec = expectedTypeSpec;
|
||||||
|
|
||||||
|
valueFieldTypeSpec.onBlockFieldSelection(fieldType);
|
||||||
|
expectedFieldTypeSpec.onBlockFieldSelection(fieldType);
|
||||||
|
|
||||||
|
// Get the field type id.
|
||||||
|
const spirv::IdRef fieldTypeId = mBuilder.getTypeData(fieldType, valueFieldTypeSpec).id;
|
||||||
|
|
||||||
|
// Extract the field.
|
||||||
|
const spirv::IdRef fieldId = mBuilder.getNewId(mBuilder.getDecorations(fieldType));
|
||||||
|
spirv::WriteCompositeExtract(mBuilder.getSpirvCurrentFunctionBlock(), fieldTypeId,
|
||||||
|
fieldId, value, {spirv::LiteralInteger(fieldIndex++)});
|
||||||
|
|
||||||
|
constituents.push_back(
|
||||||
|
cast(fieldId, fieldType, valueFieldTypeSpec, expectedFieldTypeSpec));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: support bool in interface blocks. http://anglebug.com/4889.
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the value with the expected type from its cast constituents.
|
||||||
|
const spirv::IdRef expectedTypeId = mBuilder.getTypeData(valueType, expectedTypeSpec).id;
|
||||||
|
const spirv::IdRef expectedId = mBuilder.getNewId(mBuilder.getDecorations(valueType));
|
||||||
|
|
||||||
|
spirv::WriteCompositeConstruct(mBuilder.getSpirvCurrentFunctionBlock(), expectedTypeId,
|
||||||
|
expectedId, constituents);
|
||||||
|
|
||||||
|
return expectedId;
|
||||||
|
}
|
||||||
|
|
||||||
spirv::IdRef OutputSPIRVTraverser::reduceBoolVector(TOperator op,
|
spirv::IdRef OutputSPIRVTraverser::reduceBoolVector(TOperator op,
|
||||||
const spirv::IdRefList &valueIds,
|
const spirv::IdRefList &valueIds,
|
||||||
spirv::IdRef typeId,
|
spirv::IdRef typeId,
|
||||||
|
@ -4161,8 +4265,8 @@ bool OutputSPIRVTraverser::visitBinary(Visit visit, TIntermBinary *node)
|
||||||
case EOpIndexIndirect:
|
case EOpIndexIndirect:
|
||||||
{
|
{
|
||||||
// Load the index.
|
// Load the index.
|
||||||
const spirv::IdRef rightValue = accessChainLoad(
|
const spirv::IdRef rightValue =
|
||||||
&mNodeData.back(), mBuilder.getDecorations(node->getRight()->getType()));
|
accessChainLoad(&mNodeData.back(), node->getRight()->getType());
|
||||||
mNodeData.pop_back();
|
mNodeData.pop_back();
|
||||||
|
|
||||||
if (!node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())
|
if (!node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())
|
||||||
|
@ -4179,14 +4283,13 @@ bool OutputSPIRVTraverser::visitBinary(Visit visit, TIntermBinary *node)
|
||||||
case EOpAssign:
|
case EOpAssign:
|
||||||
{
|
{
|
||||||
// Load the right hand side of assignment.
|
// Load the right hand side of assignment.
|
||||||
const spirv::IdRef rightValue = accessChainLoad(
|
const spirv::IdRef rightValue =
|
||||||
&mNodeData.back(), mBuilder.getDecorations(node->getRight()->getType()));
|
accessChainLoad(&mNodeData.back(), node->getRight()->getType());
|
||||||
mNodeData.pop_back();
|
mNodeData.pop_back();
|
||||||
|
|
||||||
// Store into the access chain. Since the result of the (a = b) expression is b, change
|
// Store into the access chain. Since the result of the (a = b) expression is b, change
|
||||||
// the access chain to an unindexed rvalue which is |rightValue|.
|
// the access chain to an unindexed rvalue which is |rightValue|.
|
||||||
// TODO: handle mismatching types. http://anglebug.com/4889.
|
accessChainStore(&mNodeData.back(), rightValue, node->getLeft()->getType());
|
||||||
accessChainStore(&mNodeData.back(), rightValue);
|
|
||||||
nodeDataInitRValue(&mNodeData.back(), rightValue, resultTypeId);
|
nodeDataInitRValue(&mNodeData.back(), rightValue, resultTypeId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4287,9 +4390,9 @@ bool OutputSPIRVTraverser::visitTernary(Visit visit, TIntermTernary *node)
|
||||||
|
|
||||||
if (lastChildIndex == 0)
|
if (lastChildIndex == 0)
|
||||||
{
|
{
|
||||||
spirv::IdRef typeId = getAccessChainTypeId(&mNodeData.back());
|
spirv::IdRef typeId = getAccessChainTypeId(&mNodeData.back());
|
||||||
spirv::IdRef conditionValue = accessChainLoad(
|
spirv::IdRef conditionValue =
|
||||||
&mNodeData.back(), mBuilder.getDecorations(node->getCondition()->getType()));
|
accessChainLoad(&mNodeData.back(), node->getCondition()->getType());
|
||||||
|
|
||||||
// If OpSelect can be used, keep the condition for later usage.
|
// If OpSelect can be used, keep the condition for later usage.
|
||||||
if (canUseOpSelect)
|
if (canUseOpSelect)
|
||||||
|
@ -4326,9 +4429,8 @@ bool OutputSPIRVTraverser::visitTernary(Visit visit, TIntermTernary *node)
|
||||||
|
|
||||||
// Load the result of the true or false part, and keep it for the end. It's either used in
|
// Load the result of the true or false part, and keep it for the end. It's either used in
|
||||||
// OpSelect or OpPhi.
|
// OpSelect or OpPhi.
|
||||||
// TODO: handle mismatching types. http://anglebug.com/4889.
|
|
||||||
const spirv::IdRef typeId = getAccessChainTypeId(&mNodeData.back());
|
const spirv::IdRef typeId = getAccessChainTypeId(&mNodeData.back());
|
||||||
const spirv::IdRef value = accessChainLoad(&mNodeData.back(), mBuilder.getDecorations(type));
|
const spirv::IdRef value = accessChainLoad(&mNodeData.back(), type);
|
||||||
mNodeData.pop_back();
|
mNodeData.pop_back();
|
||||||
mNodeData.back().idList.push_back(value);
|
mNodeData.back().idList.push_back(value);
|
||||||
|
|
||||||
|
@ -4388,8 +4490,8 @@ bool OutputSPIRVTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
|
||||||
// If the condition was just visited, evaluate it and create the branch instructions.
|
// If the condition was just visited, evaluate it and create the branch instructions.
|
||||||
if (lastChildIndex == 0)
|
if (lastChildIndex == 0)
|
||||||
{
|
{
|
||||||
const spirv::IdRef conditionValue = accessChainLoad(
|
const spirv::IdRef conditionValue =
|
||||||
&mNodeData.back(), mBuilder.getDecorations(node->getCondition()->getType()));
|
accessChainLoad(&mNodeData.back(), node->getCondition()->getType());
|
||||||
|
|
||||||
// Create a conditional with maximum 3 blocks, one for the true block (if any), one for the
|
// Create a conditional with maximum 3 blocks, one for the true block (if any), one for the
|
||||||
// else block (if any), and one for the merge block. getChildCount() works here as it
|
// else block (if any), and one for the merge block. getChildCount() works here as it
|
||||||
|
@ -4510,7 +4612,7 @@ bool OutputSPIRVTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
|
||||||
ASSERT(getLastTraversedChildIndex(visit) == 0);
|
ASSERT(getLastTraversedChildIndex(visit) == 0);
|
||||||
|
|
||||||
const spirv::IdRef conditionValue =
|
const spirv::IdRef conditionValue =
|
||||||
accessChainLoad(&mNodeData.back(), mBuilder.getDecorations(node->getInit()->getType()));
|
accessChainLoad(&mNodeData.back(), node->getInit()->getType());
|
||||||
|
|
||||||
// First, need to find out how many blocks are there in the switch.
|
// First, need to find out how many blocks are there in the switch.
|
||||||
const TIntermSequence &statements = *node->getStatementList()->getSequence();
|
const TIntermSequence &statements = *node->getStatementList()->getSequence();
|
||||||
|
@ -5024,12 +5126,9 @@ bool OutputSPIRVTraverser::visitDeclaration(Visit visit, TIntermDeclaration *nod
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Otherwise generate code to load from right hand side expression.
|
// Otherwise generate code to load from right hand side expression.
|
||||||
initializerId =
|
initializerId = accessChainLoad(&mNodeData.back(), symbol->getType());
|
||||||
accessChainLoad(&mNodeData.back(), mBuilder.getDecorations(initializer->getType()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle mismatching types. http://anglebug.com/4889.
|
|
||||||
|
|
||||||
// Clean up the initializer data.
|
// Clean up the initializer data.
|
||||||
mNodeData.pop_back();
|
mNodeData.pop_back();
|
||||||
}
|
}
|
||||||
|
@ -5297,8 +5396,8 @@ bool OutputSPIRVTraverser::visitLoop(Visit visit, TIntermLoop *node)
|
||||||
node->getCondition()->traverse(this);
|
node->getCondition()->traverse(this);
|
||||||
|
|
||||||
// Generate the branch at the end of the %cond block.
|
// Generate the branch at the end of the %cond block.
|
||||||
const spirv::IdRef conditionValue = accessChainLoad(
|
const spirv::IdRef conditionValue =
|
||||||
&mNodeData.back(), mBuilder.getDecorations(node->getCondition()->getType()));
|
accessChainLoad(&mNodeData.back(), node->getCondition()->getType());
|
||||||
mBuilder.writeLoopConditionEnd(conditionValue, bodyBlock, mergeBlock);
|
mBuilder.writeLoopConditionEnd(conditionValue, bodyBlock, mergeBlock);
|
||||||
|
|
||||||
mNodeData.pop_back();
|
mNodeData.pop_back();
|
||||||
|
@ -5340,8 +5439,8 @@ bool OutputSPIRVTraverser::visitLoop(Visit visit, TIntermLoop *node)
|
||||||
node->getCondition()->traverse(this);
|
node->getCondition()->traverse(this);
|
||||||
|
|
||||||
// Generate the branch at the end of the %cond block.
|
// Generate the branch at the end of the %cond block.
|
||||||
const spirv::IdRef conditionValue = accessChainLoad(
|
const spirv::IdRef conditionValue =
|
||||||
&mNodeData.back(), mBuilder.getDecorations(node->getCondition()->getType()));
|
accessChainLoad(&mNodeData.back(), node->getCondition()->getType());
|
||||||
mBuilder.writeLoopConditionEnd(conditionValue, headerBlock, mergeBlock);
|
mBuilder.writeLoopConditionEnd(conditionValue, headerBlock, mergeBlock);
|
||||||
|
|
||||||
mNodeData.pop_back();
|
mNodeData.pop_back();
|
||||||
|
@ -5388,12 +5487,10 @@ bool OutputSPIRVTraverser::visitBranch(Visit visit, TIntermBranch *node)
|
||||||
{
|
{
|
||||||
ASSERT(mNodeData.size() >= 1);
|
ASSERT(mNodeData.size() >= 1);
|
||||||
|
|
||||||
const spirv::IdRef expressionValue = accessChainLoad(
|
const spirv::IdRef expressionValue =
|
||||||
&mNodeData.back(), mBuilder.getDecorations(node->getExpression()->getType()));
|
accessChainLoad(&mNodeData.back(), node->getExpression()->getType());
|
||||||
mNodeData.pop_back();
|
mNodeData.pop_back();
|
||||||
|
|
||||||
// TODO: handle mismatching types. http://anglebug.com/6000
|
|
||||||
|
|
||||||
spirv::WriteReturnValue(mBuilder.getSpirvCurrentFunctionBlock(), expressionValue);
|
spirv::WriteReturnValue(mBuilder.getSpirvCurrentFunctionBlock(), expressionValue);
|
||||||
mBuilder.terminateCurrentFunctionBlock();
|
mBuilder.terminateCurrentFunctionBlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,6 @@
|
||||||
4889 VULKAN : GLSLTest.MoreNestedCompoundStructsWithSamplersAsFunctionArg/ES2_Vulkan_DirectSPIRVGen = SKIP
|
4889 VULKAN : GLSLTest.MoreNestedCompoundStructsWithSamplersAsFunctionArg/ES2_Vulkan_DirectSPIRVGen = SKIP
|
||||||
4889 VULKAN : GLSLTest.NestedCompoundStructsWithSamplersAsFunctionArg/ES2_Vulkan_DirectSPIRVGen = SKIP
|
4889 VULKAN : GLSLTest.NestedCompoundStructsWithSamplersAsFunctionArg/ES2_Vulkan_DirectSPIRVGen = SKIP
|
||||||
4889 VULKAN : GLSLTest.SamplerInStructMemberIndexing/ES2_Vulkan_DirectSPIRVGen = SKIP
|
4889 VULKAN : GLSLTest.SamplerInStructMemberIndexing/ES2_Vulkan_DirectSPIRVGen = SKIP
|
||||||
// SPIR-V generation doesn't yet handle copy between different SPIR-V types generated from the same GLSL type
|
|
||||||
4889 VULKAN : GLSLTest_ES31.MixedRowAndColumnMajorMatrices/ES3_1_Vulkan_DirectSPIRVGen = SKIP
|
|
||||||
4889 VULKAN : GLSLTest_ES31.BasicTypeArrayAndArrayOfSampler/ES3_1_Vulkan_DirectSPIRVGen = SKIP
|
|
||||||
4889 VULKAN : GLSLTest_ES31.StructBothInvariantAndNot/ES3_1_Vulkan_DirectSPIRVGen = SKIP
|
|
||||||
|
|
||||||
// Windows
|
// Windows
|
||||||
3786 WIN NVIDIA D3D11 : BufferDataOverflowTest.VertexBufferIntegerOverflow/* = SKIP
|
3786 WIN NVIDIA D3D11 : BufferDataOverflowTest.VertexBufferIntegerOverflow/* = SKIP
|
||||||
|
@ -41,6 +37,8 @@
|
||||||
6065 LINUX INTEL VULKAN : SimpleStateChangeTestES31.DrawThenUpdateUBOThenDrawThenDrawIndexed/* = SKIP
|
6065 LINUX INTEL VULKAN : SimpleStateChangeTestES31.DrawThenUpdateUBOThenDrawThenDrawIndexed/* = SKIP
|
||||||
// Fails in older mesa
|
// Fails in older mesa
|
||||||
6109 LINUX INTEL : GLSLTestLoops.*While*/* = SKIP
|
6109 LINUX INTEL : GLSLTestLoops.*While*/* = SKIP
|
||||||
|
// Crashes when compiling the shader
|
||||||
|
6173 LINUX INTEL OPENGL : GLSLTest_ES31.TypesUsedInDifferentBlockStorages/* = SKIP
|
||||||
|
|
||||||
// Nvidia
|
// Nvidia
|
||||||
6115 NVIDIA OPENGL : GLSLTestLoops.DoWhileContinue/* = SKIP
|
6115 NVIDIA OPENGL : GLSLTestLoops.DoWhileContinue/* = SKIP
|
||||||
|
@ -51,6 +49,9 @@
|
||||||
6115 NVIDIA GLES : GLSLTestLoops.DoWhileUnconditionalContinue/* = SKIP
|
6115 NVIDIA GLES : GLSLTestLoops.DoWhileUnconditionalContinue/* = SKIP
|
||||||
6115 NVIDIA GLES : GLSLTestLoops.DoWhileContinueInSwitch/* = SKIP
|
6115 NVIDIA GLES : GLSLTestLoops.DoWhileContinueInSwitch/* = SKIP
|
||||||
6115 NVIDIA GLES : GLSLTestLoops.WhileBreak/* = SKIP
|
6115 NVIDIA GLES : GLSLTestLoops.WhileBreak/* = SKIP
|
||||||
|
// Generates invalid errors when compiling the shader in the GL backend
|
||||||
|
6172 NVIDIA OpenGL : GLSLTest_ES31.TypesUsedInDifferentBlockStorages/* = SKIP
|
||||||
|
6172 NVIDIA GLES : GLSLTest_ES31.TypesUsedInDifferentBlockStorages/* = SKIP
|
||||||
|
|
||||||
// Intel Vulkan
|
// Intel Vulkan
|
||||||
|
|
||||||
|
@ -80,6 +81,8 @@
|
||||||
6091 WIN D3D11 : GLSLTest_ES3.InitGlobalComplexConstant/* = SKIP
|
6091 WIN D3D11 : GLSLTest_ES3.InitGlobalComplexConstant/* = SKIP
|
||||||
6122 WIN D3D11 : GLSLTestLoops.*ContinueInSwitch/* = SKIP
|
6122 WIN D3D11 : GLSLTestLoops.*ContinueInSwitch/* = SKIP
|
||||||
6150 WIN D3D11 : GLSLTest_ES31.StructAndArrayEqualOperator/* = SKIP
|
6150 WIN D3D11 : GLSLTest_ES31.StructAndArrayEqualOperator/* = SKIP
|
||||||
|
// Fails on assertion in translation to D3D
|
||||||
|
3841 WIN D3D11 : GLSLTest_ES31.TypesUsedInDifferentBlockStorages/* = SKIP
|
||||||
|
|
||||||
// Android
|
// Android
|
||||||
6095 ANDROID GLES : GLSLTest_ES3.InitGlobalComplexConstant/ES3_OpenGLES = SKIP
|
6095 ANDROID GLES : GLSLTest_ES3.InitGlobalComplexConstant/ES3_OpenGLES = SKIP
|
||||||
|
@ -181,9 +184,14 @@
|
||||||
6167 PIXEL4ORXL GLES : DepthStencilTestES3.FramebufferClearThenStencilTestStateThenStencilAttached/* = SKIP
|
6167 PIXEL4ORXL GLES : DepthStencilTestES3.FramebufferClearThenStencilTestStateThenStencilAttached/* = SKIP
|
||||||
6167 PIXEL4ORXL GLES : DepthStencilTestES3.StencilTestStateThenFramebufferClearThenStencilAttached/* = SKIP
|
6167 PIXEL4ORXL GLES : DepthStencilTestES3.StencilTestStateThenFramebufferClearThenStencilAttached/* = SKIP
|
||||||
|
|
||||||
|
// Internal driver failures on both GLES and Vulkan
|
||||||
|
3839 NEXUS5X : GLSLTest_ES31.TypesUsedInDifferentBlockStorages/* = SKIP
|
||||||
|
3839 PIXEL4ORXL : GLSLTest_ES31.TypesUsedInDifferentBlockStorages/* = SKIP
|
||||||
|
|
||||||
// AMD windows failures. The GPU and driver on our bots are very old and buggy.
|
// AMD windows failures. The GPU and driver on our bots are very old and buggy.
|
||||||
// http://crbug.com/1224996
|
// http://crbug.com/1224996
|
||||||
4889 WIN AMD VULKAN : GLSLTest.StructWithInitializer/ES2_Vulkan_DirectSPIRVGen = SKIP
|
4889 WIN AMD VULKAN : GLSLTest.StructWithInitializer/ES2_Vulkan_DirectSPIRVGen = SKIP
|
||||||
4889 WIN AMD VULKAN : GLSLTest.StructWithUniformInitializer/ES2_Vulkan_DirectSPIRVGen = SKIP
|
4889 WIN AMD VULKAN : GLSLTest.StructWithUniformInitializer/ES2_Vulkan_DirectSPIRVGen = SKIP
|
||||||
4889 WIN AMD VULKAN : GLSLTest_ES3.ValidIndexClampES300/ES3_Vulkan_DirectSPIRVGen = SKIP
|
4889 WIN AMD VULKAN : GLSLTest_ES3.ValidIndexClampES300/ES3_Vulkan_DirectSPIRVGen = SKIP
|
||||||
4889 WIN AMD VULKAN : GLSLTest_ES3.InitGlobalComplexConstant/ES3_Vulkan_DirectSPIRVGen = SKIP
|
4889 WIN AMD VULKAN : GLSLTest_ES3.InitGlobalComplexConstant/ES3_Vulkan_DirectSPIRVGen = SKIP
|
||||||
|
4889 WIN AMD VULKAN : GLSLTest_ES31.TypesUsedInDifferentBlockStorages/* = SKIP
|
||||||
|
|
|
@ -8604,7 +8604,7 @@ void InitBuffer(GLuint program,
|
||||||
const char *name,
|
const char *name,
|
||||||
GLuint buffer,
|
GLuint buffer,
|
||||||
uint32_t bindingIndex,
|
uint32_t bindingIndex,
|
||||||
float data[],
|
const float data[],
|
||||||
uint32_t dataSize,
|
uint32_t dataSize,
|
||||||
bool isUniform)
|
bool isUniform)
|
||||||
{
|
{
|
||||||
|
@ -10315,6 +10315,343 @@ void main()
|
||||||
EXPECT_TRUE(VerifyBuffer(ssbo, data, size));
|
EXPECT_TRUE(VerifyBuffer(ssbo, data, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that types used differently (in different block storages, differently qualified etc) work
|
||||||
|
// when copied around.
|
||||||
|
TEST_P(GLSLTest_ES31, TypesUsedInDifferentBlockStorages)
|
||||||
|
{
|
||||||
|
constexpr char kCS[] = R"(#version 310 es
|
||||||
|
precision highp float;
|
||||||
|
layout(local_size_x=1) in;
|
||||||
|
|
||||||
|
struct Inner
|
||||||
|
{
|
||||||
|
mat3x2 m;
|
||||||
|
float f[3];
|
||||||
|
uvec2 u[2][4];
|
||||||
|
ivec3 i;
|
||||||
|
mat2x3 m2[3][2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Outer
|
||||||
|
{
|
||||||
|
Inner i[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std140, column_major) uniform Ubo140c
|
||||||
|
{
|
||||||
|
mat2 m;
|
||||||
|
layout(row_major) Outer o;
|
||||||
|
} ubo140cIn;
|
||||||
|
|
||||||
|
layout(std430, row_major, binding = 0) buffer Ubo430r
|
||||||
|
{
|
||||||
|
mat2 m;
|
||||||
|
layout(column_major) Outer o;
|
||||||
|
} ubo430rIn;
|
||||||
|
|
||||||
|
layout(std140, column_major, binding = 1) buffer Ssbo140c
|
||||||
|
{
|
||||||
|
layout(row_major) mat2 m[2];
|
||||||
|
Outer o;
|
||||||
|
layout(row_major) Inner i;
|
||||||
|
} ssbo140cOut;
|
||||||
|
|
||||||
|
layout(std430, row_major, binding = 2) buffer Ssbo430r
|
||||||
|
{
|
||||||
|
layout(column_major) mat2 m[2];
|
||||||
|
Outer o;
|
||||||
|
layout(column_major) Inner i;
|
||||||
|
} ssbo430rOut;
|
||||||
|
|
||||||
|
void writeArgToStd140(uvec2 u[2][4], int innerIndex)
|
||||||
|
{
|
||||||
|
ssbo140cOut.o.i[innerIndex].u = u;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeBlockArgToStd140(Inner i, int innerIndex)
|
||||||
|
{
|
||||||
|
ssbo140cOut.o.i[innerIndex] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat2x3[3][2] readFromStd140(int innerIndex)
|
||||||
|
{
|
||||||
|
return ubo140cIn.o.i[0].m2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inner readBlockFromStd430(int innerIndex)
|
||||||
|
{
|
||||||
|
return ubo430rIn.o.i[innerIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
void copyFromStd140(out Inner i)
|
||||||
|
{
|
||||||
|
i = ubo140cIn.o.i[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
// Directly copy from one layout to another.
|
||||||
|
ssbo140cOut.m[0] = ubo140cIn.m;
|
||||||
|
ssbo140cOut.m[1] = ubo430rIn.m;
|
||||||
|
ssbo140cOut.o.i[0].m = ubo140cIn.o.i[0].m;
|
||||||
|
ssbo140cOut.o.i[0].f = ubo140cIn.o.i[0].f;
|
||||||
|
ssbo140cOut.o.i[0].i = ubo140cIn.o.i[0].i;
|
||||||
|
|
||||||
|
// Read from block and pass to function.
|
||||||
|
writeArgToStd140(ubo140cIn.o.i[0].u, 0);
|
||||||
|
writeBlockArgToStd140(ubo430rIn.o.i[0], 1);
|
||||||
|
|
||||||
|
// Have function return value read from block.
|
||||||
|
ssbo140cOut.o.i[0].m2 = readFromStd140(0);
|
||||||
|
|
||||||
|
// Have function fill in value as out parameter.
|
||||||
|
copyFromStd140(ssbo140cOut.i);
|
||||||
|
|
||||||
|
// Initialize local variable.
|
||||||
|
mat2 mStd140 = ubo140cIn.m;
|
||||||
|
|
||||||
|
// Copy to variable, through multiple assignments.
|
||||||
|
mat2 mStd430, temp;
|
||||||
|
mStd430 = temp = ubo430rIn.m;
|
||||||
|
|
||||||
|
// Copy from local variable
|
||||||
|
ssbo430rOut.m[0] = mStd140;
|
||||||
|
ssbo430rOut.m[1] = mStd430;
|
||||||
|
|
||||||
|
// Construct from struct.
|
||||||
|
Inner iStd140 = ubo140cIn.o.i[1];
|
||||||
|
Outer oStd140 = Outer(Inner[2](iStd140, ubo430rIn.o.i[1]));
|
||||||
|
|
||||||
|
// Copy struct from local variable.
|
||||||
|
ssbo430rOut.o = oStd140;
|
||||||
|
|
||||||
|
// Construct from arrays
|
||||||
|
Inner iStd430 = Inner(ubo430rIn.o.i[1].m,
|
||||||
|
ubo430rIn.o.i[1].f,
|
||||||
|
ubo430rIn.o.i[1].u,
|
||||||
|
ubo430rIn.o.i[1].i,
|
||||||
|
ubo430rIn.o.i[1].m2);
|
||||||
|
ssbo430rOut.i = iStd430;
|
||||||
|
})";
|
||||||
|
|
||||||
|
ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
|
||||||
|
EXPECT_GL_NO_ERROR();
|
||||||
|
|
||||||
|
// Test data, laid out with padding (0) based on std140/std430 rules.
|
||||||
|
// clang-format off
|
||||||
|
const std::vector<float> ubo140cData = {
|
||||||
|
// m (mat2, column-major)
|
||||||
|
1, 2, 0, 0, 3, 4, 0, 0,
|
||||||
|
|
||||||
|
// o.i[0].m (mat3x2, row-major)
|
||||||
|
5, 7, 9, 0, 6, 8, 10, 0,
|
||||||
|
// o.i[0].f (float[3])
|
||||||
|
12, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0,
|
||||||
|
// o.i[0].u (uvec2[2][4])
|
||||||
|
15, 16, 0, 0, 17, 18, 0, 0, 19, 20, 0, 0, 21, 22, 0, 0,
|
||||||
|
23, 24, 0, 0, 25, 26, 0, 0, 27, 28, 0, 0, 29, 30, 0, 0,
|
||||||
|
// o.i[0].i (ivec3)
|
||||||
|
31, 32, 33, 0,
|
||||||
|
// o.i[0].m2 (mat2x3[3][2], row-major)
|
||||||
|
34, 37, 0, 0, 35, 38, 0, 0, 36, 39, 0, 0,
|
||||||
|
40, 43, 0, 0, 41, 44, 0, 0, 42, 45, 0, 0,
|
||||||
|
46, 49, 0, 0, 47, 50, 0, 0, 48, 51, 0, 0,
|
||||||
|
52, 55, 0, 0, 53, 56, 0, 0, 54, 57, 0, 0,
|
||||||
|
58, 61, 0, 0, 59, 62, 0, 0, 60, 63, 0, 0,
|
||||||
|
64, 67, 0, 0, 65, 68, 0, 0, 66, 69, 0, 0,
|
||||||
|
|
||||||
|
// o.i[1].m (mat3x2, row-major)
|
||||||
|
70, 72, 74, 0, 71, 73, 75, 0,
|
||||||
|
// o.i[1].f (float[3])
|
||||||
|
77, 0, 0, 0, 78, 0, 0, 0, 79, 0, 0, 0,
|
||||||
|
// o.i[1].u (uvec2[2][4])
|
||||||
|
80, 81, 0, 0, 82, 83, 0, 0, 84, 85, 0, 0, 86, 87, 0, 0,
|
||||||
|
88, 89, 0, 0, 90, 91, 0, 0, 92, 93, 0, 0, 94, 95, 0, 0,
|
||||||
|
// o.i[1].i (ivec3)
|
||||||
|
96, 97, 98, 0,
|
||||||
|
// o.i[1].m2 (mat2x3[3][2], row-major)
|
||||||
|
99, 102, 0, 0, 100, 103, 0, 0, 101, 104, 0, 0,
|
||||||
|
105, 108, 0, 0, 106, 109, 0, 0, 107, 110, 0, 0,
|
||||||
|
111, 114, 0, 0, 112, 115, 0, 0, 113, 116, 0, 0,
|
||||||
|
117, 120, 0, 0, 118, 121, 0, 0, 119, 122, 0, 0,
|
||||||
|
123, 126, 0, 0, 124, 127, 0, 0, 125, 128, 0, 0,
|
||||||
|
129, 132, 0, 0, 130, 133, 0, 0, 131, 134, 0, 0,
|
||||||
|
};
|
||||||
|
const std::vector<float> ubo430rData = {
|
||||||
|
// m (mat2, row-major)
|
||||||
|
135, 137, 136, 138,
|
||||||
|
|
||||||
|
// o.i[0].m (mat3x2, column-major)
|
||||||
|
139, 140, 141, 142, 143, 144,
|
||||||
|
// o.i[0].f (float[3])
|
||||||
|
146, 147, 148, 0,
|
||||||
|
// o.i[0].u (uvec2[2][4])
|
||||||
|
149, 150, 151, 152, 153, 154, 155, 156,
|
||||||
|
157, 158, 159, 160, 161, 162, 163, 164, 0, 0,
|
||||||
|
// o.i[0].i (ivec3)
|
||||||
|
165, 166, 167, 0,
|
||||||
|
// o.i[0].m2 (mat2x3[3][2], column-major)
|
||||||
|
168, 169, 170, 0, 171, 172, 173, 0,
|
||||||
|
174, 175, 176, 0, 177, 178, 179, 0,
|
||||||
|
180, 181, 182, 0, 183, 184, 185, 0,
|
||||||
|
186, 187, 188, 0, 189, 190, 191, 0,
|
||||||
|
192, 193, 194, 0, 195, 196, 197, 0,
|
||||||
|
198, 199, 200, 0, 201, 202, 203, 0,
|
||||||
|
|
||||||
|
// o.i[1].m (mat3x2, column-major)
|
||||||
|
204, 205, 206, 207, 208, 209,
|
||||||
|
// o.i[1].f (float[3])
|
||||||
|
211, 212, 213, 0,
|
||||||
|
// o.i[1].u (uvec2[2][4])
|
||||||
|
214, 215, 216, 217, 218, 219, 220, 221,
|
||||||
|
222, 223, 224, 225, 226, 227, 228, 229, 0, 0,
|
||||||
|
// o.i[1].i (ivec3)
|
||||||
|
230, 231, 232, 0,
|
||||||
|
// o.i[1].m2 (mat2x3[3][2], column-major)
|
||||||
|
233, 234, 235, 0, 236, 237, 238, 0,
|
||||||
|
239, 240, 241, 0, 242, 243, 244, 0,
|
||||||
|
245, 246, 247, 0, 248, 249, 250, 0,
|
||||||
|
251, 252, 253, 0, 254, 255, 256, 0,
|
||||||
|
257, 258, 259, 0, 260, 261, 262, 0,
|
||||||
|
263, 264, 265, 0, 266, 267, 268, 0,
|
||||||
|
};
|
||||||
|
const std::vector<float> ssbo140cExpect = {
|
||||||
|
// m (mat2[2], row-major), m[0] copied from ubo140cIn.m, m[1] from ubo430rIn.m
|
||||||
|
1, 3, 0, 0, 2, 4, 0, 0,
|
||||||
|
135, 137, 0, 0, 136, 138, 0, 0,
|
||||||
|
|
||||||
|
// o.i[0].m (mat3x2, column-major), copied from ubo140cIn.o.i[0].m
|
||||||
|
5, 6, 0, 0, 7, 8, 0, 0, 9, 10, 0, 0,
|
||||||
|
// o.i[0].f (float[3]), copied from ubo140cIn.o.i[0].f
|
||||||
|
12, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0,
|
||||||
|
// o.i[0].u (uvec2[2][4]), copied from ubo140cIn.o.i[0].u
|
||||||
|
15, 16, 0, 0, 17, 18, 0, 0, 19, 20, 0, 0, 21, 22, 0, 0,
|
||||||
|
23, 24, 0, 0, 25, 26, 0, 0, 27, 28, 0, 0, 29, 30, 0, 0,
|
||||||
|
// o.i[0].i (ivec3), copied from ubo140cIn.o.i[0].i
|
||||||
|
31, 32, 33, 0,
|
||||||
|
// o.i[0].m2 (mat2x3[3][2], column-major), copied from ubo140cIn.o.i[0].m2
|
||||||
|
34, 35, 36, 0, 37, 38, 39, 0,
|
||||||
|
40, 41, 42, 0, 43, 44, 45, 0,
|
||||||
|
46, 47, 48, 0, 49, 50, 51, 0,
|
||||||
|
52, 53, 54, 0, 55, 56, 57, 0,
|
||||||
|
58, 59, 60, 0, 61, 62, 63, 0,
|
||||||
|
64, 65, 66, 0, 67, 68, 69, 0,
|
||||||
|
|
||||||
|
// o.i[1].m (mat3x2, column-major), copied from ubo430rIn.o.i[0].m
|
||||||
|
139, 140, 0, 0, 141, 142, 0, 0, 143, 144, 0, 0,
|
||||||
|
// o.i[1].f (float[3]), copied from ubo430rIn.o.i[0].f
|
||||||
|
146, 0, 0, 0, 147, 0, 0, 0, 148, 0, 0, 0,
|
||||||
|
// o.i[1].u (uvec2[2][4]), copied from ubo430rIn.o.i[0].u
|
||||||
|
149, 150, 0, 0, 151, 152, 0, 0, 153, 154, 0, 0, 155, 156, 0, 0,
|
||||||
|
157, 158, 0, 0, 159, 160, 0, 0, 161, 162, 0, 0, 163, 164, 0, 0,
|
||||||
|
// o.i[1].i (ivec3), copied from ubo430rIn.o.i[0].i
|
||||||
|
165, 166, 167, 0,
|
||||||
|
// o.i[1].m2 (mat2x3[3][2], column-major), copied from ubo430rIn.o.i[0].m2
|
||||||
|
168, 169, 170, 0, 171, 172, 173, 0,
|
||||||
|
174, 175, 176, 0, 177, 178, 179, 0,
|
||||||
|
180, 181, 182, 0, 183, 184, 185, 0,
|
||||||
|
186, 187, 188, 0, 189, 190, 191, 0,
|
||||||
|
192, 193, 194, 0, 195, 196, 197, 0,
|
||||||
|
198, 199, 200, 0, 201, 202, 203, 0,
|
||||||
|
|
||||||
|
// i.m (mat3x2, row-major), copied from ubo140cIn.o.i[1].m
|
||||||
|
70, 72, 74, 0, 71, 73, 75, 0,
|
||||||
|
// i.f (float[3]), copied from ubo140cIn.o.i[1].f
|
||||||
|
77, 0, 0, 0, 78, 0, 0, 0, 79, 0, 0, 0,
|
||||||
|
// i.u (uvec2[2][4]), copied from ubo430rIn.o.i[1].u
|
||||||
|
80, 81, 0, 0, 82, 83, 0, 0, 84, 85, 0, 0, 86, 87, 0, 0,
|
||||||
|
88, 89, 0, 0, 90, 91, 0, 0, 92, 93, 0, 0, 94, 95, 0, 0,
|
||||||
|
// i.i (ivec3), copied from ubo140cIn.o.i[1].i
|
||||||
|
96, 97, 98, 0,
|
||||||
|
// i.m2 (mat2x3[3][2], row-major), copied from ubo140cIn.o.i[1].m2
|
||||||
|
99, 102, 0, 0, 100, 103, 0, 0, 101, 104, 0, 0,
|
||||||
|
105, 108, 0, 0, 106, 109, 0, 0, 107, 110, 0, 0,
|
||||||
|
111, 114, 0, 0, 112, 115, 0, 0, 113, 116, 0, 0,
|
||||||
|
117, 120, 0, 0, 118, 121, 0, 0, 119, 122, 0, 0,
|
||||||
|
123, 126, 0, 0, 124, 127, 0, 0, 125, 128, 0, 0,
|
||||||
|
129, 132, 0, 0, 130, 133, 0, 0, 131, 134, 0, 0,
|
||||||
|
};
|
||||||
|
const std::vector<float> ssbo430rExpect = {
|
||||||
|
// m (mat2[2], column-major), m[0] copied from ubo140cIn.m, m[1] from ubo430rIn.m
|
||||||
|
1, 2, 3, 4,
|
||||||
|
135, 136, 137, 138,
|
||||||
|
|
||||||
|
// o.i[0].m (mat3x2, row-major), copied from ubo140cIn.o.i[1].m
|
||||||
|
70, 72, 74, 0, 71, 73, 75, 0,
|
||||||
|
// o.i[0].f (float[3]), copied from ubo140cIn.o.i[1].f
|
||||||
|
77, 78, 79, 0,
|
||||||
|
// o.i[0].u (uvec2[2][4]), copied from ubo140cIn.o.i[1].u
|
||||||
|
80, 81, 82, 83, 84, 85, 86, 87,
|
||||||
|
88, 89, 90, 91, 92, 93, 94, 95,
|
||||||
|
// o.i[0].i (ivec3), copied from ubo140cIn.o.i[1].i
|
||||||
|
96, 97, 98, 0,
|
||||||
|
// o.i[0].m2 (mat2x3[3][2], row-major), copied from ubo140cIn.o.i[1].m2
|
||||||
|
99, 102, 100, 103, 101, 104,
|
||||||
|
105, 108, 106, 109, 107, 110,
|
||||||
|
111, 114, 112, 115, 113, 116,
|
||||||
|
117, 120, 118, 121, 119, 122,
|
||||||
|
123, 126, 124, 127, 125, 128,
|
||||||
|
129, 132, 130, 133, 131, 134,
|
||||||
|
|
||||||
|
// o.i[1].m (mat3x2, row-major), copied from ubo430rIn.o.i[1].m
|
||||||
|
204, 206, 208, 0, 205, 207, 209, 0,
|
||||||
|
// o.i[1].f (float[3]), copied from ubo430rIn.o.i[1].f
|
||||||
|
211, 212, 213, 0,
|
||||||
|
// o.i[1].u (uvec2[2][4]), copied from ubo430rIn.o.i[1].u
|
||||||
|
214, 215, 216, 217, 218, 219, 220, 221,
|
||||||
|
222, 223, 224, 225, 226, 227, 228, 229,
|
||||||
|
// o.i[1].i (ivec3), copied from ubo430rIn.o.i[1].i
|
||||||
|
230, 231, 232, 0,
|
||||||
|
// o.i[1].m2 (mat2x3[3][2], row-major), copied from ubo430rIn.o.i[1].m2
|
||||||
|
233, 236, 234, 237, 235, 238,
|
||||||
|
239, 242, 240, 243, 241, 244,
|
||||||
|
245, 248, 246, 249, 247, 250,
|
||||||
|
251, 254, 252, 255, 253, 256,
|
||||||
|
257, 260, 258, 261, 259, 262,
|
||||||
|
263, 266, 264, 267, 265, 268,
|
||||||
|
|
||||||
|
// i.m (mat3x2, column-major), copied from ubo430rIn.o.i[1].m
|
||||||
|
204, 205, 206, 207, 208, 209,
|
||||||
|
// i.f (float[3]), copied from ubo430rIn.o.i[1].f
|
||||||
|
211, 212, 213, 0,
|
||||||
|
// i.u (uvec2[2][4]), copied from ubo430rIn.o.i[1].u
|
||||||
|
214, 215, 216, 217, 218, 219, 220, 221,
|
||||||
|
222, 223, 224, 225, 226, 227, 228, 229, 0, 0,
|
||||||
|
// i.i (ivec3), copied from ubo430rIn.o.i[1].i
|
||||||
|
230, 231, 232, 0,
|
||||||
|
// i.m2 (mat2x3[3][2], column-major), copied from ubo430rIn.o.i[1].m2
|
||||||
|
233, 234, 235, 0, 236, 237, 238, 0,
|
||||||
|
239, 240, 241, 0, 242, 243, 244, 0,
|
||||||
|
245, 246, 247, 0, 248, 249, 250, 0,
|
||||||
|
251, 252, 253, 0, 254, 255, 256, 0,
|
||||||
|
257, 258, 259, 0, 260, 261, 262, 0,
|
||||||
|
263, 264, 265, 0, 266, 267, 268, 0,
|
||||||
|
};
|
||||||
|
const std::vector<float> zeros(std::max(ssbo140cExpect.size(), ssbo430rExpect.size()), 0);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
GLBuffer uboStd140ColMajor, uboStd430RowMajor;
|
||||||
|
GLBuffer ssboStd140ColMajor, ssboStd430RowMajor;
|
||||||
|
|
||||||
|
InitBuffer(program, "Ubo140c", uboStd140ColMajor, 0, ubo140cData.data(),
|
||||||
|
static_cast<uint32_t>(ubo140cData.size()), true);
|
||||||
|
InitBuffer(program, "Ubo430r", uboStd430RowMajor, 0, ubo430rData.data(),
|
||||||
|
static_cast<uint32_t>(ubo430rData.size()), false);
|
||||||
|
InitBuffer(program, "Ssbo140c", ssboStd140ColMajor, 1, zeros.data(),
|
||||||
|
static_cast<uint32_t>(ssbo140cExpect.size()), false);
|
||||||
|
InitBuffer(program, "Ssbo430r", ssboStd430RowMajor, 2, zeros.data(),
|
||||||
|
static_cast<uint32_t>(ssbo430rExpect.size()), false);
|
||||||
|
EXPECT_GL_NO_ERROR();
|
||||||
|
|
||||||
|
glUseProgram(program);
|
||||||
|
glDispatchCompute(1, 1, 1);
|
||||||
|
EXPECT_GL_NO_ERROR();
|
||||||
|
|
||||||
|
EXPECT_TRUE(VerifyBuffer(ssboStd140ColMajor, ssbo140cExpect.data(),
|
||||||
|
static_cast<uint32_t>(ssbo140cExpect.size())));
|
||||||
|
EXPECT_TRUE(VerifyBuffer(ssboStd430RowMajor, ssbo430rExpect.data(),
|
||||||
|
static_cast<uint32_t>(ssbo430rExpect.size())));
|
||||||
|
}
|
||||||
|
|
||||||
// Test that the precise keyword is not reserved before ES3.1.
|
// Test that the precise keyword is not reserved before ES3.1.
|
||||||
TEST_P(GLSLTest_ES3, PreciseNotReserved)
|
TEST_P(GLSLTest_ES3, PreciseNotReserved)
|
||||||
{
|
{
|
||||||
|
@ -11947,10 +12284,10 @@ ANGLE_INSTANTIATE_TEST_ES3_AND(GLSLTest_ES3, WithDirectSPIRVGeneration(ES3_VULKA
|
||||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GLSLTestLoops);
|
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GLSLTestLoops);
|
||||||
ANGLE_INSTANTIATE_TEST_ES3_AND(GLSLTestLoops, WithDirectSPIRVGeneration(ES3_VULKAN()));
|
ANGLE_INSTANTIATE_TEST_ES3_AND(GLSLTestLoops, WithDirectSPIRVGeneration(ES3_VULKAN()));
|
||||||
|
|
||||||
ANGLE_INSTANTIATE_TEST_ES2(WebGLGLSLTest);
|
ANGLE_INSTANTIATE_TEST_ES2_AND(WebGLGLSLTest, WithDirectSPIRVGeneration(ES2_VULKAN()));
|
||||||
|
|
||||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2GLSLTest);
|
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2GLSLTest);
|
||||||
ANGLE_INSTANTIATE_TEST_ES3(WebGL2GLSLTest);
|
ANGLE_INSTANTIATE_TEST_ES3_AND(WebGL2GLSLTest, WithDirectSPIRVGeneration(ES3_VULKAN()));
|
||||||
|
|
||||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GLSLTest_ES31);
|
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GLSLTest_ES31);
|
||||||
ANGLE_INSTANTIATE_TEST_ES31_AND(GLSLTest_ES31, WithDirectSPIRVGeneration(ES31_VULKAN()));
|
ANGLE_INSTANTIATE_TEST_ES31_AND(GLSLTest_ES31, WithDirectSPIRVGeneration(ES31_VULKAN()));
|
||||||
|
|
Загрузка…
Ссылка в новой задаче