Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 2.0 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Shader matrix arithmetic tests.
     22  *
     23  * Variables:
     24  *  + operation
     25  *    - mat OP mat
     26  *    - mat OP vec
     27  *    - vec OP mat
     28  *    - mat OP scalar
     29  *    - OP mat
     30  *  + matrix source
     31  *    - constant (ctor)
     32  *    - uniform
     33  *    - vertex input
     34  *    - fragment input
     35  *  + other operand: always dynamic data?
     36  *  + how to reduce to vec3?
     37  *//*--------------------------------------------------------------------*/
     38 
     39 #include "es2fShaderMatrixTests.hpp"
     40 #include "glsShaderRenderCase.hpp"
     41 #include "gluShaderUtil.hpp"
     42 #include "tcuVector.hpp"
     43 #include "tcuMatrix.hpp"
     44 #include "tcuMatrixUtil.hpp"
     45 #include "deStringUtil.hpp"
     46 
     47 #include "glwEnums.hpp"
     48 #include "glwFunctions.hpp"
     49 
     50 namespace deqp
     51 {
     52 namespace gles2
     53 {
     54 namespace Functional
     55 {
     56 
     57 using std::string;
     58 using std::vector;
     59 using namespace glu;
     60 using namespace deqp::gls;
     61 
     62 using tcu::Vec2;
     63 using tcu::Vec3;
     64 using tcu::Vec4;
     65 using tcu::Mat2;
     66 using tcu::Mat3;
     67 using tcu::Mat4;
     68 
     69 // Uniform / constant values for tests.
     70 // \note Input1 should not contain 0 components as it is used as divisor in div cases.
     71 // \todo [2012-02-14 pyry] Make these dynamic.
     72 static const float	s_constInFloat[2]	= { 0.5f, -0.2f };
     73 static const Vec2	s_constInVec2[2]	= { Vec2(1.2f, 0.5f), Vec2(0.5f, 1.0f) };
     74 static const Vec3	s_constInVec3[2]	= { Vec3(1.1f, 0.1f, 0.5f), Vec3(-0.2f, 0.5f, 0.8f) };
     75 static const Vec4	s_constInVec4[2]	= { Vec4(1.4f, 0.2f, -0.5f, 0.7f), Vec4(0.2f, -1.0f, 0.5f, 0.8f) };
     76 
     77 static const float s_constInMat20[] = { 0.6f, -1.0f, 0.7f, 0.4f };
     78 static const float s_constInMat21[] = { -0.5f, -0.4f, 0.7f, -0.8f };
     79 
     80 static const float s_constInMat31[] =
     81 {
     82 	1.2f,  0.1f, -0.1f,
     83 	0.1f,  0.9f,  0.2f,
     84 	0.2f, -0.1f,  0.7f
     85 };
     86 static const float s_constInMat41[] =
     87 {
     88 	 1.2f, -0.2f,  0.4f,  0.1f,
     89 	 0.1f,  0.8f, -0.1f, -0.2f,
     90 	-0.2f,  0.1f, -1.1f,  0.3f,
     91 	 0.1f,  0.2f,  0.3f,  0.9f
     92 };
     93 
     94 static const Mat2	s_constInMat2[2]	= { tcu::Mat2(s_constInMat20), tcu::Mat2(s_constInMat21) };
     95 static const Mat3	s_constInMat3[2]	= { tcu::translationMatrix(tcu::Vec2(0.2f, -0.3f)), tcu::Mat3(s_constInMat31) };
     96 static const Mat4	s_constInMat4[2]	= { tcu::translationMatrix(tcu::Vec3(0.2f, -0.3f, 0.15f)), tcu::Mat4(s_constInMat41) };
     97 
     98 namespace MatrixCaseUtils
     99 {
    100 
    101 enum InputType
    102 {
    103 	INPUTTYPE_CONST = 0,
    104 	INPUTTYPE_UNIFORM,
    105 	INPUTTYPE_DYNAMIC,
    106 
    107 	INPUTTYPE_LAST
    108 };
    109 
    110 struct ShaderInput
    111 {
    112 	ShaderInput (InputType inputType_, DataType dataType_, Precision precision_)
    113 		: inputType	(inputType_)
    114 		, dataType	(dataType_)
    115 		, precision	(precision_)
    116 	{
    117 	}
    118 
    119 	InputType		inputType;
    120 	DataType		dataType;
    121 	Precision		precision;
    122 };
    123 
    124 enum MatrixOp
    125 {
    126 	OP_ADD = 0,
    127 	OP_SUB,
    128 	OP_MUL,
    129 	OP_DIV,
    130 	OP_COMP_MUL,
    131 	OP_UNARY_PLUS,
    132 	OP_NEGATION,
    133 	OP_PRE_INCREMENT,
    134 	OP_PRE_DECREMENT,
    135 	OP_POST_INCREMENT,
    136 	OP_POST_DECREMENT,
    137 	OP_ADD_INTO,
    138 	OP_SUBTRACT_FROM,
    139 	OP_MULTIPLY_INTO,
    140 	OP_DIVIDE_INTO,
    141 
    142 	OP_LAST
    143 };
    144 
    145 // Type traits.
    146 
    147 template <int DataT>
    148 struct TypeTraits;
    149 
    150 #define DECLARE_TYPE_TRAIT(DATATYPE, TYPE)	\
    151 template<>									\
    152 struct TypeTraits<DATATYPE> {				\
    153 	typedef TYPE Type;						\
    154 }
    155 
    156 DECLARE_TYPE_TRAIT(TYPE_FLOAT,		float);
    157 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC2,	tcu::Vec2);
    158 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC3,	tcu::Vec3);
    159 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC4,	tcu::Vec4);
    160 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2, tcu::Mat2);
    161 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3, tcu::Mat3);
    162 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4, tcu::Mat4);
    163 
    164 // Operation info
    165 
    166 enum OperationType
    167 {
    168 	OPERATIONTYPE_BINARY_OPERATOR = 0,
    169 	OPERATIONTYPE_BINARY_FUNCTION,
    170 	OPERATIONTYPE_UNARY_PREFIX_OPERATOR,
    171 	OPERATIONTYPE_UNARY_POSTFIX_OPERATOR,
    172 	OPERATIONTYPE_ASSIGNMENT,
    173 
    174 	OPERATIONTYPE_LAST
    175 };
    176 
    177 static const char* getOperationName (MatrixOp op)
    178 {
    179 	switch (op)
    180 	{
    181 		case OP_ADD:			return "+";
    182 		case OP_SUB:			return "-";
    183 		case OP_MUL:			return "*";
    184 		case OP_DIV:			return "/";
    185 		case OP_COMP_MUL:		return "matrixCompMult";
    186 		case OP_UNARY_PLUS:		return "+";
    187 		case OP_NEGATION:		return "-";
    188 		case OP_PRE_INCREMENT:	return "++";
    189 		case OP_PRE_DECREMENT:	return "--";
    190 		case OP_POST_INCREMENT:	return "++";
    191 		case OP_POST_DECREMENT:	return "--";
    192 		case OP_ADD_INTO:		return "+=";
    193 		case OP_SUBTRACT_FROM:	return "-=";
    194 		case OP_MULTIPLY_INTO:	return "*=";
    195 		case OP_DIVIDE_INTO:	return "/=";
    196 		default:
    197 			DE_ASSERT(DE_FALSE);
    198 			return "";
    199 	}
    200 }
    201 
    202 static OperationType getOperationType (MatrixOp op)
    203 {
    204 	switch (op)
    205 	{
    206 		case OP_ADD:			return OPERATIONTYPE_BINARY_OPERATOR;
    207 		case OP_SUB:			return OPERATIONTYPE_BINARY_OPERATOR;
    208 		case OP_MUL:			return OPERATIONTYPE_BINARY_OPERATOR;
    209 		case OP_DIV:			return OPERATIONTYPE_BINARY_OPERATOR;
    210 		case OP_COMP_MUL:		return OPERATIONTYPE_BINARY_FUNCTION;
    211 		case OP_UNARY_PLUS:		return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
    212 		case OP_NEGATION:		return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
    213 		case OP_PRE_INCREMENT:	return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
    214 		case OP_PRE_DECREMENT:	return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
    215 		case OP_POST_INCREMENT:	return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR;
    216 		case OP_POST_DECREMENT:	return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR;
    217 		case OP_ADD_INTO:		return OPERATIONTYPE_ASSIGNMENT;
    218 		case OP_SUBTRACT_FROM:	return OPERATIONTYPE_ASSIGNMENT;
    219 		case OP_MULTIPLY_INTO:	return OPERATIONTYPE_ASSIGNMENT;
    220 		case OP_DIVIDE_INTO:	return OPERATIONTYPE_ASSIGNMENT;
    221 		default:
    222 			DE_ASSERT(DE_FALSE);
    223 			return OPERATIONTYPE_LAST;
    224 	}
    225 }
    226 
    227 enum TestMatrixType
    228 {
    229 	TESTMATRIXTYPE_DEFAULT = 0,
    230 	TESTMATRIXTYPE_NEGATED,
    231 	TESTMATRIXTYPE_INCREMENTED,
    232 	TESTMATRIXTYPE_DECREMENTED,
    233 
    234 	TESTMATRIXTYPE_LAST
    235 };
    236 
    237 static TestMatrixType getOperationTestMatrixType (MatrixOp op)
    238 {
    239 	switch(op)
    240 	{
    241 		case OP_ADD:			return TESTMATRIXTYPE_DEFAULT;
    242 		case OP_SUB:			return TESTMATRIXTYPE_DEFAULT;
    243 		case OP_MUL:			return TESTMATRIXTYPE_DEFAULT;
    244 		case OP_DIV:			return TESTMATRIXTYPE_DEFAULT;
    245 		case OP_COMP_MUL:		return TESTMATRIXTYPE_DEFAULT;
    246 		case OP_UNARY_PLUS:		return TESTMATRIXTYPE_DEFAULT;
    247 		case OP_NEGATION:		return TESTMATRIXTYPE_NEGATED;
    248 		case OP_PRE_INCREMENT:	return TESTMATRIXTYPE_NEGATED;
    249 		case OP_PRE_DECREMENT:	return TESTMATRIXTYPE_INCREMENTED;
    250 		case OP_POST_INCREMENT:	return TESTMATRIXTYPE_NEGATED;
    251 		case OP_POST_DECREMENT:	return TESTMATRIXTYPE_DEFAULT;
    252 		case OP_ADD_INTO:		return TESTMATRIXTYPE_DECREMENTED;
    253 		case OP_SUBTRACT_FROM:	return TESTMATRIXTYPE_DEFAULT;
    254 		case OP_MULTIPLY_INTO:	return TESTMATRIXTYPE_DEFAULT;
    255 		case OP_DIVIDE_INTO:	return TESTMATRIXTYPE_DEFAULT;
    256 
    257 		default:
    258 			DE_ASSERT(DE_FALSE);
    259 			return TESTMATRIXTYPE_LAST;
    260 	}
    261 }
    262 
    263 static bool isOperationBinary (MatrixOp op)
    264 {
    265 	return getOperationType(op) == OPERATIONTYPE_BINARY_OPERATOR ||
    266 	       getOperationType(op) == OPERATIONTYPE_BINARY_FUNCTION ||
    267 	       getOperationType(op) == OPERATIONTYPE_ASSIGNMENT;
    268 }
    269 
    270 static bool isOperationMatrixScalar (MatrixOp op)
    271 {
    272 	return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV;
    273 }
    274 
    275 static bool isOperationMatrixVector (MatrixOp op)
    276 {
    277 	return op == OP_MUL;
    278 }
    279 
    280 static bool isOperationMatrixMatrix (MatrixOp op)
    281 {
    282 	return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV || op == OP_COMP_MUL;
    283 }
    284 
    285 static bool isOperationUnary (MatrixOp op)
    286 {
    287 	return  op == OP_UNARY_PLUS			||
    288 			op == OP_NEGATION			||
    289 			op == OP_PRE_INCREMENT		||
    290 			op == OP_PRE_DECREMENT		||
    291 			op == OP_POST_INCREMENT		||
    292 			op == OP_POST_DECREMENT;
    293 }
    294 
    295 static bool isOperationValueModifying (MatrixOp op)
    296 {
    297 	return  op == OP_PRE_INCREMENT		||
    298 			op == OP_PRE_DECREMENT		||
    299 			op == OP_POST_INCREMENT		||
    300 			op == OP_POST_DECREMENT;
    301 }
    302 
    303 static bool isOperationAssignment (MatrixOp op)
    304 {
    305 	return  op == OP_ADD_INTO		 ||
    306 			op == OP_SUBTRACT_FROM	 ||
    307 			op == OP_MULTIPLY_INTO	 ||
    308 			op == OP_DIVIDE_INTO;
    309 }
    310 
    311 // Operation nature
    312 
    313 enum OperationNature
    314 {
    315 	OPERATIONNATURE_PURE = 0,
    316 	OPERATIONNATURE_MUTATING,
    317 	OPERATIONNATURE_ASSIGNMENT,
    318 
    319 	OPERATIONNATURE_LAST
    320 };
    321 
    322 static OperationNature getOperationNature (MatrixOp op)
    323 {
    324 	if (isOperationAssignment(op))
    325 		return OPERATIONNATURE_ASSIGNMENT;
    326 
    327 	if (isOperationValueModifying(op))
    328 		return OPERATIONNATURE_MUTATING;
    329 
    330 	return OPERATIONNATURE_PURE;
    331 }
    332 
    333 // Input value loader.
    334 
    335 template <int InputT, int DataT>
    336 typename TypeTraits<DataT>::Type getInputValue (const ShaderEvalContext& evalCtx, int inputNdx);
    337 
    338 template <> inline float		getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT>			(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInFloat[inputNdx];	}
    339 template <> inline tcu::Vec2	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_VEC2>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec2[inputNdx];	}
    340 template <> inline tcu::Vec3	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_VEC3>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec3[inputNdx];	}
    341 template <> inline tcu::Vec4	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_VEC4>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec4[inputNdx];	}
    342 template <> inline tcu::Mat2	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT2>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInMat2[inputNdx];	}
    343 template <> inline tcu::Mat3	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT3>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInMat3[inputNdx];	}
    344 template <> inline tcu::Mat4	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT4>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInMat4[inputNdx];	}
    345 
    346 template <> inline float		getInputValue<INPUTTYPE_DYNAMIC,	TYPE_FLOAT>			(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.x();					}
    347 template <> inline tcu::Vec2	getInputValue<INPUTTYPE_DYNAMIC,	TYPE_FLOAT_VEC2>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.swizzle(0, 1);			}
    348 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);		}
    349 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);	}
    350 
    351 template <> inline tcu::Mat2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2> (const ShaderEvalContext& evalCtx, int inputNdx)
    352 {
    353 	DE_UNREF(inputNdx); // Not used.
    354 	tcu::Mat2 m;
    355 	m.setColumn(0, evalCtx.in[0].swizzle(0,1));
    356 	m.setColumn(1, evalCtx.in[1].swizzle(0,1));
    357 	return m;
    358 }
    359 
    360 template <> inline tcu::Mat3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3> (const ShaderEvalContext& evalCtx, int inputNdx)
    361 {
    362 	DE_UNREF(inputNdx); // Not used.
    363 	tcu::Mat3 m;
    364 	m.setColumn(0, evalCtx.in[0].swizzle(0,1,2));
    365 	m.setColumn(1, evalCtx.in[1].swizzle(0,1,2));
    366 	m.setColumn(2, evalCtx.in[2].swizzle(0,1,2));
    367 	return m;
    368 }
    369 
    370 template <> inline tcu::Mat4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4> (const ShaderEvalContext& evalCtx, int inputNdx)
    371 {
    372 	DE_UNREF(inputNdx); // Not used.
    373 	tcu::Mat4 m;
    374 	m.setColumn(0, evalCtx.in[0]);
    375 	m.setColumn(1, evalCtx.in[1]);
    376 	m.setColumn(2, evalCtx.in[2]);
    377 	m.setColumn(3, evalCtx.in[3]);
    378 	return m;
    379 }
    380 
    381 // Reduction from expression result to vec3.
    382 
    383 inline tcu::Vec3 reduceToVec3 (const tcu::Vec2& value) { return value.swizzle(0,1,0); }
    384 inline tcu::Vec3 reduceToVec3 (const tcu::Vec3& value) { return value; }
    385 inline tcu::Vec3 reduceToVec3 (const tcu::Vec4& value) { return tcu::Vec3(value.x(), value.y(), value.z()+value.w()); }
    386 inline tcu::Vec3 reduceToVec3 (const tcu::Mat2& value) { return tcu::Vec3(value(0, 0), value(0, 1), value(1, 0)+value(1, 1)); }
    387 inline tcu::Vec3 reduceToVec3 (const tcu::Mat3& value) { return value.getColumn(0) + value.getColumn(1) + value.getColumn(2); }
    388 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); }
    389 
    390 // matrixCompMult
    391 
    392 template <typename T, int Rows, int Cols>
    393 tcu::Matrix<T, Rows, Cols> matrixCompMult (const tcu::Matrix<T, Rows, Cols>& a, const tcu::Matrix<T, Rows, Cols>& b)
    394 {
    395 	tcu::Matrix<T, Rows, Cols> retVal;
    396 
    397 	for (int r = 0; r < Rows; ++r)
    398 		for (int c = 0; c < Cols; ++c)
    399 			retVal(r,c) = a(r,c) * b(r, c);
    400 
    401 	return retVal;
    402 }
    403 
    404 // negate
    405 
    406 template <typename T, int Rows, int Cols>
    407 tcu::Matrix<T, Rows, Cols> negate (const tcu::Matrix<T, Rows, Cols>& mat)
    408 {
    409 	tcu::Matrix<T, Rows, Cols> retVal;
    410 
    411 	for (int r = 0; r < Rows; ++r)
    412 		for (int c = 0; c < Cols; ++c)
    413 			retVal(r,c) = -mat(r, c);
    414 
    415 	return retVal;
    416 }
    417 
    418 // increment/decrement
    419 
    420 template <typename T, int Rows, int Cols>
    421 tcu::Matrix<T, Rows, Cols> increment (const tcu::Matrix<T, Rows, Cols>& mat)
    422 {
    423 	tcu::Matrix<T, Rows, Cols> retVal;
    424 
    425 	for (int r = 0; r < Rows; ++r)
    426 		for (int c = 0; c < Cols; ++c)
    427 			retVal(r,c) = mat(r, c) + 1.0f;
    428 
    429 	return retVal;
    430 }
    431 
    432 template <typename T, int Rows, int Cols>
    433 tcu::Matrix<T, Rows, Cols> decrement (const tcu::Matrix<T, Rows, Cols>& mat)
    434 {
    435 	tcu::Matrix<T, Rows, Cols> retVal;
    436 
    437 	for (int r = 0; r < Rows; ++r)
    438 		for (int c = 0; c < Cols; ++c)
    439 			retVal(r,c) = mat(r, c) - 1.0f;
    440 
    441 	return retVal;
    442 }
    443 
    444 // Evaluator template.
    445 
    446 template <int Op, int In0Type, int In0DataType, int In1Type, int In1DataType>
    447 struct Evaluator;
    448 
    449 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    450 struct Evaluator<OP_ADD, In0Type, In0DataType, In1Type, In1DataType>
    451 {
    452 	static void evaluate (ShaderEvalContext& evalCtx)
    453 	{
    454 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) + getInputValue<In1Type, In1DataType>(evalCtx, 1));
    455 	}
    456 };
    457 
    458 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    459 struct Evaluator<OP_SUB, In0Type, In0DataType, In1Type, In1DataType>
    460 {
    461 	static void evaluate (ShaderEvalContext& evalCtx)
    462 	{
    463 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) - getInputValue<In1Type, In1DataType>(evalCtx, 1));
    464 	}
    465 };
    466 
    467 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    468 struct Evaluator<OP_MUL, In0Type, In0DataType, In1Type, In1DataType>
    469 {
    470 	static void evaluate (ShaderEvalContext& evalCtx)
    471 	{
    472 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) * getInputValue<In1Type, In1DataType>(evalCtx, 1));
    473 	}
    474 };
    475 
    476 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    477 struct Evaluator<OP_DIV, In0Type, In0DataType, In1Type, In1DataType>
    478 {
    479 	static void evaluate (ShaderEvalContext& evalCtx)
    480 	{
    481 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) / getInputValue<In1Type, In1DataType>(evalCtx, 1));
    482 	}
    483 };
    484 
    485 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    486 struct Evaluator<OP_COMP_MUL, In0Type, In0DataType, In1Type, In1DataType>
    487 {
    488 	static void evaluate (ShaderEvalContext& evalCtx)
    489 	{
    490 		evalCtx.color.xyz() = reduceToVec3(matrixCompMult(getInputValue<In0Type, In0DataType>(evalCtx, 0), getInputValue<In1Type, In1DataType>(evalCtx, 1)));
    491 	}
    492 };
    493 
    494 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    495 struct Evaluator<OP_UNARY_PLUS, In0Type, In0DataType, In1Type, In1DataType>
    496 {
    497 	static void evaluate (ShaderEvalContext& evalCtx)
    498 	{
    499 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0));
    500 	}
    501 };
    502 
    503 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    504 struct Evaluator<OP_NEGATION, In0Type, In0DataType, In1Type, In1DataType>
    505 {
    506 	static void evaluate (ShaderEvalContext& evalCtx)
    507 	{
    508 		evalCtx.color.xyz() = reduceToVec3(negate(getInputValue<In0Type, In0DataType>(evalCtx, 0)));
    509 	}
    510 };
    511 
    512 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    513 struct Evaluator<OP_PRE_INCREMENT, In0Type, In0DataType, In1Type, In1DataType>
    514 {
    515 	static void evaluate (ShaderEvalContext& evalCtx)
    516 	{
    517 		// modifying reduction: sum modified value too
    518 		evalCtx.color.xyz() = reduceToVec3(increment(getInputValue<In0Type, In0DataType>(evalCtx, 0))) + reduceToVec3(increment(getInputValue<In0Type, In0DataType>(evalCtx, 0)));
    519 	}
    520 };
    521 
    522 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    523 struct Evaluator<OP_PRE_DECREMENT, In0Type, In0DataType, In1Type, In1DataType>
    524 {
    525 	static void evaluate (ShaderEvalContext& evalCtx)
    526 	{
    527 		// modifying reduction: sum modified value too
    528 		evalCtx.color.xyz() = reduceToVec3(decrement(getInputValue<In0Type, In0DataType>(evalCtx, 0))) + reduceToVec3(decrement(getInputValue<In0Type, In0DataType>(evalCtx, 0)));
    529 	}
    530 };
    531 
    532 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    533 struct Evaluator<OP_POST_INCREMENT, In0Type, In0DataType, In1Type, In1DataType>
    534 {
    535 	static void evaluate (ShaderEvalContext& evalCtx)
    536 	{
    537 		// modifying reduction: sum modified value too
    538 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0)) + reduceToVec3(increment(getInputValue<In0Type, In0DataType>(evalCtx, 0)));
    539 	}
    540 };
    541 
    542 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    543 struct Evaluator<OP_POST_DECREMENT, In0Type, In0DataType, In1Type, In1DataType>
    544 {
    545 	static void evaluate (ShaderEvalContext& evalCtx)
    546 	{
    547 		// modifying reduction: sum modified value too
    548 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0)) + reduceToVec3(decrement(getInputValue<In0Type, In0DataType>(evalCtx, 0)));
    549 	}
    550 };
    551 
    552 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    553 struct Evaluator<OP_ADD_INTO, In0Type, In0DataType, In1Type, In1DataType>
    554 {
    555 	static void evaluate (ShaderEvalContext& evalCtx)
    556 	{
    557 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) + getInputValue<In1Type, In1DataType>(evalCtx, 1));
    558 	}
    559 };
    560 
    561 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    562 struct Evaluator<OP_SUBTRACT_FROM, In0Type, In0DataType, In1Type, In1DataType>
    563 {
    564 	static void evaluate (ShaderEvalContext& evalCtx)
    565 	{
    566 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) - getInputValue<In1Type, In1DataType>(evalCtx, 1));
    567 	}
    568 };
    569 
    570 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    571 struct Evaluator<OP_MULTIPLY_INTO, In0Type, In0DataType, In1Type, In1DataType>
    572 {
    573 	static void evaluate (ShaderEvalContext& evalCtx)
    574 	{
    575 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) * getInputValue<In1Type, In1DataType>(evalCtx, 1));
    576 	}
    577 };
    578 
    579 template <int In0Type, int In0DataType, int In1Type, int In1DataType>
    580 struct Evaluator<OP_DIVIDE_INTO, In0Type, In0DataType, In1Type, In1DataType>
    581 {
    582 	static void evaluate (ShaderEvalContext& evalCtx)
    583 	{
    584 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) / getInputValue<In1Type, In1DataType>(evalCtx, 1));
    585 	}
    586 };
    587 
    588 ShaderEvalFunc getEvalFunc (const ShaderInput& in0, const ShaderInput& in1, MatrixOp op)
    589 {
    590 	DE_STATIC_ASSERT(TYPE_LAST		<= (1<<7));
    591 	DE_STATIC_ASSERT(OP_LAST		<= (1<<4));
    592 	DE_STATIC_ASSERT(INPUTTYPE_LAST	<= (1<<2));
    593 
    594 #define PACK_EVAL_CASE(OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)	(((OP) << 18) | ((IN0TYPE) << 16) | ((IN0DATATYPE) << 9) | ((IN1TYPE) << 7) | (IN1DATATYPE))
    595 
    596 #define MAKE_EVAL_CASE(OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)		\
    597 	case PACK_EVAL_CASE(OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE):	\
    598 		return Evaluator<OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE>::evaluate
    599 
    600 #define SCALAR_OPS(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)	\
    601 	MAKE_EVAL_CASE(OP_ADD,		IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);	\
    602 	MAKE_EVAL_CASE(OP_SUB,		IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);	\
    603 	MAKE_EVAL_CASE(OP_MUL,		IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);	\
    604 	MAKE_EVAL_CASE(OP_DIV,		IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)
    605 
    606 #define ALL_OPS(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)	\
    607 	MAKE_EVAL_CASE(OP_ADD,			IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);	\
    608 	MAKE_EVAL_CASE(OP_SUB,			IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);	\
    609 	MAKE_EVAL_CASE(OP_MUL,			IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);	\
    610 	MAKE_EVAL_CASE(OP_DIV,			IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);	\
    611 	MAKE_EVAL_CASE(OP_COMP_MUL,		IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);
    612 
    613 #define MUL_OP(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)	\
    614 	MAKE_EVAL_CASE(OP_MUL, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)
    615 
    616 #define MAKE_MAT_SCALAR_VEC_CASES(OP, TYPE0, TYPE1)				\
    617 	OP(INPUTTYPE_CONST,		TYPE0, INPUTTYPE_CONST,		TYPE1);	\
    618 	OP(INPUTTYPE_DYNAMIC,	TYPE0, INPUTTYPE_CONST,		TYPE1);	\
    619 	OP(INPUTTYPE_CONST,		TYPE0, INPUTTYPE_DYNAMIC,	TYPE1);	\
    620 	OP(INPUTTYPE_DYNAMIC,	TYPE0, INPUTTYPE_DYNAMIC,	TYPE1)
    621 
    622 #define MAKE_MAT_MAT_CASES(OP, MATTYPE)								\
    623 	OP(INPUTTYPE_CONST,		MATTYPE, INPUTTYPE_CONST,	MATTYPE);	\
    624 	OP(INPUTTYPE_DYNAMIC,	MATTYPE, INPUTTYPE_CONST,	MATTYPE)
    625 
    626 #define UNARY_OP(IN0TYPE, IN0DATATYPE)														\
    627 	MAKE_EVAL_CASE(OP_UNARY_PLUS,		IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST);	\
    628 	MAKE_EVAL_CASE(OP_NEGATION,			IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST);	\
    629 	MAKE_EVAL_CASE(OP_PRE_INCREMENT,	IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST);	\
    630 	MAKE_EVAL_CASE(OP_PRE_DECREMENT,	IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST);	\
    631 	MAKE_EVAL_CASE(OP_POST_INCREMENT,	IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST);	\
    632 	MAKE_EVAL_CASE(OP_POST_DECREMENT,	IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST)
    633 
    634 #define MAKE_UNARY_CASES(OP, MATTYPE)	\
    635 	OP(INPUTTYPE_CONST,		MATTYPE);	\
    636 	OP(INPUTTYPE_DYNAMIC,	MATTYPE)
    637 
    638 #define ASSIGN_OP(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)							\
    639 	MAKE_EVAL_CASE(OP_ADD_INTO,			IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);	\
    640 	MAKE_EVAL_CASE(OP_SUBTRACT_FROM,	IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);	\
    641 	MAKE_EVAL_CASE(OP_MULTIPLY_INTO,	IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE);	\
    642 	MAKE_EVAL_CASE(OP_DIVIDE_INTO,		IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE)
    643 
    644 #define MAKE_ASSIGNMENT_CASES(OP, MATTYPE)						\
    645 	OP(INPUTTYPE_CONST,		MATTYPE, INPUTTYPE_CONST,	MATTYPE);	\
    646 	OP(INPUTTYPE_DYNAMIC,	MATTYPE, INPUTTYPE_CONST,	MATTYPE);	\
    647 	OP(INPUTTYPE_CONST,		MATTYPE, INPUTTYPE_DYNAMIC,	MATTYPE);	\
    648 	OP(INPUTTYPE_DYNAMIC,	MATTYPE, INPUTTYPE_DYNAMIC,	MATTYPE)
    649 
    650 	// \note At the moment there is no difference between uniform and const inputs. This saves binary size.
    651 	InputType in0Type = in0.inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_DYNAMIC : INPUTTYPE_CONST;
    652 	InputType in1Type = in1.inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_DYNAMIC : INPUTTYPE_CONST;
    653 
    654 	switch (PACK_EVAL_CASE(op, in0Type, in0.dataType, in1Type, in1.dataType))
    655 	{
    656 		// Matrix-scalar.
    657 		MAKE_MAT_SCALAR_VEC_CASES(SCALAR_OPS,	TYPE_FLOAT_MAT2, TYPE_FLOAT);
    658 		MAKE_MAT_SCALAR_VEC_CASES(SCALAR_OPS,	TYPE_FLOAT_MAT3, TYPE_FLOAT);
    659 		MAKE_MAT_SCALAR_VEC_CASES(SCALAR_OPS,	TYPE_FLOAT_MAT4, TYPE_FLOAT);
    660 
    661 		// Matrix-vector.
    662 		MAKE_MAT_SCALAR_VEC_CASES(MUL_OP,		TYPE_FLOAT_MAT2, TYPE_FLOAT_VEC2);
    663 		MAKE_MAT_SCALAR_VEC_CASES(MUL_OP,		TYPE_FLOAT_MAT3, TYPE_FLOAT_VEC3);
    664 		MAKE_MAT_SCALAR_VEC_CASES(MUL_OP,		TYPE_FLOAT_MAT4, TYPE_FLOAT_VEC4);
    665 
    666 		// Vector-matrix.
    667 		MAKE_MAT_SCALAR_VEC_CASES(MUL_OP,		TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT2);
    668 		MAKE_MAT_SCALAR_VEC_CASES(MUL_OP,		TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT3);
    669 		MAKE_MAT_SCALAR_VEC_CASES(MUL_OP,		TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT4);
    670 
    671 		// Matrix-matrix.
    672 		MAKE_MAT_MAT_CASES(ALL_OPS,	TYPE_FLOAT_MAT2);
    673 		MAKE_MAT_MAT_CASES(ALL_OPS,	TYPE_FLOAT_MAT3);
    674 		MAKE_MAT_MAT_CASES(ALL_OPS,	TYPE_FLOAT_MAT4);
    675 
    676 		// Unary matrix
    677 		MAKE_UNARY_CASES(UNARY_OP, TYPE_FLOAT_MAT2);
    678 		MAKE_UNARY_CASES(UNARY_OP, TYPE_FLOAT_MAT3);
    679 		MAKE_UNARY_CASES(UNARY_OP, TYPE_FLOAT_MAT4);
    680 
    681 		// Assignment matrix
    682 		MAKE_ASSIGNMENT_CASES(ASSIGN_OP, TYPE_FLOAT_MAT2);
    683 		MAKE_ASSIGNMENT_CASES(ASSIGN_OP, TYPE_FLOAT_MAT3);
    684 		MAKE_ASSIGNMENT_CASES(ASSIGN_OP, TYPE_FLOAT_MAT4);
    685 
    686 		default:
    687 			DE_ASSERT(DE_FALSE);
    688 			return DE_NULL;
    689 	}
    690 
    691 #undef PACK_EVAL_CASE
    692 #undef MAKE_EVAL_CASE
    693 #undef MUL_OP
    694 #undef ALL_OPS
    695 #undef MAKE_MAT_SCALAR_VEC_CASES
    696 #undef MAKE_MAT_MAT_CASES
    697 }
    698 
    699 // Shader source format utilities.
    700 
    701 template <int Size>
    702 void writeVectorConstructor (std::ostream& str, const tcu::Vector<float, Size>& v)
    703 {
    704 	str << "vec" << Size << "(";
    705 	for (int ndx = 0; ndx < Size; ndx++)
    706 	{
    707 		if (ndx != 0)
    708 			str << ", ";
    709 		str << de::floatToString(v[ndx], 1);
    710 	}
    711 	str << ")";
    712 }
    713 
    714 template <int Cols, int Rows>
    715 void writeMatrixConstructor (std::ostream& str, const tcu::Matrix<float, Rows, Cols>& m)
    716 {
    717 	if (Rows == Cols)
    718 		str << "mat" << Cols;
    719 	else
    720 		str << "mat" << Cols << "x" << Rows;
    721 
    722 	str << "(";
    723 	for (int colNdx = 0; colNdx < Cols; colNdx++)
    724 	{
    725 		for (int rowNdx = 0; rowNdx < Rows; rowNdx++)
    726 		{
    727 			if (rowNdx > 0 || colNdx > 0)
    728 				str << ", ";
    729 			str << de::floatToString(m(rowNdx, colNdx), 1);
    730 		}
    731 	}
    732 	str << ")";
    733 }
    734 
    735 } // MatrixCaseUtils
    736 
    737 using namespace MatrixCaseUtils;
    738 
    739 class ShaderMatrixCase : public ShaderRenderCase
    740 {
    741 public:
    742 					ShaderMatrixCase			(Context& context, const char* name, const char* desc, const ShaderInput& in0, const ShaderInput& in1, MatrixOp op, bool isVertexCase);
    743 					~ShaderMatrixCase			(void);
    744 
    745 	void			init						(void);
    746 
    747 protected:
    748 	std::string		genGLSLMatToVec3Reduction	(const glu::DataType& matType, const char* varName);
    749 	void			setupUniforms				(int programID, const tcu::Vec4& constCoords);
    750 
    751 private:
    752 	ShaderInput		m_in0;
    753 	ShaderInput		m_in1;
    754 	MatrixOp		m_op;
    755 };
    756 
    757 ShaderMatrixCase::ShaderMatrixCase (Context& context, const char* name, const char* desc, const ShaderInput& in0, const ShaderInput& in1, MatrixOp op, bool isVertexCase)
    758 	: ShaderRenderCase	(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, getEvalFunc(in0, in1, op))
    759 	, m_in0				(in0)
    760 	, m_in1				(in1)
    761 	, m_op				(op)
    762 {
    763 }
    764 
    765 ShaderMatrixCase::~ShaderMatrixCase (void)
    766 {
    767 }
    768 
    769 void ShaderMatrixCase::init (void)
    770 {
    771 	std::ostringstream	vtx;
    772 	std::ostringstream	frag;
    773 	std::ostringstream&	op				= m_isVertexCase ? vtx : frag;
    774 
    775 	bool				isInDynMat0		= isDataTypeMatrix(m_in0.dataType) && m_in0.inputType == INPUTTYPE_DYNAMIC;
    776 	bool				isInDynMat1		= isDataTypeMatrix(m_in1.dataType) && m_in1.inputType == INPUTTYPE_DYNAMIC;
    777 	string				inValue0;
    778 	string				inValue1;
    779 	DataType			resultType		= TYPE_LAST;
    780 	Precision			resultPrec		= m_in0.precision;
    781 	vector<string>		passVars;
    782 	int					numInputs		= (isOperationBinary(m_op)) ? (2) : (1);
    783 
    784 	std::string			operationValue0;
    785 	std::string			operationValue1;
    786 
    787 	DE_ASSERT(!isInDynMat0 || !isInDynMat1); // Only single dynamic matrix input is allowed.
    788 	DE_UNREF(isInDynMat0 && isInDynMat1);
    789 
    790 	// Compute result type.
    791 	if (isDataTypeMatrix(m_in0.dataType) && isDataTypeMatrix(m_in1.dataType))
    792 	{
    793 		DE_ASSERT(m_in0.dataType == m_in1.dataType);
    794 		resultType = m_in0.dataType;
    795 	}
    796 	else if (getOperationType(m_op) == OPERATIONTYPE_UNARY_PREFIX_OPERATOR ||
    797 			 getOperationType(m_op) == OPERATIONTYPE_UNARY_POSTFIX_OPERATOR)
    798 	{
    799 		resultType = m_in0.dataType;
    800 	}
    801 	else
    802 	{
    803 		int			matNdx		= isDataTypeMatrix(m_in0.dataType) ? 0 : 1;
    804 		DataType	matrixType	= matNdx == 0 ? m_in0.dataType : m_in1.dataType;
    805 		DataType	otherType	= matNdx == 0 ? m_in1.dataType : m_in0.dataType;
    806 
    807 		if (otherType == TYPE_FLOAT)
    808 			resultType = matrixType;
    809 		else
    810 		{
    811 			DE_ASSERT(isDataTypeVector(otherType));
    812 			resultType = otherType;
    813 		}
    814 	}
    815 
    816 	vtx << "attribute highp vec4 a_position;\n";
    817 	if (m_isVertexCase)
    818 	{
    819 		vtx << "varying mediump vec4 v_color;\n";
    820 		frag << "varying mediump vec4 v_color;\n";
    821 	}
    822 
    823 	// Input declarations.
    824 	for (int inNdx = 0; inNdx < numInputs; inNdx++)
    825 	{
    826 		const ShaderInput&	in			= inNdx > 0 ? m_in1 : m_in0;
    827 		const char*			precName	= getPrecisionName(in.precision);
    828 		const char*			typeName	= getDataTypeName(in.dataType);
    829 		string&				inValue		= inNdx > 0 ? inValue1 : inValue0;
    830 
    831 		if (in.inputType == INPUTTYPE_DYNAMIC)
    832 		{
    833 			vtx << "attribute " << precName << " " << typeName << " a_";
    834 
    835 			if (isDataTypeMatrix(in.dataType))
    836 			{
    837 				// a_matN, v_matN
    838 				vtx << typeName << ";\n";
    839 				if (!m_isVertexCase)
    840 				{
    841 					vtx << "varying " << precName << " " << typeName << " v_" << typeName << ";\n";
    842 					frag << "varying " << precName << " " << typeName << " v_" << typeName << ";\n";
    843 					passVars.push_back(typeName);
    844 				}
    845 
    846 				inValue = string(m_isVertexCase ? "a_" : "v_") + getDataTypeName(in.dataType);
    847 			}
    848 			else
    849 			{
    850 				// a_coords, v_coords
    851 				vtx << "coords;\n";
    852 				if (!m_isVertexCase)
    853 				{
    854 					vtx << "varying " << precName << " " << typeName << " v_coords;\n";
    855 					frag << "varying " << precName << " " << typeName << " v_coords;\n";
    856 					passVars.push_back("coords");
    857 				}
    858 
    859 				inValue = m_isVertexCase ? "a_coords" : "v_coords";
    860 			}
    861 		}
    862 		else if (in.inputType == INPUTTYPE_UNIFORM)
    863 		{
    864 			op << "uniform " << precName << " " << typeName << " u_in" << inNdx << ";\n";
    865 			inValue = string("u_in") + de::toString(inNdx);
    866 		}
    867 		else if (in.inputType == INPUTTYPE_CONST)
    868 		{
    869 			op << "const " << precName << " " << typeName << " in" << inNdx << " = ";
    870 
    871 			// Generate declaration.
    872 			switch (in.dataType)
    873 			{
    874 				case TYPE_FLOAT:		op << de::floatToString(s_constInFloat[inNdx], 1);					break;
    875 				case TYPE_FLOAT_VEC2:	writeVectorConstructor<2>(op, s_constInVec2[inNdx]);				break;
    876 				case TYPE_FLOAT_VEC3:	writeVectorConstructor<3>(op, s_constInVec3[inNdx]);				break;
    877 				case TYPE_FLOAT_VEC4:	writeVectorConstructor<4>(op, s_constInVec4[inNdx]);				break;
    878 				case TYPE_FLOAT_MAT2:	writeMatrixConstructor<2, 2>(op, Mat2(s_constInMat2[inNdx]));		break;
    879 				case TYPE_FLOAT_MAT3:	writeMatrixConstructor<3, 3>(op, Mat3(s_constInMat3[inNdx]));		break;
    880 				case TYPE_FLOAT_MAT4:	writeMatrixConstructor<4, 4>(op, Mat4(s_constInMat4[inNdx]));		break;
    881 
    882 				default:
    883 					DE_ASSERT(DE_FALSE);
    884 			}
    885 
    886 			op << ";\n";
    887 
    888 			inValue = string("in") + de::toString(inNdx);
    889 		}
    890 	}
    891 
    892 	vtx << "\n"
    893 		<< "void main (void)\n"
    894 		<< "{\n"
    895 		<< "	gl_Position = a_position;\n";
    896 	frag << "\n"
    897 		 << "void main (void)\n"
    898 		 << "{\n";
    899 
    900 	if (m_isVertexCase)
    901 	{
    902 		frag << "	gl_FragColor = v_color;\n";
    903 	}
    904 	else
    905 	{
    906 		for (vector<string>::const_iterator copyIter = passVars.begin(); copyIter != passVars.end(); copyIter++)
    907 			vtx << "	v_" << *copyIter << " = " << "a_" << *copyIter << ";\n";
    908 	}
    909 
    910 	// Operation.
    911 
    912 	switch (getOperationNature(m_op))
    913 	{
    914 		case OPERATIONNATURE_PURE:
    915 			DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
    916 
    917 			operationValue0 = inValue0;
    918 			operationValue1 = inValue1;
    919 			break;
    920 
    921 		case OPERATIONNATURE_MUTATING:
    922 			DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
    923 
    924 			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " tmpValue = " << inValue0 << ";\n";
    925 
    926 			operationValue0 = "tmpValue";
    927 			operationValue1 = inValue1;
    928 			break;
    929 
    930 		case OPERATIONNATURE_ASSIGNMENT:
    931 			DE_ASSERT(getOperationType(m_op) == OPERATIONTYPE_ASSIGNMENT);
    932 
    933 			operationValue0 = inValue0;
    934 			operationValue1 = inValue1;
    935 			break;
    936 
    937 		default:
    938 			DE_ASSERT(DE_FALSE);
    939 	}
    940 
    941 	switch (getOperationType(m_op))
    942 	{
    943 		case OPERATIONTYPE_BINARY_OPERATOR:
    944 			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << " " << getOperationName(m_op) << " " << operationValue1 << ";\n";
    945 			break;
    946 
    947 		case OPERATIONTYPE_UNARY_PREFIX_OPERATOR:
    948 			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << operationValue0 << ";\n";
    949 			break;
    950 
    951 		case OPERATIONTYPE_UNARY_POSTFIX_OPERATOR:
    952 			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << getOperationName(m_op) << ";\n";
    953 			break;
    954 
    955 		case OPERATIONTYPE_BINARY_FUNCTION:
    956 			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << "(" << operationValue0 << ", " << operationValue1 << ");\n";
    957 			break;
    958 
    959 		case OPERATIONTYPE_ASSIGNMENT:
    960 			op << "	" << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << ";\n";
    961 			op << "	res " << getOperationName(m_op) << " " << operationValue1 << ";\n";
    962 			break;
    963 
    964 		default:
    965 			DE_ASSERT(DE_FALSE);
    966 	}
    967 
    968 	// Reduction to vec3 (rgb). Check the used value too if it was modified.
    969 	op << "	" << (m_isVertexCase ? "v_color" : "gl_FragColor") << " = ";
    970 
    971 	if (isOperationValueModifying(m_op))
    972 		op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0) + vec4(" << genGLSLMatToVec3Reduction(resultType, "tmpValue") << ", 0.0);\n";
    973 	else
    974 		op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0);\n";
    975 
    976 	vtx << "}\n";
    977 	frag << "}\n";
    978 
    979 	m_vertShaderSource	= vtx.str();
    980 	m_fragShaderSource	= frag.str();
    981 
    982 	// \todo [2012-02-14 pyry] Compute better values for matrix tests.
    983 	m_userAttribTransforms.resize(4);
    984 	for (int attribNdx = 0; attribNdx < 4; attribNdx++)
    985 	{
    986 		m_userAttribTransforms[attribNdx] = Mat4(0.0f);
    987 		m_userAttribTransforms[attribNdx]((0 + attribNdx) % 4, 0) = 1.0f;
    988 		m_userAttribTransforms[attribNdx]((1 + attribNdx) % 4, 1) = 1.0f;
    989 		m_userAttribTransforms[attribNdx]((2 + attribNdx) % 4, 2) = 1.0f;
    990 		m_userAttribTransforms[attribNdx]((3 + attribNdx) % 4, 3) = 1.0f;
    991 	}
    992 
    993 	// prevent bad reference cases such as black result images by fine-tuning used matrices
    994 	if (getOperationTestMatrixType(m_op) != TESTMATRIXTYPE_DEFAULT)
    995 	{
    996 		for (int attribNdx = 0; attribNdx < 4; attribNdx++)
    997 		{
    998 			for (int row = 0; row < 4; row++)
    999 			for (int col = 0; col < 4; col++)
   1000 			{
   1001 				switch (getOperationTestMatrixType(m_op))
   1002 				{
   1003 					case TESTMATRIXTYPE_NEGATED:
   1004 						m_userAttribTransforms[attribNdx](row, col) = -m_userAttribTransforms[attribNdx](row, col);
   1005 						break;
   1006 					case TESTMATRIXTYPE_INCREMENTED:
   1007 						m_userAttribTransforms[attribNdx](row, col) += 0.3f;
   1008 						break;
   1009 					case TESTMATRIXTYPE_DECREMENTED:
   1010 						m_userAttribTransforms[attribNdx](row, col) -= 0.1f;
   1011 						break;
   1012 
   1013 					default:
   1014 						DE_ASSERT(DE_FALSE);
   1015 						break;
   1016 				}
   1017 			}
   1018 		}
   1019 	}
   1020 
   1021 	ShaderRenderCase::init();
   1022 }
   1023 
   1024 std::string ShaderMatrixCase::genGLSLMatToVec3Reduction (const glu::DataType& matType, const char* varName)
   1025 {
   1026 	std::ostringstream op;
   1027 
   1028 	switch (matType)
   1029 	{
   1030 		case TYPE_FLOAT:		op << varName << ", "		<< varName << ", "			<< varName << "";										break;
   1031 		case TYPE_FLOAT_VEC2:	op << varName << ".x, "		<< varName << ".y, "		<< varName << ".x";										break;
   1032 		case TYPE_FLOAT_VEC3:	op << varName << "";																							break;
   1033 		case TYPE_FLOAT_VEC4:	op << varName << ".x, "		<< varName << ".y, "		<< varName << ".z+"			<< varName << ".w";			break;
   1034 		case TYPE_FLOAT_MAT2:	op << varName << "[0][0], "	<< varName << "[1][0], "	<< varName << "[0][1]+"		<< varName << "[1][1]";		break;
   1035 		case TYPE_FLOAT_MAT3:	op << varName << "[0]+"		<< varName << "[1]+"		<< varName << "[2]";									break;
   1036 		case TYPE_FLOAT_MAT4:	op << varName << "[0].xyz+"	<< varName << "[1].yzw+"	<< varName << "[2].zwx+"	<< varName << "[3].wxy";	break;
   1037 
   1038 		default:
   1039 			DE_ASSERT(DE_FALSE);
   1040 	}
   1041 
   1042 	return op.str();
   1043 }
   1044 
   1045 void ShaderMatrixCase::setupUniforms (int programID, const tcu::Vec4& constCoords)
   1046 {
   1047 	const glw::Functions& gl = m_renderCtx.getFunctions();
   1048 
   1049 	DE_UNREF(constCoords);
   1050 
   1051 	for (int inNdx = 0; inNdx < 2; inNdx++)
   1052 	{
   1053 		const ShaderInput& in = inNdx > 0 ? m_in1 : m_in0;
   1054 
   1055 		if (in.inputType == INPUTTYPE_UNIFORM)
   1056 		{
   1057 			int loc = gl.getUniformLocation(programID, (string("u_in") + de::toString(inNdx)).c_str());
   1058 
   1059 			if (loc < 0)
   1060 				continue;
   1061 
   1062 			switch (in.dataType)
   1063 			{
   1064 				case TYPE_FLOAT:		gl.uniform1f(loc, s_constInFloat[inNdx]);													break;
   1065 				case TYPE_FLOAT_VEC2:	gl.uniform2fv(loc, 1, s_constInVec2[inNdx].getPtr());										break;
   1066 				case TYPE_FLOAT_VEC3:	gl.uniform3fv(loc, 1, s_constInVec3[inNdx].getPtr());										break;
   1067 				case TYPE_FLOAT_VEC4:	gl.uniform4fv(loc, 1, s_constInVec4[inNdx].getPtr());										break;
   1068 				case TYPE_FLOAT_MAT2:	gl.uniformMatrix2fv(loc, 1, GL_FALSE, s_constInMat2[inNdx].getColumnMajorData().getPtr());	break;
   1069 				case TYPE_FLOAT_MAT3:	gl.uniformMatrix3fv(loc, 1, GL_FALSE, s_constInMat3[inNdx].getColumnMajorData().getPtr());	break;
   1070 				case TYPE_FLOAT_MAT4:	gl.uniformMatrix4fv(loc, 1, GL_FALSE, s_constInMat4[inNdx].getColumnMajorData().getPtr());	break;
   1071 				default:
   1072 					DE_ASSERT(false);
   1073 			}
   1074 		}
   1075 	}
   1076 }
   1077 
   1078 ShaderMatrixTests::ShaderMatrixTests (Context& context)
   1079 	: TestCaseGroup(context, "matrix", "Matrix Tests")
   1080 {
   1081 }
   1082 
   1083 ShaderMatrixTests::~ShaderMatrixTests (void)
   1084 {
   1085 }
   1086 
   1087 void ShaderMatrixTests::init (void)
   1088 {
   1089 	static const struct
   1090 	{
   1091 		const char*		name;
   1092 		const char*		desc;
   1093 		MatrixOp		op;
   1094 		bool			extendedInputTypeCases; // !< test with const and uniform types too
   1095 	} ops[] =
   1096 	{
   1097 		{ "add",			"Matrix addition tests",						OP_ADD,				true	},
   1098 		{ "sub",			"Matrix subtraction tests",						OP_SUB,				true	},
   1099 		{ "mul",			"Matrix multiplication tests",					OP_MUL,				true	},
   1100 		{ "div",			"Matrix division tests",						OP_DIV,				true	},
   1101 		{ "matrixcompmult",	"Matrix component-wise multiplication tests",	OP_COMP_MUL,		false	},
   1102 		{ "unary_addition",	"Matrix unary addition tests",					OP_UNARY_PLUS,		false	},
   1103 		{ "negation",		"Matrix negation tests",						OP_NEGATION,		false	},
   1104 		{ "pre_increment",	"Matrix prefix increment tests",				OP_PRE_INCREMENT,	false	},
   1105 		{ "pre_decrement",	"Matrix prefix decrement tests",				OP_PRE_DECREMENT,	false	},
   1106 		{ "post_increment",	"Matrix postfix increment tests",				OP_POST_INCREMENT,	false	},
   1107 		{ "post_decrement",	"Matrix postfix decrement tests",				OP_POST_DECREMENT,	false	},
   1108 		{ "add_assign",		"Matrix add into tests",						OP_ADD_INTO,		false	},
   1109 		{ "sub_assign",		"Matrix subtract from tests",					OP_SUBTRACT_FROM,	false	},
   1110 		{ "mul_assign",		"Matrix multiply into tests",					OP_MULTIPLY_INTO,	false	},
   1111 		{ "div_assign",		"Matrix divide into tests",						OP_DIVIDE_INTO,		false	},
   1112 	};
   1113 
   1114 	struct InputTypeSpec
   1115 	{
   1116 		const char*		name;
   1117 		const char*		desc;
   1118 		InputType		type;
   1119 	};
   1120 	static const InputTypeSpec extendedInputTypes[] =
   1121 	{
   1122 		{ "const",		"Constant matrix input",	INPUTTYPE_CONST		},
   1123 		{ "uniform",	"Uniform matrix input",		INPUTTYPE_UNIFORM	},
   1124 		{ "dynamic",	"Dynamic matrix input",		INPUTTYPE_DYNAMIC	}
   1125 	};
   1126 	static const InputTypeSpec reducedInputTypes[] =
   1127 	{
   1128 		{ "dynamic",	"Dynamic matrix input",		INPUTTYPE_DYNAMIC	}
   1129 	};
   1130 
   1131 	static const DataType matrixTypes[] =
   1132 	{
   1133 		TYPE_FLOAT_MAT2,
   1134 		TYPE_FLOAT_MAT3,
   1135 		TYPE_FLOAT_MAT4
   1136 	};
   1137 
   1138 	static const Precision precisions[] =
   1139 	{
   1140 		PRECISION_LOWP,
   1141 		PRECISION_MEDIUMP,
   1142 		PRECISION_HIGHP
   1143 	};
   1144 
   1145 	for (int opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
   1146 	{
   1147 		const InputTypeSpec*	inTypeList		= (ops[opNdx].extendedInputTypeCases) ? (extendedInputTypes) : (reducedInputTypes);
   1148 		const int				inTypeListSize	= (ops[opNdx].extendedInputTypeCases) ? (DE_LENGTH_OF_ARRAY(extendedInputTypes)) : (DE_LENGTH_OF_ARRAY(reducedInputTypes));
   1149 		const MatrixOp			op				= ops[opNdx].op;
   1150 		tcu::TestCaseGroup*		opGroup			= new tcu::TestCaseGroup(m_testCtx, ops[opNdx].name, ops[opNdx].desc);
   1151 
   1152 		addChild(opGroup);
   1153 
   1154 		for (int inTypeNdx = 0; inTypeNdx < inTypeListSize; inTypeNdx++)
   1155 		{
   1156 			const InputType		inputType	= inTypeList[inTypeNdx].type;
   1157 
   1158 			for (int matTypeNdx = 0; matTypeNdx < DE_LENGTH_OF_ARRAY(matrixTypes); matTypeNdx++)
   1159 			{
   1160 				DataType	matType		= matrixTypes[matTypeNdx];
   1161 				const char*	matTypeName	= getDataTypeName(matType);
   1162 
   1163 				for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
   1164 				{
   1165 					Precision	precision	= precisions[precNdx];
   1166 					const char*	precName	= getPrecisionName(precision);
   1167 					string		baseName	= string(inTypeList[inTypeNdx].name) + "_" + precName + "_" + matTypeName + "_";
   1168 					ShaderInput	matIn		(inputType, matType, precision);
   1169 
   1170 					if (isOperationMatrixScalar(op))
   1171 					{
   1172 						// Matrix-scalar \note For div cases we use uniform input.
   1173 						ShaderInput scalarIn(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, TYPE_FLOAT, precision);
   1174 						opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(),		"Matrix-scalar case", matIn, scalarIn, op, true));
   1175 						opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(),	"Matrix-scalar case", matIn, scalarIn, op, false));
   1176 					}
   1177 
   1178 					if (isOperationMatrixVector(op))
   1179 					{
   1180 						// Matrix-vector.
   1181 						DataType	vecType	= getDataTypeFloatVec(getDataTypeMatrixNumColumns(matType));
   1182 						ShaderInput vecIn	(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, vecType, precision);
   1183 
   1184 						opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(vecType) + "_vertex").c_str(),	"Matrix-vector case", matIn, vecIn, op, true));
   1185 						opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(vecType) + "_fragment").c_str(),	"Matrix-vector case", matIn, vecIn, op, false));
   1186 
   1187 						// Vector-matrix.
   1188 						string vecMatName = string(inTypeList[inTypeNdx].name) + "_" + precName + "_" + getDataTypeName(vecType) + "_" + matTypeName;
   1189 						opGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_vertex").c_str(),		"Vector-matrix case", vecIn, matIn, op, true));
   1190 						opGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_fragment").c_str(),	"Vector-matrix case", vecIn, matIn, op, false));
   1191 					}
   1192 
   1193 					if (isOperationMatrixMatrix(op))
   1194 					{
   1195 						// Matrix-matrix.
   1196 						ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType, precision);
   1197 						opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + matTypeName + "_vertex").c_str(),		"Matrix-matrix case", matIn, otherMatIn, op, true));
   1198 						opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + matTypeName + "_fragment").c_str(),	"Matrix-matrix case", matIn, otherMatIn, op, false));
   1199 					}
   1200 
   1201 					if (isOperationUnary(op))
   1202 					{
   1203 						// op matrix
   1204 						ShaderInput voidInput(INPUTTYPE_LAST, TYPE_LAST, PRECISION_LAST);
   1205 						opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "vertex").c_str(),		"Matrix case", matIn, voidInput, op, true));
   1206 						opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "fragment").c_str(),	"Matrix case", matIn, voidInput, op, false));
   1207 					}
   1208 
   1209 					if (isOperationAssignment(op))
   1210 					{
   1211 						ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType, precision);
   1212 						opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "vertex").c_str(),		"Matrix assignment case", matIn, otherMatIn, op, true));
   1213 						opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "fragment").c_str(),	"Matrix assignment case", matIn, otherMatIn, op, false));
   1214 					}
   1215 				}
   1216 			}
   1217 		}
   1218 	}
   1219 }
   1220 
   1221 } // Functional
   1222 } // gles2
   1223 } // deqp
   1224