HLSL: vector shape conversions for all ops: Fix #839. Fix #653. Fix #631.

This commit is contained in:
John Kessenich 2017-04-18 21:07:05 -06:00
parent 2aa12b1c05
commit d5d9ffbdfd
5 changed files with 330 additions and 67 deletions

View File

@ -95,27 +95,66 @@ gl_FragCoord origin is upper left
0:22 Construct vec4 ( temp 4-component vector of float)
0:22 'f' ( in float)
0:22 'v' ( temp 4-component vector of float)
0:26 Compare Equal ( temp bool)
0:26 'f1' ( temp 1-component vector of float)
0:26 Construct float ( temp 1-component vector of float)
0:26 'v' ( temp 4-component vector of float)
0:27 Compare Less Than ( temp bool)
0:27 Construct float ( temp 1-component vector of float)
0:27 'v' ( temp 4-component vector of float)
0:27 'f1' ( temp 1-component vector of float)
0:26 Equal ( temp 4-component vector of bool)
0:26 Construct vec4 ( temp 4-component vector of float)
0:26 'f1' ( temp 1-component vector of float)
0:26 'v' ( temp 4-component vector of float)
0:27 Compare Less Than ( temp 4-component vector of bool)
0:27 'v' ( temp 4-component vector of float)
0:27 Construct vec4 ( temp 4-component vector of float)
0:27 'f1' ( temp 1-component vector of float)
0:28 Construct float ( temp float)
0:28 'f1' ( temp 1-component vector of float)
0:29 Construct vec3 ( temp 3-component vector of float)
0:29 Construct float ( temp float)
0:29 'f1' ( temp 1-component vector of float)
0:33 Branch: Return with expression
0:33 component-wise multiply ( temp 4-component vector of float)
0:33 'input' ( in 4-component vector of float)
0:33 Constant:
0:33 3.000000
0:33 3.000000
0:33 3.000000
0:33 3.000000
0:36 right-shift ( temp 3-component vector of uint)
0:36 Construct uvec3 ( temp 3-component vector of uint)
0:36 'ui' ( temp uint)
0:36 'ui3' ( temp 3-component vector of uint)
0:37 right-shift ( temp 3-component vector of uint)
0:37 'ui3' ( temp 3-component vector of uint)
0:37 'ui' ( temp uint)
0:39 multiply second child into first child ( temp 4-component vector of float)
0:39 'v' ( temp 4-component vector of float)
0:39 'f1' ( temp 1-component vector of float)
0:40 multiply second child into first child ( temp 1-component vector of float)
0:40 'f1' ( temp 1-component vector of float)
0:40 Construct float ( temp 1-component vector of float)
0:40 'v' ( temp 4-component vector of float)
0:42 Sequence
0:42 move second child to first child ( temp 3-component vector of float)
0:42 'mixed' ( temp 3-component vector of float)
0:42 component-wise multiply ( temp 3-component vector of float)
0:42 'u' ( temp 3-component vector of float)
0:42 Construct vec3 ( temp 3-component vector of float)
0:42 'v' ( temp 4-component vector of float)
0:43 move second child to first child ( temp float)
0:43 'f' ( in float)
0:43 Construct float ( in float)
0:43 'u' ( temp 3-component vector of float)
0:44 move second child to first child ( temp 1-component vector of float)
0:44 'f1' ( temp 1-component vector of float)
0:44 Construct float ( temp 1-component vector of float)
0:44 'u' ( temp 3-component vector of float)
0:45 Sequence
0:45 move second child to first child ( temp float)
0:45 'sf' ( temp float)
0:45 Construct float ( temp float)
0:45 'v' ( temp 4-component vector of float)
0:46 Sequence
0:46 move second child to first child ( temp 1-component vector of float)
0:46 'sf1' ( temp 1-component vector of float)
0:46 Construct float ( temp 1-component vector of float)
0:46 'v' ( temp 4-component vector of float)
0:48 Branch: Return with expression
0:48 component-wise multiply ( temp 4-component vector of float)
0:48 'input' ( in 4-component vector of float)
0:48 Constant:
0:48 3.000000
0:48 3.000000
0:48 3.000000
0:48 3.000000
0:? Linker Objects
@ -219,32 +258,71 @@ gl_FragCoord origin is upper left
0:22 Construct vec4 ( temp 4-component vector of float)
0:22 'f' ( in float)
0:22 'v' ( temp 4-component vector of float)
0:26 Compare Equal ( temp bool)
0:26 'f1' ( temp 1-component vector of float)
0:26 Construct float ( temp 1-component vector of float)
0:26 'v' ( temp 4-component vector of float)
0:27 Compare Less Than ( temp bool)
0:27 Construct float ( temp 1-component vector of float)
0:27 'v' ( temp 4-component vector of float)
0:27 'f1' ( temp 1-component vector of float)
0:26 Equal ( temp 4-component vector of bool)
0:26 Construct vec4 ( temp 4-component vector of float)
0:26 'f1' ( temp 1-component vector of float)
0:26 'v' ( temp 4-component vector of float)
0:27 Compare Less Than ( temp 4-component vector of bool)
0:27 'v' ( temp 4-component vector of float)
0:27 Construct vec4 ( temp 4-component vector of float)
0:27 'f1' ( temp 1-component vector of float)
0:28 Construct float ( temp float)
0:28 'f1' ( temp 1-component vector of float)
0:29 Construct vec3 ( temp 3-component vector of float)
0:29 Construct float ( temp float)
0:29 'f1' ( temp 1-component vector of float)
0:33 Branch: Return with expression
0:33 component-wise multiply ( temp 4-component vector of float)
0:33 'input' ( in 4-component vector of float)
0:33 Constant:
0:33 3.000000
0:33 3.000000
0:33 3.000000
0:33 3.000000
0:36 right-shift ( temp 3-component vector of uint)
0:36 Construct uvec3 ( temp 3-component vector of uint)
0:36 'ui' ( temp uint)
0:36 'ui3' ( temp 3-component vector of uint)
0:37 right-shift ( temp 3-component vector of uint)
0:37 'ui3' ( temp 3-component vector of uint)
0:37 'ui' ( temp uint)
0:39 multiply second child into first child ( temp 4-component vector of float)
0:39 'v' ( temp 4-component vector of float)
0:39 'f1' ( temp 1-component vector of float)
0:40 multiply second child into first child ( temp 1-component vector of float)
0:40 'f1' ( temp 1-component vector of float)
0:40 Construct float ( temp 1-component vector of float)
0:40 'v' ( temp 4-component vector of float)
0:42 Sequence
0:42 move second child to first child ( temp 3-component vector of float)
0:42 'mixed' ( temp 3-component vector of float)
0:42 component-wise multiply ( temp 3-component vector of float)
0:42 'u' ( temp 3-component vector of float)
0:42 Construct vec3 ( temp 3-component vector of float)
0:42 'v' ( temp 4-component vector of float)
0:43 move second child to first child ( temp float)
0:43 'f' ( in float)
0:43 Construct float ( in float)
0:43 'u' ( temp 3-component vector of float)
0:44 move second child to first child ( temp 1-component vector of float)
0:44 'f1' ( temp 1-component vector of float)
0:44 Construct float ( temp 1-component vector of float)
0:44 'u' ( temp 3-component vector of float)
0:45 Sequence
0:45 move second child to first child ( temp float)
0:45 'sf' ( temp float)
0:45 Construct float ( temp float)
0:45 'v' ( temp 4-component vector of float)
0:46 Sequence
0:46 move second child to first child ( temp 1-component vector of float)
0:46 'sf1' ( temp 1-component vector of float)
0:46 Construct float ( temp 1-component vector of float)
0:46 'v' ( temp 4-component vector of float)
0:48 Branch: Return with expression
0:48 component-wise multiply ( temp 4-component vector of float)
0:48 'input' ( in 4-component vector of float)
0:48 Constant:
0:48 3.000000
0:48 3.000000
0:48 3.000000
0:48 3.000000
0:? Linker Objects
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 88
// Id's are bound by 127
Capability Shader
1: ExtInstImport "GLSL.std.450"
@ -263,6 +341,11 @@ gl_FragCoord origin is upper left
Name 34 "MyVal"
Name 37 "foo"
Name 70 "f1"
Name 83 "ui"
Name 88 "ui3"
Name 103 "mixed"
Name 115 "sf"
Name 118 "sf1"
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
@ -294,8 +377,11 @@ gl_FragCoord origin is upper left
56: TypeInt 32 0
57: 56(int) Constant 0
62: TypeVector 41(bool) 4
83: 6(float) Constant 1077936128
84: 7(fvec4) ConstantComposite 83 83 83 83
82: TypePointer Function 56(int)
85: TypeVector 56(int) 3
87: TypePointer Function 85(ivec3)
122: 6(float) Constant 1077936128
123: 7(fvec4) ConstantComposite 122 122 122 122
4(main): 2 Function None 3
5: Label
Return
@ -311,6 +397,11 @@ gl_FragCoord origin is upper left
34(MyVal): 23(ptr) Variable Function
37(foo): 23(ptr) Variable Function
70(f1): 9(ptr) Variable Function
83(ui): 82(ptr) Variable Function
88(ui3): 87(ptr) Variable Function
103(mixed): 23(ptr) Variable Function
115(sf): 9(ptr) Variable Function
118(sf1): 9(ptr) Variable Function
Store 15(v) 17
Store 15(v) 19
20: 6(float) Load 12(f)
@ -346,17 +437,55 @@ gl_FragCoord origin is upper left
68: 62(bvec4) FOrdNotEqual 66 67
69: 41(bool) Any 68
71: 6(float) Load 70(f1)
72: 7(fvec4) Load 15(v)
73: 6(float) CompositeExtract 72 0
74: 41(bool) FOrdEqual 71 73
72: 7(fvec4) CompositeConstruct 71 71 71 71
73: 7(fvec4) Load 15(v)
74: 62(bvec4) FOrdEqual 72 73
75: 7(fvec4) Load 15(v)
76: 6(float) CompositeExtract 75 0
77: 6(float) Load 70(f1)
78: 41(bool) FOrdLessThan 76 77
76: 6(float) Load 70(f1)
77: 7(fvec4) CompositeConstruct 76 76 76 76
78: 62(bvec4) FOrdLessThan 75 77
79: 6(float) Load 70(f1)
80: 6(float) Load 70(f1)
81: 22(fvec3) CompositeConstruct 80 80 80
82: 7(fvec4) Load 11(input)
85: 7(fvec4) FMul 82 84
ReturnValue 85
84: 56(int) Load 83(ui)
86: 85(ivec3) CompositeConstruct 84 84 84
89: 85(ivec3) Load 88(ui3)
90: 85(ivec3) ShiftRightLogical 86 89
91: 85(ivec3) Load 88(ui3)
92: 56(int) Load 83(ui)
93: 85(ivec3) CompositeConstruct 92 92 92
94: 85(ivec3) ShiftRightLogical 91 93
95: 6(float) Load 70(f1)
96: 7(fvec4) Load 15(v)
97: 7(fvec4) CompositeConstruct 95 95 95 95
98: 7(fvec4) FMul 96 97
Store 15(v) 98
99: 7(fvec4) Load 15(v)
100: 6(float) CompositeExtract 99 0
101: 6(float) Load 70(f1)
102: 6(float) FMul 101 100
Store 70(f1) 102
104: 22(fvec3) Load 24(u)
105: 7(fvec4) Load 15(v)
106: 6(float) CompositeExtract 105 0
107: 6(float) CompositeExtract 105 1
108: 6(float) CompositeExtract 105 2
109: 22(fvec3) CompositeConstruct 106 107 108
110: 22(fvec3) FMul 104 109
Store 103(mixed) 110
111: 22(fvec3) Load 24(u)
112: 6(float) CompositeExtract 111 0
Store 12(f) 112
113: 22(fvec3) Load 24(u)
114: 6(float) CompositeExtract 113 0
Store 70(f1) 114
116: 7(fvec4) Load 15(v)
117: 6(float) CompositeExtract 116 0
Store 115(sf) 117
119: 7(fvec4) Load 15(v)
120: 6(float) CompositeExtract 119 0
Store 118(sf1) 120
121: 7(fvec4) Load 11(input)
124: 7(fvec4) FMul 121 123
ReturnValue 124
FunctionEnd

View File

@ -30,5 +30,20 @@ float4 PixelShaderFunction(float4 input, float f) : COLOR0
const float4 f4 = 3.0;
uint ui;
uint3 ui3;
ui >> ui3;
ui3 >> ui;
v *= f1;
f1 *= v;
float3 mixed = u * v;
f = u;
f1 = u;
float sf = v;
float1 sf1 = v;
return input * f4;
}

View File

@ -130,8 +130,9 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn
}
// Convert the children's type shape to be compatible.
right = addShapeConversion(op, left->getType(), right);
left = addShapeConversion(op, right->getType(), left);
addBiShapeConversion(op, left, right);
if (left == nullptr || right == nullptr)
return nullptr;
//
// Need a new node holding things together. Make
@ -238,7 +239,7 @@ TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TInterm
return nullptr;
// convert shape
right = addShapeConversion(op, left->getType(), right);
right = addUniShapeConversion(op, left->getType(), right);
// build the node
TIntermBinary* node = addBinaryNode(op, left, right, loc);
@ -788,7 +789,10 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
}
// Convert the node's shape of type for the given type, as allowed by the
// operation involved: 'op'.
// operation involved: 'op'. This is for situations where there is only one
// direction to consider doing the shape conversion.
//
// This implements policy, it call addShapeConversion() for the mechanism.
//
// Generally, the AST represents allowed GLSL shapes, so this isn't needed
// for GLSL. Bad shapes are caught in conversion or promotion.
@ -796,7 +800,7 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
// Return 'node' if no conversion was done. Promotion handles final shape
// checking.
//
TIntermTyped* TIntermediate::addShapeConversion(TOperator op, const TType& type, TIntermTyped* node)
TIntermTyped* TIntermediate::addUniShapeConversion(TOperator op, const TType& type, TIntermTyped* node)
{
// some source languages don't do this
switch (source) {
@ -809,23 +813,137 @@ TIntermTyped* TIntermediate::addShapeConversion(TOperator op, const TType& type,
// some operations don't do this
switch (op) {
case EOpFunctionCall:
case EOpReturn:
break;
case EOpMulAssign:
// want to support vector *= scalar native ops in AST and lower, not smear, similarly for
// matrix *= scalar, etc.
case EOpAddAssign:
case EOpSubAssign:
case EOpDivAssign:
case EOpAndAssign:
case EOpInclusiveOrAssign:
case EOpExclusiveOrAssign:
case EOpRightShiftAssign:
case EOpLeftShiftAssign:
if (node->getVectorSize() == 1)
return node;
break;
case EOpAssign:
break;
default:
return node;
}
return addShapeConversion(type, node);
}
// Convert the nodes' shapes to be compatible for the operation 'op'.
//
// This implements policy, it call addShapeConversion() for the mechanism.
//
// Generally, the AST represents allowed GLSL shapes, so this isn't needed
// for GLSL. Bad shapes are caught in conversion or promotion.
//
void TIntermediate::addBiShapeConversion(TOperator op, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode)
{
// some source languages don't do this
switch (source) {
case EShSourceHlsl:
break;
case EShSourceGlsl:
default:
return;
}
// some operations don't do this
// 'break' will mean attempt bidirectional conversion
switch (op) {
case EOpMulAssign:
case EOpAssign:
case EOpAddAssign:
case EOpSubAssign:
case EOpDivAssign:
case EOpAndAssign:
case EOpInclusiveOrAssign:
case EOpExclusiveOrAssign:
case EOpRightShiftAssign:
case EOpLeftShiftAssign:
// switch to unidirectional conversion (the lhs can't change)
rhsNode = addUniShapeConversion(op, lhsNode->getType(), rhsNode);
return;
case EOpAdd:
case EOpSub:
case EOpMul:
case EOpDiv:
// want to support vector * scalar native ops in AST and lower, not smear, similarly for
// matrix * vector, etc.
if (lhsNode->getVectorSize() == 1 || rhsNode->getVectorSize() == 1)
return;
break;
case EOpRightShift:
case EOpLeftShift:
// can natively support the right operand being a scalar and the left a vector,
// but not the reverse
if (rhsNode->getVectorSize() == 1)
return;
break;
case EOpLessThan:
case EOpGreaterThan:
case EOpLessThanEqual:
case EOpGreaterThanEqual:
case EOpEqual:
case EOpNotEqual:
case EOpFunctionCall:
case EOpReturn:
case EOpLogicalAnd:
case EOpLogicalOr:
case EOpLogicalXor:
case EOpAnd:
case EOpInclusiveOr:
case EOpExclusiveOr:
break;
default:
return node;
return;
}
// Do bidirectional conversions
if (lhsNode->getType().isScalarOrVec1() || rhsNode->getType().isScalarOrVec1()) {
if (lhsNode->getType().isScalarOrVec1())
lhsNode = addShapeConversion(rhsNode->getType(), lhsNode);
else
rhsNode = addShapeConversion(lhsNode->getType(), rhsNode);
}
lhsNode = addShapeConversion(rhsNode->getType(), lhsNode);
rhsNode = addShapeConversion(lhsNode->getType(), rhsNode);
}
// Convert the node's shape of type for the given type. It's not necessarily
// an error if they are different and not converted, as some operations accept
// mixed types. Promotion will do final shape checking.
//
// If there is a chance of two nodes, with conversions possible in each direction,
// the policy for what to ask for must be in the caller; this will do what is asked.
//
// Return 'node' if no conversion was done. Promotion handles final shape
// checking.
//
TIntermTyped* TIntermediate::addShapeConversion(const TType& type, TIntermTyped* node)
{
// no conversion needed
if (node->getType() == type)
return node;
// structures and arrays don't change shape, either to or from
if (node->getType().isStruct() || node->getType().isArray() ||
type.isStruct() || type.isArray())
@ -834,12 +952,12 @@ TIntermTyped* TIntermediate::addShapeConversion(TOperator op, const TType& type,
// The new node that handles the conversion
TOperator constructorOp = mapTypeToConstructorOp(type);
// scalar -> smeared -> vector, or
// vec1 -> scalar, or
// bigger vector -> smaller vector or scalar
if ((type.isVector() && node->getType().isScalar()) ||
(node->getType().isVector() && node->getVectorSize() == 1 && type.isScalar()) ||
(node->getVectorSize() > type.getVectorSize() && type.isVector()))
// scalar -> vector or vec1 -> vector or
// vector -> scalar or
// bigger vector -> smaller vector
if ((node->getType().isScalarOrVec1() && type.isVector()) ||
(node->getType().isVector() && type.isScalar()) ||
(node->isVector() && type.isVector() && node->getVectorSize() > type.getVectorSize()))
return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
return node;
@ -1314,9 +1432,9 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true
cond->getType().getVectorSize());
// smear true/false operations if needed
if (trueBlock->getType().isScalarOrVec1())
trueBlock = addShapeConversion(EOpAssign, targetVectorType, trueBlock);
trueBlock = addShapeConversion(targetVectorType, trueBlock);
if (falseBlock->getType().isScalarOrVec1())
falseBlock = addShapeConversion(EOpAssign, targetVectorType, falseBlock);
falseBlock = addShapeConversion(targetVectorType, falseBlock);
// make the mix operation
TIntermAggregate* mix = makeAggregate(loc);
@ -2139,8 +2257,6 @@ bool TIntermediate::promoteBinary(TIntermBinary& node)
case EOpLogicalXor:
return left->getType() == right->getType();
// no shifts: they can mix types (scalar int can shift a vector uint, etc.)
case EOpMod:
case EOpModAssign:
@ -2154,6 +2270,7 @@ bool TIntermediate::promoteBinary(TIntermBinary& node)
case EOpAdd:
case EOpSub:
case EOpDiv:
case EOpAddAssign:
case EOpSubAssign:
case EOpDivAssign:
@ -2178,7 +2295,7 @@ bool TIntermediate::promoteBinary(TIntermBinary& node)
return true;
// Finish handling the case, for all ops, where there are two vectors of different sizes
if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize())
if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize() && right->getVectorSize() > 1)
return false;
//

View File

@ -243,7 +243,9 @@ public:
TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
TIntermSymbol* addSymbol(const TIntermSymbol&);
TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
TIntermTyped* addShapeConversion(TOperator, const TType&, TIntermTyped*);
TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*);
void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode);
TIntermTyped* addShapeConversion(const TType&, TIntermTyped*);
TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc);

View File

@ -2087,7 +2087,7 @@ TIntermNode* HlslParseContext::handleReturnValue(const TSourceLoc& loc, TIntermT
} else if (*currentFunctionType != value->getType()) {
value = intermediate.addConversion(EOpReturn, *currentFunctionType, value);
if (value && *currentFunctionType != value->getType())
value = intermediate.addShapeConversion(EOpReturn, *currentFunctionType, value);
value = intermediate.addUniShapeConversion(EOpReturn, *currentFunctionType, value);
if (value == nullptr) {
error(loc, "type does not match, or is not convertible to, the function's return type", "return", "");
return value;
@ -4105,7 +4105,7 @@ void HlslParseContext::addInputArgumentConversions(const TFunction& function, TI
// convert to the correct type.
TIntermTyped* convArg = intermediate.addConversion(EOpFunctionCall, *function[i].type, arg);
if (convArg != nullptr)
convArg = intermediate.addShapeConversion(EOpFunctionCall, *function[i].type, convArg);
convArg = intermediate.addUniShapeConversion(EOpFunctionCall, *function[i].type, convArg);
if (convArg != nullptr)
setArg(i, convArg);
else
@ -6439,7 +6439,7 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm
initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer);
if (initializer != nullptr && variable->getType() != initializer->getType())
initializer = intermediate.addShapeConversion(EOpAssign, variable->getType(), initializer);
initializer = intermediate.addUniShapeConversion(EOpAssign, variable->getType(), initializer);
if (initializer == nullptr || !initializer->getAsConstantUnion() ||
variable->getType() != initializer->getType()) {
error(loc, "non-matching or non-convertible constant type for const initializer",