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