xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fShaderMatrixTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.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  *    - vec OP vec
31  *    - OP mat
32  *  + matrix source
33  *    - constant (ctor)
34  *    - uniform
35  *    - vertex input
36  *    - fragment input
37  *  + other operand: always dynamic data?
38  *  + how to reduce to vec3?
39  *//*--------------------------------------------------------------------*/
40 
41 #include "es3fShaderMatrixTests.hpp"
42 #include "glsShaderRenderCase.hpp"
43 #include "gluShaderUtil.hpp"
44 #include "tcuVector.hpp"
45 #include "tcuMatrix.hpp"
46 #include "tcuMatrixUtil.hpp"
47 #include "deStringUtil.hpp"
48 #include "deFloat16.h"
49 
50 #include "glwEnums.hpp"
51 #include "glwFunctions.hpp"
52 
53 namespace deqp
54 {
55 namespace gles3
56 {
57 namespace Functional
58 {
59 
60 using std::string;
61 using std::vector;
62 using namespace glu;
63 using namespace deqp::gls;
64 
65 using tcu::Mat2;
66 using tcu::Mat2x3;
67 using tcu::Mat2x4;
68 using tcu::Mat3;
69 using tcu::Mat3x2;
70 using tcu::Mat3x4;
71 using tcu::Mat4;
72 using tcu::Mat4x2;
73 using tcu::Mat4x3;
74 using tcu::Vec2;
75 using tcu::Vec3;
76 using tcu::Vec4;
77 
78 // Uniform / constant values for tests.
79 // \note Input1 should not contain 0 components as it is used as divisor in div cases.
80 // \todo [2012-02-14 pyry] Make these dynamic.
81 static const float s_constInFloat[2] = {0.5f, -0.2f};
82 static const Vec2 s_constInVec2[2]   = {Vec2(1.2f, 0.5f), Vec2(0.5f, 1.0f)};
83 static const Vec3 s_constInVec3[2]   = {Vec3(1.1f, 0.1f, 0.5f), Vec3(-0.2f, 0.5f, 0.8f)};
84 static const Vec4 s_constInVec4[2]   = {Vec4(1.4f, 0.2f, -0.5f, 0.7f), Vec4(0.2f, -1.0f, 0.5f, 0.8f)};
85 
86 static const float s_constInMat2x2[2][4] = {
87     {
88         -0.1f,
89         1.0f,
90         -0.2f,
91         0.0f,
92     },
93     {
94         0.8f,
95         0.1f,
96         0.5f,
97         -0.9f,
98     },
99 };
100 static const float s_constInMat3x2[2][6] = {
101     {
102         0.8f,
103         -0.3f,
104         0.3f,
105         1.0f,
106         1.2f,
107         -1.2f,
108     },
109     {
110         1.2f,
111         -1.0f,
112         0.5f,
113         -0.8f,
114         1.1f,
115         0.3f,
116     },
117 };
118 static const float s_constInMat4x2[2][8] = {
119     {
120         -0.2f,
121         0.5f,
122         0.0f,
123         -1.0f,
124         1.2f,
125         -0.5f,
126         0.3f,
127         -0.9f,
128     },
129     {
130         1.0f,
131         0.1f,
132         -1.1f,
133         0.6f,
134         0.8f,
135         -1.2f,
136         -1.1f,
137         0.7f,
138     },
139 };
140 static const float s_constInMat2x3[2][6] = {
141     {
142         -0.6f,
143         -0.1f,
144         -0.7f,
145         -1.2f,
146         -0.2f,
147         0.0f,
148     },
149     {
150         1.1f,
151         0.6f,
152         0.8f,
153         1.0f,
154         0.7f,
155         0.1f,
156     },
157 };
158 static const float s_constInMat3x3[2][9] = {
159     {
160         -0.2f,
161         1.1f,
162         1.2f,
163         -1.0f,
164         1.2f,
165         0.5f,
166         0.7f,
167         -0.2f,
168         1.0f,
169     },
170     {
171         -0.1f,
172         -0.1f,
173         0.1f,
174         -0.1f,
175         -0.2f,
176         1.0f,
177         -0.5f,
178         0.1f,
179         -0.4f,
180     },
181 };
182 static const float s_constInMat4x3[2][12] = {
183     {
184         -0.9f,
185         0.0f,
186         0.6f,
187         0.2f,
188         0.9f,
189         -0.1f,
190         -0.3f,
191         -0.7f,
192         -0.1f,
193         0.1f,
194         1.0f,
195         0.0f,
196     },
197     {
198         0.5f,
199         0.7f,
200         0.7f,
201         1.2f,
202         1.1f,
203         0.1f,
204         1.0f,
205         -1.0f,
206         -0.2f,
207         -0.2f,
208         -0.3f,
209         -0.5f,
210     },
211 };
212 static const float s_constInMat2x4[2][8] = {
213     {
214         -0.6f,
215         -1.1f,
216         -0.6f,
217         -0.6f,
218         -0.2f,
219         -0.6f,
220         -0.1f,
221         -0.1f,
222     },
223     {
224         -1.2f,
225         -1.0f,
226         0.7f,
227         -1.0f,
228         0.7f,
229         0.7f,
230         -0.4f,
231         -0.3f,
232     },
233 };
234 static const float s_constInMat3x4[2][12] = {
235     {
236         0.6f,
237         -0.4f,
238         1.2f,
239         0.9f,
240         0.8f,
241         0.4f,
242         1.1f,
243         0.3f,
244         0.5f,
245         -0.2f,
246         0.0f,
247         1.1f,
248     },
249     {
250         -0.8f,
251         1.2f,
252         -0.2f,
253         -1.1f,
254         -0.9f,
255         -0.5f,
256         -1.2f,
257         1.0f,
258         1.2f,
259         0.1f,
260         -0.7f,
261         -0.5f,
262     },
263 };
264 static const float s_constInMat4x4[2][16] = {
265     {
266         0.3f,
267         0.9f,
268         -0.2f,
269         1.0f,
270         -0.4f,
271         -0.6f,
272         0.6f,
273         -1.0f,
274         -0.9f,
275         -0.1f,
276         0.3f,
277         -0.2f,
278         -0.3f,
279         -0.9f,
280         1.0f,
281         0.1f,
282     },
283     {
284         0.4f,
285         -0.7f,
286         -0.8f,
287         0.7f,
288         -0.4f,
289         -0.8f,
290         0.6f,
291         -0.3f,
292         0.7f,
293         -1.0f,
294         0.1f,
295         -0.3f,
296         0.2f,
297         0.6f,
298         0.4f,
299         -1.0f,
300     },
301 };
302 
303 namespace MatrixCaseUtils
304 {
305 
306 enum InputType
307 {
308     INPUTTYPE_CONST = 0,
309     INPUTTYPE_UNIFORM,
310     INPUTTYPE_DYNAMIC,
311 
312     INPUTTYPE_LAST
313 };
314 
315 struct ShaderInput
316 {
ShaderInputdeqp::gles3::Functional::MatrixCaseUtils::ShaderInput317     ShaderInput(InputType inputType_, DataType dataType_, Precision precision_)
318         : inputType(inputType_)
319         , dataType(dataType_)
320         , precision(precision_)
321     {
322     }
323 
324     InputType inputType;
325     DataType dataType;
326     Precision precision;
327 };
328 
329 enum MatrixOp
330 {
331     OP_ADD = 0,
332     OP_SUB,
333     OP_MUL,
334     OP_DIV,
335     OP_COMP_MUL,
336     OP_OUTER_PRODUCT,
337     OP_TRANSPOSE,
338     OP_INVERSE,
339     OP_DETERMINANT,
340     OP_UNARY_PLUS,
341     OP_NEGATION,
342     OP_PRE_INCREMENT,
343     OP_PRE_DECREMENT,
344     OP_POST_INCREMENT,
345     OP_POST_DECREMENT,
346     OP_ADD_INTO,
347     OP_SUBTRACT_FROM,
348     OP_MULTIPLY_INTO,
349     OP_DIVIDE_INTO,
350     OP_LAST
351 };
352 
353 // Type traits.
354 
355 template <int DataT>
356 struct TypeTraits;
357 
358 #define DECLARE_TYPE_TRAIT(DATATYPE, TYPE) \
359     template <>                            \
360     struct TypeTraits<DATATYPE>            \
361     {                                      \
362         typedef TYPE Type;                 \
363     }
364 
365 DECLARE_TYPE_TRAIT(TYPE_FLOAT, float);
366 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC2, tcu::Vec2);
367 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC3, tcu::Vec3);
368 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC4, tcu::Vec4);
369 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2, tcu::Mat2);
370 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2X3, tcu::Mat2x3);
371 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2X4, tcu::Mat2x4);
372 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3X2, tcu::Mat3x2);
373 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3, tcu::Mat3);
374 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3X4, tcu::Mat3x4);
375 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4X2, tcu::Mat4x2);
376 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4X3, tcu::Mat4x3);
377 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4, tcu::Mat4);
378 
379 // Operation info
380 
381 enum OperationType
382 {
383     OPERATIONTYPE_BINARY_OPERATOR = 0,
384     OPERATIONTYPE_BINARY_FUNCTION,
385     OPERATIONTYPE_UNARY_PREFIX_OPERATOR,
386     OPERATIONTYPE_UNARY_POSTFIX_OPERATOR,
387     OPERATIONTYPE_UNARY_FUNCTION,
388     OPERATIONTYPE_ASSIGNMENT,
389 
390     OPERATIONTYPE_LAST
391 };
392 
getOperationName(MatrixOp op)393 static const char *getOperationName(MatrixOp op)
394 {
395     switch (op)
396     {
397     case OP_ADD:
398         return "+";
399     case OP_SUB:
400         return "-";
401     case OP_MUL:
402         return "*";
403     case OP_DIV:
404         return "/";
405     case OP_COMP_MUL:
406         return "matrixCompMult";
407     case OP_OUTER_PRODUCT:
408         return "outerProduct";
409     case OP_TRANSPOSE:
410         return "transpose";
411     case OP_INVERSE:
412         return "inverse";
413     case OP_DETERMINANT:
414         return "determinant";
415     case OP_UNARY_PLUS:
416         return "+";
417     case OP_NEGATION:
418         return "-";
419     case OP_PRE_INCREMENT:
420         return "++";
421     case OP_PRE_DECREMENT:
422         return "--";
423     case OP_POST_INCREMENT:
424         return "++";
425     case OP_POST_DECREMENT:
426         return "--";
427     case OP_ADD_INTO:
428         return "+=";
429     case OP_SUBTRACT_FROM:
430         return "-=";
431     case OP_MULTIPLY_INTO:
432         return "*=";
433     case OP_DIVIDE_INTO:
434         return "/=";
435 
436     default:
437         DE_ASSERT(false);
438         return "";
439     }
440 }
441 
getOperationType(MatrixOp op)442 static OperationType getOperationType(MatrixOp op)
443 {
444     switch (op)
445     {
446     case OP_ADD:
447         return OPERATIONTYPE_BINARY_OPERATOR;
448     case OP_SUB:
449         return OPERATIONTYPE_BINARY_OPERATOR;
450     case OP_MUL:
451         return OPERATIONTYPE_BINARY_OPERATOR;
452     case OP_DIV:
453         return OPERATIONTYPE_BINARY_OPERATOR;
454     case OP_COMP_MUL:
455         return OPERATIONTYPE_BINARY_FUNCTION;
456     case OP_OUTER_PRODUCT:
457         return OPERATIONTYPE_BINARY_FUNCTION;
458     case OP_TRANSPOSE:
459         return OPERATIONTYPE_UNARY_FUNCTION;
460     case OP_INVERSE:
461         return OPERATIONTYPE_UNARY_FUNCTION;
462     case OP_DETERMINANT:
463         return OPERATIONTYPE_UNARY_FUNCTION;
464     case OP_UNARY_PLUS:
465         return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
466     case OP_NEGATION:
467         return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
468     case OP_PRE_INCREMENT:
469         return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
470     case OP_PRE_DECREMENT:
471         return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
472     case OP_POST_INCREMENT:
473         return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR;
474     case OP_POST_DECREMENT:
475         return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR;
476     case OP_ADD_INTO:
477         return OPERATIONTYPE_ASSIGNMENT;
478     case OP_SUBTRACT_FROM:
479         return OPERATIONTYPE_ASSIGNMENT;
480     case OP_MULTIPLY_INTO:
481         return OPERATIONTYPE_ASSIGNMENT;
482     case OP_DIVIDE_INTO:
483         return OPERATIONTYPE_ASSIGNMENT;
484     default:
485         DE_ASSERT(false);
486         return OPERATIONTYPE_LAST;
487     }
488 }
489 
490 enum TestMatrixType
491 {
492     TESTMATRIXTYPE_DEFAULT = 0,
493     TESTMATRIXTYPE_NEGATED,
494     TESTMATRIXTYPE_INCREMENTED,
495     TESTMATRIXTYPE_DECREMENTED,
496     TESTMATRIXTYPE_NEGATED_INCREMENTED,
497     TESTMATRIXTYPE_INCREMENTED_LESS,
498 
499     TESTMATRIXTYPE_LAST
500 };
501 
getOperationTestMatrixType(MatrixOp op)502 static TestMatrixType getOperationTestMatrixType(MatrixOp op)
503 {
504     switch (op)
505     {
506     case OP_ADD:
507         return TESTMATRIXTYPE_DEFAULT;
508     case OP_SUB:
509         return TESTMATRIXTYPE_DEFAULT;
510     case OP_MUL:
511         return TESTMATRIXTYPE_DEFAULT;
512     case OP_DIV:
513         return TESTMATRIXTYPE_DEFAULT;
514     case OP_COMP_MUL:
515         return TESTMATRIXTYPE_DEFAULT;
516     case OP_OUTER_PRODUCT:
517         return TESTMATRIXTYPE_DEFAULT;
518     case OP_TRANSPOSE:
519         return TESTMATRIXTYPE_DEFAULT;
520     case OP_INVERSE:
521         return TESTMATRIXTYPE_DEFAULT;
522     case OP_DETERMINANT:
523         return TESTMATRIXTYPE_DEFAULT;
524     case OP_UNARY_PLUS:
525         return TESTMATRIXTYPE_DECREMENTED;
526     case OP_NEGATION:
527         return TESTMATRIXTYPE_NEGATED_INCREMENTED;
528     case OP_PRE_INCREMENT:
529         return TESTMATRIXTYPE_NEGATED;
530     case OP_PRE_DECREMENT:
531         return TESTMATRIXTYPE_INCREMENTED;
532     case OP_POST_INCREMENT:
533         return TESTMATRIXTYPE_NEGATED;
534     case OP_POST_DECREMENT:
535         return TESTMATRIXTYPE_DEFAULT;
536     case OP_ADD_INTO:
537         return TESTMATRIXTYPE_DEFAULT;
538     case OP_SUBTRACT_FROM:
539         return TESTMATRIXTYPE_INCREMENTED_LESS;
540     case OP_MULTIPLY_INTO:
541         return TESTMATRIXTYPE_NEGATED;
542     case OP_DIVIDE_INTO:
543         return TESTMATRIXTYPE_DECREMENTED;
544 
545     default:
546         DE_ASSERT(false);
547         return TESTMATRIXTYPE_LAST;
548     }
549 }
550 
isOperationBinary(MatrixOp op)551 static bool isOperationBinary(MatrixOp op)
552 {
553     return getOperationType(op) == OPERATIONTYPE_BINARY_OPERATOR ||
554            getOperationType(op) == OPERATIONTYPE_BINARY_FUNCTION || getOperationType(op) == OPERATIONTYPE_ASSIGNMENT;
555 }
556 
isOperationMatrixScalar(MatrixOp op)557 static bool isOperationMatrixScalar(MatrixOp op)
558 {
559     return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV;
560 }
561 
isOperationMatrixVector(MatrixOp op)562 static bool isOperationMatrixVector(MatrixOp op)
563 {
564     return op == OP_MUL;
565 }
566 
isOperationArithmeticMatrixMatrix(MatrixOp op)567 static bool isOperationArithmeticMatrixMatrix(MatrixOp op)
568 {
569     return op == OP_MUL;
570 }
571 
isOperationComponentwiseMatrixMatrix(MatrixOp op)572 static bool isOperationComponentwiseMatrixMatrix(MatrixOp op)
573 {
574     return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV || op == OP_COMP_MUL;
575 }
576 
isOperationVectorVector(MatrixOp op)577 static bool isOperationVectorVector(MatrixOp op)
578 {
579     return op == OP_OUTER_PRODUCT;
580 }
581 
isOperationUnaryAnyMatrix(MatrixOp op)582 static bool isOperationUnaryAnyMatrix(MatrixOp op)
583 {
584     return op == OP_TRANSPOSE || op == OP_UNARY_PLUS || op == OP_NEGATION || op == OP_PRE_INCREMENT ||
585            op == OP_PRE_DECREMENT || op == OP_POST_INCREMENT || op == OP_POST_DECREMENT;
586 }
587 
isOperationUnarySymmetricMatrix(MatrixOp op)588 static bool isOperationUnarySymmetricMatrix(MatrixOp op)
589 {
590     return op == OP_INVERSE || op == OP_DETERMINANT;
591 }
592 
isOperationValueModifying(MatrixOp op)593 static bool isOperationValueModifying(MatrixOp op)
594 {
595     return op == OP_PRE_INCREMENT || op == OP_PRE_DECREMENT || op == OP_POST_INCREMENT || op == OP_POST_DECREMENT;
596 }
597 
isOperationAssignment(MatrixOp op)598 static bool isOperationAssignment(MatrixOp op)
599 {
600     return op == OP_ADD_INTO || op == OP_SUBTRACT_FROM || op == OP_MULTIPLY_INTO || op == OP_DIVIDE_INTO;
601 }
602 
isOperationAssignmentAnyMatrix(MatrixOp op)603 static bool isOperationAssignmentAnyMatrix(MatrixOp op)
604 {
605     return op == OP_ADD_INTO || op == OP_SUBTRACT_FROM || op == OP_DIVIDE_INTO;
606 }
607 
isOperationAssignmentSymmetricMatrix(MatrixOp op)608 static bool isOperationAssignmentSymmetricMatrix(MatrixOp op)
609 {
610     return op == OP_MULTIPLY_INTO;
611 }
612 
613 // Operation nature
614 
615 enum OperationNature
616 {
617     OPERATIONNATURE_PURE = 0,
618     OPERATIONNATURE_MUTATING,
619     OPERATIONNATURE_ASSIGNMENT,
620 
621     OPERATIONNATURE_LAST
622 };
623 
getOperationNature(MatrixOp op)624 static OperationNature getOperationNature(MatrixOp op)
625 {
626     if (isOperationAssignment(op))
627         return OPERATIONNATURE_ASSIGNMENT;
628 
629     if (isOperationValueModifying(op))
630         return OPERATIONNATURE_MUTATING;
631 
632     return OPERATIONNATURE_PURE;
633 }
634 
635 // Input value loader.
636 
637 template <int InputT, int DataT>
638 typename TypeTraits<DataT>::Type getInputValue(const ShaderEvalContext &evalCtx, int inputNdx);
639 
640 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)641 inline float getInputValue<INPUTTYPE_CONST, TYPE_FLOAT>(const ShaderEvalContext &evalCtx, int inputNdx)
642 {
643     DE_UNREF(evalCtx);
644     return s_constInFloat[inputNdx];
645 }
646 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)647 inline tcu::Vec2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC2>(const ShaderEvalContext &evalCtx, int inputNdx)
648 {
649     DE_UNREF(evalCtx);
650     return s_constInVec2[inputNdx];
651 }
652 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)653 inline tcu::Vec3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC3>(const ShaderEvalContext &evalCtx, int inputNdx)
654 {
655     DE_UNREF(evalCtx);
656     return s_constInVec3[inputNdx];
657 }
658 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)659 inline tcu::Vec4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC4>(const ShaderEvalContext &evalCtx, int inputNdx)
660 {
661     DE_UNREF(evalCtx);
662     return s_constInVec4[inputNdx];
663 }
664 
665 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)666 inline tcu::Mat2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2>(const ShaderEvalContext &evalCtx, int inputNdx)
667 {
668     DE_UNREF(evalCtx);
669     return tcu::Mat2(s_constInMat2x2[inputNdx]);
670 }
671 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)672 inline tcu::Mat2x3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2X3>(const ShaderEvalContext &evalCtx, int inputNdx)
673 {
674     DE_UNREF(evalCtx);
675     return tcu::Mat2x3(s_constInMat2x3[inputNdx]);
676 }
677 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)678 inline tcu::Mat2x4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2X4>(const ShaderEvalContext &evalCtx, int inputNdx)
679 {
680     DE_UNREF(evalCtx);
681     return tcu::Mat2x4(s_constInMat2x4[inputNdx]);
682 }
683 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)684 inline tcu::Mat3x2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3X2>(const ShaderEvalContext &evalCtx, int inputNdx)
685 {
686     DE_UNREF(evalCtx);
687     return tcu::Mat3x2(s_constInMat3x2[inputNdx]);
688 }
689 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)690 inline tcu::Mat3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3>(const ShaderEvalContext &evalCtx, int inputNdx)
691 {
692     DE_UNREF(evalCtx);
693     return tcu::Mat3(s_constInMat3x3[inputNdx]);
694 }
695 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)696 inline tcu::Mat3x4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3X4>(const ShaderEvalContext &evalCtx, int inputNdx)
697 {
698     DE_UNREF(evalCtx);
699     return tcu::Mat3x4(s_constInMat3x4[inputNdx]);
700 }
701 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)702 inline tcu::Mat4x2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT4X2>(const ShaderEvalContext &evalCtx, int inputNdx)
703 {
704     DE_UNREF(evalCtx);
705     return tcu::Mat4x2(s_constInMat4x2[inputNdx]);
706 }
707 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)708 inline tcu::Mat4x3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT4X3>(const ShaderEvalContext &evalCtx, int inputNdx)
709 {
710     DE_UNREF(evalCtx);
711     return tcu::Mat4x3(s_constInMat4x3[inputNdx]);
712 }
713 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)714 inline tcu::Mat4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT4>(const ShaderEvalContext &evalCtx, int inputNdx)
715 {
716     DE_UNREF(evalCtx);
717     return tcu::Mat4(s_constInMat4x4[inputNdx]);
718 }
719 
720 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)721 inline float getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT>(const ShaderEvalContext &evalCtx, int inputNdx)
722 {
723     DE_UNREF(inputNdx);
724     return evalCtx.coords.x();
725 }
726 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)727 inline tcu::Vec2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC2>(const ShaderEvalContext &evalCtx, int inputNdx)
728 {
729     DE_UNREF(inputNdx);
730     return evalCtx.coords.swizzle(0, 1);
731 }
732 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)733 inline tcu::Vec3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC3>(const ShaderEvalContext &evalCtx, int inputNdx)
734 {
735     DE_UNREF(inputNdx);
736     return evalCtx.coords.swizzle(0, 1, 2);
737 }
738 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)739 inline tcu::Vec4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC4>(const ShaderEvalContext &evalCtx, int inputNdx)
740 {
741     DE_UNREF(inputNdx);
742     return evalCtx.coords.swizzle(0, 1, 2, 3);
743 }
744 
745 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)746 inline tcu::Mat2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2>(const ShaderEvalContext &evalCtx, int inputNdx)
747 {
748     DE_UNREF(inputNdx); // Not used.
749     tcu::Mat2 m;
750     m.setColumn(0, evalCtx.in[0].swizzle(0, 1));
751     m.setColumn(1, evalCtx.in[1].swizzle(0, 1));
752     return m;
753 }
754 
755 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)756 inline tcu::Mat2x3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2X3>(const ShaderEvalContext &evalCtx, int inputNdx)
757 {
758     DE_UNREF(inputNdx); // Not used.
759     tcu::Mat2x3 m;
760     m.setColumn(0, evalCtx.in[0].swizzle(0, 1, 2));
761     m.setColumn(1, evalCtx.in[1].swizzle(0, 1, 2));
762     return m;
763 }
764 
765 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)766 inline tcu::Mat2x4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2X4>(const ShaderEvalContext &evalCtx, int inputNdx)
767 {
768     DE_UNREF(inputNdx); // Not used.
769     tcu::Mat2x4 m;
770     m.setColumn(0, evalCtx.in[0]);
771     m.setColumn(1, evalCtx.in[1]);
772     return m;
773 }
774 
775 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)776 inline tcu::Mat3x2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3X2>(const ShaderEvalContext &evalCtx, int inputNdx)
777 {
778     DE_UNREF(inputNdx); // Not used.
779     tcu::Mat3x2 m;
780     m.setColumn(0, evalCtx.in[0].swizzle(0, 1));
781     m.setColumn(1, evalCtx.in[1].swizzle(0, 1));
782     m.setColumn(2, evalCtx.in[2].swizzle(0, 1));
783     return m;
784 }
785 
786 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)787 inline tcu::Mat3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3>(const ShaderEvalContext &evalCtx, int inputNdx)
788 {
789     DE_UNREF(inputNdx); // Not used.
790     tcu::Mat3 m;
791     m.setColumn(0, evalCtx.in[0].swizzle(0, 1, 2));
792     m.setColumn(1, evalCtx.in[1].swizzle(0, 1, 2));
793     m.setColumn(2, evalCtx.in[2].swizzle(0, 1, 2));
794     return m;
795 }
796 
797 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)798 inline tcu::Mat3x4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3X4>(const ShaderEvalContext &evalCtx, int inputNdx)
799 {
800     DE_UNREF(inputNdx); // Not used.
801     tcu::Mat3x4 m;
802     m.setColumn(0, evalCtx.in[0]);
803     m.setColumn(1, evalCtx.in[1]);
804     m.setColumn(2, evalCtx.in[2]);
805     return m;
806 }
807 
808 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)809 inline tcu::Mat4x2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4X2>(const ShaderEvalContext &evalCtx, int inputNdx)
810 {
811     DE_UNREF(inputNdx); // Not used.
812     tcu::Mat4x2 m;
813     m.setColumn(0, evalCtx.in[0].swizzle(0, 1));
814     m.setColumn(1, evalCtx.in[1].swizzle(0, 1));
815     m.setColumn(2, evalCtx.in[2].swizzle(0, 1));
816     m.setColumn(3, evalCtx.in[3].swizzle(0, 1));
817     return m;
818 }
819 
820 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)821 inline tcu::Mat4x3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4X3>(const ShaderEvalContext &evalCtx, int inputNdx)
822 {
823     DE_UNREF(inputNdx); // Not used.
824     tcu::Mat4x3 m;
825     m.setColumn(0, evalCtx.in[0].swizzle(0, 1, 2));
826     m.setColumn(1, evalCtx.in[1].swizzle(0, 1, 2));
827     m.setColumn(2, evalCtx.in[2].swizzle(0, 1, 2));
828     m.setColumn(3, evalCtx.in[3].swizzle(0, 1, 2));
829     return m;
830 }
831 
832 template <>
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)833 inline tcu::Mat4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4>(const ShaderEvalContext &evalCtx, int inputNdx)
834 {
835     DE_UNREF(inputNdx); // Not used.
836     tcu::Mat4 m;
837     m.setColumn(0, evalCtx.in[0]);
838     m.setColumn(1, evalCtx.in[1]);
839     m.setColumn(2, evalCtx.in[2]);
840     m.setColumn(3, evalCtx.in[3]);
841     return m;
842 }
843 
844 // Reduction from expression result to vec3.
845 
reduceToVec3(const tcu::Vec2 & value)846 inline tcu::Vec3 reduceToVec3(const tcu::Vec2 &value)
847 {
848     return value.swizzle(0, 1, 0);
849 }
reduceToVec3(const tcu::Vec3 & value)850 inline tcu::Vec3 reduceToVec3(const tcu::Vec3 &value)
851 {
852     return value;
853 }
reduceToVec3(const tcu::Vec4 & value)854 inline tcu::Vec3 reduceToVec3(const tcu::Vec4 &value)
855 {
856     return tcu::Vec3(value.x(), value.y(), value.z() + value.w());
857 }
reduceToVec3(const tcu::Mat2 & value)858 inline tcu::Vec3 reduceToVec3(const tcu::Mat2 &value)
859 {
860     return tcu::Vec3(value(0, 0), value(0, 1), value(1, 0) + value(1, 1));
861 }
reduceToVec3(const tcu::Mat2x3 & value)862 inline tcu::Vec3 reduceToVec3(const tcu::Mat2x3 &value)
863 {
864     return value.getColumn(0) + value.getColumn(1);
865 }
reduceToVec3(const tcu::Mat2x4 & value)866 inline tcu::Vec3 reduceToVec3(const tcu::Mat2x4 &value)
867 {
868     return value.getColumn(0).swizzle(0, 1, 2) + value.getColumn(1).swizzle(1, 2, 3);
869 }
reduceToVec3(const tcu::Mat3x2 & value)870 inline tcu::Vec3 reduceToVec3(const tcu::Mat3x2 &value)
871 {
872     return tcu::Vec3(value(0, 0) + value(1, 0), value(0, 1) + value(1, 1), value(0, 2) + value(1, 2));
873 }
reduceToVec3(const tcu::Mat3 & value)874 inline tcu::Vec3 reduceToVec3(const tcu::Mat3 &value)
875 {
876     return value.getColumn(0) + value.getColumn(1) + value.getColumn(2);
877 }
reduceToVec3(const tcu::Mat3x4 & value)878 inline tcu::Vec3 reduceToVec3(const tcu::Mat3x4 &value)
879 {
880     return value.getColumn(0).swizzle(0, 1, 2) + value.getColumn(1).swizzle(1, 2, 3) +
881            value.getColumn(2).swizzle(2, 3, 0);
882 }
reduceToVec3(const tcu::Mat4x2 & value)883 inline tcu::Vec3 reduceToVec3(const tcu::Mat4x2 &value)
884 {
885     return tcu::Vec3(value(0, 0) + value(1, 0) + value(0, 3), value(0, 1) + value(1, 1) + value(1, 3),
886                      value(0, 2) + value(1, 2));
887 }
reduceToVec3(const tcu::Mat4x3 & value)888 inline tcu::Vec3 reduceToVec3(const tcu::Mat4x3 &value)
889 {
890     return value.getColumn(0) + value.getColumn(1) + value.getColumn(2) + value.getColumn(3);
891 }
reduceToVec3(const tcu::Mat4 & value)892 inline tcu::Vec3 reduceToVec3(const tcu::Mat4 &value)
893 {
894     return value.getColumn(0).swizzle(0, 1, 2) + value.getColumn(1).swizzle(1, 2, 3) +
895            value.getColumn(2).swizzle(2, 3, 0) + value.getColumn(3).swizzle(3, 0, 1);
896 }
897 
898 // matrixCompMult
899 
900 template <typename T, int Rows, int Cols>
matrixCompMult(const tcu::Matrix<T,Rows,Cols> & a,const tcu::Matrix<T,Rows,Cols> & b)901 tcu::Matrix<T, Rows, Cols> matrixCompMult(const tcu::Matrix<T, Rows, Cols> &a, const tcu::Matrix<T, Rows, Cols> &b)
902 {
903     tcu::Matrix<T, Rows, Cols> retVal;
904 
905     for (int r = 0; r < Rows; ++r)
906         for (int c = 0; c < Cols; ++c)
907             retVal(r, c) = a(r, c) * b(r, c);
908 
909     return retVal;
910 }
911 
912 // outerProduct
913 
914 template <typename T, int Rows, int Cols>
outerProduct(const tcu::Vector<T,Cols> & a,const tcu::Vector<T,Rows> & b)915 tcu::Matrix<T, Cols, Rows> outerProduct(const tcu::Vector<T, Cols> &a, const tcu::Vector<T, Rows> &b)
916 {
917     tcu::Matrix<T, Rows, Cols> retVal;
918 
919     for (int r = 0; r < Rows; ++r)
920         for (int c = 0; c < Cols; ++c)
921             retVal(r, c) = a[c] * b[r];
922 
923     return transpose(retVal); // to gl-form (column-major)
924 }
925 
926 // Determinant
927 
928 template <int Size>
929 float determinant(const tcu::Matrix<float, Size, Size> &mat);
930 
931 template <>
determinant(const tcu::Matrix<float,2,2> & mat)932 float determinant<2>(const tcu::Matrix<float, 2, 2> &mat)
933 {
934     return mat(0, 0) * mat(1, 1) - mat(1, 0) * mat(0, 1);
935 }
936 
937 template <>
determinant(const tcu::Matrix<float,3,3> & mat)938 float determinant<3>(const tcu::Matrix<float, 3, 3> &mat)
939 {
940     return +mat(0, 0) * mat(1, 1) * mat(2, 2) + mat(0, 1) * mat(1, 2) * mat(2, 0) + mat(0, 2) * mat(1, 0) * mat(2, 1) -
941            mat(0, 0) * mat(1, 2) * mat(2, 1) - mat(0, 1) * mat(1, 0) * mat(2, 2) - mat(0, 2) * mat(1, 1) * mat(2, 0);
942 }
943 
944 template <>
determinant(const tcu::Matrix<float,4,4> & mat)945 float determinant<4>(const tcu::Matrix<float, 4, 4> &mat)
946 {
947     const float minorMatrices[4][3 * 3] = {{
948                                                mat(1, 1),
949                                                mat(2, 1),
950                                                mat(3, 1),
951                                                mat(1, 2),
952                                                mat(2, 2),
953                                                mat(3, 2),
954                                                mat(1, 3),
955                                                mat(2, 3),
956                                                mat(3, 3),
957                                            },
958                                            {
959                                                mat(1, 0),
960                                                mat(2, 0),
961                                                mat(3, 0),
962                                                mat(1, 2),
963                                                mat(2, 2),
964                                                mat(3, 2),
965                                                mat(1, 3),
966                                                mat(2, 3),
967                                                mat(3, 3),
968                                            },
969                                            {
970                                                mat(1, 0),
971                                                mat(2, 0),
972                                                mat(3, 0),
973                                                mat(1, 1),
974                                                mat(2, 1),
975                                                mat(3, 1),
976                                                mat(1, 3),
977                                                mat(2, 3),
978                                                mat(3, 3),
979                                            },
980                                            {
981                                                mat(1, 0),
982                                                mat(2, 0),
983                                                mat(3, 0),
984                                                mat(1, 1),
985                                                mat(2, 1),
986                                                mat(3, 1),
987                                                mat(1, 2),
988                                                mat(2, 2),
989                                                mat(3, 2),
990                                            }};
991 
992     return +mat(0, 0) * determinant(tcu::Mat3(minorMatrices[0])) -
993            mat(0, 1) * determinant(tcu::Mat3(minorMatrices[1])) + mat(0, 2) * determinant(tcu::Mat3(minorMatrices[2])) -
994            mat(0, 3) * determinant(tcu::Mat3(minorMatrices[3]));
995 }
996 
997 // Inverse
998 
999 template <int Size>
1000 tcu::Matrix<float, Size, Size> inverse(const tcu::Matrix<float, Size, Size> &mat);
1001 
1002 template <>
inverse(const tcu::Matrix<float,2,2> & mat)1003 tcu::Matrix<float, 2, 2> inverse<2>(const tcu::Matrix<float, 2, 2> &mat)
1004 {
1005     const float det = determinant(mat);
1006     tcu::Matrix<float, 2, 2> retVal;
1007 
1008     DE_ASSERT(det != 0.0f);
1009 
1010     retVal(0, 0) = mat(1, 1) / det;
1011     retVal(0, 1) = -mat(0, 1) / det;
1012     retVal(1, 0) = -mat(1, 0) / det;
1013     retVal(1, 1) = mat(0, 0) / det;
1014 
1015     return retVal;
1016 }
1017 
1018 template <>
inverse(const tcu::Matrix<float,3,3> & mat)1019 tcu::Matrix<float, 3, 3> inverse<3>(const tcu::Matrix<float, 3, 3> &mat)
1020 {
1021     // Blockwise inversion
1022 
1023     DE_ASSERT(determinant(mat) != 0.0f);
1024 
1025     const float areaA[2 * 2] = {mat(0, 0), mat(0, 1), mat(1, 0), mat(1, 1)};
1026     const float areaB[2]     = {
1027         mat(0, 2),
1028         mat(1, 2),
1029     };
1030     const float areaC[2] = {
1031         mat(2, 0),
1032         mat(2, 1),
1033     };
1034     const float areaD[1]     = {mat(2, 2)};
1035     const float nullField[4] = {0.0f};
1036 
1037     const tcu::Matrix<float, 2, 2> invA = inverse(tcu::Matrix<float, 2, 2>(areaA));
1038     const tcu::Matrix<float, 2, 1> matB = tcu::Matrix<float, 2, 1>(areaB);
1039     const tcu::Matrix<float, 1, 2> matC = tcu::Matrix<float, 1, 2>(areaC);
1040     const tcu::Matrix<float, 1, 1> matD = tcu::Matrix<float, 1, 1>(areaD);
1041 
1042     const float schurComplement            = 1.0f / (matD - matC * invA * matB)(0, 0);
1043     const tcu::Matrix<float, 2, 2> zeroMat = Mat2(nullField);
1044 
1045     const tcu::Matrix<float, 2, 2> blockA = invA + invA * matB * schurComplement * matC * invA;
1046     const tcu::Matrix<float, 2, 1> blockB = (zeroMat - invA) * matB * schurComplement;
1047     const tcu::Matrix<float, 1, 2> blockC = matC * invA * (-schurComplement);
1048     const float blockD                    = schurComplement;
1049 
1050     const float result[3 * 3] = {
1051         blockA(0, 0), blockA(0, 1), blockB(0, 0), blockA(1, 0), blockA(1, 1),
1052         blockB(1, 0), blockC(0, 0), blockC(0, 1), blockD,
1053     };
1054 
1055     return Mat3(result);
1056 }
1057 
1058 template <>
inverse(const tcu::Matrix<float,4,4> & mat)1059 tcu::Matrix<float, 4, 4> inverse<4>(const tcu::Matrix<float, 4, 4> &mat)
1060 {
1061     // Blockwise inversion
1062 
1063     DE_ASSERT(determinant(mat) != 0.0f);
1064 
1065     const float areaA[2 * 2] = {mat(0, 0), mat(0, 1), mat(1, 0), mat(1, 1)};
1066     const float areaB[2 * 2] = {mat(0, 2), mat(0, 3), mat(1, 2), mat(1, 3)};
1067     const float areaC[2 * 2] = {mat(2, 0), mat(2, 1), mat(3, 0), mat(3, 1)};
1068     const float areaD[2 * 2] = {mat(2, 2), mat(2, 3), mat(3, 2), mat(3, 3)};
1069     const float nullField[4] = {0.0f};
1070 
1071     const tcu::Matrix<float, 2, 2> invA = inverse(Mat2(areaA));
1072     const tcu::Matrix<float, 2, 2> matB = Mat2(areaB);
1073     const tcu::Matrix<float, 2, 2> matC = Mat2(areaC);
1074     const tcu::Matrix<float, 2, 2> matD = Mat2(areaD);
1075 
1076     const tcu::Matrix<float, 2, 2> schurComplement = inverse(matD - matC * invA * matB);
1077     const tcu::Matrix<float, 2, 2> zeroMat         = Mat2(nullField);
1078 
1079     const tcu::Matrix<float, 2, 2> blockA = invA + invA * matB * schurComplement * matC * invA;
1080     const tcu::Matrix<float, 2, 2> blockB = (zeroMat - invA) * matB * schurComplement;
1081     const tcu::Matrix<float, 2, 2> blockC = (zeroMat - schurComplement) * matC * invA;
1082     const tcu::Matrix<float, 2, 2> blockD = schurComplement;
1083 
1084     const float result[4 * 4] = {
1085         blockA(0, 0), blockA(0, 1), blockB(0, 0), blockB(0, 1), blockA(1, 0), blockA(1, 1), blockB(1, 0), blockB(1, 1),
1086         blockC(0, 0), blockC(0, 1), blockD(0, 0), blockD(0, 1), blockC(1, 0), blockC(1, 1), blockD(1, 0), blockD(1, 1),
1087     };
1088 
1089     return Mat4(result);
1090 }
1091 
1092 // negate
1093 
1094 template <typename T, int Rows, int Cols>
negate(const tcu::Matrix<T,Rows,Cols> & mat)1095 tcu::Matrix<T, Rows, Cols> negate(const tcu::Matrix<T, Rows, Cols> &mat)
1096 {
1097     tcu::Matrix<T, Rows, Cols> retVal;
1098 
1099     for (int r = 0; r < Rows; ++r)
1100         for (int c = 0; c < Cols; ++c)
1101             retVal(r, c) = -mat(r, c);
1102 
1103     return retVal;
1104 }
1105 
1106 // increment/decrement
1107 
1108 template <typename T, int Rows, int Cols>
increment(const tcu::Matrix<T,Rows,Cols> & mat)1109 tcu::Matrix<T, Rows, Cols> increment(const tcu::Matrix<T, Rows, Cols> &mat)
1110 {
1111     tcu::Matrix<T, Rows, Cols> retVal;
1112 
1113     for (int r = 0; r < Rows; ++r)
1114         for (int c = 0; c < Cols; ++c)
1115             retVal(r, c) = mat(r, c) + 1.0f;
1116 
1117     return retVal;
1118 }
1119 
1120 template <typename T, int Rows, int Cols>
decrement(const tcu::Matrix<T,Rows,Cols> & mat)1121 tcu::Matrix<T, Rows, Cols> decrement(const tcu::Matrix<T, Rows, Cols> &mat)
1122 {
1123     tcu::Matrix<T, Rows, Cols> retVal;
1124 
1125     for (int r = 0; r < Rows; ++r)
1126         for (int c = 0; c < Cols; ++c)
1127             retVal(r, c) = mat(r, c) - 1.0f;
1128 
1129     return retVal;
1130 }
1131 
1132 // Evaluator template.
1133 
1134 typedef void (*MatrixShaderEvalFunc)(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type);
1135 
1136 template <int Op, int In0DataType, int In1DataType>
1137 struct Evaluator;
1138 
1139 template <int In0DataType, int In1DataType>
1140 struct Evaluator<OP_ADD, In0DataType, In1DataType>
1141 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1142     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1143     {
1144         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1145                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1146                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1147         typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ?
1148                                                          getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1) :
1149                                                          getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
1150         evalCtx.color.xyz()                        = reduceToVec3(in0 + in1);
1151     }
1152 };
1153 
1154 template <int In0DataType, int In1DataType>
1155 struct Evaluator<OP_SUB, In0DataType, In1DataType>
1156 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1157     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1158     {
1159         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1160                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1161                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1162         typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ?
1163                                                          getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1) :
1164                                                          getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
1165         evalCtx.color.xyz()                        = reduceToVec3(in0 - in1);
1166     }
1167 };
1168 
1169 template <int In0DataType, int In1DataType>
1170 struct Evaluator<OP_MUL, In0DataType, In1DataType>
1171 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1172     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1173     {
1174         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1175                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1176                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1177         typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ?
1178                                                          getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1) :
1179                                                          getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
1180         evalCtx.color.xyz()                        = reduceToVec3(in0 * in1);
1181     }
1182 };
1183 
1184 template <int In0DataType, int In1DataType>
1185 struct Evaluator<OP_DIV, In0DataType, In1DataType>
1186 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1187     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1188     {
1189         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1190                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1191                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1192         typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ?
1193                                                          getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1) :
1194                                                          getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
1195         evalCtx.color.xyz()                        = reduceToVec3(in0 / in1);
1196     }
1197 };
1198 
1199 template <int In0DataType, int In1DataType>
1200 struct Evaluator<OP_COMP_MUL, In0DataType, In1DataType>
1201 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1202     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1203     {
1204         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1205                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1206                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1207         typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ?
1208                                                          getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1) :
1209                                                          getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
1210         evalCtx.color.xyz()                        = reduceToVec3(matrixCompMult(in0, in1));
1211     }
1212 };
1213 
1214 template <int In0DataType, int In1DataType>
1215 struct Evaluator<OP_OUTER_PRODUCT, In0DataType, In1DataType>
1216 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1217     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1218     {
1219         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1220                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1221                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1222         typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ?
1223                                                          getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1) :
1224                                                          getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
1225         evalCtx.color.xyz()                        = reduceToVec3(outerProduct(in0, in1));
1226     }
1227 };
1228 
1229 template <int In0DataType, int In1DataType>
1230 struct Evaluator<OP_TRANSPOSE, In0DataType, In1DataType>
1231 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1232     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1233     {
1234         DE_UNREF(in1Type);
1235         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1236                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1237                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1238         evalCtx.color.xyz()                        = reduceToVec3(transpose(in0));
1239     }
1240 };
1241 
1242 template <int In0DataType, int In1DataType>
1243 struct Evaluator<OP_INVERSE, In0DataType, In1DataType>
1244 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1245     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1246     {
1247         DE_UNREF(in1Type);
1248         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1249                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1250                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1251         evalCtx.color.xyz()                        = reduceToVec3(inverse(in0));
1252     }
1253 };
1254 
1255 template <int In0DataType, int In1DataType>
1256 struct Evaluator<OP_DETERMINANT, In0DataType, In1DataType>
1257 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1258     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1259     {
1260         DE_UNREF(in1Type);
1261         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1262                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1263                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1264         evalCtx.color.xyz()                        = Vec3(determinant(in0));
1265     }
1266 };
1267 
1268 template <int In0DataType, int In1DataType>
1269 struct Evaluator<OP_UNARY_PLUS, In0DataType, In1DataType>
1270 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1271     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1272     {
1273         DE_UNREF(in1Type);
1274         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1275                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1276                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1277         evalCtx.color.xyz()                        = reduceToVec3(in0);
1278     }
1279 };
1280 
1281 template <int In0DataType, int In1DataType>
1282 struct Evaluator<OP_NEGATION, In0DataType, In1DataType>
1283 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1284     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1285     {
1286         DE_UNREF(in1Type);
1287         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1288                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1289                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1290         evalCtx.color.xyz()                        = reduceToVec3(negate(in0));
1291     }
1292 };
1293 
1294 template <int In0DataType, int In1DataType>
1295 struct Evaluator<OP_PRE_INCREMENT, In0DataType, In1DataType>
1296 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1297     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1298     {
1299         DE_UNREF(in1Type);
1300         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1301                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1302                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1303 
1304         // modifying reduction: sum modified value too
1305         evalCtx.color.xyz() = reduceToVec3(increment(in0)) + reduceToVec3(increment(in0));
1306     }
1307 };
1308 
1309 template <int In0DataType, int In1DataType>
1310 struct Evaluator<OP_PRE_DECREMENT, In0DataType, In1DataType>
1311 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1312     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1313     {
1314         DE_UNREF(in1Type);
1315         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1316                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1317                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1318 
1319         // modifying reduction: sum modified value too
1320         evalCtx.color.xyz() = reduceToVec3(decrement(in0)) + reduceToVec3(decrement(in0));
1321     }
1322 };
1323 
1324 template <int In0DataType, int In1DataType>
1325 struct Evaluator<OP_POST_INCREMENT, In0DataType, In1DataType>
1326 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1327     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1328     {
1329         DE_UNREF(in1Type);
1330         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1331                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1332                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1333 
1334         // modifying reduction: sum modified value too
1335         evalCtx.color.xyz() = reduceToVec3(in0) + reduceToVec3(increment(in0));
1336     }
1337 };
1338 
1339 template <int In0DataType, int In1DataType>
1340 struct Evaluator<OP_POST_DECREMENT, In0DataType, In1DataType>
1341 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1342     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1343     {
1344         DE_UNREF(in1Type);
1345         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1346                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1347                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1348 
1349         // modifying reduction: sum modified value too
1350         evalCtx.color.xyz() = reduceToVec3(in0) + reduceToVec3(decrement(in0));
1351     }
1352 };
1353 
1354 template <int In0DataType, int In1DataType>
1355 struct Evaluator<OP_ADD_INTO, In0DataType, In1DataType>
1356 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1357     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1358     {
1359         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1360                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1361                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1362         typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ?
1363                                                          getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1) :
1364                                                          getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
1365         evalCtx.color.xyz()                        = reduceToVec3(in0 + in1);
1366     }
1367 };
1368 
1369 template <int In0DataType, int In1DataType>
1370 struct Evaluator<OP_SUBTRACT_FROM, In0DataType, In1DataType>
1371 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1372     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1373     {
1374         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1375                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1376                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1377         typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ?
1378                                                          getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1) :
1379                                                          getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
1380         evalCtx.color.xyz()                        = reduceToVec3(in0 - in1);
1381     }
1382 };
1383 
1384 template <int In0DataType, int In1DataType>
1385 struct Evaluator<OP_MULTIPLY_INTO, In0DataType, In1DataType>
1386 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1387     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1388     {
1389         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1390                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1391                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1392         typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ?
1393                                                          getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1) :
1394                                                          getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
1395         evalCtx.color.xyz()                        = reduceToVec3(in0 * in1);
1396     }
1397 };
1398 
1399 template <int In0DataType, int In1DataType>
1400 struct Evaluator<OP_DIVIDE_INTO, In0DataType, In1DataType>
1401 {
evaluatedeqp::gles3::Functional::MatrixCaseUtils::Evaluator1402     static void evaluate(ShaderEvalContext &evalCtx, InputType in0Type, InputType in1Type)
1403     {
1404         typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ?
1405                                                          getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0) :
1406                                                          getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
1407         typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ?
1408                                                          getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1) :
1409                                                          getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
1410         evalCtx.color.xyz()                        = reduceToVec3(in0 / in1);
1411     }
1412 };
1413 
getEvalFunc(const ShaderInput & in0,const ShaderInput & in1,MatrixOp op)1414 MatrixShaderEvalFunc getEvalFunc(const ShaderInput &in0, const ShaderInput &in1, MatrixOp op)
1415 {
1416     // Evaluator is selected based on op and input data types.
1417     // For efficient lookup the types and op enums are packed together to form a 19-bit key:
1418     // [18..14 OP] [13..7 TYPE0] [6..0 TYPE1]
1419 
1420     DE_STATIC_ASSERT(TYPE_LAST <= (1 << 7));
1421     DE_STATIC_ASSERT(OP_LAST <= (1 << 5));
1422 
1423 #define PACK_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE) (((OP) << 14) | ((IN0DATATYPE) << 7) | (IN1DATATYPE))
1424 
1425 #define MAKE_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE)   \
1426     case PACK_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE): \
1427         return Evaluator<OP, IN0DATATYPE, IN1DATATYPE>::evaluate
1428 
1429 #define MAKE_SCALAR_OPS(IN0DATATYPE, IN1DATATYPE)     \
1430     MAKE_EVAL_CASE(OP_ADD, IN0DATATYPE, IN1DATATYPE); \
1431     MAKE_EVAL_CASE(OP_SUB, IN0DATATYPE, IN1DATATYPE); \
1432     MAKE_EVAL_CASE(OP_MUL, IN0DATATYPE, IN1DATATYPE); \
1433     MAKE_EVAL_CASE(OP_DIV, IN0DATATYPE, IN1DATATYPE)
1434 
1435 #define MAKE_CWISE_OPS(IN0DATATYPE, IN1DATATYPE)      \
1436     MAKE_EVAL_CASE(OP_ADD, IN0DATATYPE, IN1DATATYPE); \
1437     MAKE_EVAL_CASE(OP_SUB, IN0DATATYPE, IN1DATATYPE); \
1438     MAKE_EVAL_CASE(OP_DIV, IN0DATATYPE, IN1DATATYPE); \
1439     MAKE_EVAL_CASE(OP_COMP_MUL, IN0DATATYPE, IN1DATATYPE)
1440 
1441 #define MAKE_MUL_OP(IN0DATATYPE, IN1DATATYPE) MAKE_EVAL_CASE(OP_MUL, IN0DATATYPE, IN1DATATYPE)
1442 
1443 #define MAKE_VECVEC_OP(IN0DATATYPE, IN1DATATYPE) MAKE_EVAL_CASE(OP_OUTER_PRODUCT, IN0DATATYPE, IN1DATATYPE)
1444 
1445 #define MAKE_UNARY_OP(IN0DATATYPE)                             \
1446     MAKE_EVAL_CASE(OP_TRANSPOSE, IN0DATATYPE, TYPE_LAST);      \
1447     MAKE_EVAL_CASE(OP_UNARY_PLUS, IN0DATATYPE, TYPE_LAST);     \
1448     MAKE_EVAL_CASE(OP_NEGATION, IN0DATATYPE, TYPE_LAST);       \
1449     MAKE_EVAL_CASE(OP_PRE_INCREMENT, IN0DATATYPE, TYPE_LAST);  \
1450     MAKE_EVAL_CASE(OP_PRE_DECREMENT, IN0DATATYPE, TYPE_LAST);  \
1451     MAKE_EVAL_CASE(OP_POST_INCREMENT, IN0DATATYPE, TYPE_LAST); \
1452     MAKE_EVAL_CASE(OP_POST_DECREMENT, IN0DATATYPE, TYPE_LAST)
1453 
1454 #define MAKE_UNARY_SYMMETRIC_OP(IN0DATATYPE)                \
1455     MAKE_UNARY_OP(IN0DATATYPE);                             \
1456     MAKE_EVAL_CASE(OP_DETERMINANT, IN0DATATYPE, TYPE_LAST); \
1457     MAKE_EVAL_CASE(OP_INVERSE, IN0DATATYPE, TYPE_LAST)
1458 
1459 #define MAKE_ASSIGNMENT_OP(IN0DATATYPE)                         \
1460     MAKE_EVAL_CASE(OP_ADD_INTO, IN0DATATYPE, IN0DATATYPE);      \
1461     MAKE_EVAL_CASE(OP_SUBTRACT_FROM, IN0DATATYPE, IN0DATATYPE); \
1462     MAKE_EVAL_CASE(OP_DIVIDE_INTO, IN0DATATYPE, IN0DATATYPE)
1463 
1464 #define MAKE_ASSIGNMENT_SYMMETRIC_OP(IN0DATATYPE) \
1465     MAKE_ASSIGNMENT_OP(IN0DATATYPE);              \
1466     MAKE_EVAL_CASE(OP_MULTIPLY_INTO, IN0DATATYPE, IN0DATATYPE)
1467 
1468     switch (PACK_EVAL_CASE(op, in0.dataType, in1.dataType))
1469     {
1470         // Matrix-scalar.
1471         MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2, TYPE_FLOAT);
1472         MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2X3, TYPE_FLOAT);
1473         MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2X4, TYPE_FLOAT);
1474         MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3X2, TYPE_FLOAT);
1475         MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3, TYPE_FLOAT);
1476         MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3X4, TYPE_FLOAT);
1477         MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4X2, TYPE_FLOAT);
1478         MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4X3, TYPE_FLOAT);
1479         MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4, TYPE_FLOAT);
1480 
1481         // Matrix-vector.
1482         MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_VEC2);
1483         MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_VEC2);
1484         MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_VEC2);
1485         MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_VEC3);
1486         MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_VEC3);
1487         MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_VEC3);
1488         MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_VEC4);
1489         MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_VEC4);
1490         MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_VEC4);
1491 
1492         // Vector-matrix.
1493         MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT2);
1494         MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT2X3);
1495         MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT2X4);
1496         MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT3X2);
1497         MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT3);
1498         MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT3X4);
1499         MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT4X2);
1500         MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT4X3);
1501         MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT4);
1502 
1503         // Matrix-matrix.
1504         MAKE_CWISE_OPS(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT2);
1505         MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT2);
1506         MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT3X2);
1507         MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT4X2);
1508 
1509         MAKE_CWISE_OPS(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT2X3);
1510         MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT2);
1511         MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT3X2);
1512         MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT4X2);
1513 
1514         MAKE_CWISE_OPS(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT2X4);
1515         MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT2);
1516         MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT3X2);
1517         MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT4X2);
1518 
1519         MAKE_CWISE_OPS(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT3X2);
1520         MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT2X3);
1521         MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT3);
1522         MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT4X3);
1523 
1524         MAKE_CWISE_OPS(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT3);
1525         MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT2X3);
1526         MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT3);
1527         MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT4X3);
1528 
1529         MAKE_CWISE_OPS(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT3X4);
1530         MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT2X3);
1531         MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT3);
1532         MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT4X3);
1533 
1534         MAKE_CWISE_OPS(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT4X2);
1535         MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT2X4);
1536         MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT3X4);
1537         MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT4);
1538 
1539         MAKE_CWISE_OPS(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT4X3);
1540         MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT2X4);
1541         MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT3X4);
1542         MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT4);
1543 
1544         MAKE_CWISE_OPS(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT4);
1545         MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT2X4);
1546         MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT3X4);
1547         MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT4);
1548 
1549         // Vector-vector.
1550         MAKE_VECVEC_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_VEC2);
1551         MAKE_VECVEC_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_VEC3);
1552         MAKE_VECVEC_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_VEC4);
1553         MAKE_VECVEC_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_VEC2);
1554         MAKE_VECVEC_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_VEC3);
1555         MAKE_VECVEC_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_VEC4);
1556         MAKE_VECVEC_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC2);
1557         MAKE_VECVEC_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC3);
1558         MAKE_VECVEC_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC4);
1559 
1560         // Unary Matrix.
1561         MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT2);
1562         MAKE_UNARY_OP(TYPE_FLOAT_MAT2X3);
1563         MAKE_UNARY_OP(TYPE_FLOAT_MAT2X4);
1564         MAKE_UNARY_OP(TYPE_FLOAT_MAT3X2);
1565         MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT3);
1566         MAKE_UNARY_OP(TYPE_FLOAT_MAT3X4);
1567         MAKE_UNARY_OP(TYPE_FLOAT_MAT4X2);
1568         MAKE_UNARY_OP(TYPE_FLOAT_MAT4X3);
1569         MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT4);
1570 
1571         // Assignments
1572         MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT2);
1573         MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT2X3);
1574         MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT2X4);
1575         MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT3X2);
1576         MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT3);
1577         MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT3X4);
1578         MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT4X2);
1579         MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT4X3);
1580         MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT4);
1581 
1582     default:
1583         DE_ASSERT(false);
1584         return DE_NULL;
1585     }
1586 
1587 #undef PACK_EVAL_CASE
1588 #undef MAKE_EVAL_CASE
1589 #undef MUL_OP
1590 #undef ALL_OPS
1591 #undef MAKE_MAT_SCALAR_VEC_CASES
1592 #undef MAKE_MAT_MAT_CASES
1593 }
1594 
1595 // Shader source format utilities.
1596 
1597 template <int Size>
writeVectorConstructor(std::ostream & str,const tcu::Vector<float,Size> & v)1598 void writeVectorConstructor(std::ostream &str, const tcu::Vector<float, Size> &v)
1599 {
1600     str << "vec" << Size << "(";
1601     for (int ndx = 0; ndx < Size; ndx++)
1602     {
1603         if (ndx != 0)
1604             str << ", ";
1605         str << de::floatToString(v[ndx], 1);
1606     }
1607     str << ")";
1608 }
1609 
1610 template <int Cols, int Rows>
writeMatrixConstructor(std::ostream & str,const tcu::Matrix<float,Rows,Cols> & m)1611 void writeMatrixConstructor(std::ostream &str, const tcu::Matrix<float, Rows, Cols> &m)
1612 {
1613     if (Rows == Cols)
1614         str << "mat" << Cols;
1615     else
1616         str << "mat" << Cols << "x" << Rows;
1617 
1618     str << "(";
1619     for (int colNdx = 0; colNdx < Cols; colNdx++)
1620     {
1621         for (int rowNdx = 0; rowNdx < Rows; rowNdx++)
1622         {
1623             if (rowNdx > 0 || colNdx > 0)
1624                 str << ", ";
1625             str << de::floatToString(m(rowNdx, colNdx), 1);
1626         }
1627     }
1628     str << ")";
1629 }
1630 
1631 } // namespace MatrixCaseUtils
1632 
1633 using namespace MatrixCaseUtils;
1634 
1635 class MatrixShaderEvaluator : public ShaderEvaluator
1636 {
1637 public:
1638     MatrixShaderEvaluator(MatrixShaderEvalFunc evalFunc, InputType inType0, InputType inType1);
1639 
1640     virtual void evaluate(ShaderEvalContext &evalCtx);
1641 
1642 private:
1643     MatrixShaderEvalFunc m_matEvalFunc;
1644     InputType m_inType0;
1645     InputType m_inType1;
1646 };
1647 
MatrixShaderEvaluator(MatrixShaderEvalFunc evalFunc,InputType inType0,InputType inType1)1648 MatrixShaderEvaluator::MatrixShaderEvaluator(MatrixShaderEvalFunc evalFunc, InputType inType0, InputType inType1)
1649     : m_matEvalFunc(evalFunc)
1650     , m_inType0(inType0)
1651     , m_inType1(inType1)
1652 {
1653 }
1654 
evaluate(ShaderEvalContext & evalCtx)1655 void MatrixShaderEvaluator::evaluate(ShaderEvalContext &evalCtx)
1656 {
1657     m_matEvalFunc(evalCtx, m_inType0, m_inType1);
1658 }
1659 
1660 class ShaderMatrixCase : public ShaderRenderCase
1661 {
1662 public:
1663     ShaderMatrixCase(Context &context, const char *name, const char *desc, const ShaderInput &in0,
1664                      const ShaderInput &in1, MatrixOp op, bool isVertexCase);
1665     ~ShaderMatrixCase(void);
1666 
1667     void init(void);
1668 
1669 protected:
1670     std::string genGLSLMatToVec3Reduction(const glu::DataType &matType, const char *varName);
1671     void setupUniforms(int programID, const tcu::Vec4 &constCoords);
1672 
1673 private:
1674     ShaderInput m_in0;
1675     ShaderInput m_in1;
1676     MatrixOp m_op;
1677     MatrixShaderEvaluator m_matEvaluator;
1678 };
1679 
ShaderMatrixCase(Context & context,const char * name,const char * desc,const ShaderInput & in0,const ShaderInput & in1,MatrixOp op,bool isVertexCase)1680 ShaderMatrixCase::ShaderMatrixCase(Context &context, const char *name, const char *desc, const ShaderInput &in0,
1681                                    const ShaderInput &in1, MatrixOp op, bool isVertexCase)
1682     : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc,
1683                        isVertexCase, m_matEvaluator)
1684     , m_in0(in0)
1685     , m_in1(in1)
1686     , m_op(op)
1687     , m_matEvaluator(getEvalFunc(in0, in1, op), in0.inputType, in1.inputType)
1688 {
1689 }
1690 
~ShaderMatrixCase(void)1691 ShaderMatrixCase::~ShaderMatrixCase(void)
1692 {
1693 }
1694 
init(void)1695 void ShaderMatrixCase::init(void)
1696 {
1697     std::ostringstream vtx;
1698     std::ostringstream frag;
1699     std::ostringstream &op = m_isVertexCase ? vtx : frag;
1700 
1701     bool isInDynMat0 = isDataTypeMatrix(m_in0.dataType) && m_in0.inputType == INPUTTYPE_DYNAMIC;
1702     bool isInDynMat1 = isDataTypeMatrix(m_in1.dataType) && m_in1.inputType == INPUTTYPE_DYNAMIC;
1703     string inValue0;
1704     string inValue1;
1705     DataType resultType  = TYPE_LAST;
1706     Precision resultPrec = m_in0.precision;
1707     vector<string> passVars;
1708     int numInputs = (isOperationBinary(m_op)) ? (2) : (1);
1709 
1710     std::string operationValue0;
1711     std::string operationValue1;
1712 
1713     DE_ASSERT(!isInDynMat0 || !isInDynMat1); // Only single dynamic matrix input is allowed.
1714     DE_UNREF(isInDynMat0 && isInDynMat1);
1715 
1716     // Compute result type.
1717     if (m_op == OP_MUL && isDataTypeMatrix(m_in0.dataType) && isDataTypeMatrix(m_in1.dataType))
1718     {
1719         resultType =
1720             getDataTypeMatrix(getDataTypeMatrixNumColumns(m_in1.dataType), getDataTypeMatrixNumRows(m_in0.dataType));
1721     }
1722     else if (m_op == OP_OUTER_PRODUCT)
1723     {
1724         resultType = getDataTypeMatrix(getDataTypeScalarSize(m_in1.dataType), getDataTypeScalarSize(m_in0.dataType));
1725     }
1726     else if (m_op == OP_TRANSPOSE)
1727     {
1728         resultType =
1729             getDataTypeMatrix(getDataTypeMatrixNumRows(m_in0.dataType), getDataTypeMatrixNumColumns(m_in0.dataType));
1730     }
1731     else if (m_op == OP_INVERSE)
1732     {
1733         resultType = m_in0.dataType;
1734     }
1735     else if (m_op == OP_DETERMINANT)
1736     {
1737         resultType = TYPE_FLOAT;
1738     }
1739     else if (getOperationType(m_op) == OPERATIONTYPE_UNARY_PREFIX_OPERATOR ||
1740              getOperationType(m_op) == OPERATIONTYPE_UNARY_POSTFIX_OPERATOR)
1741     {
1742         resultType = m_in0.dataType;
1743     }
1744     else if (isDataTypeMatrix(m_in0.dataType) && isDataTypeMatrix(m_in1.dataType))
1745     {
1746         DE_ASSERT(m_in0.dataType == m_in1.dataType);
1747         resultType = m_in0.dataType;
1748     }
1749     else if (isDataTypeMatrix(m_in0.dataType) || isDataTypeMatrix(m_in1.dataType))
1750     {
1751         int matNdx          = isDataTypeMatrix(m_in0.dataType) ? 0 : 1;
1752         DataType matrixType = matNdx == 0 ? m_in0.dataType : m_in1.dataType;
1753         DataType otherType  = matNdx == 0 ? m_in1.dataType : m_in0.dataType;
1754 
1755         if (otherType == TYPE_FLOAT)
1756             resultType = matrixType;
1757         else
1758         {
1759             DE_ASSERT(isDataTypeVector(otherType));
1760             resultType = getDataTypeFloatVec(matNdx == 0 ? getDataTypeMatrixNumRows(matrixType) :
1761                                                            getDataTypeMatrixNumColumns(matrixType));
1762         }
1763     }
1764     else
1765     {
1766         DE_ASSERT(false);
1767     }
1768 
1769     vtx << "#version 300 es\n";
1770     frag << "#version 300 es\n";
1771 
1772     vtx << "in highp vec4 a_position;\n";
1773     frag << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1774     if (m_isVertexCase)
1775     {
1776         vtx << "out mediump vec4 v_color;\n";
1777         frag << "in mediump vec4 v_color;\n";
1778     }
1779 
1780     // Input declarations.
1781     for (int inNdx = 0; inNdx < numInputs; inNdx++)
1782     {
1783         const ShaderInput &in = inNdx > 0 ? m_in1 : m_in0;
1784         const char *precName  = getPrecisionName(in.precision);
1785         const char *typeName  = getDataTypeName(in.dataType);
1786         string &inValue       = inNdx > 0 ? inValue1 : inValue0;
1787 
1788         if (in.inputType == INPUTTYPE_DYNAMIC)
1789         {
1790             vtx << "in " << precName << " " << typeName << " a_";
1791 
1792             if (isDataTypeMatrix(in.dataType))
1793             {
1794                 // a_matN, v_matN
1795                 vtx << typeName << ";\n";
1796                 if (!m_isVertexCase)
1797                 {
1798                     vtx << "out " << precName << " " << typeName << " v_" << typeName << ";\n";
1799                     frag << "in " << precName << " " << typeName << " v_" << typeName << ";\n";
1800                     passVars.push_back(typeName);
1801                 }
1802 
1803                 inValue = string(m_isVertexCase ? "a_" : "v_") + getDataTypeName(in.dataType);
1804             }
1805             else
1806             {
1807                 // a_coords, v_coords
1808                 vtx << "coords;\n";
1809                 if (!m_isVertexCase)
1810                 {
1811                     vtx << "out " << precName << " " << typeName << " v_coords;\n";
1812                     frag << "in " << precName << " " << typeName << " v_coords;\n";
1813                     passVars.push_back("coords");
1814                 }
1815 
1816                 inValue = m_isVertexCase ? "a_coords" : "v_coords";
1817             }
1818         }
1819         else if (in.inputType == INPUTTYPE_UNIFORM)
1820         {
1821             op << "uniform " << precName << " " << typeName << " u_in" << inNdx << ";\n";
1822             inValue = string("u_in") + de::toString(inNdx);
1823         }
1824         else if (in.inputType == INPUTTYPE_CONST)
1825         {
1826             op << "const " << precName << " " << typeName << " in" << inNdx << " = ";
1827 
1828             // Generate declaration.
1829             switch (in.dataType)
1830             {
1831             case TYPE_FLOAT:
1832                 op << de::floatToString(s_constInFloat[inNdx], 1);
1833                 break;
1834             case TYPE_FLOAT_VEC2:
1835                 writeVectorConstructor<2>(op, s_constInVec2[inNdx]);
1836                 break;
1837             case TYPE_FLOAT_VEC3:
1838                 writeVectorConstructor<3>(op, s_constInVec3[inNdx]);
1839                 break;
1840             case TYPE_FLOAT_VEC4:
1841                 writeVectorConstructor<4>(op, s_constInVec4[inNdx]);
1842                 break;
1843             case TYPE_FLOAT_MAT2:
1844                 writeMatrixConstructor<2, 2>(op, Mat2(s_constInMat2x2[inNdx]));
1845                 break;
1846             case TYPE_FLOAT_MAT2X3:
1847                 writeMatrixConstructor<2, 3>(op, Mat2x3(s_constInMat2x3[inNdx]));
1848                 break;
1849             case TYPE_FLOAT_MAT2X4:
1850                 writeMatrixConstructor<2, 4>(op, Mat2x4(s_constInMat2x4[inNdx]));
1851                 break;
1852             case TYPE_FLOAT_MAT3X2:
1853                 writeMatrixConstructor<3, 2>(op, Mat3x2(s_constInMat3x2[inNdx]));
1854                 break;
1855             case TYPE_FLOAT_MAT3:
1856                 writeMatrixConstructor<3, 3>(op, Mat3(s_constInMat3x3[inNdx]));
1857                 break;
1858             case TYPE_FLOAT_MAT3X4:
1859                 writeMatrixConstructor<3, 4>(op, Mat3x4(s_constInMat3x4[inNdx]));
1860                 break;
1861             case TYPE_FLOAT_MAT4X2:
1862                 writeMatrixConstructor<4, 2>(op, Mat4x2(s_constInMat4x2[inNdx]));
1863                 break;
1864             case TYPE_FLOAT_MAT4X3:
1865                 writeMatrixConstructor<4, 3>(op, Mat4x3(s_constInMat4x3[inNdx]));
1866                 break;
1867             case TYPE_FLOAT_MAT4:
1868                 writeMatrixConstructor<4, 4>(op, Mat4(s_constInMat4x4[inNdx]));
1869                 break;
1870 
1871             default:
1872                 DE_ASSERT(false);
1873             }
1874 
1875             op << ";\n";
1876 
1877             inValue = string("in") + de::toString(inNdx);
1878         }
1879     }
1880 
1881     vtx << "\n"
1882         << "void main (void)\n"
1883         << "{\n"
1884         << "    gl_Position = a_position;\n";
1885     frag << "\n"
1886          << "void main (void)\n"
1887          << "{\n";
1888 
1889     if (m_isVertexCase)
1890         frag << "    dEQP_FragColor = v_color;\n";
1891     else
1892     {
1893         for (vector<string>::const_iterator copyIter = passVars.begin(); copyIter != passVars.end(); copyIter++)
1894             vtx << "    v_" << *copyIter << " = "
1895                 << "a_" << *copyIter << ";\n";
1896     }
1897 
1898     // Operation.
1899 
1900     switch (getOperationNature(m_op))
1901     {
1902     case OPERATIONNATURE_PURE:
1903         DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
1904 
1905         operationValue0 = inValue0;
1906         operationValue1 = inValue1;
1907         break;
1908 
1909     case OPERATIONNATURE_MUTATING:
1910         DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
1911 
1912         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " tmpValue = " << inValue0
1913            << ";\n";
1914 
1915         operationValue0 = "tmpValue";
1916         operationValue1 = inValue1;
1917         break;
1918 
1919     case OPERATIONNATURE_ASSIGNMENT:
1920         DE_ASSERT(getOperationType(m_op) == OPERATIONTYPE_ASSIGNMENT);
1921 
1922         operationValue0 = inValue0;
1923         operationValue1 = inValue1;
1924         break;
1925 
1926     default:
1927         DE_ASSERT(false);
1928     }
1929 
1930     switch (getOperationType(m_op))
1931     {
1932     case OPERATIONTYPE_BINARY_OPERATOR:
1933         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType)
1934            << " res = " << operationValue0 << " " << getOperationName(m_op) << " " << operationValue1 << ";\n";
1935         break;
1936 
1937     case OPERATIONTYPE_UNARY_PREFIX_OPERATOR:
1938         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType)
1939            << " res = " << getOperationName(m_op) << operationValue0 << ";\n";
1940         break;
1941 
1942     case OPERATIONTYPE_UNARY_POSTFIX_OPERATOR:
1943         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType)
1944            << " res = " << operationValue0 << getOperationName(m_op) << ";\n";
1945         break;
1946 
1947     case OPERATIONTYPE_BINARY_FUNCTION:
1948         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType)
1949            << " res = " << getOperationName(m_op) << "(" << operationValue0 << ", " << operationValue1 << ");\n";
1950         break;
1951 
1952     case OPERATIONTYPE_UNARY_FUNCTION:
1953         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType)
1954            << " res = " << getOperationName(m_op) << "(" << operationValue0 << ");\n";
1955         break;
1956 
1957     case OPERATIONTYPE_ASSIGNMENT:
1958         op << "    " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType)
1959            << " res = " << operationValue0 << ";\n";
1960         op << "    res " << getOperationName(m_op) << " " << operationValue1 << ";\n";
1961         break;
1962 
1963     default:
1964         DE_ASSERT(false);
1965     }
1966 
1967     // Reduction to vec3 (rgb). Check the used value too if it was modified
1968     op << "    " << (m_isVertexCase ? "v_color" : "dEQP_FragColor") << " = ";
1969 
1970     if (isOperationValueModifying(m_op))
1971         op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0) + vec4("
1972            << genGLSLMatToVec3Reduction(resultType, "tmpValue") << ", 0.0);\n";
1973     else
1974         op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0);\n";
1975 
1976     vtx << "}\n";
1977     frag << "}\n";
1978 
1979     m_vertShaderSource = vtx.str();
1980     m_fragShaderSource = frag.str();
1981 
1982     // \todo [2012-02-14 pyry] Compute better values for matrix tests.
1983     m_userAttribTransforms.resize(4);
1984     for (int attribNdx = 0; attribNdx < 4; attribNdx++)
1985     {
1986         m_userAttribTransforms[attribNdx] = Mat4(0.0f);
1987         m_userAttribTransforms[attribNdx](0, 3) =
1988             0.1f + 0.1f * float(attribNdx); // !< prevent matrix*vec from going into zero (assuming vec.w != 0)
1989         m_userAttribTransforms[attribNdx](1, 3)                   = 0.2f + 0.1f * float(attribNdx); // !<
1990         m_userAttribTransforms[attribNdx](2, 3)                   = 0.3f + 0.1f * float(attribNdx); // !<
1991         m_userAttribTransforms[attribNdx](3, 3)                   = 0.4f + 0.1f * float(attribNdx); // !<
1992         m_userAttribTransforms[attribNdx]((0 + attribNdx) % 4, 0) = 1.0f;
1993         m_userAttribTransforms[attribNdx]((1 + attribNdx) % 4, 1) = 1.0f;
1994         m_userAttribTransforms[attribNdx]((2 + attribNdx) % 4, 2) = 1.0f;
1995         m_userAttribTransforms[attribNdx]((3 + attribNdx) % 4, 3) = 1.0f;
1996     }
1997 
1998     // prevent bad reference cases such as black result images by fine-tuning used matrices
1999     if (getOperationTestMatrixType(m_op) != TESTMATRIXTYPE_DEFAULT)
2000     {
2001         for (int attribNdx = 0; attribNdx < 4; attribNdx++)
2002         {
2003             for (int row = 0; row < 4; row++)
2004                 for (int col = 0; col < 4; col++)
2005                 {
2006                     switch (getOperationTestMatrixType(m_op))
2007                     {
2008                     case TESTMATRIXTYPE_NEGATED:
2009                         m_userAttribTransforms[attribNdx](row, col) = -m_userAttribTransforms[attribNdx](row, col);
2010                         break;
2011                     case TESTMATRIXTYPE_INCREMENTED:
2012                         m_userAttribTransforms[attribNdx](row, col) += 0.3f;
2013                         break;
2014                     case TESTMATRIXTYPE_DECREMENTED:
2015                         m_userAttribTransforms[attribNdx](row, col) -= 0.3f;
2016                         break;
2017                     case TESTMATRIXTYPE_NEGATED_INCREMENTED:
2018                         m_userAttribTransforms[attribNdx](row, col) =
2019                             -m_userAttribTransforms[attribNdx](row, col) + 0.3f;
2020                         break;
2021                     case TESTMATRIXTYPE_INCREMENTED_LESS:
2022                         m_userAttribTransforms[attribNdx](row, col) -= 0.1f;
2023                         break;
2024 
2025                     default:
2026                         DE_ASSERT(false);
2027                         break;
2028                     }
2029                 }
2030         }
2031     }
2032     // The verification code doesn't deal with reduced precision, so we must quantize the data
2033     // here to try to avoid verification errors. No implementation seems to use lowp, so reduce
2034     // to mediump.
2035     if (resultPrec != PRECISION_HIGHP)
2036     {
2037         for (int attribNdx = 0; attribNdx < 4; attribNdx++)
2038         {
2039             for (int row = 0; row < 4; row++)
2040                 for (int col = 0; col < 4; col++)
2041                 {
2042                     m_userAttribTransforms[attribNdx](row, col) =
2043                         deFloat16To32(deFloat32To16(m_userAttribTransforms[attribNdx](row, col)));
2044                 }
2045         }
2046     }
2047 
2048     ShaderRenderCase::init();
2049 
2050     // reassign grid size prevent matrix inverse inf value.
2051     m_gridSize = 64;
2052 }
2053 
genGLSLMatToVec3Reduction(const glu::DataType & matType,const char * varName)2054 std::string ShaderMatrixCase::genGLSLMatToVec3Reduction(const glu::DataType &matType, const char *varName)
2055 {
2056     std::ostringstream op;
2057 
2058     switch (matType)
2059     {
2060     case TYPE_FLOAT:
2061         op << varName << ", " << varName << ", " << varName << "";
2062         break;
2063     case TYPE_FLOAT_VEC2:
2064         op << varName << ".x, " << varName << ".y, " << varName << ".x";
2065         break;
2066     case TYPE_FLOAT_VEC3:
2067         op << varName << "";
2068         break;
2069     case TYPE_FLOAT_VEC4:
2070         op << varName << ".x, " << varName << ".y, " << varName << ".z+" << varName << ".w";
2071         break;
2072     case TYPE_FLOAT_MAT2:
2073         op << varName << "[0][0], " << varName << "[1][0], " << varName << "[0][1]+" << varName << "[1][1]";
2074         break;
2075     case TYPE_FLOAT_MAT2X3:
2076         op << varName << "[0] + " << varName << "[1]";
2077         break;
2078     case TYPE_FLOAT_MAT2X4:
2079         op << varName << "[0].xyz + " << varName << "[1].yzw";
2080         break;
2081     case TYPE_FLOAT_MAT3X2:
2082         op << varName << "[0][0]+" << varName << "[0][1], " << varName << "[1][0]+" << varName << "[1][1], " << varName
2083            << "[2][0]+" << varName << "[2][1]";
2084         break;
2085     case TYPE_FLOAT_MAT3:
2086         op << varName << "[0] + " << varName << "[1] + " << varName << "[2]";
2087         break;
2088     case TYPE_FLOAT_MAT3X4:
2089         op << varName << "[0].xyz + " << varName << "[1].yzw + " << varName << "[2].zwx";
2090         break;
2091     case TYPE_FLOAT_MAT4X2:
2092         op << varName << "[0][0]+" << varName << "[0][1]+" << varName << "[3][0], " << varName << "[1][0]+" << varName
2093            << "[1][1]+" << varName << "[3][1], " << varName << "[2][0]+" << varName << "[2][1]";
2094         break;
2095     case TYPE_FLOAT_MAT4X3:
2096         op << varName << "[0] + " << varName << "[1] + " << varName << "[2] + " << varName << "[3]";
2097         break;
2098     case TYPE_FLOAT_MAT4:
2099         op << varName << "[0].xyz+" << varName << "[1].yzw+" << varName << "[2].zwx+" << varName << "[3].wxy";
2100         break;
2101 
2102     default:
2103         DE_ASSERT(false);
2104     }
2105 
2106     return op.str();
2107 }
2108 
setupUniforms(int programID,const tcu::Vec4 & constCoords)2109 void ShaderMatrixCase::setupUniforms(int programID, const tcu::Vec4 &constCoords)
2110 {
2111     const glw::Functions &gl = m_renderCtx.getFunctions();
2112 
2113     DE_UNREF(constCoords);
2114 
2115     for (int inNdx = 0; inNdx < 2; inNdx++)
2116     {
2117         const ShaderInput &in = inNdx > 0 ? m_in1 : m_in0;
2118 
2119         if (in.inputType == INPUTTYPE_UNIFORM)
2120         {
2121             int loc = gl.getUniformLocation(programID, (string("u_in") + de::toString(inNdx)).c_str());
2122 
2123             if (loc < 0)
2124                 continue;
2125 
2126             switch (in.dataType)
2127             {
2128             case TYPE_FLOAT:
2129                 gl.uniform1f(loc, s_constInFloat[inNdx]);
2130                 break;
2131             case TYPE_FLOAT_VEC2:
2132                 gl.uniform2fv(loc, 1, s_constInVec2[inNdx].getPtr());
2133                 break;
2134             case TYPE_FLOAT_VEC3:
2135                 gl.uniform3fv(loc, 1, s_constInVec3[inNdx].getPtr());
2136                 break;
2137             case TYPE_FLOAT_VEC4:
2138                 gl.uniform4fv(loc, 1, s_constInVec4[inNdx].getPtr());
2139                 break;
2140             // \note GLES3 supports transpose in matrix upload.
2141             case TYPE_FLOAT_MAT2:
2142                 gl.uniformMatrix2fv(loc, 1, GL_TRUE, s_constInMat2x2[inNdx]);
2143                 break;
2144             case TYPE_FLOAT_MAT2X3:
2145                 gl.uniformMatrix2x3fv(loc, 1, GL_TRUE, s_constInMat2x3[inNdx]);
2146                 break;
2147             case TYPE_FLOAT_MAT2X4:
2148                 gl.uniformMatrix2x4fv(loc, 1, GL_TRUE, s_constInMat2x4[inNdx]);
2149                 break;
2150             case TYPE_FLOAT_MAT3X2:
2151                 gl.uniformMatrix3x2fv(loc, 1, GL_TRUE, s_constInMat3x2[inNdx]);
2152                 break;
2153             case TYPE_FLOAT_MAT3:
2154                 gl.uniformMatrix3fv(loc, 1, GL_TRUE, s_constInMat3x3[inNdx]);
2155                 break;
2156             case TYPE_FLOAT_MAT3X4:
2157                 gl.uniformMatrix3x4fv(loc, 1, GL_TRUE, s_constInMat3x4[inNdx]);
2158                 break;
2159             case TYPE_FLOAT_MAT4X2:
2160                 gl.uniformMatrix4x2fv(loc, 1, GL_TRUE, s_constInMat4x2[inNdx]);
2161                 break;
2162             case TYPE_FLOAT_MAT4X3:
2163                 gl.uniformMatrix4x3fv(loc, 1, GL_TRUE, s_constInMat4x3[inNdx]);
2164                 break;
2165             case TYPE_FLOAT_MAT4:
2166                 gl.uniformMatrix4fv(loc, 1, GL_TRUE, s_constInMat4x4[inNdx]);
2167                 break;
2168             default:
2169                 DE_ASSERT(false);
2170             }
2171         }
2172     }
2173 }
2174 
ShaderMatrixTests(Context & context)2175 ShaderMatrixTests::ShaderMatrixTests(Context &context) : TestCaseGroup(context, "matrix", "Matrix Tests")
2176 {
2177 }
2178 
~ShaderMatrixTests(void)2179 ShaderMatrixTests::~ShaderMatrixTests(void)
2180 {
2181 }
2182 
init(void)2183 void ShaderMatrixTests::init(void)
2184 {
2185     static const struct
2186     {
2187         const char *name;
2188         const char *desc;
2189         MatrixOp op;
2190         bool extendedInputTypeCases; // !< test with const and uniform types too
2191         bool createInputTypeGroup;   // !< create group for input types
2192     } ops[] = {
2193         {"add", "Matrix addition tests", OP_ADD, true, true},
2194         {"sub", "Matrix subtraction tests", OP_SUB, true, true},
2195         {"mul", "Matrix multiplication tests", OP_MUL, true, true},
2196         {"div", "Matrix division tests", OP_DIV, true, true},
2197         {"matrixcompmult", "Matrix component-wise multiplication tests", OP_COMP_MUL, false, true},
2198         {"outerproduct", "Matrix outerProduct() tests", OP_OUTER_PRODUCT, false, true},
2199         {"transpose", "Matrix transpose() tests", OP_TRANSPOSE, false, true},
2200         {"determinant", "Matrix determinant() tests", OP_DETERMINANT, false, true},
2201         {"inverse", "Matrix inverse() tests", OP_INVERSE, false, true},
2202         {"unary_addition", "Matrix unary addition tests", OP_UNARY_PLUS, false, false},
2203         {"negation", "Matrix negation tests", OP_NEGATION, false, false},
2204         {"pre_increment", "Matrix prefix increment tests", OP_PRE_INCREMENT, false, false},
2205         {"pre_decrement", "Matrix prefix decrement tests", OP_PRE_DECREMENT, false, false},
2206         {"post_increment", "Matrix postfix increment tests", OP_POST_INCREMENT, false, false},
2207         {"post_decrement", "Matrix postfix decrement tests", OP_POST_DECREMENT, false, false},
2208         {"add_assign", "Matrix add into tests", OP_ADD_INTO, false, false},
2209         {"sub_assign", "Matrix subtract from tests", OP_SUBTRACT_FROM, false, false},
2210         {"mul_assign", "Matrix multiply into tests", OP_MULTIPLY_INTO, false, false},
2211         {"div_assign", "Matrix divide into tests", OP_DIVIDE_INTO, false, false},
2212     };
2213 
2214     struct InputTypeSpec
2215     {
2216         const char *name;
2217         const char *desc;
2218         InputType type;
2219     };
2220     static const InputTypeSpec extendedInputTypes[] = {{"const", "Constant matrix input", INPUTTYPE_CONST},
2221                                                        {"uniform", "Uniform matrix input", INPUTTYPE_UNIFORM},
2222                                                        {"dynamic", "Dynamic matrix input", INPUTTYPE_DYNAMIC}};
2223     static const InputTypeSpec reducedInputTypes[]  = {{"dynamic", "Dynamic matrix input", INPUTTYPE_DYNAMIC}};
2224 
2225     static const DataType matrixTypes[] = {TYPE_FLOAT_MAT2,   TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT2X4,
2226                                            TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT3,   TYPE_FLOAT_MAT3X4,
2227                                            TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT4};
2228 
2229     static const Precision precisions[] = {PRECISION_LOWP, PRECISION_MEDIUMP, PRECISION_HIGHP};
2230 
2231     for (int opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
2232     {
2233         const InputTypeSpec *inTypeList =
2234             (ops[opNdx].extendedInputTypeCases) ? (extendedInputTypes) : (reducedInputTypes);
2235         const int inTypeListSize    = (ops[opNdx].extendedInputTypeCases) ? (DE_LENGTH_OF_ARRAY(extendedInputTypes)) :
2236                                                                             (DE_LENGTH_OF_ARRAY(reducedInputTypes));
2237         const MatrixOp op           = ops[opNdx].op;
2238         tcu::TestCaseGroup *opGroup = new tcu::TestCaseGroup(m_testCtx, ops[opNdx].name, ops[opNdx].desc);
2239 
2240         addChild(opGroup);
2241 
2242         for (int inTypeNdx = 0; inTypeNdx < inTypeListSize; inTypeNdx++)
2243         {
2244             const InputType inputType = inTypeList[inTypeNdx].type;
2245             tcu::TestCaseGroup *inGroup;
2246 
2247             if (ops[opNdx].createInputTypeGroup)
2248             {
2249                 inGroup = new tcu::TestCaseGroup(m_testCtx, inTypeList[inTypeNdx].name, inTypeList[inTypeNdx].desc);
2250                 opGroup->addChild(inGroup);
2251             }
2252             else
2253                 inGroup = opGroup;
2254 
2255             for (int matTypeNdx = 0; matTypeNdx < DE_LENGTH_OF_ARRAY(matrixTypes); matTypeNdx++)
2256             {
2257                 DataType matType        = matrixTypes[matTypeNdx];
2258                 int numCols             = getDataTypeMatrixNumColumns(matType);
2259                 int numRows             = getDataTypeMatrixNumRows(matType);
2260                 const char *matTypeName = getDataTypeName(matType);
2261 
2262                 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
2263                 {
2264                     Precision precision  = precisions[precNdx];
2265                     const char *precName = getPrecisionName(precision);
2266                     string baseName      = string(precName) + "_" + matTypeName + "_";
2267                     ShaderInput matIn(inputType, matType, precision);
2268 
2269                     if (isOperationMatrixScalar(op))
2270                     {
2271                         // Matrix-scalar \note For div cases we use uniform input.
2272                         ShaderInput scalarIn(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, TYPE_FLOAT,
2273                                              precision);
2274                         inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(),
2275                                                                "Matrix-scalar case", matIn, scalarIn, op, true));
2276                         inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(),
2277                                                                "Matrix-scalar case", matIn, scalarIn, op, false));
2278                     }
2279 
2280                     if (isOperationMatrixVector(op))
2281                     {
2282                         // Matrix-vector.
2283                         DataType colVecType = getDataTypeFloatVec(numCols);
2284                         ShaderInput colVecIn(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, colVecType,
2285                                              precision);
2286 
2287                         inGroup->addChild(new ShaderMatrixCase(
2288                             m_context, (baseName + getDataTypeName(colVecType) + "_vertex").c_str(),
2289                             "Matrix-vector case", matIn, colVecIn, op, true));
2290                         inGroup->addChild(new ShaderMatrixCase(
2291                             m_context, (baseName + getDataTypeName(colVecType) + "_fragment").c_str(),
2292                             "Matrix-vector case", matIn, colVecIn, op, false));
2293 
2294                         // Vector-matrix.
2295                         DataType rowVecType = getDataTypeFloatVec(numRows);
2296                         ShaderInput rowVecIn(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, rowVecType,
2297                                              precision);
2298                         string vecMatName = string(precName) + "_" + getDataTypeName(rowVecType) + "_" + matTypeName;
2299 
2300                         inGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_vertex").c_str(),
2301                                                                "Vector-matrix case", rowVecIn, matIn, op, true));
2302                         inGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_fragment").c_str(),
2303                                                                "Vector-matrix case", rowVecIn, matIn, op, false));
2304                     }
2305 
2306                     if (isOperationArithmeticMatrixMatrix(op))
2307                     {
2308                         // Arithmetic matrix-matrix multiplication.
2309                         for (int otherCols = 2; otherCols <= 4; otherCols++)
2310                         {
2311                             ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType,
2312                                                    getDataTypeMatrix(otherCols, numCols /* rows */), precision);
2313                             inGroup->addChild(new ShaderMatrixCase(
2314                                 m_context, (baseName + getDataTypeName(otherMatIn.dataType) + "_vertex").c_str(),
2315                                 "Matrix-matrix case", matIn, otherMatIn, op, true));
2316                             inGroup->addChild(new ShaderMatrixCase(
2317                                 m_context, (baseName + getDataTypeName(otherMatIn.dataType) + "_fragment").c_str(),
2318                                 "Matrix-matrix case", matIn, otherMatIn, op, false));
2319                         }
2320                     }
2321                     else if (isOperationComponentwiseMatrixMatrix(op))
2322                     {
2323                         // Component-wise.
2324                         ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType,
2325                                                precision);
2326                         inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + matTypeName + "_vertex").c_str(),
2327                                                                "Matrix-matrix case", matIn, otherMatIn, op, true));
2328                         inGroup->addChild(new ShaderMatrixCase(m_context,
2329                                                                (baseName + matTypeName + "_fragment").c_str(),
2330                                                                "Matrix-matrix case", matIn, otherMatIn, op, false));
2331                     }
2332 
2333                     if (isOperationVectorVector(op))
2334                     {
2335                         ShaderInput vec1In(inputType, getDataTypeFloatVec(numRows), precision);
2336                         ShaderInput vec2In((inputType == INPUTTYPE_DYNAMIC) ? (INPUTTYPE_UNIFORM) : (inputType),
2337                                            getDataTypeFloatVec(numCols), precision);
2338 
2339                         inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(),
2340                                                                "Vector-vector case", vec1In, vec2In, op, true));
2341                         inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(),
2342                                                                "Vector-vector case", vec1In, vec2In, op, false));
2343                     }
2344 
2345                     if ((isOperationUnaryAnyMatrix(op)) || (isOperationUnarySymmetricMatrix(op) && numCols == numRows))
2346                     {
2347                         ShaderInput voidInput(INPUTTYPE_LAST, TYPE_LAST, PRECISION_LAST);
2348                         inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(),
2349                                                                "Matrix case", matIn, voidInput, op, true));
2350                         inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(),
2351                                                                "Matrix case", matIn, voidInput, op, false));
2352                     }
2353 
2354                     if ((isOperationAssignmentAnyMatrix(op)) ||
2355                         (isOperationAssignmentSymmetricMatrix(op) && numCols == numRows))
2356                     {
2357                         ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType,
2358                                                precision);
2359                         inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(),
2360                                                                "Matrix assignment case", matIn, otherMatIn, op, true));
2361                         inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(),
2362                                                                "Matrix assignment case", matIn, otherMatIn, op, false));
2363                     }
2364                 }
2365             }
2366         }
2367     }
2368 }
2369 
2370 } // namespace Functional
2371 } // namespace gles3
2372 } // namespace deqp
2373 
2374 #if defined(_MSC_VER) && _MSC_FULL_VER == 191125507
2375 // Work around crbug.com/759402 which is a code-gen bug in VC++ 2017, version
2376 // 15.3.2.
2377 #pragma optimize("", off)
2378 #endif
2379