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