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