xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fShaderMatrixTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Shader matrix arithmetic tests.
22  *
23  * Variables:
24  *  + operation
25  *    - mat OP mat
26  *    - mat OP vec
27  *    - vec OP mat
28  *    - mat OP scalar
29  *    - OP mat
30  *  + matrix source
31  *    - constant (ctor)
32  *    - uniform
33  *    - vertex input
34  *    - fragment input
35  *  + other operand: always dynamic data?
36  *  + how to reduce to vec3?
37  *//*--------------------------------------------------------------------*/
38 
39 #include "es2fShaderMatrixTests.hpp"
40 #include "glsShaderRenderCase.hpp"
41 #include "gluShaderUtil.hpp"
42 #include "tcuVector.hpp"
43 #include "tcuMatrix.hpp"
44 #include "tcuMatrixUtil.hpp"
45 #include "deStringUtil.hpp"
46 
47 #include "glwEnums.hpp"
48 #include "glwFunctions.hpp"
49 
50 namespace deqp
51 {
52 namespace gles2
53 {
54 namespace Functional
55 {
56 
57 using std::string;
58 using std::vector;
59 using namespace glu;
60 using namespace deqp::gls;
61 
62 using tcu::Mat2;
63 using tcu::Mat3;
64 using tcu::Mat4;
65 using tcu::Vec2;
66 using tcu::Vec3;
67 using tcu::Vec4;
68 
69 // Uniform / constant values for tests.
70 // \note Input1 should not contain 0 components as it is used as divisor in div cases.
71 // \todo [2012-02-14 pyry] Make these dynamic.
72 static const float s_constInFloat[2] = {0.5f, -0.2f};
73 static const Vec2 s_constInVec2[2]   = {Vec2(1.2f, 0.5f), Vec2(0.5f, 1.0f)};
74 static const Vec3 s_constInVec3[2]   = {Vec3(1.1f, 0.1f, 0.5f), Vec3(-0.2f, 0.5f, 0.8f)};
75 static const Vec4 s_constInVec4[2]   = {Vec4(1.4f, 0.2f, -0.5f, 0.7f), Vec4(0.2f, -1.0f, 0.5f, 0.8f)};
76 
77 static const float s_constInMat20[] = {0.6f, -1.0f, 0.7f, 0.4f};
78 static const float s_constInMat21[] = {-0.5f, -0.4f, 0.7f, -0.8f};
79 
80 static const float s_constInMat31[] = {1.2f, 0.1f, -0.1f, 0.1f, 0.9f, 0.2f, 0.2f, -0.1f, 0.7f};
81 static const float s_constInMat41[] = {1.2f,  -0.2f, 0.4f,  0.1f, 0.1f, 0.8f, -0.1f, -0.2f,
82                                        -0.2f, 0.1f,  -1.1f, 0.3f, 0.1f, 0.2f, 0.3f,  0.9f};
83 
84 static const Mat2 s_constInMat2[2] = {tcu::Mat2(s_constInMat20), tcu::Mat2(s_constInMat21)};
85 static const Mat3 s_constInMat3[2] = {tcu::translationMatrix(tcu::Vec2(0.2f, -0.3f)), tcu::Mat3(s_constInMat31)};
86 static const Mat4 s_constInMat4[2] = {tcu::translationMatrix(tcu::Vec3(0.2f, -0.3f, 0.15f)), tcu::Mat4(s_constInMat41)};
87 
88 namespace MatrixCaseUtils
89 {
90 
91 enum InputType
92 {
93     INPUTTYPE_CONST = 0,
94     INPUTTYPE_UNIFORM,
95     INPUTTYPE_DYNAMIC,
96 
97     INPUTTYPE_LAST
98 };
99 
100 struct ShaderInput
101 {
ShaderInputdeqp::gles2::Functional::MatrixCaseUtils::ShaderInput102     ShaderInput(InputType inputType_, DataType dataType_, Precision precision_)
103         : inputType(inputType_)
104         , dataType(dataType_)
105         , precision(precision_)
106     {
107     }
108 
109     InputType inputType;
110     DataType dataType;
111     Precision precision;
112 };
113 
114 enum MatrixOp
115 {
116     OP_ADD = 0,
117     OP_SUB,
118     OP_MUL,
119     OP_DIV,
120     OP_COMP_MUL,
121     OP_UNARY_PLUS,
122     OP_NEGATION,
123     OP_PRE_INCREMENT,
124     OP_PRE_DECREMENT,
125     OP_POST_INCREMENT,
126     OP_POST_DECREMENT,
127     OP_ADD_INTO,
128     OP_SUBTRACT_FROM,
129     OP_MULTIPLY_INTO,
130     OP_DIVIDE_INTO,
131 
132     OP_LAST
133 };
134 
135 // Type traits.
136 
137 template <int DataT>
138 struct TypeTraits;
139 
140 #define DECLARE_TYPE_TRAIT(DATATYPE, TYPE) \
141     template <>                            \
142     struct TypeTraits<DATATYPE>            \
143     {                                      \
144         typedef TYPE Type;                 \
145     }
146 
147 DECLARE_TYPE_TRAIT(TYPE_FLOAT, float);
148 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC2, tcu::Vec2);
149 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC3, tcu::Vec3);
150 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC4, tcu::Vec4);
151 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2, tcu::Mat2);
152 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3, tcu::Mat3);
153 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4, tcu::Mat4);
154 
155 // Operation info
156 
157 enum OperationType
158 {
159     OPERATIONTYPE_BINARY_OPERATOR = 0,
160     OPERATIONTYPE_BINARY_FUNCTION,
161     OPERATIONTYPE_UNARY_PREFIX_OPERATOR,
162     OPERATIONTYPE_UNARY_POSTFIX_OPERATOR,
163     OPERATIONTYPE_ASSIGNMENT,
164 
165     OPERATIONTYPE_LAST
166 };
167 
getOperationName(MatrixOp op)168 static const char *getOperationName(MatrixOp op)
169 {
170     switch (op)
171     {
172     case OP_ADD:
173         return "+";
174     case OP_SUB:
175         return "-";
176     case OP_MUL:
177         return "*";
178     case OP_DIV:
179         return "/";
180     case OP_COMP_MUL:
181         return "matrixCompMult";
182     case OP_UNARY_PLUS:
183         return "+";
184     case OP_NEGATION:
185         return "-";
186     case OP_PRE_INCREMENT:
187         return "++";
188     case OP_PRE_DECREMENT:
189         return "--";
190     case OP_POST_INCREMENT:
191         return "++";
192     case OP_POST_DECREMENT:
193         return "--";
194     case OP_ADD_INTO:
195         return "+=";
196     case OP_SUBTRACT_FROM:
197         return "-=";
198     case OP_MULTIPLY_INTO:
199         return "*=";
200     case OP_DIVIDE_INTO:
201         return "/=";
202     default:
203         DE_ASSERT(false);
204         return "";
205     }
206 }
207 
getOperationType(MatrixOp op)208 static OperationType getOperationType(MatrixOp op)
209 {
210     switch (op)
211     {
212     case OP_ADD:
213         return OPERATIONTYPE_BINARY_OPERATOR;
214     case OP_SUB:
215         return OPERATIONTYPE_BINARY_OPERATOR;
216     case OP_MUL:
217         return OPERATIONTYPE_BINARY_OPERATOR;
218     case OP_DIV:
219         return OPERATIONTYPE_BINARY_OPERATOR;
220     case OP_COMP_MUL:
221         return OPERATIONTYPE_BINARY_FUNCTION;
222     case OP_UNARY_PLUS:
223         return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
224     case OP_NEGATION:
225         return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
226     case OP_PRE_INCREMENT:
227         return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
228     case OP_PRE_DECREMENT:
229         return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
230     case OP_POST_INCREMENT:
231         return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR;
232     case OP_POST_DECREMENT:
233         return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR;
234     case OP_ADD_INTO:
235         return OPERATIONTYPE_ASSIGNMENT;
236     case OP_SUBTRACT_FROM:
237         return OPERATIONTYPE_ASSIGNMENT;
238     case OP_MULTIPLY_INTO:
239         return OPERATIONTYPE_ASSIGNMENT;
240     case OP_DIVIDE_INTO:
241         return OPERATIONTYPE_ASSIGNMENT;
242     default:
243         DE_ASSERT(false);
244         return OPERATIONTYPE_LAST;
245     }
246 }
247 
248 enum TestMatrixType
249 {
250     TESTMATRIXTYPE_DEFAULT = 0,
251     TESTMATRIXTYPE_NEGATED,
252     TESTMATRIXTYPE_INCREMENTED,
253     TESTMATRIXTYPE_DECREMENTED,
254 
255     TESTMATRIXTYPE_LAST
256 };
257 
getOperationTestMatrixType(MatrixOp op)258 static TestMatrixType getOperationTestMatrixType(MatrixOp op)
259 {
260     switch (op)
261     {
262     case OP_ADD:
263         return TESTMATRIXTYPE_DEFAULT;
264     case OP_SUB:
265         return TESTMATRIXTYPE_DEFAULT;
266     case OP_MUL:
267         return TESTMATRIXTYPE_DEFAULT;
268     case OP_DIV:
269         return TESTMATRIXTYPE_DEFAULT;
270     case OP_COMP_MUL:
271         return TESTMATRIXTYPE_DEFAULT;
272     case OP_UNARY_PLUS:
273         return TESTMATRIXTYPE_DEFAULT;
274     case OP_NEGATION:
275         return TESTMATRIXTYPE_NEGATED;
276     case OP_PRE_INCREMENT:
277         return TESTMATRIXTYPE_NEGATED;
278     case OP_PRE_DECREMENT:
279         return TESTMATRIXTYPE_INCREMENTED;
280     case OP_POST_INCREMENT:
281         return TESTMATRIXTYPE_NEGATED;
282     case OP_POST_DECREMENT:
283         return TESTMATRIXTYPE_DEFAULT;
284     case OP_ADD_INTO:
285         return TESTMATRIXTYPE_DECREMENTED;
286     case OP_SUBTRACT_FROM:
287         return TESTMATRIXTYPE_DEFAULT;
288     case OP_MULTIPLY_INTO:
289         return TESTMATRIXTYPE_DEFAULT;
290     case OP_DIVIDE_INTO:
291         return TESTMATRIXTYPE_DEFAULT;
292 
293     default:
294         DE_ASSERT(false);
295         return TESTMATRIXTYPE_LAST;
296     }
297 }
298 
isOperationBinary(MatrixOp op)299 static bool isOperationBinary(MatrixOp op)
300 {
301     return getOperationType(op) == OPERATIONTYPE_BINARY_OPERATOR ||
302            getOperationType(op) == OPERATIONTYPE_BINARY_FUNCTION || getOperationType(op) == OPERATIONTYPE_ASSIGNMENT;
303 }
304 
isOperationMatrixScalar(MatrixOp op)305 static bool isOperationMatrixScalar(MatrixOp op)
306 {
307     return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV;
308 }
309 
isOperationMatrixVector(MatrixOp op)310 static bool isOperationMatrixVector(MatrixOp op)
311 {
312     return op == OP_MUL;
313 }
314 
isOperationMatrixMatrix(MatrixOp op)315 static bool isOperationMatrixMatrix(MatrixOp op)
316 {
317     return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV || op == OP_COMP_MUL;
318 }
319 
isOperationUnary(MatrixOp op)320 static bool isOperationUnary(MatrixOp op)
321 {
322     return op == OP_UNARY_PLUS || op == OP_NEGATION || op == OP_PRE_INCREMENT || op == OP_PRE_DECREMENT ||
323            op == OP_POST_INCREMENT || op == OP_POST_DECREMENT;
324 }
325 
isOperationValueModifying(MatrixOp op)326 static bool isOperationValueModifying(MatrixOp op)
327 {
328     return op == OP_PRE_INCREMENT || op == OP_PRE_DECREMENT || op == OP_POST_INCREMENT || op == OP_POST_DECREMENT;
329 }
330 
isOperationAssignment(MatrixOp op)331 static bool isOperationAssignment(MatrixOp op)
332 {
333     return op == OP_ADD_INTO || op == OP_SUBTRACT_FROM || op == OP_MULTIPLY_INTO || op == OP_DIVIDE_INTO;
334 }
335 
336 // Operation nature
337 
338 enum OperationNature
339 {
340     OPERATIONNATURE_PURE = 0,
341     OPERATIONNATURE_MUTATING,
342     OPERATIONNATURE_ASSIGNMENT,
343 
344     OPERATIONNATURE_LAST
345 };
346 
getOperationNature(MatrixOp op)347 static OperationNature getOperationNature(MatrixOp op)
348 {
349     if (isOperationAssignment(op))
350         return OPERATIONNATURE_ASSIGNMENT;
351 
352     if (isOperationValueModifying(op))
353         return OPERATIONNATURE_MUTATING;
354 
355     return OPERATIONNATURE_PURE;
356 }
357 
358 // Input value loader.
359 
360 template <int InputT, int DataT>
361 typename TypeTraits<DataT>::Type getInputValue(const ShaderEvalContext &evalCtx, int inputNdx);
362 
363 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)364 inline float getInputValue<INPUTTYPE_CONST, TYPE_FLOAT>(const ShaderEvalContext &evalCtx, int inputNdx)
365 {
366     DE_UNREF(evalCtx);
367     return s_constInFloat[inputNdx];
368 }
369 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)370 inline tcu::Vec2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC2>(const ShaderEvalContext &evalCtx, int inputNdx)
371 {
372     DE_UNREF(evalCtx);
373     return s_constInVec2[inputNdx];
374 }
375 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)376 inline tcu::Vec3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC3>(const ShaderEvalContext &evalCtx, int inputNdx)
377 {
378     DE_UNREF(evalCtx);
379     return s_constInVec3[inputNdx];
380 }
381 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)382 inline tcu::Vec4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC4>(const ShaderEvalContext &evalCtx, int inputNdx)
383 {
384     DE_UNREF(evalCtx);
385     return s_constInVec4[inputNdx];
386 }
387 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)388 inline tcu::Mat2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2>(const ShaderEvalContext &evalCtx, int inputNdx)
389 {
390     DE_UNREF(evalCtx);
391     return s_constInMat2[inputNdx];
392 }
393 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)394 inline tcu::Mat3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3>(const ShaderEvalContext &evalCtx, int inputNdx)
395 {
396     DE_UNREF(evalCtx);
397     return s_constInMat3[inputNdx];
398 }
399 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)400 inline tcu::Mat4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT4>(const ShaderEvalContext &evalCtx, int inputNdx)
401 {
402     DE_UNREF(evalCtx);
403     return s_constInMat4[inputNdx];
404 }
405 
406 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)407 inline float getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT>(const ShaderEvalContext &evalCtx, int inputNdx)
408 {
409     DE_UNREF(inputNdx);
410     return evalCtx.coords.x();
411 }
412 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)413 inline tcu::Vec2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC2>(const ShaderEvalContext &evalCtx, int inputNdx)
414 {
415     DE_UNREF(inputNdx);
416     return evalCtx.coords.swizzle(0, 1);
417 }
418 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)419 inline tcu::Vec3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC3>(const ShaderEvalContext &evalCtx, int inputNdx)
420 {
421     DE_UNREF(inputNdx);
422     return evalCtx.coords.swizzle(0, 1, 2);
423 }
424 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)425 inline tcu::Vec4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC4>(const ShaderEvalContext &evalCtx, int inputNdx)
426 {
427     DE_UNREF(inputNdx);
428     return evalCtx.coords.swizzle(0, 1, 2, 3);
429 }
430 
431 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)432 inline tcu::Mat2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2>(const ShaderEvalContext &evalCtx, int inputNdx)
433 {
434     DE_UNREF(inputNdx); // Not used.
435     tcu::Mat2 m;
436     m.setColumn(0, evalCtx.in[0].swizzle(0, 1));
437     m.setColumn(1, evalCtx.in[1].swizzle(0, 1));
438     return m;
439 }
440 
441 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)442 inline tcu::Mat3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3>(const ShaderEvalContext &evalCtx, int inputNdx)
443 {
444     DE_UNREF(inputNdx); // Not used.
445     tcu::Mat3 m;
446     m.setColumn(0, evalCtx.in[0].swizzle(0, 1, 2));
447     m.setColumn(1, evalCtx.in[1].swizzle(0, 1, 2));
448     m.setColumn(2, evalCtx.in[2].swizzle(0, 1, 2));
449     return m;
450 }
451 
452 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)453 inline tcu::Mat4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4>(const ShaderEvalContext &evalCtx, int inputNdx)
454 {
455     DE_UNREF(inputNdx); // Not used.
456     tcu::Mat4 m;
457     m.setColumn(0, evalCtx.in[0]);
458     m.setColumn(1, evalCtx.in[1]);
459     m.setColumn(2, evalCtx.in[2]);
460     m.setColumn(3, evalCtx.in[3]);
461     return m;
462 }
463 
464 // Reduction from expression result to vec3.
465 
reduceToVec3(const tcu::Vec2 & value)466 inline tcu::Vec3 reduceToVec3(const tcu::Vec2 &value)
467 {
468     return value.swizzle(0, 1, 0);
469 }
reduceToVec3(const tcu::Vec3 & value)470 inline tcu::Vec3 reduceToVec3(const tcu::Vec3 &value)
471 {
472     return value;
473 }
reduceToVec3(const tcu::Vec4 & value)474 inline tcu::Vec3 reduceToVec3(const tcu::Vec4 &value)
475 {
476     return tcu::Vec3(value.x(), value.y(), value.z() + value.w());
477 }
reduceToVec3(const tcu::Mat2 & value)478 inline tcu::Vec3 reduceToVec3(const tcu::Mat2 &value)
479 {
480     return tcu::Vec3(value(0, 0), value(0, 1), value(1, 0) + value(1, 1));
481 }
reduceToVec3(const tcu::Mat3 & value)482 inline tcu::Vec3 reduceToVec3(const tcu::Mat3 &value)
483 {
484     return value.getColumn(0) + value.getColumn(1) + value.getColumn(2);
485 }
reduceToVec3(const tcu::Mat4 & value)486 inline tcu::Vec3 reduceToVec3(const tcu::Mat4 &value)
487 {
488     return value.getColumn(0).swizzle(0, 1, 2) + value.getColumn(1).swizzle(1, 2, 3) +
489            value.getColumn(2).swizzle(2, 3, 0) + value.getColumn(3).swizzle(3, 0, 1);
490 }
491 
492 // matrixCompMult
493 
494 template <typename T, int Rows, int Cols>
matrixCompMult(const tcu::Matrix<T,Rows,Cols> & a,const tcu::Matrix<T,Rows,Cols> & b)495 tcu::Matrix<T, Rows, Cols> matrixCompMult(const tcu::Matrix<T, Rows, Cols> &a, const tcu::Matrix<T, Rows, Cols> &b)
496 {
497     tcu::Matrix<T, Rows, Cols> retVal;
498 
499     for (int r = 0; r < Rows; ++r)
500         for (int c = 0; c < Cols; ++c)
501             retVal(r, c) = a(r, c) * b(r, c);
502 
503     return retVal;
504 }
505 
506 // negate
507 
508 template <typename T, int Rows, int Cols>
negate(const tcu::Matrix<T,Rows,Cols> & mat)509 tcu::Matrix<T, Rows, Cols> negate(const tcu::Matrix<T, Rows, Cols> &mat)
510 {
511     tcu::Matrix<T, Rows, Cols> retVal;
512 
513     for (int r = 0; r < Rows; ++r)
514         for (int c = 0; c < Cols; ++c)
515             retVal(r, c) = -mat(r, c);
516 
517     return retVal;
518 }
519 
520 // increment/decrement
521 
522 template <typename T, int Rows, int Cols>
increment(const tcu::Matrix<T,Rows,Cols> & mat)523 tcu::Matrix<T, Rows, Cols> increment(const tcu::Matrix<T, Rows, Cols> &mat)
524 {
525     tcu::Matrix<T, Rows, Cols> retVal;
526 
527     for (int r = 0; r < Rows; ++r)
528         for (int c = 0; c < Cols; ++c)
529             retVal(r, c) = mat(r, c) + 1.0f;
530 
531     return retVal;
532 }
533 
534 template <typename T, int Rows, int Cols>
decrement(const tcu::Matrix<T,Rows,Cols> & mat)535 tcu::Matrix<T, Rows, Cols> decrement(const tcu::Matrix<T, Rows, Cols> &mat)
536 {
537     tcu::Matrix<T, Rows, Cols> retVal;
538 
539     for (int r = 0; r < Rows; ++r)
540         for (int c = 0; c < Cols; ++c)
541             retVal(r, c) = mat(r, c) - 1.0f;
542 
543     return retVal;
544 }
545 
546 // Evaluator template.
547 
548 template <int Op, int In0Type, int In0DataType, int In1Type, int In1DataType>
549 struct Evaluator;
550 
551 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
552 struct Evaluator<OP_ADD, In0Type, In0DataType, In1Type, In1DataType>
553 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator554     static void evaluate(ShaderEvalContext &evalCtx)
555     {
556         evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) +
557                                            getInputValue<In1Type, In1DataType>(evalCtx, 1));
558     }
559 };
560 
561 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
562 struct Evaluator<OP_SUB, In0Type, In0DataType, In1Type, In1DataType>
563 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator564     static void evaluate(ShaderEvalContext &evalCtx)
565     {
566         evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) -
567                                            getInputValue<In1Type, In1DataType>(evalCtx, 1));
568     }
569 };
570 
571 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
572 struct Evaluator<OP_MUL, In0Type, In0DataType, In1Type, In1DataType>
573 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator574     static void evaluate(ShaderEvalContext &evalCtx)
575     {
576         evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) *
577                                            getInputValue<In1Type, In1DataType>(evalCtx, 1));
578     }
579 };
580 
581 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
582 struct Evaluator<OP_DIV, In0Type, In0DataType, In1Type, In1DataType>
583 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator584     static void evaluate(ShaderEvalContext &evalCtx)
585     {
586         evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) /
587                                            getInputValue<In1Type, In1DataType>(evalCtx, 1));
588     }
589 };
590 
591 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
592 struct Evaluator<OP_COMP_MUL, In0Type, In0DataType, In1Type, In1DataType>
593 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator594     static void evaluate(ShaderEvalContext &evalCtx)
595     {
596         evalCtx.color.xyz() = reduceToVec3(matrixCompMult(getInputValue<In0Type, In0DataType>(evalCtx, 0),
597                                                           getInputValue<In1Type, In1DataType>(evalCtx, 1)));
598     }
599 };
600 
601 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
602 struct Evaluator<OP_UNARY_PLUS, In0Type, In0DataType, In1Type, In1DataType>
603 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator604     static void evaluate(ShaderEvalContext &evalCtx)
605     {
606         evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0));
607     }
608 };
609 
610 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
611 struct Evaluator<OP_NEGATION, In0Type, In0DataType, In1Type, In1DataType>
612 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator613     static void evaluate(ShaderEvalContext &evalCtx)
614     {
615         evalCtx.color.xyz() = reduceToVec3(negate(getInputValue<In0Type, In0DataType>(evalCtx, 0)));
616     }
617 };
618 
619 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
620 struct Evaluator<OP_PRE_INCREMENT, In0Type, In0DataType, In1Type, In1DataType>
621 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator622     static void evaluate(ShaderEvalContext &evalCtx)
623     {
624         // modifying reduction: sum modified value too
625         evalCtx.color.xyz() = reduceToVec3(increment(getInputValue<In0Type, In0DataType>(evalCtx, 0))) +
626                               reduceToVec3(increment(getInputValue<In0Type, In0DataType>(evalCtx, 0)));
627     }
628 };
629 
630 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
631 struct Evaluator<OP_PRE_DECREMENT, In0Type, In0DataType, In1Type, In1DataType>
632 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator633     static void evaluate(ShaderEvalContext &evalCtx)
634     {
635         // modifying reduction: sum modified value too
636         evalCtx.color.xyz() = reduceToVec3(decrement(getInputValue<In0Type, In0DataType>(evalCtx, 0))) +
637                               reduceToVec3(decrement(getInputValue<In0Type, In0DataType>(evalCtx, 0)));
638     }
639 };
640 
641 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
642 struct Evaluator<OP_POST_INCREMENT, In0Type, In0DataType, In1Type, In1DataType>
643 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator644     static void evaluate(ShaderEvalContext &evalCtx)
645     {
646         // modifying reduction: sum modified value too
647         evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0)) +
648                               reduceToVec3(increment(getInputValue<In0Type, In0DataType>(evalCtx, 0)));
649     }
650 };
651 
652 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
653 struct Evaluator<OP_POST_DECREMENT, In0Type, In0DataType, In1Type, In1DataType>
654 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator655     static void evaluate(ShaderEvalContext &evalCtx)
656     {
657         // modifying reduction: sum modified value too
658         evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0)) +
659                               reduceToVec3(decrement(getInputValue<In0Type, In0DataType>(evalCtx, 0)));
660     }
661 };
662 
663 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
664 struct Evaluator<OP_ADD_INTO, In0Type, In0DataType, In1Type, In1DataType>
665 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator666     static void evaluate(ShaderEvalContext &evalCtx)
667     {
668         evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) +
669                                            getInputValue<In1Type, In1DataType>(evalCtx, 1));
670     }
671 };
672 
673 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
674 struct Evaluator<OP_SUBTRACT_FROM, In0Type, In0DataType, In1Type, In1DataType>
675 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator676     static void evaluate(ShaderEvalContext &evalCtx)
677     {
678         evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) -
679                                            getInputValue<In1Type, In1DataType>(evalCtx, 1));
680     }
681 };
682 
683 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
684 struct Evaluator<OP_MULTIPLY_INTO, In0Type, In0DataType, In1Type, In1DataType>
685 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator686     static void evaluate(ShaderEvalContext &evalCtx)
687     {
688         evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) *
689                                            getInputValue<In1Type, In1DataType>(evalCtx, 1));
690     }
691 };
692 
693 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
694 struct Evaluator<OP_DIVIDE_INTO, In0Type, In0DataType, In1Type, In1DataType>
695 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator696     static void evaluate(ShaderEvalContext &evalCtx)
697     {
698         evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) /
699                                            getInputValue<In1Type, In1DataType>(evalCtx, 1));
700     }
701 };
702 
getEvalFunc(const ShaderInput & in0,const ShaderInput & in1,MatrixOp op)703 ShaderEvalFunc getEvalFunc(const ShaderInput &in0, const ShaderInput &in1, MatrixOp op)
704 {
705     DE_STATIC_ASSERT(TYPE_LAST <= (1 << 7));
706     DE_STATIC_ASSERT(OP_LAST <= (1 << 4));
707     DE_STATIC_ASSERT(INPUTTYPE_LAST <= (1 << 2));
708 
709 #define PACK_EVAL_CASE(OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE) \
710     (((OP) << 18) | ((IN0TYPE) << 16) | ((IN0DATATYPE) << 9) | ((IN1TYPE) << 7) | (IN1DATATYPE))
711 
712 #define MAKE_EVAL_CASE(OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)   \
713     case PACK_EVAL_CASE(OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE): \
714         return Evaluator<OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE>::evaluate
715 
716 #define SCALAR_OPS(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)          \
717     MAKE_EVAL_CASE(OP_ADD, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \
718     MAKE_EVAL_CASE(OP_SUB, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \
719     MAKE_EVAL_CASE(OP_MUL, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \
720     MAKE_EVAL_CASE(OP_DIV, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)
721 
722 #define ALL_OPS(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)             \
723     MAKE_EVAL_CASE(OP_ADD, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \
724     MAKE_EVAL_CASE(OP_SUB, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \
725     MAKE_EVAL_CASE(OP_MUL, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \
726     MAKE_EVAL_CASE(OP_DIV, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \
727     MAKE_EVAL_CASE(OP_COMP_MUL, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)
728 
729 #define MUL_OP(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE) \
730     MAKE_EVAL_CASE(OP_MUL, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)
731 
732 #define MAKE_MAT_SCALAR_VEC_CASES(OP, TYPE0, TYPE1)       \
733     OP(INPUTTYPE_CONST, TYPE0, INPUTTYPE_CONST, TYPE1);   \
734     OP(INPUTTYPE_DYNAMIC, TYPE0, INPUTTYPE_CONST, TYPE1); \
735     OP(INPUTTYPE_CONST, TYPE0, INPUTTYPE_DYNAMIC, TYPE1); \
736     OP(INPUTTYPE_DYNAMIC, TYPE0, INPUTTYPE_DYNAMIC, TYPE1)
737 
738 #define MAKE_MAT_MAT_CASES(OP, MATTYPE)                     \
739     OP(INPUTTYPE_CONST, MATTYPE, INPUTTYPE_CONST, MATTYPE); \
740     OP(INPUTTYPE_DYNAMIC, MATTYPE, INPUTTYPE_CONST, MATTYPE)
741 
742 #define UNARY_OP(IN0TYPE, IN0DATATYPE)                                                   \
743     MAKE_EVAL_CASE(OP_UNARY_PLUS, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST);     \
744     MAKE_EVAL_CASE(OP_NEGATION, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST);       \
745     MAKE_EVAL_CASE(OP_PRE_INCREMENT, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST);  \
746     MAKE_EVAL_CASE(OP_PRE_DECREMENT, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST);  \
747     MAKE_EVAL_CASE(OP_POST_INCREMENT, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST); \
748     MAKE_EVAL_CASE(OP_POST_DECREMENT, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST)
749 
750 #define MAKE_UNARY_CASES(OP, MATTYPE) \
751     OP(INPUTTYPE_CONST, MATTYPE);     \
752     OP(INPUTTYPE_DYNAMIC, MATTYPE)
753 
754 #define ASSIGN_OP(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)                     \
755     MAKE_EVAL_CASE(OP_ADD_INTO, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);      \
756     MAKE_EVAL_CASE(OP_SUBTRACT_FROM, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \
757     MAKE_EVAL_CASE(OP_MULTIPLY_INTO, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \
758     MAKE_EVAL_CASE(OP_DIVIDE_INTO, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)
759 
760 #define MAKE_ASSIGNMENT_CASES(OP, MATTYPE)                    \
761     OP(INPUTTYPE_CONST, MATTYPE, INPUTTYPE_CONST, MATTYPE);   \
762     OP(INPUTTYPE_DYNAMIC, MATTYPE, INPUTTYPE_CONST, MATTYPE); \
763     OP(INPUTTYPE_CONST, MATTYPE, INPUTTYPE_DYNAMIC, MATTYPE); \
764     OP(INPUTTYPE_DYNAMIC, MATTYPE, INPUTTYPE_DYNAMIC, MATTYPE)
765 
766     // \note At the moment there is no difference between uniform and const inputs. This saves binary size.
767     InputType in0Type = in0.inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_DYNAMIC : INPUTTYPE_CONST;
768     InputType in1Type = in1.inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_DYNAMIC : INPUTTYPE_CONST;
769 
770     switch (PACK_EVAL_CASE(op, in0Type, in0.dataType, in1Type, in1.dataType))
771     {
772         // Matrix-scalar.
773         MAKE_MAT_SCALAR_VEC_CASES(SCALAR_OPS, TYPE_FLOAT_MAT2, TYPE_FLOAT);
774         MAKE_MAT_SCALAR_VEC_CASES(SCALAR_OPS, TYPE_FLOAT_MAT3, TYPE_FLOAT);
775         MAKE_MAT_SCALAR_VEC_CASES(SCALAR_OPS, TYPE_FLOAT_MAT4, TYPE_FLOAT);
776 
777         // Matrix-vector.
778         MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_MAT2, TYPE_FLOAT_VEC2);
779         MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_MAT3, TYPE_FLOAT_VEC3);
780         MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_MAT4, TYPE_FLOAT_VEC4);
781 
782         // Vector-matrix.
783         MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT2);
784         MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT3);
785         MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT4);
786 
787         // Matrix-matrix.
788         MAKE_MAT_MAT_CASES(ALL_OPS, TYPE_FLOAT_MAT2);
789         MAKE_MAT_MAT_CASES(ALL_OPS, TYPE_FLOAT_MAT3);
790         MAKE_MAT_MAT_CASES(ALL_OPS, TYPE_FLOAT_MAT4);
791 
792         // Unary matrix
793         MAKE_UNARY_CASES(UNARY_OP, TYPE_FLOAT_MAT2);
794         MAKE_UNARY_CASES(UNARY_OP, TYPE_FLOAT_MAT3);
795         MAKE_UNARY_CASES(UNARY_OP, TYPE_FLOAT_MAT4);
796 
797         // Assignment matrix
798         MAKE_ASSIGNMENT_CASES(ASSIGN_OP, TYPE_FLOAT_MAT2);
799         MAKE_ASSIGNMENT_CASES(ASSIGN_OP, TYPE_FLOAT_MAT3);
800         MAKE_ASSIGNMENT_CASES(ASSIGN_OP, TYPE_FLOAT_MAT4);
801 
802     default:
803         DE_ASSERT(false);
804         return DE_NULL;
805     }
806 
807 #undef PACK_EVAL_CASE
808 #undef MAKE_EVAL_CASE
809 #undef MUL_OP
810 #undef ALL_OPS
811 #undef MAKE_MAT_SCALAR_VEC_CASES
812 #undef MAKE_MAT_MAT_CASES
813 }
814 
815 // Shader source format utilities.
816 
817 template <int Size>
writeVectorConstructor(std::ostream & str,const tcu::Vector<float,Size> & v)818 void writeVectorConstructor(std::ostream &str, const tcu::Vector<float, Size> &v)
819 {
820     str << "vec" << Size << "(";
821     for (int ndx = 0; ndx < Size; ndx++)
822     {
823         if (ndx != 0)
824             str << ", ";
825         str << de::floatToString(v[ndx], 1);
826     }
827     str << ")";
828 }
829 
830 template <int Cols, int Rows>
writeMatrixConstructor(std::ostream & str,const tcu::Matrix<float,Rows,Cols> & m)831 void writeMatrixConstructor(std::ostream &str, const tcu::Matrix<float, Rows, Cols> &m)
832 {
833     if (Rows == Cols)
834         str << "mat" << Cols;
835     else
836         str << "mat" << Cols << "x" << Rows;
837 
838     str << "(";
839     for (int colNdx = 0; colNdx < Cols; colNdx++)
840     {
841         for (int rowNdx = 0; rowNdx < Rows; rowNdx++)
842         {
843             if (rowNdx > 0 || colNdx > 0)
844                 str << ", ";
845             str << de::floatToString(m(rowNdx, colNdx), 1);
846         }
847     }
848     str << ")";
849 }
850 
851 } // namespace MatrixCaseUtils
852 
853 using namespace MatrixCaseUtils;
854 
855 class ShaderMatrixCase : public ShaderRenderCase
856 {
857 public:
858     ShaderMatrixCase(Context &context, const char *name, const char *desc, const ShaderInput &in0,
859                      const ShaderInput &in1, MatrixOp op, bool isVertexCase);
860     ~ShaderMatrixCase(void);
861 
862     void init(void);
863 
864 protected:
865     std::string genGLSLMatToVec3Reduction(const glu::DataType &matType, const char *varName);
866     void setupUniforms(int programID, const tcu::Vec4 &constCoords);
867 
868 private:
869     ShaderInput m_in0;
870     ShaderInput m_in1;
871     MatrixOp m_op;
872 };
873 
ShaderMatrixCase(Context & context,const char * name,const char * desc,const ShaderInput & in0,const ShaderInput & in1,MatrixOp op,bool isVertexCase)874 ShaderMatrixCase::ShaderMatrixCase(Context &context, const char *name, const char *desc, const ShaderInput &in0,
875                                    const ShaderInput &in1, MatrixOp op, bool isVertexCase)
876     : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc,
877                        isVertexCase, getEvalFunc(in0, in1, op))
878     , m_in0(in0)
879     , m_in1(in1)
880     , m_op(op)
881 {
882 }
883 
~ShaderMatrixCase(void)884 ShaderMatrixCase::~ShaderMatrixCase(void)
885 {
886 }
887 
init(void)888 void ShaderMatrixCase::init(void)
889 {
890     std::ostringstream vtx;
891     std::ostringstream frag;
892     std::ostringstream &op = m_isVertexCase ? vtx : frag;
893 
894     bool isInDynMat0 = isDataTypeMatrix(m_in0.dataType) && m_in0.inputType == INPUTTYPE_DYNAMIC;
895     bool isInDynMat1 = isDataTypeMatrix(m_in1.dataType) && m_in1.inputType == INPUTTYPE_DYNAMIC;
896     string inValue0;
897     string inValue1;
898     DataType resultType  = TYPE_LAST;
899     Precision resultPrec = m_in0.precision;
900     vector<string> passVars;
901     int numInputs = (isOperationBinary(m_op)) ? (2) : (1);
902 
903     std::string operationValue0;
904     std::string operationValue1;
905 
906     DE_ASSERT(!isInDynMat0 || !isInDynMat1); // Only single dynamic matrix input is allowed.
907     DE_UNREF(isInDynMat0 && isInDynMat1);
908 
909     // Compute result type.
910     if (isDataTypeMatrix(m_in0.dataType) && isDataTypeMatrix(m_in1.dataType))
911     {
912         DE_ASSERT(m_in0.dataType == m_in1.dataType);
913         resultType = m_in0.dataType;
914     }
915     else if (getOperationType(m_op) == OPERATIONTYPE_UNARY_PREFIX_OPERATOR ||
916              getOperationType(m_op) == OPERATIONTYPE_UNARY_POSTFIX_OPERATOR)
917     {
918         resultType = m_in0.dataType;
919     }
920     else
921     {
922         int matNdx          = isDataTypeMatrix(m_in0.dataType) ? 0 : 1;
923         DataType matrixType = matNdx == 0 ? m_in0.dataType : m_in1.dataType;
924         DataType otherType  = matNdx == 0 ? m_in1.dataType : m_in0.dataType;
925 
926         if (otherType == TYPE_FLOAT)
927             resultType = matrixType;
928         else
929         {
930             DE_ASSERT(isDataTypeVector(otherType));
931             resultType = otherType;
932         }
933     }
934 
935     vtx << "attribute highp vec4 a_position;\n";
936     if (m_isVertexCase)
937     {
938         vtx << "varying mediump vec4 v_color;\n";
939         frag << "varying mediump vec4 v_color;\n";
940     }
941 
942     // Input declarations.
943     for (int inNdx = 0; inNdx < numInputs; inNdx++)
944     {
945         const ShaderInput &in = inNdx > 0 ? m_in1 : m_in0;
946         const char *precName  = getPrecisionName(in.precision);
947         const char *typeName  = getDataTypeName(in.dataType);
948         string &inValue       = inNdx > 0 ? inValue1 : inValue0;
949 
950         if (in.inputType == INPUTTYPE_DYNAMIC)
951         {
952             vtx << "attribute " << precName << " " << typeName << " a_";
953 
954             if (isDataTypeMatrix(in.dataType))
955             {
956                 // a_matN, v_matN
957                 vtx << typeName << ";\n";
958                 if (!m_isVertexCase)
959                 {
960                     vtx << "varying " << precName << " " << typeName << " v_" << typeName << ";\n";
961                     frag << "varying " << precName << " " << typeName << " v_" << typeName << ";\n";
962                     passVars.push_back(typeName);
963                 }
964 
965                 inValue = string(m_isVertexCase ? "a_" : "v_") + getDataTypeName(in.dataType);
966             }
967             else
968             {
969                 // a_coords, v_coords
970                 vtx << "coords;\n";
971                 if (!m_isVertexCase)
972                 {
973                     vtx << "varying " << precName << " " << typeName << " v_coords;\n";
974                     frag << "varying " << precName << " " << typeName << " v_coords;\n";
975                     passVars.push_back("coords");
976                 }
977 
978                 inValue = m_isVertexCase ? "a_coords" : "v_coords";
979             }
980         }
981         else if (in.inputType == INPUTTYPE_UNIFORM)
982         {
983             op << "uniform " << precName << " " << typeName << " u_in" << inNdx << ";\n";
984             inValue = string("u_in") + de::toString(inNdx);
985         }
986         else if (in.inputType == INPUTTYPE_CONST)
987         {
988             op << "const " << precName << " " << typeName << " in" << inNdx << " = ";
989 
990             // Generate declaration.
991             switch (in.dataType)
992             {
993             case TYPE_FLOAT:
994                 op << de::floatToString(s_constInFloat[inNdx], 1);
995                 break;
996             case TYPE_FLOAT_VEC2:
997                 writeVectorConstructor<2>(op, s_constInVec2[inNdx]);
998                 break;
999             case TYPE_FLOAT_VEC3:
1000                 writeVectorConstructor<3>(op, s_constInVec3[inNdx]);
1001                 break;
1002             case TYPE_FLOAT_VEC4:
1003                 writeVectorConstructor<4>(op, s_constInVec4[inNdx]);
1004                 break;
1005             case TYPE_FLOAT_MAT2:
1006                 writeMatrixConstructor<2, 2>(op, Mat2(s_constInMat2[inNdx]));
1007                 break;
1008             case TYPE_FLOAT_MAT3:
1009                 writeMatrixConstructor<3, 3>(op, Mat3(s_constInMat3[inNdx]));
1010                 break;
1011             case TYPE_FLOAT_MAT4:
1012                 writeMatrixConstructor<4, 4>(op, Mat4(s_constInMat4[inNdx]));
1013                 break;
1014 
1015             default:
1016                 DE_ASSERT(false);
1017             }
1018 
1019             op << ";\n";
1020 
1021             inValue = string("in") + de::toString(inNdx);
1022         }
1023     }
1024 
1025     vtx << "\n"
1026         << "void main (void)\n"
1027         << "{\n"
1028         << "    gl_Position = a_position;\n";
1029     frag << "\n"
1030          << "void main (void)\n"
1031          << "{\n";
1032 
1033     if (m_isVertexCase)
1034     {
1035         frag << "    gl_FragColor = v_color;\n";
1036     }
1037     else
1038     {
1039         for (vector<string>::const_iterator copyIter = passVars.begin(); copyIter != passVars.end(); copyIter++)
1040             vtx << "    v_" << *copyIter << " = "
1041                 << "a_" << *copyIter << ";\n";
1042     }
1043 
1044     // Operation.
1045 
1046     switch (getOperationNature(m_op))
1047     {
1048     case OPERATIONNATURE_PURE:
1049         DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
1050 
1051         operationValue0 = inValue0;
1052         operationValue1 = inValue1;
1053         break;
1054 
1055     case OPERATIONNATURE_MUTATING:
1056         DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
1057 
1058         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " tmpValue = " << inValue0
1059            << ";\n";
1060 
1061         operationValue0 = "tmpValue";
1062         operationValue1 = inValue1;
1063         break;
1064 
1065     case OPERATIONNATURE_ASSIGNMENT:
1066         DE_ASSERT(getOperationType(m_op) == OPERATIONTYPE_ASSIGNMENT);
1067 
1068         operationValue0 = inValue0;
1069         operationValue1 = inValue1;
1070         break;
1071 
1072     default:
1073         DE_ASSERT(false);
1074     }
1075 
1076     switch (getOperationType(m_op))
1077     {
1078     case OPERATIONTYPE_BINARY_OPERATOR:
1079         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType)
1080            << " res = " << operationValue0 << " " << getOperationName(m_op) << " " << operationValue1 << ";\n";
1081         break;
1082 
1083     case OPERATIONTYPE_UNARY_PREFIX_OPERATOR:
1084         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType)
1085            << " res = " << getOperationName(m_op) << operationValue0 << ";\n";
1086         break;
1087 
1088     case OPERATIONTYPE_UNARY_POSTFIX_OPERATOR:
1089         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType)
1090            << " res = " << operationValue0 << getOperationName(m_op) << ";\n";
1091         break;
1092 
1093     case OPERATIONTYPE_BINARY_FUNCTION:
1094         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType)
1095            << " res = " << getOperationName(m_op) << "(" << operationValue0 << ", " << operationValue1 << ");\n";
1096         break;
1097 
1098     case OPERATIONTYPE_ASSIGNMENT:
1099         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType)
1100            << " res = " << operationValue0 << ";\n";
1101         op << "    res " << getOperationName(m_op) << " " << operationValue1 << ";\n";
1102         break;
1103 
1104     default:
1105         DE_ASSERT(false);
1106     }
1107 
1108     // Reduction to vec3 (rgb). Check the used value too if it was modified.
1109     op << "    " << (m_isVertexCase ? "v_color" : "gl_FragColor") << " = ";
1110 
1111     if (isOperationValueModifying(m_op))
1112         op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0) + vec4("
1113            << genGLSLMatToVec3Reduction(resultType, "tmpValue") << ", 0.0);\n";
1114     else
1115         op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0);\n";
1116 
1117     vtx << "}\n";
1118     frag << "}\n";
1119 
1120     m_vertShaderSource = vtx.str();
1121     m_fragShaderSource = frag.str();
1122 
1123     // \todo [2012-02-14 pyry] Compute better values for matrix tests.
1124     m_userAttribTransforms.resize(4);
1125     for (int attribNdx = 0; attribNdx < 4; attribNdx++)
1126     {
1127         m_userAttribTransforms[attribNdx]                         = Mat4(0.0f);
1128         m_userAttribTransforms[attribNdx]((0 + attribNdx) % 4, 0) = 1.0f;
1129         m_userAttribTransforms[attribNdx]((1 + attribNdx) % 4, 1) = 1.0f;
1130         m_userAttribTransforms[attribNdx]((2 + attribNdx) % 4, 2) = 1.0f;
1131         m_userAttribTransforms[attribNdx]((3 + attribNdx) % 4, 3) = 1.0f;
1132     }
1133 
1134     // prevent bad reference cases such as black result images by fine-tuning used matrices
1135     if (getOperationTestMatrixType(m_op) != TESTMATRIXTYPE_DEFAULT)
1136     {
1137         for (int attribNdx = 0; attribNdx < 4; attribNdx++)
1138         {
1139             for (int row = 0; row < 4; row++)
1140                 for (int col = 0; col < 4; col++)
1141                 {
1142                     switch (getOperationTestMatrixType(m_op))
1143                     {
1144                     case TESTMATRIXTYPE_NEGATED:
1145                         m_userAttribTransforms[attribNdx](row, col) = -m_userAttribTransforms[attribNdx](row, col);
1146                         break;
1147                     case TESTMATRIXTYPE_INCREMENTED:
1148                         m_userAttribTransforms[attribNdx](row, col) += 0.3f;
1149                         break;
1150                     case TESTMATRIXTYPE_DECREMENTED:
1151                         m_userAttribTransforms[attribNdx](row, col) -= 0.1f;
1152                         break;
1153 
1154                     default:
1155                         DE_ASSERT(false);
1156                         break;
1157                     }
1158                 }
1159         }
1160     }
1161 
1162     ShaderRenderCase::init();
1163 }
1164 
genGLSLMatToVec3Reduction(const glu::DataType & matType,const char * varName)1165 std::string ShaderMatrixCase::genGLSLMatToVec3Reduction(const glu::DataType &matType, const char *varName)
1166 {
1167     std::ostringstream op;
1168 
1169     switch (matType)
1170     {
1171     case TYPE_FLOAT:
1172         op << varName << ", " << varName << ", " << varName << "";
1173         break;
1174     case TYPE_FLOAT_VEC2:
1175         op << varName << ".x, " << varName << ".y, " << varName << ".x";
1176         break;
1177     case TYPE_FLOAT_VEC3:
1178         op << varName << "";
1179         break;
1180     case TYPE_FLOAT_VEC4:
1181         op << varName << ".x, " << varName << ".y, " << varName << ".z+" << varName << ".w";
1182         break;
1183     case TYPE_FLOAT_MAT2:
1184         op << varName << "[0][0], " << varName << "[1][0], " << varName << "[0][1]+" << varName << "[1][1]";
1185         break;
1186     case TYPE_FLOAT_MAT3:
1187         op << varName << "[0]+" << varName << "[1]+" << varName << "[2]";
1188         break;
1189     case TYPE_FLOAT_MAT4:
1190         op << varName << "[0].xyz+" << varName << "[1].yzw+" << varName << "[2].zwx+" << varName << "[3].wxy";
1191         break;
1192 
1193     default:
1194         DE_ASSERT(false);
1195     }
1196 
1197     return op.str();
1198 }
1199 
setupUniforms(int programID,const tcu::Vec4 & constCoords)1200 void ShaderMatrixCase::setupUniforms(int programID, const tcu::Vec4 &constCoords)
1201 {
1202     const glw::Functions &gl = m_renderCtx.getFunctions();
1203 
1204     DE_UNREF(constCoords);
1205 
1206     for (int inNdx = 0; inNdx < 2; inNdx++)
1207     {
1208         const ShaderInput &in = inNdx > 0 ? m_in1 : m_in0;
1209 
1210         if (in.inputType == INPUTTYPE_UNIFORM)
1211         {
1212             int loc = gl.getUniformLocation(programID, (string("u_in") + de::toString(inNdx)).c_str());
1213 
1214             if (loc < 0)
1215                 continue;
1216 
1217             switch (in.dataType)
1218             {
1219             case TYPE_FLOAT:
1220                 gl.uniform1f(loc, s_constInFloat[inNdx]);
1221                 break;
1222             case TYPE_FLOAT_VEC2:
1223                 gl.uniform2fv(loc, 1, s_constInVec2[inNdx].getPtr());
1224                 break;
1225             case TYPE_FLOAT_VEC3:
1226                 gl.uniform3fv(loc, 1, s_constInVec3[inNdx].getPtr());
1227                 break;
1228             case TYPE_FLOAT_VEC4:
1229                 gl.uniform4fv(loc, 1, s_constInVec4[inNdx].getPtr());
1230                 break;
1231             case TYPE_FLOAT_MAT2:
1232                 gl.uniformMatrix2fv(loc, 1, GL_FALSE, s_constInMat2[inNdx].getColumnMajorData().getPtr());
1233                 break;
1234             case TYPE_FLOAT_MAT3:
1235                 gl.uniformMatrix3fv(loc, 1, GL_FALSE, s_constInMat3[inNdx].getColumnMajorData().getPtr());
1236                 break;
1237             case TYPE_FLOAT_MAT4:
1238                 gl.uniformMatrix4fv(loc, 1, GL_FALSE, s_constInMat4[inNdx].getColumnMajorData().getPtr());
1239                 break;
1240             default:
1241                 DE_ASSERT(false);
1242             }
1243         }
1244     }
1245 }
1246 
ShaderMatrixTests(Context & context)1247 ShaderMatrixTests::ShaderMatrixTests(Context &context) : TestCaseGroup(context, "matrix", "Matrix Tests")
1248 {
1249 }
1250 
~ShaderMatrixTests(void)1251 ShaderMatrixTests::~ShaderMatrixTests(void)
1252 {
1253 }
1254 
init(void)1255 void ShaderMatrixTests::init(void)
1256 {
1257     static const struct
1258     {
1259         const char *name;
1260         const char *desc;
1261         MatrixOp op;
1262         bool extendedInputTypeCases; // !< test with const and uniform types too
1263     } ops[] = {
1264         {"add", "Matrix addition tests", OP_ADD, true},
1265         {"sub", "Matrix subtraction tests", OP_SUB, true},
1266         {"mul", "Matrix multiplication tests", OP_MUL, true},
1267         {"div", "Matrix division tests", OP_DIV, true},
1268         {"matrixcompmult", "Matrix component-wise multiplication tests", OP_COMP_MUL, false},
1269         {"unary_addition", "Matrix unary addition tests", OP_UNARY_PLUS, false},
1270         {"negation", "Matrix negation tests", OP_NEGATION, false},
1271         {"pre_increment", "Matrix prefix increment tests", OP_PRE_INCREMENT, false},
1272         {"pre_decrement", "Matrix prefix decrement tests", OP_PRE_DECREMENT, false},
1273         {"post_increment", "Matrix postfix increment tests", OP_POST_INCREMENT, false},
1274         {"post_decrement", "Matrix postfix decrement tests", OP_POST_DECREMENT, false},
1275         {"add_assign", "Matrix add into tests", OP_ADD_INTO, false},
1276         {"sub_assign", "Matrix subtract from tests", OP_SUBTRACT_FROM, false},
1277         {"mul_assign", "Matrix multiply into tests", OP_MULTIPLY_INTO, false},
1278         {"div_assign", "Matrix divide into tests", OP_DIVIDE_INTO, false},
1279     };
1280 
1281     struct InputTypeSpec
1282     {
1283         const char *name;
1284         const char *desc;
1285         InputType type;
1286     };
1287     static const InputTypeSpec extendedInputTypes[] = {{"const", "Constant matrix input", INPUTTYPE_CONST},
1288                                                        {"uniform", "Uniform matrix input", INPUTTYPE_UNIFORM},
1289                                                        {"dynamic", "Dynamic matrix input", INPUTTYPE_DYNAMIC}};
1290     static const InputTypeSpec reducedInputTypes[]  = {{"dynamic", "Dynamic matrix input", INPUTTYPE_DYNAMIC}};
1291 
1292     static const DataType matrixTypes[] = {TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT4};
1293 
1294     static const Precision precisions[] = {PRECISION_LOWP, PRECISION_MEDIUMP, PRECISION_HIGHP};
1295 
1296     for (int opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
1297     {
1298         const InputTypeSpec *inTypeList =
1299             (ops[opNdx].extendedInputTypeCases) ? (extendedInputTypes) : (reducedInputTypes);
1300         const int inTypeListSize    = (ops[opNdx].extendedInputTypeCases) ? (DE_LENGTH_OF_ARRAY(extendedInputTypes)) :
1301                                                                             (DE_LENGTH_OF_ARRAY(reducedInputTypes));
1302         const MatrixOp op           = ops[opNdx].op;
1303         tcu::TestCaseGroup *opGroup = new tcu::TestCaseGroup(m_testCtx, ops[opNdx].name, ops[opNdx].desc);
1304 
1305         addChild(opGroup);
1306 
1307         for (int inTypeNdx = 0; inTypeNdx < inTypeListSize; inTypeNdx++)
1308         {
1309             const InputType inputType = inTypeList[inTypeNdx].type;
1310 
1311             for (int matTypeNdx = 0; matTypeNdx < DE_LENGTH_OF_ARRAY(matrixTypes); matTypeNdx++)
1312             {
1313                 DataType matType        = matrixTypes[matTypeNdx];
1314                 const char *matTypeName = getDataTypeName(matType);
1315 
1316                 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1317                 {
1318                     Precision precision  = precisions[precNdx];
1319                     const char *precName = getPrecisionName(precision);
1320                     string baseName = string(inTypeList[inTypeNdx].name) + "_" + precName + "_" + matTypeName + "_";
1321                     ShaderInput matIn(inputType, matType, precision);
1322 
1323                     if (isOperationMatrixScalar(op))
1324                     {
1325                         // Matrix-scalar \note For div cases we use uniform input.
1326                         ShaderInput scalarIn(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, TYPE_FLOAT,
1327                                              precision);
1328                         opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(),
1329                                                                "Matrix-scalar case", matIn, scalarIn, op, true));
1330                         opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(),
1331                                                                "Matrix-scalar case", matIn, scalarIn, op, false));
1332                     }
1333 
1334                     if (isOperationMatrixVector(op))
1335                     {
1336                         // Matrix-vector.
1337                         DataType vecType = getDataTypeFloatVec(getDataTypeMatrixNumColumns(matType));
1338                         ShaderInput vecIn(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, vecType, precision);
1339 
1340                         opGroup->addChild(
1341                             new ShaderMatrixCase(m_context, (baseName + getDataTypeName(vecType) + "_vertex").c_str(),
1342                                                  "Matrix-vector case", matIn, vecIn, op, true));
1343                         opGroup->addChild(
1344                             new ShaderMatrixCase(m_context, (baseName + getDataTypeName(vecType) + "_fragment").c_str(),
1345                                                  "Matrix-vector case", matIn, vecIn, op, false));
1346 
1347                         // Vector-matrix.
1348                         string vecMatName = string(inTypeList[inTypeNdx].name) + "_" + precName + "_" +
1349                                             getDataTypeName(vecType) + "_" + matTypeName;
1350                         opGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_vertex").c_str(),
1351                                                                "Vector-matrix case", vecIn, matIn, op, true));
1352                         opGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_fragment").c_str(),
1353                                                                "Vector-matrix case", vecIn, matIn, op, false));
1354                     }
1355 
1356                     if (isOperationMatrixMatrix(op))
1357                     {
1358                         // Matrix-matrix.
1359                         ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType,
1360                                                precision);
1361                         opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + matTypeName + "_vertex").c_str(),
1362                                                                "Matrix-matrix case", matIn, otherMatIn, op, true));
1363                         opGroup->addChild(new ShaderMatrixCase(m_context,
1364                                                                (baseName + matTypeName + "_fragment").c_str(),
1365                                                                "Matrix-matrix case", matIn, otherMatIn, op, false));
1366                     }
1367 
1368                     if (isOperationUnary(op))
1369                     {
1370                         // op matrix
1371                         ShaderInput voidInput(INPUTTYPE_LAST, TYPE_LAST, PRECISION_LAST);
1372                         opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "vertex").c_str(), "Matrix case",
1373                                                                matIn, voidInput, op, true));
1374                         opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "fragment").c_str(),
1375                                                                "Matrix case", matIn, voidInput, op, false));
1376                     }
1377 
1378                     if (isOperationAssignment(op))
1379                     {
1380                         ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType,
1381                                                precision);
1382                         opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "vertex").c_str(),
1383                                                                "Matrix assignment case", matIn, otherMatIn, op, true));
1384                         opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "fragment").c_str(),
1385                                                                "Matrix assignment case", matIn, otherMatIn, op, false));
1386                     }
1387                 }
1388             }
1389         }
1390     }
1391 }
1392 
1393 } // namespace Functional
1394 } // namespace gles2
1395 } // namespace deqp
1396 
1397 #if defined(_MSC_VER) && _MSC_FULL_VER == 191125507
1398 // Work around crbug.com/759402 which is a code-gen bug in VC++ 2017, version
1399 // 15.3.2.
1400 #pragma optimize("", off)
1401 #endif
1402