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