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
52namespace deqp
53{
54namespace gles3
55{
56namespace Functional
57{
58
59using std::string;
60using std::vector;
61using namespace glu;
62using namespace deqp::gls;
63
64using tcu::Vec2;
65using tcu::Vec3;
66using tcu::Vec4;
67using tcu::Mat2;
68using tcu::Mat2x3;
69using tcu::Mat2x4;
70using tcu::Mat3x2;
71using tcu::Mat3;
72using tcu::Mat3x4;
73using tcu::Mat4x2;
74using tcu::Mat4x3;
75using 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.
80static const float	s_constInFloat[2]	= { 0.5f, -0.2f };
81static const Vec2	s_constInVec2[2]	= { Vec2(1.2f, 0.5f), Vec2(0.5f, 1.0f) };
82static const Vec3	s_constInVec3[2]	= { Vec3(1.1f, 0.1f, 0.5f), Vec3(-0.2f, 0.5f, 0.8f) };
83static const Vec4	s_constInVec4[2]	= { Vec4(1.4f, 0.2f, -0.5f, 0.7f), Vec4(0.2f, -1.0f, 0.5f, 0.8f) };
84
85static 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};
96static 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};
107static 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};
118static 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};
131static 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};
144static 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};
157static 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};
172static 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};
187static 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
203namespace MatrixCaseUtils
204{
205
206enum InputType
207{
208	INPUTTYPE_CONST = 0,
209	INPUTTYPE_UNIFORM,
210	INPUTTYPE_DYNAMIC,
211
212	INPUTTYPE_LAST
213};
214
215struct ShaderInput
216{
217	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
229enum 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
255template <int DataT>
256struct TypeTraits;
257
258#define DECLARE_TYPE_TRAIT(DATATYPE, TYPE)	\
259template<>									\
260struct TypeTraits<DATATYPE> {				\
261	typedef TYPE Type;						\
262}
263
264DECLARE_TYPE_TRAIT(TYPE_FLOAT,			float);
265DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC2,		tcu::Vec2);
266DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC3,		tcu::Vec3);
267DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC4,		tcu::Vec4);
268DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2,		tcu::Mat2);
269DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2X3,	tcu::Mat2x3);
270DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2X4,	tcu::Mat2x4);
271DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3X2,	tcu::Mat3x2);
272DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3,		tcu::Mat3);
273DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3X4,	tcu::Mat3x4);
274DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4X2,	tcu::Mat4x2);
275DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4X3,	tcu::Mat4x3);
276DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4,		tcu::Mat4);
277
278// Operation info
279
280enum 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
292static 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
322static 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
351enum 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
363static 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
393static 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
400static bool isOperationMatrixScalar (MatrixOp op)
401{
402	return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV;
403}
404
405static bool isOperationMatrixVector (MatrixOp op)
406{
407	return op == OP_MUL;
408}
409
410static bool isOperationArithmeticMatrixMatrix (MatrixOp op)
411{
412	return op == OP_MUL;
413}
414
415static 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
420static bool isOperationVectorVector (MatrixOp op)
421{
422	return op == OP_OUTER_PRODUCT;
423}
424
425static 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
436static bool isOperationUnarySymmetricMatrix (MatrixOp op)
437{
438	return op == OP_INVERSE || op == OP_DETERMINANT;
439}
440
441static 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
449static 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
457static bool isOperationAssignmentAnyMatrix (MatrixOp op)
458{
459	return  op == OP_ADD_INTO		 ||
460			op == OP_SUBTRACT_FROM	 ||
461			op == OP_DIVIDE_INTO;
462}
463
464static bool isOperationAssignmentSymmetricMatrix (MatrixOp op)
465{
466	return op == OP_MULTIPLY_INTO;
467}
468
469// Operation nature
470
471enum OperationNature
472{
473	OPERATIONNATURE_PURE = 0,
474	OPERATIONNATURE_MUTATING,
475	OPERATIONNATURE_ASSIGNMENT,
476
477	OPERATIONNATURE_LAST
478};
479
480static 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
493template <int InputT, int DataT>
494typename TypeTraits<DataT>::Type getInputValue (const ShaderEvalContext& evalCtx, int inputNdx);
495
496template <> inline float		getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT>			(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInFloat[inputNdx];	}
497template <> inline tcu::Vec2	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_VEC2>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec2[inputNdx];	}
498template <> inline tcu::Vec3	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_VEC3>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec3[inputNdx];	}
499template <> inline tcu::Vec4	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_VEC4>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec4[inputNdx];	}
500
501template <> inline tcu::Mat2	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT2>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat2(s_constInMat2x2[inputNdx]);		}
502template <> inline tcu::Mat2x3	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT2X3>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat2x3(s_constInMat2x3[inputNdx]);	}
503template <> inline tcu::Mat2x4	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT2X4>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat2x4(s_constInMat2x4[inputNdx]);	}
504template <> inline tcu::Mat3x2	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT3X2>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat3x2(s_constInMat3x2[inputNdx]);	}
505template <> inline tcu::Mat3	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT3>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat3(s_constInMat3x3[inputNdx]);		}
506template <> inline tcu::Mat3x4	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT3X4>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat3x4(s_constInMat3x4[inputNdx]);	}
507template <> inline tcu::Mat4x2	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT4X2>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat4x2(s_constInMat4x2[inputNdx]);	}
508template <> inline tcu::Mat4x3	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT4X3>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat4x3(s_constInMat4x3[inputNdx]);	}
509template <> inline tcu::Mat4	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT4>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat4(s_constInMat4x4[inputNdx]);		}
510
511template <> inline float		getInputValue<INPUTTYPE_DYNAMIC,	TYPE_FLOAT>			(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.x();					}
512template <> inline tcu::Vec2	getInputValue<INPUTTYPE_DYNAMIC,	TYPE_FLOAT_VEC2>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.swizzle(0, 1);			}
513template <> inline tcu::Vec3	getInputValue<INPUTTYPE_DYNAMIC,	TYPE_FLOAT_VEC3>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.swizzle(0, 1, 2);		}
514template <> 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
516template <> 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
525template <> 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
534template <> 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
543template <> 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
553template <> 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
563template <> 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
573template <> 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
584template <> 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
595template <> 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
608inline tcu::Vec3 reduceToVec3 (const tcu::Vec2& value)		{ return value.swizzle(0,1,0); }
609inline tcu::Vec3 reduceToVec3 (const tcu::Vec3& value)		{ return value; }
610inline tcu::Vec3 reduceToVec3 (const tcu::Vec4& value)		{ return tcu::Vec3(value.x(), value.y(), value.z()+value.w()); }
611inline tcu::Vec3 reduceToVec3 (const tcu::Mat2& value)		{ return tcu::Vec3(value(0, 0), value(0, 1), value(1, 0)+value(1, 1)); }
612inline tcu::Vec3 reduceToVec3 (const tcu::Mat2x3& value)	{ return value.getColumn(0) + value.getColumn(1); }
613inline tcu::Vec3 reduceToVec3 (const tcu::Mat2x4& value)	{ return value.getColumn(0).swizzle(0,1,2) + value.getColumn(1).swizzle(1,2,3); }
614inline 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)); }
615inline tcu::Vec3 reduceToVec3 (const tcu::Mat3& value)		{ return value.getColumn(0) + value.getColumn(1) + value.getColumn(2); }
616inline 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); }
617inline 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)); }
618inline tcu::Vec3 reduceToVec3 (const tcu::Mat4x3& value)	{ return value.getColumn(0) + value.getColumn(1) + value.getColumn(2) + value.getColumn(3); }
619inline 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
623template <typename T, int Rows, int Cols>
624tcu::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// transpose
636
637template <typename T, int Rows, int Cols>
638tcu::Matrix<T, Cols, Rows> transpose (const tcu::Matrix<T, Rows, Cols>& mat)
639{
640	tcu::Matrix<T, Cols, Rows> retVal;
641
642	for (int r = 0; r < Rows; ++r)
643		for (int c = 0; c < Cols; ++c)
644			retVal(c, r) = mat(r, c);
645
646	return retVal;
647}
648
649// outerProduct
650
651template <typename T, int Rows, int Cols>
652tcu::Matrix<T, Cols, Rows> outerProduct (const tcu::Vector<T, Cols>& a, const tcu::Vector<T, Rows>& b)
653{
654	tcu::Matrix<T, Rows, Cols> retVal;
655
656	for (int r = 0; r < Rows; ++r)
657		for (int c = 0; c < Cols; ++c)
658			retVal(r,c) = a[c] * b[r];
659
660	return transpose(retVal); // to gl-form (column-major)
661}
662
663// Determinant
664
665template <int Size>
666float determinant (const tcu::Matrix<float, Size, Size>& mat);
667
668template <>
669float determinant<2> (const tcu::Matrix<float, 2, 2>& mat)
670{
671	return mat(0,0) * mat(1,1) - mat(1,0) * mat(0,1);
672}
673
674template <>
675float determinant<3> (const tcu::Matrix<float, 3, 3>& mat)
676{
677	return	+ mat(0,0) * mat(1,1) * mat(2,2)
678			+ mat(0,1) * mat(1,2) * mat(2,0)
679			+ mat(0,2) * mat(1,0) * mat(2,1)
680			- mat(0,0) * mat(1,2) * mat(2,1)
681			- mat(0,1) * mat(1,0) * mat(2,2)
682			- mat(0,2) * mat(1,1) * mat(2,0);
683}
684
685template <>
686float determinant<4> (const tcu::Matrix<float, 4, 4>& mat)
687{
688	const float minorMatrices[4][3*3] =
689	{
690		{
691			mat(1,1),	mat(2,1),	mat(3,1),
692			mat(1,2),	mat(2,2),	mat(3,2),
693			mat(1,3),	mat(2,3),	mat(3,3),
694		},
695		{
696			mat(1,0),	mat(2,0),	mat(3,0),
697			mat(1,2),	mat(2,2),	mat(3,2),
698			mat(1,3),	mat(2,3),	mat(3,3),
699		},
700		{
701			mat(1,0),	mat(2,0),	mat(3,0),
702			mat(1,1),	mat(2,1),	mat(3,1),
703			mat(1,3),	mat(2,3),	mat(3,3),
704		},
705		{
706			mat(1,0),	mat(2,0),	mat(3,0),
707			mat(1,1),	mat(2,1),	mat(3,1),
708			mat(1,2),	mat(2,2),	mat(3,2),
709		}
710	};
711
712	return	+ mat(0,0) * determinant(tcu::Mat3(minorMatrices[0]))
713			- mat(0,1) * determinant(tcu::Mat3(minorMatrices[1]))
714			+ mat(0,2) * determinant(tcu::Mat3(minorMatrices[2]))
715			- mat(0,3) * determinant(tcu::Mat3(minorMatrices[3]));
716}
717
718// Inverse
719
720template <int Size>
721tcu::Matrix<float, Size, Size> inverse (const tcu::Matrix<float, Size, Size>& mat);
722
723template <>
724tcu::Matrix<float, 2, 2> inverse<2> (const tcu::Matrix<float, 2, 2>& mat)
725{
726	const float					det		= determinant(mat);
727	tcu::Matrix<float, 2, 2>	retVal;
728
729	DE_ASSERT(det != 0.0f);
730
731	retVal(0, 0) =  mat(1, 1) / det;
732	retVal(0, 1) = -mat(0, 1) / det;
733	retVal(1, 0) = -mat(1, 0) / det;
734	retVal(1, 1) =  mat(0, 0) / det;
735
736	return retVal;
737}
738
739template <>
740tcu::Matrix<float, 3, 3> inverse<3> (const tcu::Matrix<float, 3, 3>& mat)
741{
742	// Blockwise inversion
743
744	DE_ASSERT(determinant(mat) != 0.0f);
745
746	const float areaA[2*2] =
747	{
748		mat(0,0),	mat(0,1),
749		mat(1,0),	mat(1,1)
750	};
751	const float areaB[2] =
752	{
753		mat(0,2),
754		mat(1,2),
755	};
756	const float areaC[2] =
757	{
758		mat(2,0),	mat(2,1),
759	};
760	const float areaD[1] =
761	{
762		mat(2,2)
763	};
764	const float nullField[4] = { 0.0f };
765
766	const tcu::Matrix<float, 2, 2>	invA = inverse(tcu::Matrix<float, 2, 2>(areaA));
767	const tcu::Matrix<float, 2, 1>	matB =         tcu::Matrix<float, 2, 1>(areaB);
768	const tcu::Matrix<float, 1, 2>	matC =         tcu::Matrix<float, 1, 2>(areaC);
769	const tcu::Matrix<float, 1, 1>	matD =         tcu::Matrix<float, 1, 1>(areaD);
770
771	const float						schurComplement = 1.0f / (matD - matC*invA*matB)(0,0);
772	const tcu::Matrix<float, 2, 2>	zeroMat         = Mat2(nullField);
773
774	const tcu::Matrix<float, 2, 2>	blockA = invA + invA*matB*schurComplement*matC*invA;
775	const tcu::Matrix<float, 2, 1>	blockB = (zeroMat-invA)*matB*schurComplement;
776	const tcu::Matrix<float, 1, 2>	blockC = matC*invA*(-schurComplement);
777	const float						blockD = schurComplement;
778
779	const float result[3*3] =
780	{
781		blockA(0,0),	blockA(0,1),	blockB(0,0),
782		blockA(1,0),	blockA(1,1),	blockB(1,0),
783		blockC(0,0),	blockC(0,1),	blockD,
784	};
785
786	return Mat3(result);
787}
788
789template <>
790tcu::Matrix<float, 4, 4> inverse<4> (const tcu::Matrix<float, 4, 4>& mat)
791{
792	// Blockwise inversion
793
794	DE_ASSERT(determinant(mat) != 0.0f);
795
796	const float areaA[2*2] =
797	{
798		mat(0,0),	mat(0,1),
799		mat(1,0),	mat(1,1)
800	};
801	const float areaB[2*2] =
802	{
803		mat(0,2),	mat(0,3),
804		mat(1,2),	mat(1,3)
805	};
806	const float areaC[2*2] =
807	{
808		mat(2,0),	mat(2,1),
809		mat(3,0),	mat(3,1)
810	};
811	const float areaD[2*2] =
812	{
813		mat(2,2),	mat(2,3),
814		mat(3,2),	mat(3,3)
815	};
816	const float nullField[4] = { 0.0f };
817
818	const tcu::Matrix<float, 2, 2> invA = inverse(Mat2(areaA));
819	const tcu::Matrix<float, 2, 2> matB =         Mat2(areaB);
820	const tcu::Matrix<float, 2, 2> matC =         Mat2(areaC);
821	const tcu::Matrix<float, 2, 2> matD =         Mat2(areaD);
822
823	const tcu::Matrix<float, 2, 2> schurComplement = inverse(matD - matC*invA*matB);
824	const tcu::Matrix<float, 2, 2> zeroMat         = Mat2(nullField);
825
826	const tcu::Matrix<float, 2, 2> blockA = invA + invA*matB*schurComplement*matC*invA;
827	const tcu::Matrix<float, 2, 2> blockB = (zeroMat-invA)*matB*schurComplement;
828	const tcu::Matrix<float, 2, 2> blockC = (zeroMat-schurComplement)*matC*invA;
829	const tcu::Matrix<float, 2, 2> blockD = schurComplement;
830
831	const float result[4*4] =
832	{
833		blockA(0,0),	blockA(0,1),	blockB(0,0),	blockB(0,1),
834		blockA(1,0),	blockA(1,1),	blockB(1,0),	blockB(1,1),
835		blockC(0,0),	blockC(0,1),	blockD(0,0),	blockD(0,1),
836		blockC(1,0),	blockC(1,1),	blockD(1,0),	blockD(1,1),
837	};
838
839	return Mat4(result);
840}
841
842// negate
843
844template <typename T, int Rows, int Cols>
845tcu::Matrix<T, Rows, Cols> negate (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);
852
853	return retVal;
854}
855
856// increment/decrement
857
858template <typename T, int Rows, int Cols>
859tcu::Matrix<T, Rows, Cols> increment (const tcu::Matrix<T, Rows, Cols>& mat)
860{
861	tcu::Matrix<T, Rows, Cols> retVal;
862
863	for (int r = 0; r < Rows; ++r)
864		for (int c = 0; c < Cols; ++c)
865			retVal(r,c) = mat(r, c) + 1.0f;
866
867	return retVal;
868}
869
870template <typename T, int Rows, int Cols>
871tcu::Matrix<T, Rows, Cols> decrement (const tcu::Matrix<T, Rows, Cols>& mat)
872{
873	tcu::Matrix<T, Rows, Cols> retVal;
874
875	for (int r = 0; r < Rows; ++r)
876		for (int c = 0; c < Cols; ++c)
877			retVal(r,c) = mat(r, c) - 1.0f;
878
879	return retVal;
880}
881
882// Evaluator template.
883
884typedef void (*MatrixShaderEvalFunc) (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type);
885
886template <int Op, int In0DataType, int In1DataType>
887struct Evaluator;
888
889template <int In0DataType, int In1DataType>
890struct Evaluator<OP_ADD, In0DataType, In1DataType>
891{
892	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
902template <int In0DataType, int In1DataType>
903struct Evaluator<OP_SUB, In0DataType, In1DataType>
904{
905	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
915template <int In0DataType, int In1DataType>
916struct Evaluator<OP_MUL, In0DataType, In1DataType>
917{
918	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
928template <int In0DataType, int In1DataType>
929struct Evaluator<OP_DIV, In0DataType, In1DataType>
930{
931	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(in0 / in1);
938	}
939};
940
941template <int In0DataType, int In1DataType>
942struct Evaluator<OP_COMP_MUL, In0DataType, In1DataType>
943{
944	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(matrixCompMult(in0, in1));
951	}
952};
953
954template <int In0DataType, int In1DataType>
955struct Evaluator<OP_OUTER_PRODUCT, In0DataType, In1DataType>
956{
957	static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
958	{
959		typename TypeTraits<In0DataType>::Type	in0	= (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
960																				     : getInputValue<INPUTTYPE_CONST,	In0DataType>(evalCtx, 0);
961		typename TypeTraits<In1DataType>::Type	in1	= (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
962																				     : getInputValue<INPUTTYPE_CONST,	In1DataType>(evalCtx, 1);
963		evalCtx.color.xyz() = reduceToVec3(outerProduct(in0, in1));
964	}
965};
966
967template <int In0DataType, int In1DataType>
968struct Evaluator<OP_TRANSPOSE, In0DataType, In1DataType>
969{
970	static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
971	{
972		DE_UNREF(in1Type);
973		typename TypeTraits<In0DataType>::Type	in0	= (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
974																				     : getInputValue<INPUTTYPE_CONST,	In0DataType>(evalCtx, 0);
975		evalCtx.color.xyz() = reduceToVec3(transpose(in0));
976	}
977};
978
979template <int In0DataType, int In1DataType>
980struct Evaluator<OP_INVERSE, In0DataType, In1DataType>
981{
982	static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
983	{
984		DE_UNREF(in1Type);
985		typename TypeTraits<In0DataType>::Type	in0	= (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
986																				     : getInputValue<INPUTTYPE_CONST,	In0DataType>(evalCtx, 0);
987		evalCtx.color.xyz() = reduceToVec3(inverse(in0));
988	}
989};
990
991template <int In0DataType, int In1DataType>
992struct Evaluator<OP_DETERMINANT, In0DataType, In1DataType>
993{
994	static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
995	{
996		DE_UNREF(in1Type);
997		typename TypeTraits<In0DataType>::Type	in0	= (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
998																				     : getInputValue<INPUTTYPE_CONST,	In0DataType>(evalCtx, 0);
999		evalCtx.color.xyz() = Vec3(determinant(in0));
1000	}
1001};
1002
1003template <int In0DataType, int In1DataType>
1004struct Evaluator<OP_UNARY_PLUS, In0DataType, In1DataType>
1005{
1006	static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
1007	{
1008		DE_UNREF(in1Type);
1009		typename TypeTraits<In0DataType>::Type	in0	= (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
1010																				     : getInputValue<INPUTTYPE_CONST,	In0DataType>(evalCtx, 0);
1011		evalCtx.color.xyz() = reduceToVec3(in0);
1012	}
1013};
1014
1015template <int In0DataType, int In1DataType>
1016struct Evaluator<OP_NEGATION, In0DataType, In1DataType>
1017{
1018	static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
1019	{
1020		DE_UNREF(in1Type);
1021		typename TypeTraits<In0DataType>::Type	in0	= (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
1022																				     : getInputValue<INPUTTYPE_CONST,	In0DataType>(evalCtx, 0);
1023		evalCtx.color.xyz() = reduceToVec3(negate(in0));
1024	}
1025};
1026
1027template <int In0DataType, int In1DataType>
1028struct Evaluator<OP_PRE_INCREMENT, In0DataType, In1DataType>
1029{
1030	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(increment(in0)) + reduceToVec3(increment(in0));
1038	}
1039};
1040
1041template <int In0DataType, int In1DataType>
1042struct Evaluator<OP_PRE_DECREMENT, In0DataType, In1DataType>
1043{
1044	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(decrement(in0)) + reduceToVec3(decrement(in0));
1052	}
1053};
1054
1055template <int In0DataType, int In1DataType>
1056struct Evaluator<OP_POST_INCREMENT, In0DataType, In1DataType>
1057{
1058	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(increment(in0));
1066	}
1067};
1068
1069template <int In0DataType, int In1DataType>
1070struct Evaluator<OP_POST_DECREMENT, In0DataType, In1DataType>
1071{
1072	static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
1073	{
1074		DE_UNREF(in1Type);
1075		typename TypeTraits<In0DataType>::Type	in0	= (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
1076																				     : getInputValue<INPUTTYPE_CONST,	In0DataType>(evalCtx, 0);
1077
1078		// modifying reduction: sum modified value too
1079		evalCtx.color.xyz() = reduceToVec3(in0) + reduceToVec3(decrement(in0));
1080	}
1081};
1082
1083template <int In0DataType, int In1DataType>
1084struct Evaluator<OP_ADD_INTO, In0DataType, In1DataType>
1085{
1086	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
1096template <int In0DataType, int In1DataType>
1097struct Evaluator<OP_SUBTRACT_FROM, In0DataType, In1DataType>
1098{
1099	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
1109template <int In0DataType, int In1DataType>
1110struct Evaluator<OP_MULTIPLY_INTO, In0DataType, In1DataType>
1111{
1112	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
1122template <int In0DataType, int In1DataType>
1123struct Evaluator<OP_DIVIDE_INTO, In0DataType, In1DataType>
1124{
1125	static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
1126	{
1127		typename TypeTraits<In0DataType>::Type	in0	= (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
1128																				     : getInputValue<INPUTTYPE_CONST,	In0DataType>(evalCtx, 0);
1129		typename TypeTraits<In1DataType>::Type	in1	= (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
1130																				     : getInputValue<INPUTTYPE_CONST,	In1DataType>(evalCtx, 1);
1131		evalCtx.color.xyz() = reduceToVec3(in0 / in1);
1132	}
1133};
1134
1135MatrixShaderEvalFunc getEvalFunc (const ShaderInput& in0, const ShaderInput& in1, MatrixOp op)
1136{
1137	// Evaluator is selected based on op and input data types.
1138	// For efficient lookup the types and op enums are packed together to form a 19-bit key:
1139	// [18..14 OP] [13..7 TYPE0] [6..0 TYPE1]
1140
1141	DE_STATIC_ASSERT(TYPE_LAST	<= (1<<7));
1142	DE_STATIC_ASSERT(OP_LAST	<= (1<<5));
1143
1144#define PACK_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE)	(((OP) << 14) | ((IN0DATATYPE) << 7) | (IN1DATATYPE))
1145
1146#define MAKE_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE)	\
1147	case PACK_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE):	\
1148		return Evaluator<OP, IN0DATATYPE, IN1DATATYPE>::evaluate
1149
1150#define MAKE_SCALAR_OPS(IN0DATATYPE, IN1DATATYPE)		\
1151	MAKE_EVAL_CASE(OP_ADD, IN0DATATYPE, IN1DATATYPE);	\
1152	MAKE_EVAL_CASE(OP_SUB, IN0DATATYPE, IN1DATATYPE);	\
1153	MAKE_EVAL_CASE(OP_MUL, IN0DATATYPE, IN1DATATYPE);	\
1154	MAKE_EVAL_CASE(OP_DIV, IN0DATATYPE, IN1DATATYPE)
1155
1156#define MAKE_CWISE_OPS(IN0DATATYPE, IN1DATATYPE)			\
1157	MAKE_EVAL_CASE(OP_ADD,		IN0DATATYPE, IN1DATATYPE);	\
1158	MAKE_EVAL_CASE(OP_SUB,		IN0DATATYPE, IN1DATATYPE);	\
1159	MAKE_EVAL_CASE(OP_DIV,		IN0DATATYPE, IN1DATATYPE);	\
1160	MAKE_EVAL_CASE(OP_COMP_MUL,	IN0DATATYPE, IN1DATATYPE)
1161
1162#define MAKE_MUL_OP(IN0DATATYPE, IN1DATATYPE)			\
1163	MAKE_EVAL_CASE(OP_MUL, IN0DATATYPE, IN1DATATYPE)
1164
1165#define MAKE_VECVEC_OP(IN0DATATYPE, IN1DATATYPE)			\
1166	MAKE_EVAL_CASE(OP_OUTER_PRODUCT, IN0DATATYPE, IN1DATATYPE)
1167
1168#define MAKE_UNARY_OP(IN0DATATYPE)								\
1169	MAKE_EVAL_CASE(OP_TRANSPOSE,		IN0DATATYPE, TYPE_LAST);	\
1170	MAKE_EVAL_CASE(OP_UNARY_PLUS,		IN0DATATYPE, TYPE_LAST);	\
1171	MAKE_EVAL_CASE(OP_NEGATION,			IN0DATATYPE, TYPE_LAST);	\
1172	MAKE_EVAL_CASE(OP_PRE_INCREMENT,	IN0DATATYPE, TYPE_LAST);	\
1173	MAKE_EVAL_CASE(OP_PRE_DECREMENT,	IN0DATATYPE, TYPE_LAST);	\
1174	MAKE_EVAL_CASE(OP_POST_INCREMENT,	IN0DATATYPE, TYPE_LAST);	\
1175	MAKE_EVAL_CASE(OP_POST_DECREMENT,	IN0DATATYPE, TYPE_LAST)
1176
1177#define MAKE_UNARY_SYMMETRIC_OP(IN0DATATYPE)					\
1178	MAKE_UNARY_OP(IN0DATATYPE);									\
1179	MAKE_EVAL_CASE(OP_DETERMINANT,	IN0DATATYPE, TYPE_LAST);	\
1180	MAKE_EVAL_CASE(OP_INVERSE,		IN0DATATYPE, TYPE_LAST)
1181
1182#define MAKE_ASSIGNMENT_OP(IN0DATATYPE)								\
1183	MAKE_EVAL_CASE(OP_ADD_INTO,			IN0DATATYPE, IN0DATATYPE);	\
1184	MAKE_EVAL_CASE(OP_SUBTRACT_FROM,	IN0DATATYPE, IN0DATATYPE);	\
1185	MAKE_EVAL_CASE(OP_DIVIDE_INTO,		IN0DATATYPE, IN0DATATYPE)
1186
1187#define MAKE_ASSIGNMENT_SYMMETRIC_OP(IN0DATATYPE)					\
1188	MAKE_ASSIGNMENT_OP(IN0DATATYPE);								\
1189	MAKE_EVAL_CASE(OP_MULTIPLY_INTO,	IN0DATATYPE, IN0DATATYPE)
1190
1191	switch (PACK_EVAL_CASE(op, in0.dataType, in1.dataType))
1192	{
1193		// Matrix-scalar.
1194		MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2,	TYPE_FLOAT);
1195		MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2X3,	TYPE_FLOAT);
1196		MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2X4,	TYPE_FLOAT);
1197		MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3X2,	TYPE_FLOAT);
1198		MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3,	TYPE_FLOAT);
1199		MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3X4,	TYPE_FLOAT);
1200		MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4X2,	TYPE_FLOAT);
1201		MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4X3,	TYPE_FLOAT);
1202		MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4,	TYPE_FLOAT);
1203
1204		// Matrix-vector.
1205		MAKE_MUL_OP(TYPE_FLOAT_MAT2,	TYPE_FLOAT_VEC2);
1206		MAKE_MUL_OP(TYPE_FLOAT_MAT2X3,	TYPE_FLOAT_VEC2);
1207		MAKE_MUL_OP(TYPE_FLOAT_MAT2X4,	TYPE_FLOAT_VEC2);
1208		MAKE_MUL_OP(TYPE_FLOAT_MAT3X2,	TYPE_FLOAT_VEC3);
1209		MAKE_MUL_OP(TYPE_FLOAT_MAT3,	TYPE_FLOAT_VEC3);
1210		MAKE_MUL_OP(TYPE_FLOAT_MAT3X4,	TYPE_FLOAT_VEC3);
1211		MAKE_MUL_OP(TYPE_FLOAT_MAT4X2,	TYPE_FLOAT_VEC4);
1212		MAKE_MUL_OP(TYPE_FLOAT_MAT4X3,	TYPE_FLOAT_VEC4);
1213		MAKE_MUL_OP(TYPE_FLOAT_MAT4,	TYPE_FLOAT_VEC4);
1214
1215		// Vector-matrix.
1216		MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT2);
1217		MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT2X3);
1218		MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT2X4);
1219		MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT3X2);
1220		MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT3);
1221		MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT3X4);
1222		MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT4X2);
1223		MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT4X3);
1224		MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT4);
1225
1226		// Matrix-matrix.
1227		MAKE_CWISE_OPS(TYPE_FLOAT_MAT2,		TYPE_FLOAT_MAT2);
1228		MAKE_MUL_OP(TYPE_FLOAT_MAT2,		TYPE_FLOAT_MAT2);
1229		MAKE_MUL_OP(TYPE_FLOAT_MAT2,		TYPE_FLOAT_MAT3X2);
1230		MAKE_MUL_OP(TYPE_FLOAT_MAT2,		TYPE_FLOAT_MAT4X2);
1231
1232		MAKE_CWISE_OPS(TYPE_FLOAT_MAT2X3,	TYPE_FLOAT_MAT2X3);
1233		MAKE_MUL_OP(TYPE_FLOAT_MAT2X3,		TYPE_FLOAT_MAT2);
1234		MAKE_MUL_OP(TYPE_FLOAT_MAT2X3,		TYPE_FLOAT_MAT3X2);
1235		MAKE_MUL_OP(TYPE_FLOAT_MAT2X3,		TYPE_FLOAT_MAT4X2);
1236
1237		MAKE_CWISE_OPS(TYPE_FLOAT_MAT2X4,	TYPE_FLOAT_MAT2X4);
1238		MAKE_MUL_OP(TYPE_FLOAT_MAT2X4,		TYPE_FLOAT_MAT2);
1239		MAKE_MUL_OP(TYPE_FLOAT_MAT2X4,		TYPE_FLOAT_MAT3X2);
1240		MAKE_MUL_OP(TYPE_FLOAT_MAT2X4,		TYPE_FLOAT_MAT4X2);
1241
1242		MAKE_CWISE_OPS(TYPE_FLOAT_MAT3X2,	TYPE_FLOAT_MAT3X2);
1243		MAKE_MUL_OP(TYPE_FLOAT_MAT3X2,		TYPE_FLOAT_MAT2X3);
1244		MAKE_MUL_OP(TYPE_FLOAT_MAT3X2,		TYPE_FLOAT_MAT3);
1245		MAKE_MUL_OP(TYPE_FLOAT_MAT3X2,		TYPE_FLOAT_MAT4X3);
1246
1247		MAKE_CWISE_OPS(TYPE_FLOAT_MAT3,		TYPE_FLOAT_MAT3);
1248		MAKE_MUL_OP(TYPE_FLOAT_MAT3,		TYPE_FLOAT_MAT2X3);
1249		MAKE_MUL_OP(TYPE_FLOAT_MAT3,		TYPE_FLOAT_MAT3);
1250		MAKE_MUL_OP(TYPE_FLOAT_MAT3,		TYPE_FLOAT_MAT4X3);
1251
1252		MAKE_CWISE_OPS(TYPE_FLOAT_MAT3X4,	TYPE_FLOAT_MAT3X4);
1253		MAKE_MUL_OP(TYPE_FLOAT_MAT3X4,		TYPE_FLOAT_MAT2X3);
1254		MAKE_MUL_OP(TYPE_FLOAT_MAT3X4,		TYPE_FLOAT_MAT3);
1255		MAKE_MUL_OP(TYPE_FLOAT_MAT3X4,		TYPE_FLOAT_MAT4X3);
1256
1257		MAKE_CWISE_OPS(TYPE_FLOAT_MAT4X2,	TYPE_FLOAT_MAT4X2);
1258		MAKE_MUL_OP(TYPE_FLOAT_MAT4X2,		TYPE_FLOAT_MAT2X4);
1259		MAKE_MUL_OP(TYPE_FLOAT_MAT4X2,		TYPE_FLOAT_MAT3X4);
1260		MAKE_MUL_OP(TYPE_FLOAT_MAT4X2,		TYPE_FLOAT_MAT4);
1261
1262		MAKE_CWISE_OPS(TYPE_FLOAT_MAT4X3,	TYPE_FLOAT_MAT4X3);
1263		MAKE_MUL_OP(TYPE_FLOAT_MAT4X3,		TYPE_FLOAT_MAT2X4);
1264		MAKE_MUL_OP(TYPE_FLOAT_MAT4X3,		TYPE_FLOAT_MAT3X4);
1265		MAKE_MUL_OP(TYPE_FLOAT_MAT4X3,		TYPE_FLOAT_MAT4);
1266
1267		MAKE_CWISE_OPS(TYPE_FLOAT_MAT4,		TYPE_FLOAT_MAT4);
1268		MAKE_MUL_OP(TYPE_FLOAT_MAT4,		TYPE_FLOAT_MAT2X4);
1269		MAKE_MUL_OP(TYPE_FLOAT_MAT4,		TYPE_FLOAT_MAT3X4);
1270		MAKE_MUL_OP(TYPE_FLOAT_MAT4,		TYPE_FLOAT_MAT4);
1271
1272		// Vector-vector.
1273		MAKE_VECVEC_OP(TYPE_FLOAT_VEC2,		TYPE_FLOAT_VEC2);
1274		MAKE_VECVEC_OP(TYPE_FLOAT_VEC2,		TYPE_FLOAT_VEC3);
1275		MAKE_VECVEC_OP(TYPE_FLOAT_VEC2,		TYPE_FLOAT_VEC4);
1276		MAKE_VECVEC_OP(TYPE_FLOAT_VEC3,		TYPE_FLOAT_VEC2);
1277		MAKE_VECVEC_OP(TYPE_FLOAT_VEC3,		TYPE_FLOAT_VEC3);
1278		MAKE_VECVEC_OP(TYPE_FLOAT_VEC3,		TYPE_FLOAT_VEC4);
1279		MAKE_VECVEC_OP(TYPE_FLOAT_VEC4,		TYPE_FLOAT_VEC2);
1280		MAKE_VECVEC_OP(TYPE_FLOAT_VEC4,		TYPE_FLOAT_VEC3);
1281		MAKE_VECVEC_OP(TYPE_FLOAT_VEC4,		TYPE_FLOAT_VEC4);
1282
1283		// Unary Matrix.
1284		MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT2);
1285		MAKE_UNARY_OP(TYPE_FLOAT_MAT2X3);
1286		MAKE_UNARY_OP(TYPE_FLOAT_MAT2X4);
1287		MAKE_UNARY_OP(TYPE_FLOAT_MAT3X2);
1288		MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT3);
1289		MAKE_UNARY_OP(TYPE_FLOAT_MAT3X4);
1290		MAKE_UNARY_OP(TYPE_FLOAT_MAT4X2);
1291		MAKE_UNARY_OP(TYPE_FLOAT_MAT4X3);
1292		MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT4);
1293
1294		// Assignments
1295		MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT2);
1296		MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT2X3);
1297		MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT2X4);
1298		MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT3X2);
1299		MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT3);
1300		MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT3X4);
1301		MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT4X2);
1302		MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT4X3);
1303		MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT4);
1304
1305		default:
1306			DE_ASSERT(DE_FALSE);
1307			return DE_NULL;
1308	}
1309
1310#undef PACK_EVAL_CASE
1311#undef MAKE_EVAL_CASE
1312#undef MUL_OP
1313#undef ALL_OPS
1314#undef MAKE_MAT_SCALAR_VEC_CASES
1315#undef MAKE_MAT_MAT_CASES
1316}
1317
1318// Shader source format utilities.
1319
1320template <int Size>
1321void writeVectorConstructor (std::ostream& str, const tcu::Vector<float, Size>& v)
1322{
1323	str << "vec" << Size << "(";
1324	for (int ndx = 0; ndx < Size; ndx++)
1325	{
1326		if (ndx != 0)
1327			str << ", ";
1328		str << de::floatToString(v[ndx], 1);
1329	}
1330	str << ")";
1331}
1332
1333template <int Cols, int Rows>
1334void writeMatrixConstructor (std::ostream& str, const tcu::Matrix<float, Rows, Cols>& m)
1335{
1336	if (Rows == Cols)
1337		str << "mat" << Cols;
1338	else
1339		str << "mat" << Cols << "x" << Rows;
1340
1341	str << "(";
1342	for (int colNdx = 0; colNdx < Cols; colNdx++)
1343	{
1344		for (int rowNdx = 0; rowNdx < Rows; rowNdx++)
1345		{
1346			if (rowNdx > 0 || colNdx > 0)
1347				str << ", ";
1348			str << de::floatToString(m(rowNdx, colNdx), 1);
1349		}
1350	}
1351	str << ")";
1352}
1353
1354} // MatrixCaseUtils
1355
1356using namespace MatrixCaseUtils;
1357
1358class MatrixShaderEvaluator : public ShaderEvaluator
1359{
1360public:
1361							MatrixShaderEvaluator	(MatrixShaderEvalFunc evalFunc, InputType inType0, InputType inType1);
1362
1363	virtual void			evaluate				(ShaderEvalContext& evalCtx);
1364
1365private:
1366	MatrixShaderEvalFunc	m_matEvalFunc;
1367	InputType				m_inType0;
1368	InputType				m_inType1;
1369};
1370
1371MatrixShaderEvaluator::MatrixShaderEvaluator (MatrixShaderEvalFunc evalFunc, InputType inType0, InputType inType1)
1372	: m_matEvalFunc	(evalFunc)
1373	, m_inType0		(inType0)
1374	, m_inType1		(inType1)
1375{
1376}
1377
1378void MatrixShaderEvaluator::evaluate (ShaderEvalContext& evalCtx)
1379{
1380	m_matEvalFunc(evalCtx, m_inType0, m_inType1);
1381}
1382
1383class ShaderMatrixCase : public ShaderRenderCase
1384{
1385public:
1386							ShaderMatrixCase			(Context& context, const char* name, const char* desc, const ShaderInput& in0, const ShaderInput& in1, MatrixOp op, bool isVertexCase);
1387							~ShaderMatrixCase			(void);
1388
1389	void					init						(void);
1390
1391protected:
1392	std::string				genGLSLMatToVec3Reduction	(const glu::DataType& matType, const char* varName);
1393	void					setupUniforms				(int programID, const tcu::Vec4& constCoords);
1394
1395private:
1396	ShaderInput				m_in0;
1397	ShaderInput				m_in1;
1398	MatrixOp				m_op;
1399	MatrixShaderEvaluator	m_matEvaluator;
1400};
1401
1402ShaderMatrixCase::ShaderMatrixCase (Context& context, const char* name, const char* desc, const ShaderInput& in0, const ShaderInput& in1, MatrixOp op, bool isVertexCase)
1403	: ShaderRenderCase	(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, m_matEvaluator)
1404	, m_in0				(in0)
1405	, m_in1				(in1)
1406	, m_op				(op)
1407	, m_matEvaluator	(getEvalFunc(in0, in1, op), in0.inputType, in1.inputType)
1408{
1409}
1410
1411ShaderMatrixCase::~ShaderMatrixCase (void)
1412{
1413}
1414
1415void ShaderMatrixCase::init (void)
1416{
1417	std::ostringstream	vtx;
1418	std::ostringstream	frag;
1419	std::ostringstream&	op				= m_isVertexCase ? vtx : frag;
1420
1421	bool				isInDynMat0		= isDataTypeMatrix(m_in0.dataType) && m_in0.inputType == INPUTTYPE_DYNAMIC;
1422	bool				isInDynMat1		= isDataTypeMatrix(m_in1.dataType) && m_in1.inputType == INPUTTYPE_DYNAMIC;
1423	string				inValue0;
1424	string				inValue1;
1425	DataType			resultType		= TYPE_LAST;
1426	Precision			resultPrec		= m_in0.precision;
1427	vector<string>		passVars;
1428	int					numInputs		= (isOperationBinary(m_op)) ? (2) : (1);
1429
1430	std::string			operationValue0;
1431	std::string			operationValue1;
1432
1433	DE_ASSERT(!isInDynMat0 || !isInDynMat1); // Only single dynamic matrix input is allowed.
1434	DE_UNREF(isInDynMat0 && isInDynMat1);
1435
1436	// Compute result type.
1437	if (m_op == OP_MUL && isDataTypeMatrix(m_in0.dataType) && isDataTypeMatrix(m_in1.dataType))
1438	{
1439		resultType = getDataTypeMatrix(getDataTypeMatrixNumColumns(m_in1.dataType), getDataTypeMatrixNumRows(m_in0.dataType));
1440	}
1441	else if (m_op == OP_OUTER_PRODUCT)
1442	{
1443		resultType = getDataTypeMatrix(getDataTypeScalarSize(m_in1.dataType), getDataTypeScalarSize(m_in0.dataType));
1444	}
1445	else if (m_op == OP_TRANSPOSE)
1446	{
1447		resultType = getDataTypeMatrix(getDataTypeMatrixNumRows(m_in0.dataType), getDataTypeMatrixNumColumns(m_in0.dataType));
1448	}
1449	else if (m_op == OP_INVERSE)
1450	{
1451		resultType = m_in0.dataType;
1452	}
1453	else if (m_op == OP_DETERMINANT)
1454	{
1455		resultType = TYPE_FLOAT;
1456	}
1457	else if (getOperationType(m_op) == OPERATIONTYPE_UNARY_PREFIX_OPERATOR ||
1458			 getOperationType(m_op) == OPERATIONTYPE_UNARY_POSTFIX_OPERATOR)
1459	{
1460		resultType = m_in0.dataType;
1461	}
1462	else if (isDataTypeMatrix(m_in0.dataType) && isDataTypeMatrix(m_in1.dataType))
1463	{
1464		DE_ASSERT(m_in0.dataType == m_in1.dataType);
1465		resultType = m_in0.dataType;
1466	}
1467	else if (isDataTypeMatrix(m_in0.dataType) || isDataTypeMatrix(m_in1.dataType))
1468	{
1469		int			matNdx		= isDataTypeMatrix(m_in0.dataType) ? 0 : 1;
1470		DataType	matrixType	= matNdx == 0 ? m_in0.dataType : m_in1.dataType;
1471		DataType	otherType	= matNdx == 0 ? m_in1.dataType : m_in0.dataType;
1472
1473		if (otherType == TYPE_FLOAT)
1474			resultType = matrixType;
1475		else
1476		{
1477			DE_ASSERT(isDataTypeVector(otherType));
1478			resultType = getDataTypeFloatVec(matNdx == 0 ? getDataTypeMatrixNumRows(matrixType) : getDataTypeMatrixNumColumns(matrixType));
1479		}
1480	}
1481	else
1482	{
1483		DE_ASSERT(DE_FALSE);
1484	}
1485
1486	vtx << "#version 300 es\n";
1487	frag << "#version 300 es\n";
1488
1489	vtx << "in highp vec4 a_position;\n";
1490	frag << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1491	if (m_isVertexCase)
1492	{
1493		vtx << "out mediump vec4 v_color;\n";
1494		frag << "in mediump vec4 v_color;\n";
1495	}
1496
1497	// Input declarations.
1498	for (int inNdx = 0; inNdx < numInputs; inNdx++)
1499	{
1500		const ShaderInput&	in			= inNdx > 0 ? m_in1 : m_in0;
1501		const char*			precName	= getPrecisionName(in.precision);
1502		const char*			typeName	= getDataTypeName(in.dataType);
1503		string&				inValue		= inNdx > 0 ? inValue1 : inValue0;
1504
1505		if (in.inputType == INPUTTYPE_DYNAMIC)
1506		{
1507			vtx << "in " << precName << " " << typeName << " a_";
1508
1509			if (isDataTypeMatrix(in.dataType))
1510			{
1511				// a_matN, v_matN
1512				vtx << typeName << ";\n";
1513				if (!m_isVertexCase)
1514				{
1515					vtx << "out " << precName << " " << typeName << " v_" << typeName << ";\n";
1516					frag << "in " << precName << " " << typeName << " v_" << typeName << ";\n";
1517					passVars.push_back(typeName);
1518				}
1519
1520				inValue = string(m_isVertexCase ? "a_" : "v_") + getDataTypeName(in.dataType);
1521			}
1522			else
1523			{
1524				// a_coords, v_coords
1525				vtx << "coords;\n";
1526				if (!m_isVertexCase)
1527				{
1528					vtx << "out " << precName << " " << typeName << " v_coords;\n";
1529					frag << "in " << precName << " " << typeName << " v_coords;\n";
1530					passVars.push_back("coords");
1531				}
1532
1533				inValue = m_isVertexCase ? "a_coords" : "v_coords";
1534			}
1535		}
1536		else if (in.inputType == INPUTTYPE_UNIFORM)
1537		{
1538			op << "uniform " << precName << " " << typeName << " u_in" << inNdx << ";\n";
1539			inValue = string("u_in") + de::toString(inNdx);
1540		}
1541		else if (in.inputType == INPUTTYPE_CONST)
1542		{
1543			op << "const " << precName << " " << typeName << " in" << inNdx << " = ";
1544
1545			// Generate declaration.
1546			switch (in.dataType)
1547			{
1548				case TYPE_FLOAT:		op << de::floatToString(s_constInFloat[inNdx], 1);					break;
1549				case TYPE_FLOAT_VEC2:	writeVectorConstructor<2>(op, s_constInVec2[inNdx]);				break;
1550				case TYPE_FLOAT_VEC3:	writeVectorConstructor<3>(op, s_constInVec3[inNdx]);				break;
1551				case TYPE_FLOAT_VEC4:	writeVectorConstructor<4>(op, s_constInVec4[inNdx]);				break;
1552				case TYPE_FLOAT_MAT2:	writeMatrixConstructor<2, 2>(op, Mat2(s_constInMat2x2[inNdx]));		break;
1553				case TYPE_FLOAT_MAT2X3:	writeMatrixConstructor<2, 3>(op, Mat2x3(s_constInMat2x3[inNdx]));	break;
1554				case TYPE_FLOAT_MAT2X4:	writeMatrixConstructor<2, 4>(op, Mat2x4(s_constInMat2x4[inNdx]));	break;
1555				case TYPE_FLOAT_MAT3X2:	writeMatrixConstructor<3, 2>(op, Mat3x2(s_constInMat3x2[inNdx]));	break;
1556				case TYPE_FLOAT_MAT3:	writeMatrixConstructor<3, 3>(op, Mat3(s_constInMat3x3[inNdx]));		break;
1557				case TYPE_FLOAT_MAT3X4:	writeMatrixConstructor<3, 4>(op, Mat3x4(s_constInMat3x4[inNdx]));	break;
1558				case TYPE_FLOAT_MAT4X2:	writeMatrixConstructor<4, 2>(op, Mat4x2(s_constInMat4x2[inNdx]));	break;
1559				case TYPE_FLOAT_MAT4X3:	writeMatrixConstructor<4, 3>(op, Mat4x3(s_constInMat4x3[inNdx]));	break;
1560				case TYPE_FLOAT_MAT4:	writeMatrixConstructor<4, 4>(op, Mat4(s_constInMat4x4[inNdx]));		break;
1561
1562				default:
1563					DE_ASSERT(DE_FALSE);
1564			}
1565
1566			op << ";\n";
1567
1568			inValue = string("in") + de::toString(inNdx);
1569		}
1570	}
1571
1572	vtx << "\n"
1573		<< "void main (void)\n"
1574		<< "{\n"
1575		<< "	gl_Position = a_position;\n";
1576	frag << "\n"
1577		 << "void main (void)\n"
1578		 << "{\n";
1579
1580	if (m_isVertexCase)
1581		frag << "	dEQP_FragColor = v_color;\n";
1582	else
1583	{
1584		for (vector<string>::const_iterator copyIter = passVars.begin(); copyIter != passVars.end(); copyIter++)
1585			vtx << "	v_" << *copyIter << " = " << "a_" << *copyIter << ";\n";
1586	}
1587
1588	// Operation.
1589
1590	switch (getOperationNature(m_op))
1591	{
1592		case OPERATIONNATURE_PURE:
1593			DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
1594
1595			operationValue0 = inValue0;
1596			operationValue1 = inValue1;
1597			break;
1598
1599		case OPERATIONNATURE_MUTATING:
1600			DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
1601
1602			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " tmpValue = " << inValue0 << ";\n";
1603
1604			operationValue0 = "tmpValue";
1605			operationValue1 = inValue1;
1606			break;
1607
1608		case OPERATIONNATURE_ASSIGNMENT:
1609			DE_ASSERT(getOperationType(m_op) == OPERATIONTYPE_ASSIGNMENT);
1610
1611			operationValue0 = inValue0;
1612			operationValue1 = inValue1;
1613			break;
1614
1615		default:
1616			DE_ASSERT(DE_FALSE);
1617	}
1618
1619	switch (getOperationType(m_op))
1620	{
1621		case OPERATIONTYPE_BINARY_OPERATOR:
1622			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << " " << getOperationName(m_op) << " " << operationValue1 << ";\n";
1623			break;
1624
1625		case OPERATIONTYPE_UNARY_PREFIX_OPERATOR:
1626			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << operationValue0 << ";\n";
1627			break;
1628
1629		case OPERATIONTYPE_UNARY_POSTFIX_OPERATOR:
1630			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << getOperationName(m_op) << ";\n";
1631			break;
1632
1633		case OPERATIONTYPE_BINARY_FUNCTION:
1634			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << "(" << operationValue0 << ", " << operationValue1 << ");\n";
1635			break;
1636
1637		case OPERATIONTYPE_UNARY_FUNCTION:
1638			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << "(" << operationValue0 << ");\n";
1639			break;
1640
1641		case OPERATIONTYPE_ASSIGNMENT:
1642			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << ";\n";
1643			op << "	res " << getOperationName(m_op) << " " << operationValue1 << ";\n";
1644			break;
1645
1646		default:
1647			DE_ASSERT(DE_FALSE);
1648	}
1649
1650	// Reduction to vec3 (rgb). Check the used value too if it was modified
1651	op << "	" << (m_isVertexCase ? "v_color" : "dEQP_FragColor") << " = ";
1652
1653	if (isOperationValueModifying(m_op))
1654		op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0) + vec4(" << genGLSLMatToVec3Reduction(resultType, "tmpValue") << ", 0.0);\n";
1655	else
1656		op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0);\n";
1657
1658	vtx << "}\n";
1659	frag << "}\n";
1660
1661	m_vertShaderSource	= vtx.str();
1662	m_fragShaderSource	= frag.str();
1663
1664	// \todo [2012-02-14 pyry] Compute better values for matrix tests.
1665	m_userAttribTransforms.resize(4);
1666	for (int attribNdx = 0; attribNdx < 4; attribNdx++)
1667	{
1668		m_userAttribTransforms[attribNdx] = Mat4(0.0f);
1669		m_userAttribTransforms[attribNdx](                  0, 3) = 0.2f;						// !< prevent matrix*vec from going into zero (assuming vec.w != 0)
1670		m_userAttribTransforms[attribNdx](                  1, 3) = 0.1f;						// !<
1671		m_userAttribTransforms[attribNdx](                  2, 3) = 0.4f + 0.15f * attribNdx;	// !<
1672		m_userAttribTransforms[attribNdx](                  3, 3) = 0.7f;						// !<
1673		m_userAttribTransforms[attribNdx]((0 + attribNdx) % 4, 0) = 1.0f;
1674		m_userAttribTransforms[attribNdx]((1 + attribNdx) % 4, 1) = 1.0f;
1675		m_userAttribTransforms[attribNdx]((2 + attribNdx) % 4, 2) = 1.0f;
1676		m_userAttribTransforms[attribNdx]((3 + attribNdx) % 4, 3) = 1.0f;
1677	}
1678
1679	// prevent bad reference cases such as black result images by fine-tuning used matrices
1680	if (getOperationTestMatrixType(m_op) != TESTMATRIXTYPE_DEFAULT)
1681	{
1682		for (int attribNdx = 0; attribNdx < 4; attribNdx++)
1683		{
1684			for (int row = 0; row < 4; row++)
1685			for (int col = 0; col < 4; col++)
1686			{
1687				switch (getOperationTestMatrixType(m_op))
1688				{
1689					case TESTMATRIXTYPE_NEGATED:
1690						m_userAttribTransforms[attribNdx](row, col) = -m_userAttribTransforms[attribNdx](row, col);
1691						break;
1692					case TESTMATRIXTYPE_INCREMENTED:
1693						m_userAttribTransforms[attribNdx](row, col) += 0.3f;
1694						break;
1695					case TESTMATRIXTYPE_DECREMENTED:
1696						m_userAttribTransforms[attribNdx](row, col) -= 0.3f;
1697						break;
1698					case TESTMATRIXTYPE_NEGATED_INCREMENTED:
1699						m_userAttribTransforms[attribNdx](row, col) = -m_userAttribTransforms[attribNdx](row, col) + 0.3f;
1700						break;
1701					case TESTMATRIXTYPE_INCREMENTED_LESS:
1702						m_userAttribTransforms[attribNdx](row, col) -= 0.1f;
1703						break;
1704
1705					default:
1706						DE_ASSERT(DE_FALSE);
1707						break;
1708				}
1709			}
1710		}
1711	}
1712
1713	ShaderRenderCase::init();
1714}
1715
1716std::string ShaderMatrixCase::genGLSLMatToVec3Reduction (const glu::DataType& matType, const char* varName)
1717{
1718	std::ostringstream op;
1719
1720	switch (matType)
1721	{
1722		case TYPE_FLOAT:		op << varName << ", "			<< varName << ", "			<< varName << "";																																			break;
1723		case TYPE_FLOAT_VEC2:	op << varName << ".x, "			<< varName << ".y, "		<< varName << ".x";																																			break;
1724		case TYPE_FLOAT_VEC3:	op << varName << "";																																																	break;
1725		case TYPE_FLOAT_VEC4:	op << varName << ".x, "			<< varName << ".y, "		<< varName << ".z+"			<< varName << ".w";																												break;
1726		case TYPE_FLOAT_MAT2:	op << varName << "[0][0], "		<< varName << "[1][0], "	<< varName << "[0][1]+"		<< varName << "[1][1]";																											break;
1727		case TYPE_FLOAT_MAT2X3:	op << varName << "[0] + "		<< varName << "[1]";																																									break;
1728		case TYPE_FLOAT_MAT2X4:	op << varName << "[0].xyz + "	<< varName << "[1].yzw";																																								break;
1729		case TYPE_FLOAT_MAT3X2:	op << varName << "[0][0]+"		<< varName << "[0][1], "	<< varName << "[1][0]+"		<< varName << "[1][1], "	<< varName << "[2][0]+" << varName << "[2][1]";														break;
1730		case TYPE_FLOAT_MAT3:	op << varName << "[0] + "		<< varName << "[1] + "		<< varName << "[2]";																																		break;
1731		case TYPE_FLOAT_MAT3X4:	op << varName << "[0].xyz + "	<< varName << "[1].yzw + "	<< varName << "[2].zwx";																																	break;
1732		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;
1733		case TYPE_FLOAT_MAT4X3:	op << varName << "[0] + "		<< varName << "[1] + "		<< varName << "[2] + "		<< varName << "[3]";																											break;
1734		case TYPE_FLOAT_MAT4:	op << varName << "[0].xyz+"		<< varName << "[1].yzw+"	<< varName << "[2].zwx+"	<< varName << "[3].wxy";																										break;
1735
1736		default:
1737			DE_ASSERT(DE_FALSE);
1738	}
1739
1740	return op.str();
1741}
1742
1743void ShaderMatrixCase::setupUniforms (int programID, const tcu::Vec4& constCoords)
1744{
1745	const glw::Functions& gl = m_renderCtx.getFunctions();
1746
1747	DE_UNREF(constCoords);
1748
1749	for (int inNdx = 0; inNdx < 2; inNdx++)
1750	{
1751		const ShaderInput& in = inNdx > 0 ? m_in1 : m_in0;
1752
1753		if (in.inputType == INPUTTYPE_UNIFORM)
1754		{
1755			int loc = gl.getUniformLocation(programID, (string("u_in") + de::toString(inNdx)).c_str());
1756
1757			if (loc < 0)
1758				continue;
1759
1760			switch (in.dataType)
1761			{
1762				case TYPE_FLOAT:		gl.uniform1f(loc, s_constInFloat[inNdx]);						break;
1763				case TYPE_FLOAT_VEC2:	gl.uniform2fv(loc, 1, s_constInVec2[inNdx].getPtr());			break;
1764				case TYPE_FLOAT_VEC3:	gl.uniform3fv(loc, 1, s_constInVec3[inNdx].getPtr());			break;
1765				case TYPE_FLOAT_VEC4:	gl.uniform4fv(loc, 1, s_constInVec4[inNdx].getPtr());			break;
1766				// \note GLES3 supports transpose in matrix upload.
1767				case TYPE_FLOAT_MAT2:	gl.uniformMatrix2fv	(loc, 1, GL_TRUE, s_constInMat2x2[inNdx]);	break;
1768				case TYPE_FLOAT_MAT2X3:	gl.uniformMatrix2x3fv(loc, 1, GL_TRUE, s_constInMat2x3[inNdx]);	break;
1769				case TYPE_FLOAT_MAT2X4:	gl.uniformMatrix2x4fv(loc, 1, GL_TRUE, s_constInMat2x4[inNdx]);	break;
1770				case TYPE_FLOAT_MAT3X2:	gl.uniformMatrix3x2fv(loc, 1, GL_TRUE, s_constInMat3x2[inNdx]);	break;
1771				case TYPE_FLOAT_MAT3:	gl.uniformMatrix3fv	(loc, 1, GL_TRUE, s_constInMat3x3[inNdx]);	break;
1772				case TYPE_FLOAT_MAT3X4:	gl.uniformMatrix3x4fv(loc, 1, GL_TRUE, s_constInMat3x4[inNdx]);	break;
1773				case TYPE_FLOAT_MAT4X2:	gl.uniformMatrix4x2fv(loc, 1, GL_TRUE, s_constInMat4x2[inNdx]);	break;
1774				case TYPE_FLOAT_MAT4X3:	gl.uniformMatrix4x3fv(loc, 1, GL_TRUE, s_constInMat4x3[inNdx]);	break;
1775				case TYPE_FLOAT_MAT4:	gl.uniformMatrix4fv	(loc, 1, GL_TRUE, s_constInMat4x4[inNdx]);	break;
1776				default:
1777					DE_ASSERT(false);
1778			}
1779		}
1780	}
1781}
1782
1783ShaderMatrixTests::ShaderMatrixTests (Context& context)
1784	: TestCaseGroup(context, "matrix", "Matrix Tests")
1785{
1786}
1787
1788ShaderMatrixTests::~ShaderMatrixTests (void)
1789{
1790}
1791
1792void ShaderMatrixTests::init (void)
1793{
1794	static const struct
1795	{
1796		const char*		name;
1797		const char*		desc;
1798		MatrixOp		op;
1799		bool			extendedInputTypeCases; // !< test with const and uniform types too
1800		bool			createInputTypeGroup;	// !< create group for input types
1801	} ops[] =
1802	{
1803		{ "add",			"Matrix addition tests",						OP_ADD,				true,	true	},
1804		{ "sub",			"Matrix subtraction tests",						OP_SUB,				true,	true	},
1805		{ "mul",			"Matrix multiplication tests",					OP_MUL,				true,	true	},
1806		{ "div",			"Matrix division tests",						OP_DIV,				true,	true	},
1807		{ "matrixcompmult",	"Matrix component-wise multiplication tests",	OP_COMP_MUL,		false,	true	},
1808		{ "outerproduct",	"Matrix outerProduct() tests",					OP_OUTER_PRODUCT,	false,	true	},
1809		{ "transpose",		"Matrix transpose() tests",						OP_TRANSPOSE,		false,	true	},
1810		{ "determinant",	"Matrix determinant() tests",					OP_DETERMINANT,		false,	true	},
1811		{ "inverse",		"Matrix inverse() tests",						OP_INVERSE,			false,	true	},
1812		{ "unary_addition",	"Matrix unary addition tests",					OP_UNARY_PLUS,		false,	false	},
1813		{ "negation",		"Matrix negation tests",						OP_NEGATION,		false,	false	},
1814		{ "pre_increment",	"Matrix prefix increment tests",				OP_PRE_INCREMENT,	false,	false	},
1815		{ "pre_decrement",	"Matrix prefix decrement tests",				OP_PRE_DECREMENT,	false,	false	},
1816		{ "post_increment",	"Matrix postfix increment tests",				OP_POST_INCREMENT,	false,	false	},
1817		{ "post_decrement",	"Matrix postfix decrement tests",				OP_POST_DECREMENT,	false,	false	},
1818		{ "add_assign",		"Matrix add into tests",						OP_ADD_INTO,		false,	false	},
1819		{ "sub_assign",		"Matrix subtract from tests",					OP_SUBTRACT_FROM,	false,	false	},
1820		{ "mul_assign",		"Matrix multiply into tests",					OP_MULTIPLY_INTO,	false,	false	},
1821		{ "div_assign",		"Matrix divide into tests",						OP_DIVIDE_INTO,		false,	false	},
1822	};
1823
1824	struct InputTypeSpec
1825	{
1826		const char*		name;
1827		const char*		desc;
1828		InputType		type;
1829	};
1830	static const InputTypeSpec extendedInputTypes[] =
1831	{
1832		{ "const",		"Constant matrix input",	INPUTTYPE_CONST		},
1833		{ "uniform",	"Uniform matrix input",		INPUTTYPE_UNIFORM	},
1834		{ "dynamic",	"Dynamic matrix input",		INPUTTYPE_DYNAMIC	}
1835	};
1836	static const InputTypeSpec reducedInputTypes[] =
1837	{
1838		{ "dynamic",	"Dynamic matrix input",		INPUTTYPE_DYNAMIC	}
1839	};
1840
1841	static const DataType matrixTypes[] =
1842	{
1843		TYPE_FLOAT_MAT2,
1844		TYPE_FLOAT_MAT2X3,
1845		TYPE_FLOAT_MAT2X4,
1846		TYPE_FLOAT_MAT3X2,
1847		TYPE_FLOAT_MAT3,
1848		TYPE_FLOAT_MAT3X4,
1849		TYPE_FLOAT_MAT4X2,
1850		TYPE_FLOAT_MAT4X3,
1851		TYPE_FLOAT_MAT4
1852	};
1853
1854	static const Precision precisions[] =
1855	{
1856		PRECISION_LOWP,
1857		PRECISION_MEDIUMP,
1858		PRECISION_HIGHP
1859	};
1860
1861	for (int opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
1862	{
1863		const InputTypeSpec*	inTypeList		= (ops[opNdx].extendedInputTypeCases) ? (extendedInputTypes) : (reducedInputTypes);
1864		const int				inTypeListSize	= (ops[opNdx].extendedInputTypeCases) ? (DE_LENGTH_OF_ARRAY(extendedInputTypes)) : (DE_LENGTH_OF_ARRAY(reducedInputTypes));
1865		const MatrixOp			op				= ops[opNdx].op;
1866		tcu::TestCaseGroup*		opGroup			= new tcu::TestCaseGroup(m_testCtx, ops[opNdx].name, ops[opNdx].desc);
1867
1868		addChild(opGroup);
1869
1870		for (int inTypeNdx = 0; inTypeNdx < inTypeListSize; inTypeNdx++)
1871		{
1872			const InputType		inputType	= inTypeList[inTypeNdx].type;
1873			tcu::TestCaseGroup* inGroup;
1874
1875			if (ops[opNdx].createInputTypeGroup)
1876			{
1877				inGroup = new tcu::TestCaseGroup(m_testCtx, inTypeList[inTypeNdx].name, inTypeList[inTypeNdx].desc);
1878				opGroup->addChild(inGroup);
1879			}
1880			else
1881				inGroup = opGroup;
1882
1883			for (int matTypeNdx = 0; matTypeNdx < DE_LENGTH_OF_ARRAY(matrixTypes); matTypeNdx++)
1884			{
1885				DataType	matType		= matrixTypes[matTypeNdx];
1886				int			numCols		= getDataTypeMatrixNumColumns(matType);
1887				int			numRows		= getDataTypeMatrixNumRows(matType);
1888				const char*	matTypeName	= getDataTypeName(matType);
1889
1890				for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1891				{
1892					Precision	precision	= precisions[precNdx];
1893					const char*	precName	= getPrecisionName(precision);
1894					string		baseName	= string(precName) + "_" + matTypeName + "_";
1895					ShaderInput	matIn		(inputType, matType, precision);
1896
1897					if (isOperationMatrixScalar(op))
1898					{
1899						// Matrix-scalar \note For div cases we use uniform input.
1900						ShaderInput scalarIn(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, TYPE_FLOAT, precision);
1901						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(),		"Matrix-scalar case", matIn, scalarIn, op, true));
1902						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(),	"Matrix-scalar case", matIn, scalarIn, op, false));
1903					}
1904
1905					if (isOperationMatrixVector(op))
1906					{
1907						// Matrix-vector.
1908						DataType	colVecType	= getDataTypeFloatVec(numCols);
1909						ShaderInput colVecIn	(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, colVecType, precision);
1910
1911						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(colVecType) + "_vertex").c_str(),		"Matrix-vector case", matIn, colVecIn, op, true));
1912						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(colVecType) + "_fragment").c_str(),	"Matrix-vector case", matIn, colVecIn, op, false));
1913
1914						// Vector-matrix.
1915						DataType	rowVecType	= getDataTypeFloatVec(numRows);
1916						ShaderInput	rowVecIn	(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, rowVecType, precision);
1917						string		vecMatName	= string(precName) + "_" + getDataTypeName(rowVecType) + "_" + matTypeName;
1918
1919						inGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_vertex").c_str(),		"Vector-matrix case", rowVecIn, matIn, op, true));
1920						inGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_fragment").c_str(),	"Vector-matrix case", rowVecIn, matIn, op, false));
1921					}
1922
1923					if (isOperationArithmeticMatrixMatrix(op))
1924					{
1925						// Arithmetic matrix-matrix multiplication.
1926						for (int otherCols = 2; otherCols <= 4; otherCols++)
1927						{
1928							ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, getDataTypeMatrix(otherCols, numCols /* rows */), precision);
1929							inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(otherMatIn.dataType) + "_vertex").c_str(),	"Matrix-matrix case", matIn, otherMatIn, op, true));
1930							inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(otherMatIn.dataType) + "_fragment").c_str(),	"Matrix-matrix case", matIn, otherMatIn, op, false));
1931						}
1932					}
1933					else if (isOperationComponentwiseMatrixMatrix(op))
1934					{
1935						// Component-wise.
1936						ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType, precision);
1937						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + matTypeName + "_vertex").c_str(),		"Matrix-matrix case", matIn, otherMatIn, op, true));
1938						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + matTypeName + "_fragment").c_str(),	"Matrix-matrix case", matIn, otherMatIn, op, false));
1939					}
1940
1941					if (isOperationVectorVector(op))
1942					{
1943						ShaderInput vec1In(inputType,																getDataTypeFloatVec(numRows), precision);
1944						ShaderInput vec2In((inputType == INPUTTYPE_DYNAMIC) ? (INPUTTYPE_UNIFORM) : (inputType),	getDataTypeFloatVec(numCols), precision);
1945
1946						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(),		"Vector-vector case", vec1In, vec2In, op, true));
1947						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(),	"Vector-vector case", vec1In, vec2In, op, false));
1948					}
1949
1950					if ((isOperationUnaryAnyMatrix(op)) ||
1951						(isOperationUnarySymmetricMatrix(op) && numCols == numRows))
1952					{
1953						ShaderInput voidInput(INPUTTYPE_LAST, TYPE_LAST, PRECISION_LAST);
1954						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(),		"Matrix case", matIn, voidInput, op, true));
1955						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(),	"Matrix case", matIn, voidInput, op, false));
1956					}
1957
1958					if ((isOperationAssignmentAnyMatrix(op)) ||
1959						(isOperationAssignmentSymmetricMatrix(op) && numCols == numRows))
1960					{
1961						ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType, precision);
1962						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(),		"Matrix assignment case", matIn, otherMatIn, op, true));
1963						inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(),	"Matrix assignment case", matIn, otherMatIn, op, false));
1964					}
1965				}
1966			}
1967		}
1968	}
1969}
1970
1971} // Functional
1972} // gles3
1973} // deqp
1974