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 {
ShaderInputdeqp::gles2::Functional::MatrixCaseUtils::ShaderInput112 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
getOperationName(MatrixOp op)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
getOperationType(MatrixOp op)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
getOperationTestMatrixType(MatrixOp op)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
isOperationBinary(MatrixOp op)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
isOperationMatrixScalar(MatrixOp op)270 static bool isOperationMatrixScalar (MatrixOp op)
271 {
272 return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV;
273 }
274
isOperationMatrixVector(MatrixOp op)275 static bool isOperationMatrixVector (MatrixOp op)
276 {
277 return op == OP_MUL;
278 }
279
isOperationMatrixMatrix(MatrixOp op)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
isOperationUnary(MatrixOp op)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
isOperationValueModifying(MatrixOp op)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
isOperationAssignment(MatrixOp op)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
getOperationNature(MatrixOp op)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
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)338 template <> inline float getInputValue<INPUTTYPE_CONST, TYPE_FLOAT> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInFloat[inputNdx]; }
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)339 template <> inline tcu::Vec2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec2[inputNdx]; }
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)340 template <> inline tcu::Vec3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec3[inputNdx]; }
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)341 template <> inline tcu::Vec4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec4[inputNdx]; }
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)342 template <> inline tcu::Mat2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInMat2[inputNdx]; }
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)343 template <> inline tcu::Mat3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInMat3[inputNdx]; }
getInputValue(const ShaderEvalContext & evalCtx,int 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
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)346 template <> inline float getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.x(); }
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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); }
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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); }
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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
reduceToVec3(const tcu::Vec2 & value)383 inline tcu::Vec3 reduceToVec3 (const tcu::Vec2& value) { return value.swizzle(0,1,0); }
reduceToVec3(const tcu::Vec3 & value)384 inline tcu::Vec3 reduceToVec3 (const tcu::Vec3& value) { return value; }
reduceToVec3(const tcu::Vec4 & value)385 inline tcu::Vec3 reduceToVec3 (const tcu::Vec4& value) { return tcu::Vec3(value.x(), value.y(), value.z()+value.w()); }
reduceToVec3(const tcu::Mat2 & value)386 inline tcu::Vec3 reduceToVec3 (const tcu::Mat2& value) { return tcu::Vec3(value(0, 0), value(0, 1), value(1, 0)+value(1, 1)); }
reduceToVec3(const tcu::Mat3 & value)387 inline tcu::Vec3 reduceToVec3 (const tcu::Mat3& value) { return value.getColumn(0) + value.getColumn(1) + value.getColumn(2); }
reduceToVec3(const tcu::Mat4 & value)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>
matrixCompMult(const tcu::Matrix<T,Rows,Cols> & a,const tcu::Matrix<T,Rows,Cols> & b)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>
negate(const tcu::Matrix<T,Rows,Cols> & mat)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>
increment(const tcu::Matrix<T,Rows,Cols> & mat)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>
decrement(const tcu::Matrix<T,Rows,Cols> & mat)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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator452 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator461 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator470 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator479 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator488 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator497 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator506 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator515 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator525 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator535 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator545 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator555 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator564 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator573 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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator582 static void evaluate (ShaderEvalContext& evalCtx)
583 {
584 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) / getInputValue<In1Type, In1DataType>(evalCtx, 1));
585 }
586 };
587
getEvalFunc(const ShaderInput & in0,const ShaderInput & in1,MatrixOp op)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>
writeVectorConstructor(std::ostream & str,const tcu::Vector<float,Size> & v)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>
writeMatrixConstructor(std::ostream & str,const tcu::Matrix<float,Rows,Cols> & m)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
ShaderMatrixCase(Context & context,const char * name,const char * desc,const ShaderInput & in0,const ShaderInput & in1,MatrixOp op,bool isVertexCase)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
~ShaderMatrixCase(void)765 ShaderMatrixCase::~ShaderMatrixCase (void)
766 {
767 }
768
init(void)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
genGLSLMatToVec3Reduction(const glu::DataType & matType,const char * varName)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
setupUniforms(int programID,const tcu::Vec4 & constCoords)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
ShaderMatrixTests(Context & context)1078 ShaderMatrixTests::ShaderMatrixTests (Context& context)
1079 : TestCaseGroup(context, "matrix", "Matrix Tests")
1080 {
1081 }
1082
~ShaderMatrixTests(void)1083 ShaderMatrixTests::~ShaderMatrixTests (void)
1084 {
1085 }
1086
init(void)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
1224