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