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