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