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 {
ShaderInputdeqp::gles2::Functional::MatrixCaseUtils::ShaderInput112 	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 
getOperationName(MatrixOp op)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 
getOperationType(MatrixOp op)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 
getOperationTestMatrixType(MatrixOp op)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 
isOperationBinary(MatrixOp op)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 
isOperationMatrixScalar(MatrixOp op)270 static bool isOperationMatrixScalar (MatrixOp op)
271 {
272 	return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV;
273 }
274 
isOperationMatrixVector(MatrixOp op)275 static bool isOperationMatrixVector (MatrixOp op)
276 {
277 	return op == OP_MUL;
278 }
279 
isOperationMatrixMatrix(MatrixOp op)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 
isOperationUnary(MatrixOp op)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 
isOperationValueModifying(MatrixOp op)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 
isOperationAssignment(MatrixOp op)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 
getOperationNature(MatrixOp op)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 
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)338 template <> inline float		getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT>			(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInFloat[inputNdx];	}
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)339 template <> inline tcu::Vec2	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_VEC2>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec2[inputNdx];	}
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)340 template <> inline tcu::Vec3	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_VEC3>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec3[inputNdx];	}
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)341 template <> inline tcu::Vec4	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_VEC4>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec4[inputNdx];	}
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)342 template <> inline tcu::Mat2	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT2>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInMat2[inputNdx];	}
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)343 template <> inline tcu::Mat3	getInputValue<INPUTTYPE_CONST,		TYPE_FLOAT_MAT3>	(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInMat3[inputNdx];	}
getInputValue(const ShaderEvalContext & evalCtx,int 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 
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)346 template <> inline float		getInputValue<INPUTTYPE_DYNAMIC,	TYPE_FLOAT>			(const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.x();					}
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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);			}
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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);		}
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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 
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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 
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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 
getInputValue(const ShaderEvalContext & evalCtx,int inputNdx)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 
reduceToVec3(const tcu::Vec2 & value)383 inline tcu::Vec3 reduceToVec3 (const tcu::Vec2& value) { return value.swizzle(0,1,0); }
reduceToVec3(const tcu::Vec3 & value)384 inline tcu::Vec3 reduceToVec3 (const tcu::Vec3& value) { return value; }
reduceToVec3(const tcu::Vec4 & value)385 inline tcu::Vec3 reduceToVec3 (const tcu::Vec4& value) { return tcu::Vec3(value.x(), value.y(), value.z()+value.w()); }
reduceToVec3(const tcu::Mat2 & value)386 inline tcu::Vec3 reduceToVec3 (const tcu::Mat2& value) { return tcu::Vec3(value(0, 0), value(0, 1), value(1, 0)+value(1, 1)); }
reduceToVec3(const tcu::Mat3 & value)387 inline tcu::Vec3 reduceToVec3 (const tcu::Mat3& value) { return value.getColumn(0) + value.getColumn(1) + value.getColumn(2); }
reduceToVec3(const tcu::Mat4 & value)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>
matrixCompMult(const tcu::Matrix<T,Rows,Cols> & a,const tcu::Matrix<T,Rows,Cols> & b)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>
negate(const tcu::Matrix<T,Rows,Cols> & mat)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>
increment(const tcu::Matrix<T,Rows,Cols> & mat)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>
decrement(const tcu::Matrix<T,Rows,Cols> & mat)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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator452 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator461 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator470 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator479 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator488 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator497 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator506 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator515 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator525 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator535 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator545 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator555 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator564 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator573 	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 {
evaluatedeqp::gles2::Functional::MatrixCaseUtils::Evaluator582 	static void evaluate (ShaderEvalContext& evalCtx)
583 	{
584 		evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) / getInputValue<In1Type, In1DataType>(evalCtx, 1));
585 	}
586 };
587 
getEvalFunc(const ShaderInput & in0,const ShaderInput & in1,MatrixOp op)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>
writeVectorConstructor(std::ostream & str,const tcu::Vector<float,Size> & v)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>
writeMatrixConstructor(std::ostream & str,const tcu::Matrix<float,Rows,Cols> & m)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 
ShaderMatrixCase(Context & context,const char * name,const char * desc,const ShaderInput & in0,const ShaderInput & in1,MatrixOp op,bool isVertexCase)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 
~ShaderMatrixCase(void)765 ShaderMatrixCase::~ShaderMatrixCase (void)
766 {
767 }
768 
init(void)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 
genGLSLMatToVec3Reduction(const glu::DataType & matType,const char * varName)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 
setupUniforms(int programID,const tcu::Vec4 & constCoords)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 
ShaderMatrixTests(Context & context)1078 ShaderMatrixTests::ShaderMatrixTests (Context& context)
1079 	: TestCaseGroup(context, "matrix", "Matrix Tests")
1080 {
1081 }
1082 
~ShaderMatrixTests(void)1083 ShaderMatrixTests::~ShaderMatrixTests (void)
1084 {
1085 }
1086 
init(void)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