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