• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 indexing (arrays, vector, matrices) tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es2fShaderIndexingTests.hpp"
25 #include "glsShaderRenderCase.hpp"
26 #include "gluShaderUtil.hpp"
27 #include "tcuStringTemplate.hpp"
28 
29 #include "deInt32.h"
30 #include "deMemory.h"
31 
32 #include <map>
33 
34 #include "glwEnums.hpp"
35 #include "glwFunctions.hpp"
36 
37 using namespace std;
38 using namespace tcu;
39 using namespace glu;
40 using namespace deqp::gls;
41 
42 namespace deqp
43 {
44 namespace gles2
45 {
46 namespace Functional
47 {
48 
49 enum IndexAccessType
50 {
51 	INDEXACCESS_STATIC = 0,
52 	INDEXACCESS_DYNAMIC,
53 	INDEXACCESS_STATIC_LOOP,
54 	INDEXACCESS_DYNAMIC_LOOP,
55 
56 	/* Must be next to last, since most loop iterations won't include
57 	 * _CONST
58 	 */
59 	INDEXACCESS_CONST,
60 	INDEXACCESS_LAST
61 };
62 
getIndexAccessTypeName(IndexAccessType accessType)63 static const char* getIndexAccessTypeName (IndexAccessType accessType)
64 {
65 	static const char* s_names[INDEXACCESS_LAST] =
66 	{
67 		"static",
68 		"dynamic",
69 		"static_loop",
70 		"dynamic_loop",
71 		"const",
72 	};
73 
74 	DE_ASSERT(deInBounds32((int)accessType, 0, INDEXACCESS_LAST));
75 	return s_names[(int)accessType];
76 }
77 
78 enum VectorAccessType
79 {
80 	DIRECT = 0,
81 	COMPONENT,
82 	SUBSCRIPT_STATIC,
83 	SUBSCRIPT_DYNAMIC,
84 	SUBSCRIPT_STATIC_LOOP,
85 	SUBSCRIPT_DYNAMIC_LOOP,
86 
87 	VECTORACCESS_LAST
88 };
89 
getVectorAccessTypeName(VectorAccessType accessType)90 static const char* getVectorAccessTypeName (VectorAccessType accessType)
91 {
92 	static const char* s_names[VECTORACCESS_LAST] =
93 	{
94 		"direct",
95 		"component",
96 		"static_subscript",
97 		"dynamic_subscript",
98 		"static_loop_subscript",
99 		"dynamic_loop_subscript"
100 	};
101 
102 	DE_ASSERT(deInBounds32((int)accessType, 0, VECTORACCESS_LAST));
103 	return s_names[(int)accessType];
104 }
105 
106 enum RequirementFlags
107 {
108 	REQUIREMENT_UNIFORM_INDEXING		= (1<<0),
109 	REQUIREMENT_VERTEX_UNIFORM_LOOPS	= (1<<1),
110 	REQUIREMENT_FRAGMENT_UNIFORM_LOOPS	= (1<<2),
111 };
112 
evalArrayCoordsFloat(ShaderEvalContext & c)113 void evalArrayCoordsFloat		(ShaderEvalContext& c) { c.color.x()	= 1.875f * c.coords.x(); }
evalArrayCoordsVec2(ShaderEvalContext & c)114 void evalArrayCoordsVec2		(ShaderEvalContext& c) { c.color.xy()	= 1.875f * c.coords.swizzle(0,1); }
evalArrayCoordsVec3(ShaderEvalContext & c)115 void evalArrayCoordsVec3		(ShaderEvalContext& c) { c.color.xyz()	= 1.875f * c.coords.swizzle(0,1,2); }
evalArrayCoordsVec4(ShaderEvalContext & c)116 void evalArrayCoordsVec4		(ShaderEvalContext& c) { c.color		= 1.875f * c.coords; }
117 
getArrayCoordsEvalFunc(DataType dataType)118 static ShaderEvalFunc getArrayCoordsEvalFunc (DataType dataType)
119 {
120 	if (dataType == TYPE_FLOAT)				return evalArrayCoordsFloat;
121 	else if (dataType == TYPE_FLOAT_VEC2)	return evalArrayCoordsVec2;
122 	else if (dataType == TYPE_FLOAT_VEC3)	return evalArrayCoordsVec3;
123 	else if (dataType == TYPE_FLOAT_VEC4)	return evalArrayCoordsVec4;
124 
125 	DE_FATAL("Invalid data type.");
126 	return NULL;
127 }
128 
evalArrayUniformFloat(ShaderEvalContext & c)129 void evalArrayUniformFloat		(ShaderEvalContext& c) { c.color.x()	= 1.875f * c.constCoords.x(); }
evalArrayUniformVec2(ShaderEvalContext & c)130 void evalArrayUniformVec2		(ShaderEvalContext& c) { c.color.xy()	= 1.875f * c.constCoords.swizzle(0,1); }
evalArrayUniformVec3(ShaderEvalContext & c)131 void evalArrayUniformVec3		(ShaderEvalContext& c) { c.color.xyz()	= 1.875f * c.constCoords.swizzle(0,1,2); }
evalArrayUniformVec4(ShaderEvalContext & c)132 void evalArrayUniformVec4		(ShaderEvalContext& c) { c.color		= 1.875f * c.constCoords; }
133 
getArrayUniformEvalFunc(DataType dataType)134 static ShaderEvalFunc getArrayUniformEvalFunc (DataType dataType)
135 {
136 	if (dataType == TYPE_FLOAT)				return evalArrayUniformFloat;
137 	else if (dataType == TYPE_FLOAT_VEC2)	return evalArrayUniformVec2;
138 	else if (dataType == TYPE_FLOAT_VEC3)	return evalArrayUniformVec3;
139 	else if (dataType == TYPE_FLOAT_VEC4)	return evalArrayUniformVec4;
140 
141 	DE_FATAL("Invalid data type.");
142 	return NULL;
143 }
144 
145 // ShaderIndexingCase
146 
147 class ShaderIndexingCase : public ShaderRenderCase
148 {
149 public:
150 								ShaderIndexingCase		(Context& context, const char* name, const char* description, bool isVertexCase, DataType varType, ShaderEvalFunc evalFunc, deUint32 requirements, const char* vertShaderSource, const char* fragShaderSource);
151 	virtual						~ShaderIndexingCase		(void);
152 
153 	virtual void				init					(void);
154 
155 private:
156 								ShaderIndexingCase		(const ShaderIndexingCase&);	// not allowed!
157 	ShaderIndexingCase&			operator=				(const ShaderIndexingCase&);	// not allowed!
158 
159 	virtual void				setup					(int programID);
160 	virtual void				setupUniforms			(int programID, const Vec4& constCoords);
161 
162 	DataType					m_varType;
163 	deUint32					m_requirements;
164 };
165 
ShaderIndexingCase(Context & context,const char * name,const char * description,bool isVertexCase,DataType varType,ShaderEvalFunc evalFunc,deUint32 requirements,const char * vertShaderSource,const char * fragShaderSource)166 ShaderIndexingCase::ShaderIndexingCase (Context& context, const char* name, const char* description, bool isVertexCase, DataType varType, ShaderEvalFunc evalFunc, deUint32 requirements, const char* vertShaderSource, const char* fragShaderSource)
167 	: ShaderRenderCase	(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, isVertexCase, evalFunc)
168 	, m_requirements	(requirements)
169 {
170 	m_varType			= varType;
171 	m_vertShaderSource	= vertShaderSource;
172 	m_fragShaderSource	= fragShaderSource;
173 }
174 
~ShaderIndexingCase(void)175 ShaderIndexingCase::~ShaderIndexingCase (void)
176 {
177 }
178 
init(void)179 void ShaderIndexingCase::init (void)
180 {
181 	const bool isSupported = !(m_requirements & REQUIREMENT_UNIFORM_INDEXING) &&
182 							 (!(m_requirements & REQUIREMENT_VERTEX_UNIFORM_LOOPS) || m_ctxInfo.isVertexUniformLoopSupported()) &&
183 							 (!(m_requirements & REQUIREMENT_FRAGMENT_UNIFORM_LOOPS) || m_ctxInfo.isFragmentUniformLoopSupported());
184 
185 	try
186 	{
187 		ShaderRenderCase::init();
188 	}
189 	catch (const CompileFailed&)
190 	{
191 		if (!isSupported)
192 			throw tcu::NotSupportedError("Shader is not supported");
193 		else
194 			throw;
195 	}
196 }
197 
setup(int programID)198 void ShaderIndexingCase::setup (int programID)
199 {
200 	DE_UNREF(programID);
201 }
202 
setupUniforms(int programID,const Vec4 & constCoords)203 void ShaderIndexingCase::setupUniforms (int programID, const Vec4& constCoords)
204 {
205 	const glw::Functions& gl = m_renderCtx.getFunctions();
206 
207 	DE_UNREF(constCoords);
208 
209 	int arrLoc = gl.getUniformLocation(programID, "u_arr");
210 	if (arrLoc != -1)
211 	{
212 		//int scalarSize = getDataTypeScalarSize(m_varType);
213 		if (m_varType == TYPE_FLOAT)
214 		{
215 			float arr[4];
216 			arr[0] = constCoords.x();
217 			arr[1] = constCoords.x() * 0.5f;
218 			arr[2] = constCoords.x() * 0.25f;
219 			arr[3] = constCoords.x() * 0.125f;
220 			gl.uniform1fv(arrLoc, 4, &arr[0]);
221 		}
222 		else if (m_varType == TYPE_FLOAT_VEC2)
223 		{
224 			Vec2 arr[4];
225 			arr[0] = constCoords.swizzle(0,1);
226 			arr[1] = constCoords.swizzle(0,1) * 0.5f;
227 			arr[2] = constCoords.swizzle(0,1) * 0.25f;
228 			arr[3] = constCoords.swizzle(0,1) * 0.125f;
229 			gl.uniform2fv(arrLoc, 4, arr[0].getPtr());
230 		}
231 		else if (m_varType == TYPE_FLOAT_VEC3)
232 		{
233 			Vec3 arr[4];
234 			arr[0] = constCoords.swizzle(0,1,2);
235 			arr[1] = constCoords.swizzle(0,1,2) * 0.5f;
236 			arr[2] = constCoords.swizzle(0,1,2) * 0.25f;
237 			arr[3] = constCoords.swizzle(0,1,2) * 0.125f;
238 			gl.uniform3fv(arrLoc, 4, arr[0].getPtr());
239 		}
240 		else if (m_varType == TYPE_FLOAT_VEC4)
241 		{
242 			Vec4 arr[4];
243 			arr[0] = constCoords.swizzle(0,1,2,3);
244 			arr[1] = constCoords.swizzle(0,1,2,3) * 0.5f;
245 			arr[2] = constCoords.swizzle(0,1,2,3) * 0.25f;
246 			arr[3] = constCoords.swizzle(0,1,2,3) * 0.125f;
247 			gl.uniform4fv(arrLoc, 4, arr[0].getPtr());
248 		}
249 		else
250 			throw tcu::TestError("u_arr should not have location assigned in this test case");
251 	}
252 }
253 
254 // Helpers.
255 
createVaryingArrayCase(Context & context,const char * caseName,const char * description,DataType varType,IndexAccessType vertAccess,IndexAccessType fragAccess)256 static ShaderIndexingCase* createVaryingArrayCase (Context& context, const char* caseName, const char* description, DataType varType, IndexAccessType vertAccess, IndexAccessType fragAccess)
257 {
258 	std::ostringstream vtx;
259 	vtx << "attribute highp vec4 a_position;\n";
260 	vtx << "attribute highp vec4 a_coords;\n";
261 	if (vertAccess == INDEXACCESS_DYNAMIC)
262 		vtx << "uniform mediump int ui_zero, ui_one, ui_two, ui_three;\n";
263 	else if (vertAccess == INDEXACCESS_DYNAMIC_LOOP)
264 		vtx << "uniform mediump int ui_four;\n";
265 	vtx << "varying ${PRECISION} ${VAR_TYPE} var[${ARRAY_LEN}];\n";
266 	vtx << "\n";
267 	vtx << "void main()\n";
268 	vtx << "{\n";
269 	vtx << "	gl_Position = a_position;\n";
270 	if (vertAccess == INDEXACCESS_STATIC)
271 	{
272 		vtx << "	var[0] = ${VAR_TYPE}(a_coords);\n";
273 		vtx << "	var[1] = ${VAR_TYPE}(a_coords) * 0.5;\n";
274 		vtx << "	var[2] = ${VAR_TYPE}(a_coords) * 0.25;\n";
275 		vtx << "	var[3] = ${VAR_TYPE}(a_coords) * 0.125;\n";
276 	}
277 	else if (vertAccess == INDEXACCESS_DYNAMIC)
278 	{
279 		vtx << "	var[ui_zero]  = ${VAR_TYPE}(a_coords);\n";
280 		vtx << "	var[ui_one]   = ${VAR_TYPE}(a_coords) * 0.5;\n";
281 		vtx << "	var[ui_two]   = ${VAR_TYPE}(a_coords) * 0.25;\n";
282 		vtx << "	var[ui_three] = ${VAR_TYPE}(a_coords) * 0.125;\n";
283 	}
284 	else if (vertAccess == INDEXACCESS_STATIC_LOOP)
285 	{
286 		vtx << "	${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
287 		vtx << "	for (int i = 0; i < 4; i++)\n";
288 		vtx << "	{\n";
289 		vtx << "		var[i] = ${VAR_TYPE}(coords);\n";
290 		vtx << "		coords = coords * 0.5;\n";
291 		vtx << "	}\n";
292 	}
293 	else
294 	{
295 		DE_ASSERT(vertAccess == INDEXACCESS_DYNAMIC_LOOP);
296 		vtx << "	${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
297 		vtx << "	for (int i = 0; i < ui_four; i++)\n";
298 		vtx << "	{\n";
299 		vtx << "		var[i] = ${VAR_TYPE}(coords);\n";
300 		vtx << "		coords = coords * 0.5;\n";
301 		vtx << "	}\n";
302 	}
303 	vtx << "}\n";
304 
305 	std::ostringstream frag;
306 	frag << "precision mediump int;\n";
307 	if (fragAccess == INDEXACCESS_DYNAMIC)
308 		frag << "uniform mediump int ui_zero, ui_one, ui_two, ui_three;\n";
309 	else if (fragAccess == INDEXACCESS_DYNAMIC_LOOP)
310 		frag << "uniform int ui_four;\n";
311 	frag << "varying ${PRECISION} ${VAR_TYPE} var[${ARRAY_LEN}];\n";
312 	frag << "\n";
313 	frag << "void main()\n";
314 	frag << "{\n";
315 	frag << "	${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
316 	if (fragAccess == INDEXACCESS_STATIC)
317 	{
318 		frag << "	res += var[0];\n";
319 		frag << "	res += var[1];\n";
320 		frag << "	res += var[2];\n";
321 		frag << "	res += var[3];\n";
322 	}
323 	else if (fragAccess == INDEXACCESS_DYNAMIC)
324 	{
325 		frag << "	res += var[ui_zero];\n";
326 		frag << "	res += var[ui_one];\n";
327 		frag << "	res += var[ui_two];\n";
328 		frag << "	res += var[ui_three];\n";
329 	}
330 	else if (fragAccess == INDEXACCESS_STATIC_LOOP)
331 	{
332 		frag << "	for (int i = 0; i < 4; i++)\n";
333 		frag << "		res += var[i];\n";
334 	}
335 	else
336 	{
337 		DE_ASSERT(fragAccess == INDEXACCESS_DYNAMIC_LOOP);
338 		frag << "	for (int i = 0; i < ui_four; i++)\n";
339 		frag << "		res += var[i];\n";
340 	}
341 	frag << "	gl_FragColor = vec4(res${PADDING});\n";
342 	frag << "}\n";
343 
344 	// Fill in shader templates.
345 	map<string, string> params;
346 	params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
347 	params.insert(pair<string, string>("ARRAY_LEN", "4"));
348 	params.insert(pair<string, string>("PRECISION", "mediump"));
349 
350 	if (varType == TYPE_FLOAT)
351 		params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
352 	else if (varType == TYPE_FLOAT_VEC2)
353 		params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
354 	else if (varType == TYPE_FLOAT_VEC3)
355 		params.insert(pair<string, string>("PADDING", ", 1.0"));
356 	else
357 		params.insert(pair<string, string>("PADDING", ""));
358 
359 	StringTemplate vertTemplate(vtx.str().c_str());
360 	StringTemplate fragTemplate(frag.str().c_str());
361 	string vertexShaderSource = vertTemplate.specialize(params);
362 	string fragmentShaderSource = fragTemplate.specialize(params);
363 
364 	ShaderEvalFunc evalFunc = getArrayCoordsEvalFunc(varType);
365 	deUint32 requirements = 0;
366 
367 	if (vertAccess == INDEXACCESS_DYNAMIC || fragAccess == INDEXACCESS_DYNAMIC)
368 		requirements |= REQUIREMENT_UNIFORM_INDEXING;
369 
370 	if (vertAccess == INDEXACCESS_DYNAMIC_LOOP)
371 		requirements |= REQUIREMENT_VERTEX_UNIFORM_LOOPS|REQUIREMENT_UNIFORM_INDEXING;
372 
373 	if (fragAccess == INDEXACCESS_DYNAMIC_LOOP)
374 		requirements |= REQUIREMENT_FRAGMENT_UNIFORM_LOOPS|REQUIREMENT_UNIFORM_INDEXING;
375 
376 	return new ShaderIndexingCase(context, caseName, description, true, varType, evalFunc, requirements, vertexShaderSource.c_str(), fragmentShaderSource.c_str());
377 }
378 
createUniformArrayCase(Context & context,const char * caseName,const char * description,bool isVertexCase,DataType varType,IndexAccessType readAccess)379 static ShaderIndexingCase* createUniformArrayCase (Context& context, const char* caseName, const char* description, bool isVertexCase, DataType varType, IndexAccessType readAccess)
380 {
381 	std::ostringstream vtx;
382 	std::ostringstream frag;
383 	std::ostringstream& op = isVertexCase ? vtx : frag;
384 
385 	vtx << "attribute highp vec4 a_position;\n";
386 	vtx << "attribute highp vec4 a_coords;\n";
387 
388 	if (isVertexCase)
389 	{
390 		vtx << "varying mediump vec4 v_color;\n";
391 		frag << "varying mediump vec4 v_color;\n";
392 	}
393 	else
394 	{
395 		vtx << "varying mediump vec4 v_coords;\n";
396 		frag << "varying mediump vec4 v_coords;\n";
397 	}
398 
399 	if (readAccess == INDEXACCESS_DYNAMIC)
400 		op << "uniform mediump int ui_zero, ui_one, ui_two, ui_three;\n";
401 	else if (readAccess == INDEXACCESS_DYNAMIC_LOOP)
402 		op << "uniform mediump int ui_four;\n";
403 
404 	op << "uniform ${PRECISION} ${VAR_TYPE} u_arr[${ARRAY_LEN}];\n";
405 
406 	vtx << "\n";
407 	vtx << "void main()\n";
408 	vtx << "{\n";
409 	vtx << "	gl_Position = a_position;\n";
410 
411 	frag << "\n";
412 	frag << "void main()\n";
413 	frag << "{\n";
414 
415 	// Read array.
416 	op << "	${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
417 	if (readAccess == INDEXACCESS_STATIC)
418 	{
419 		op << "	res += u_arr[0];\n";
420 		op << "	res += u_arr[1];\n";
421 		op << "	res += u_arr[2];\n";
422 		op << "	res += u_arr[3];\n";
423 	}
424 	else if (readAccess == INDEXACCESS_DYNAMIC)
425 	{
426 		op << "	res += u_arr[ui_zero];\n";
427 		op << "	res += u_arr[ui_one];\n";
428 		op << "	res += u_arr[ui_two];\n";
429 		op << "	res += u_arr[ui_three];\n";
430 	}
431 	else if (readAccess == INDEXACCESS_STATIC_LOOP)
432 	{
433 		op << "	for (int i = 0; i < 4; i++)\n";
434 		op << "		res += u_arr[i];\n";
435 	}
436 	else
437 	{
438 		DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
439 		op << "	for (int i = 0; i < ui_four; i++)\n";
440 		op << "		res += u_arr[i];\n";
441 	}
442 
443 	if (isVertexCase)
444 	{
445 		vtx << "	v_color = vec4(res${PADDING});\n";
446 		frag << "	gl_FragColor = v_color;\n";
447 	}
448 	else
449 	{
450 		vtx << "	v_coords = a_coords;\n";
451 		frag << "	gl_FragColor = vec4(res${PADDING});\n";
452 	}
453 
454 	vtx << "}\n";
455 	frag << "}\n";
456 
457 	// Fill in shader templates.
458 	map<string, string> params;
459 	params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
460 	params.insert(pair<string, string>("ARRAY_LEN", "4"));
461 	params.insert(pair<string, string>("PRECISION", "mediump"));
462 
463 	if (varType == TYPE_FLOAT)
464 		params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
465 	else if (varType == TYPE_FLOAT_VEC2)
466 		params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
467 	else if (varType == TYPE_FLOAT_VEC3)
468 		params.insert(pair<string, string>("PADDING", ", 1.0"));
469 	else
470 		params.insert(pair<string, string>("PADDING", ""));
471 
472 	StringTemplate vertTemplate(vtx.str().c_str());
473 	StringTemplate fragTemplate(frag.str().c_str());
474 	string vertexShaderSource = vertTemplate.specialize(params);
475 	string fragmentShaderSource = fragTemplate.specialize(params);
476 
477 	ShaderEvalFunc evalFunc = getArrayUniformEvalFunc(varType);
478 	deUint32 requirements = 0;
479 
480 	if (readAccess == INDEXACCESS_DYNAMIC)
481 		requirements |= REQUIREMENT_UNIFORM_INDEXING;
482 
483 	if (readAccess == INDEXACCESS_DYNAMIC_LOOP)
484 		requirements |= (isVertexCase ? REQUIREMENT_VERTEX_UNIFORM_LOOPS : REQUIREMENT_FRAGMENT_UNIFORM_LOOPS) | REQUIREMENT_UNIFORM_INDEXING;
485 
486 	return new ShaderIndexingCase(context, caseName, description, isVertexCase, varType, evalFunc, requirements, vertexShaderSource.c_str(), fragmentShaderSource.c_str());
487 }
488 
createTmpArrayCase(Context & context,const char * caseName,const char * description,bool isVertexCase,DataType varType,IndexAccessType writeAccess,IndexAccessType readAccess)489 static ShaderIndexingCase* createTmpArrayCase (Context& context, const char* caseName, const char* description, bool isVertexCase, DataType varType, IndexAccessType writeAccess, IndexAccessType readAccess)
490 {
491 	std::ostringstream vtx;
492 	std::ostringstream frag;
493 	std::ostringstream& op = isVertexCase ? vtx : frag;
494 
495 	vtx << "attribute highp vec4 a_position;\n";
496 	vtx << "attribute highp vec4 a_coords;\n";
497 
498 	if (isVertexCase)
499 	{
500 		vtx << "varying mediump vec4 v_color;\n";
501 		frag << "varying mediump vec4 v_color;\n";
502 	}
503 	else if (writeAccess != INDEXACCESS_CONST)
504 	{
505 		vtx << "varying mediump vec4 v_coords;\n";
506 		frag << "varying mediump vec4 v_coords;\n";
507 	}
508 
509 	if (writeAccess == INDEXACCESS_DYNAMIC || readAccess == INDEXACCESS_DYNAMIC)
510 		op << "uniform mediump int ui_zero, ui_one, ui_two, ui_three;\n";
511 
512 	if (writeAccess == INDEXACCESS_DYNAMIC_LOOP || readAccess == INDEXACCESS_DYNAMIC_LOOP)
513 		op << "uniform mediump int ui_four;\n";
514 
515 	vtx << "\n";
516 	vtx << "void main()\n";
517 	vtx << "{\n";
518 	vtx << "	gl_Position = a_position;\n";
519 
520 	frag << "\n";
521 	frag << "void main()\n";
522 	frag << "{\n";
523 
524 	// Write array.
525 	if (writeAccess != INDEXACCESS_CONST) {
526 		if (isVertexCase)
527 			op << "	${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
528 		else
529 			op << "	${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(v_coords);\n";
530 	}
531 
532 	op << "	${PRECISION} ${VAR_TYPE} arr[${ARRAY_LEN}];\n";
533 	if (writeAccess == INDEXACCESS_STATIC)
534 	{
535 		op << "	arr[0] = ${VAR_TYPE}(coords);\n";
536 		op << "	arr[1] = ${VAR_TYPE}(coords) * 0.5;\n";
537 		op << "	arr[2] = ${VAR_TYPE}(coords) * 0.25;\n";
538 		op << "	arr[3] = ${VAR_TYPE}(coords) * 0.125;\n";
539 	}
540 	else if (writeAccess == INDEXACCESS_CONST)
541 	{
542 		// Not using a loop inside the shader because we want it
543 		// unrolled to encourage the shader compiler to store it as
544 		// constant data.
545 		static const char *constructors[] = {
546 			"0.125",
547 			"0.125, 0.25",
548 			"0.125, 0.25, 0.5",
549 			"0.125, 0.25, 0.5, 1.0"
550 		};
551 		const char *constructor_args =
552 			constructors[getDataTypeNumComponents(varType) - 1];
553 
554 		op << "	arr[0] = ${VAR_TYPE}(" << constructor_args << ");\n";
555 		op << "	arr[1] = ${VAR_TYPE}(" << constructor_args << ") * 0.5;\n";
556 		op << "	arr[2] = ${VAR_TYPE}(" << constructor_args << ") * 0.25;\n";
557 		op << "	arr[3] = ${VAR_TYPE}(" << constructor_args << ") * 0.125;\n";
558 
559 		/* Stuff unused values in the rest of the array. */
560 		op << "	int i = 4;\n";
561 		for (int i = 4; i < 40; i++)
562 			op << "	arr[i++] = ${VAR_TYPE}(" << i << ".0);\n";
563 	}
564 	else if (writeAccess == INDEXACCESS_DYNAMIC)
565 	{
566 		op << "	arr[ui_zero]  = ${VAR_TYPE}(coords);\n";
567 		op << "	arr[ui_one]   = ${VAR_TYPE}(coords) * 0.5;\n";
568 		op << "	arr[ui_two]   = ${VAR_TYPE}(coords) * 0.25;\n";
569 		op << "	arr[ui_three] = ${VAR_TYPE}(coords) * 0.125;\n";
570 	}
571 	else if (writeAccess == INDEXACCESS_STATIC_LOOP)
572 	{
573 		op << "	for (int i = 0; i < 4; i++)\n";
574 		op << "	{\n";
575 		op << "		arr[i] = ${VAR_TYPE}(coords);\n";
576 		op << "		coords = coords * 0.5;\n";
577 		op << "	}\n";
578 	}
579 	else
580 	{
581 		DE_ASSERT(writeAccess == INDEXACCESS_DYNAMIC_LOOP);
582 		op << "	for (int i = 0; i < ui_four; i++)\n";
583 		op << "	{\n";
584 		op << "		arr[i] = ${VAR_TYPE}(coords);\n";
585 		op << "		coords = coords * 0.5;\n";
586 		op << "	}\n";
587 	}
588 
589 	// Read array.
590 	op << "	${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
591 	if (readAccess == INDEXACCESS_STATIC)
592 	{
593 		op << "	res += arr[0];\n";
594 		op << "	res += arr[1];\n";
595 		op << "	res += arr[2];\n";
596 		op << "	res += arr[3];\n";
597 	}
598 	else if (readAccess == INDEXACCESS_DYNAMIC)
599 	{
600 		op << "	res += arr[ui_zero];\n";
601 		op << "	res += arr[ui_one];\n";
602 		op << "	res += arr[ui_two];\n";
603 		op << "	res += arr[ui_three];\n";
604 	}
605 	else if (readAccess == INDEXACCESS_STATIC_LOOP)
606 	{
607 		op << "	for (int i = 0; i < 4; i++)\n";
608 		op << "		res += arr[i];\n";
609 	}
610 	else
611 	{
612 		DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
613 		op << "	for (int i = 0; i < ui_four; i++)\n";
614 		op << "		res += arr[i];\n";
615 	}
616 
617 	if (isVertexCase)
618 	{
619 		vtx << "	v_color = vec4(res${PADDING});\n";
620 		frag << "	gl_FragColor = v_color;\n";
621 	}
622 	else
623 	{
624 		if (writeAccess != INDEXACCESS_CONST)
625 			vtx << "	v_coords = a_coords;\n";
626 		frag << "	gl_FragColor = vec4(res${PADDING});\n";
627 	}
628 
629 	vtx << "}\n";
630 	frag << "}\n";
631 
632 	// Fill in shader templates.
633 	map<string, string> params;
634 	params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
635 	// For const indexing, size the array such that the compiler is
636 	// more likely to optimize the temporary to constants.  4 wasn't
637 	// enough for Mesa's i965 driver to do it, while 40 was enough to
638 	// trigger the pass, and also enough to trigger compile failures
639 	// on the freedreno driver at vec3/vec4 without the optimization
640 	// in place.
641 	if (writeAccess == INDEXACCESS_CONST)
642 		params.insert(pair<string, string>("ARRAY_LEN", "40"));
643 	else
644 		params.insert(pair<string, string>("ARRAY_LEN", "4"));
645 	params.insert(pair<string, string>("PRECISION", "mediump"));
646 
647 	if (varType == TYPE_FLOAT)
648 		params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
649 	else if (varType == TYPE_FLOAT_VEC2)
650 		params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
651 	else if (varType == TYPE_FLOAT_VEC3)
652 		params.insert(pair<string, string>("PADDING", ", 1.0"));
653 	else
654 		params.insert(pair<string, string>("PADDING", ""));
655 
656 	StringTemplate vertTemplate(vtx.str().c_str());
657 	StringTemplate fragTemplate(frag.str().c_str());
658 	string vertexShaderSource = vertTemplate.specialize(params);
659 	string fragmentShaderSource = fragTemplate.specialize(params);
660 
661 	ShaderEvalFunc evalFunc;
662 	if (writeAccess == INDEXACCESS_CONST)
663 		evalFunc = getArrayUniformEvalFunc(varType);
664 	else
665 		evalFunc = getArrayCoordsEvalFunc(varType);
666 	deUint32 requirements = 0;
667 
668 	if (readAccess == INDEXACCESS_DYNAMIC || writeAccess == INDEXACCESS_DYNAMIC)
669 		requirements |= REQUIREMENT_UNIFORM_INDEXING;
670 
671 	if (readAccess == INDEXACCESS_DYNAMIC_LOOP || writeAccess == INDEXACCESS_DYNAMIC_LOOP)
672 		requirements |= (isVertexCase ? REQUIREMENT_VERTEX_UNIFORM_LOOPS : REQUIREMENT_FRAGMENT_UNIFORM_LOOPS) | REQUIREMENT_UNIFORM_INDEXING;
673 
674 	return new ShaderIndexingCase(context, caseName, description, isVertexCase, varType, evalFunc, requirements, vertexShaderSource.c_str(), fragmentShaderSource.c_str());
675 }
676 
677 // VECTOR SUBSCRIPT.
678 
evalSubscriptVec2(ShaderEvalContext & c)679 void evalSubscriptVec2 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y()); }
evalSubscriptVec3(ShaderEvalContext & c)680 void evalSubscriptVec3 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y() + 0.25f*c.coords.z()); }
evalSubscriptVec4(ShaderEvalContext & c)681 void evalSubscriptVec4 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y() + 0.25f*c.coords.z() + 0.125f*c.coords.w()); }
682 
getVectorSubscriptEvalFunc(DataType dataType)683 static ShaderEvalFunc getVectorSubscriptEvalFunc (DataType dataType)
684 {
685 	if (dataType == TYPE_FLOAT_VEC2)		return evalSubscriptVec2;
686 	else if (dataType == TYPE_FLOAT_VEC3)	return evalSubscriptVec3;
687 	else if (dataType == TYPE_FLOAT_VEC4)	return evalSubscriptVec4;
688 
689 	DE_FATAL("Invalid data type.");
690 	return NULL;
691 }
692 
createVectorSubscriptCase(Context & context,const char * caseName,const char * description,bool isVertexCase,DataType varType,VectorAccessType writeAccess,VectorAccessType readAccess)693 static ShaderIndexingCase* createVectorSubscriptCase (Context& context, const char* caseName, const char* description, bool isVertexCase, DataType varType, VectorAccessType writeAccess, VectorAccessType readAccess)
694 {
695 	std::ostringstream vtx;
696 	std::ostringstream frag;
697 	std::ostringstream& op = isVertexCase ? vtx : frag;
698 
699 	int			vecLen		= getDataTypeScalarSize(varType);
700 	const char*	vecLenName	= getIntUniformName(vecLen);
701 
702 	vtx << "attribute highp vec4 a_position;\n";
703 	vtx << "attribute highp vec4 a_coords;\n";
704 
705 	if (isVertexCase)
706 	{
707 		vtx << "varying mediump vec3 v_color;\n";
708 		frag << "varying mediump vec3 v_color;\n";
709 	}
710 	else
711 	{
712 		vtx << "varying mediump vec4 v_coords;\n";
713 		frag << "varying mediump vec4 v_coords;\n";
714 	}
715 
716 	if (writeAccess == SUBSCRIPT_DYNAMIC || readAccess == SUBSCRIPT_DYNAMIC)
717 	{
718 		op << "uniform mediump int ui_zero";
719 		if (vecLen >= 2) op << ", ui_one";
720 		if (vecLen >= 3) op << ", ui_two";
721 		if (vecLen >= 4) op << ", ui_three";
722 		op << ";\n";
723 	}
724 
725 	if (writeAccess == SUBSCRIPT_DYNAMIC_LOOP || readAccess == SUBSCRIPT_DYNAMIC_LOOP)
726 		op << "uniform mediump int " << vecLenName << ";\n";
727 
728 	vtx << "\n";
729 	vtx << "void main()\n";
730 	vtx << "{\n";
731 	vtx << "	gl_Position = a_position;\n";
732 
733 	frag << "\n";
734 	frag << "void main()\n";
735 	frag << "{\n";
736 
737 	// Write vector.
738 	if (isVertexCase)
739 		op << "	${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
740 	else
741 		op << "	${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(v_coords);\n";
742 
743 	op << "	${PRECISION} ${VAR_TYPE} tmp;\n";
744 	if (writeAccess == DIRECT)
745 		op << "	tmp = coords.${SWIZZLE} * vec4(1.0, 0.5, 0.25, 0.125).${SWIZZLE};\n";
746 	else if (writeAccess == COMPONENT)
747 	{
748 		op << "	tmp.x = coords.x;\n";
749 		if (vecLen >= 2) op << "	tmp.y = coords.y * 0.5;\n";
750 		if (vecLen >= 3) op << "	tmp.z = coords.z * 0.25;\n";
751 		if (vecLen >= 4) op << "	tmp.w = coords.w * 0.125;\n";
752 	}
753 	else if (writeAccess == SUBSCRIPT_STATIC)
754 	{
755 		op << "	tmp[0] = coords.x;\n";
756 		if (vecLen >= 2) op << "	tmp[1] = coords.y * 0.5;\n";
757 		if (vecLen >= 3) op << "	tmp[2] = coords.z * 0.25;\n";
758 		if (vecLen >= 4) op << "	tmp[3] = coords.w * 0.125;\n";
759 	}
760 	else if (writeAccess == SUBSCRIPT_DYNAMIC)
761 	{
762 		op << "	tmp[ui_zero]  = coords.x;\n";
763 		if (vecLen >= 2) op << "	tmp[ui_one]   = coords.y * 0.5;\n";
764 		if (vecLen >= 3) op << "	tmp[ui_two]   = coords.z * 0.25;\n";
765 		if (vecLen >= 4) op << "	tmp[ui_three] = coords.w * 0.125;\n";
766 	}
767 	else if (writeAccess == SUBSCRIPT_STATIC_LOOP)
768 	{
769 		op << "	for (int i = 0; i < " << vecLen << "; i++)\n";
770 		op << "	{\n";
771 		op << "		tmp[i] = coords.x;\n";
772 		op << "		coords = coords.${ROT_SWIZZLE} * 0.5;\n";
773 		op << "	}\n";
774 	}
775 	else
776 	{
777 		DE_ASSERT(writeAccess == SUBSCRIPT_DYNAMIC_LOOP);
778 		op << "	for (int i = 0; i < " << vecLenName << "; i++)\n";
779 		op << "	{\n";
780 		op << "		tmp[i] = coords.x;\n";
781 		op << "		coords = coords.${ROT_SWIZZLE} * 0.5;\n";
782 		op << "	}\n";
783 	}
784 
785 	// Read vector.
786 	op << "	${PRECISION} float res = 0.0;\n";
787 	if (readAccess == DIRECT)
788 		op << "	res = dot(tmp, ${VAR_TYPE}(1.0));\n";
789 	else if (readAccess == COMPONENT)
790 	{
791 		op << "	res += tmp.x;\n";
792 		if (vecLen >= 2) op << "	res += tmp.y;\n";
793 		if (vecLen >= 3) op << "	res += tmp.z;\n";
794 		if (vecLen >= 4) op << "	res += tmp.w;\n";
795 	}
796 	else if (readAccess == SUBSCRIPT_STATIC)
797 	{
798 		op << "	res += tmp[0];\n";
799 		if (vecLen >= 2) op << "	res += tmp[1];\n";
800 		if (vecLen >= 3) op << "	res += tmp[2];\n";
801 		if (vecLen >= 4) op << "	res += tmp[3];\n";
802 	}
803 	else if (readAccess == SUBSCRIPT_DYNAMIC)
804 	{
805 		op << "	res += tmp[ui_zero];\n";
806 		if (vecLen >= 2) op << "	res += tmp[ui_one];\n";
807 		if (vecLen >= 3) op << "	res += tmp[ui_two];\n";
808 		if (vecLen >= 4) op << "	res += tmp[ui_three];\n";
809 	}
810 	else if (readAccess == SUBSCRIPT_STATIC_LOOP)
811 	{
812 		op << "	for (int i = 0; i < " << vecLen << "; i++)\n";
813 		op << "		res += tmp[i];\n";
814 	}
815 	else
816 	{
817 		DE_ASSERT(readAccess == SUBSCRIPT_DYNAMIC_LOOP);
818 		op << "	for (int i = 0; i < " << vecLenName << "; i++)\n";
819 		op << "		res += tmp[i];\n";
820 	}
821 
822 	if (isVertexCase)
823 	{
824 		vtx << "	v_color = vec3(res);\n";
825 		frag << "	gl_FragColor = vec4(v_color, 1.0);\n";
826 	}
827 	else
828 	{
829 		vtx << "	v_coords = a_coords;\n";
830 		frag << "	gl_FragColor = vec4(vec3(res), 1.0);\n";
831 	}
832 
833 	vtx << "}\n";
834 	frag << "}\n";
835 
836 	// Fill in shader templates.
837 	static const char* s_swizzles[5]	= { "", "x", "xy", "xyz", "xyzw" };
838 	static const char* s_rotSwizzles[5]	= { "", "x", "yx", "yzx", "yzwx" };
839 
840 	map<string, string> params;
841 	params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
842 	params.insert(pair<string, string>("PRECISION", "mediump"));
843 	params.insert(pair<string, string>("SWIZZLE", s_swizzles[vecLen]));
844 	params.insert(pair<string, string>("ROT_SWIZZLE", s_rotSwizzles[vecLen]));
845 
846 	StringTemplate vertTemplate(vtx.str().c_str());
847 	StringTemplate fragTemplate(frag.str().c_str());
848 	string vertexShaderSource = vertTemplate.specialize(params);
849 	string fragmentShaderSource = fragTemplate.specialize(params);
850 
851 	ShaderEvalFunc evalFunc = getVectorSubscriptEvalFunc(varType);
852 	deUint32 requirements = 0;
853 
854 	if (readAccess == SUBSCRIPT_DYNAMIC || writeAccess == SUBSCRIPT_DYNAMIC)
855 		requirements |= REQUIREMENT_UNIFORM_INDEXING;
856 
857 	if (readAccess == SUBSCRIPT_DYNAMIC_LOOP || writeAccess == SUBSCRIPT_DYNAMIC_LOOP)
858 		requirements |= (isVertexCase ? REQUIREMENT_VERTEX_UNIFORM_LOOPS : REQUIREMENT_FRAGMENT_UNIFORM_LOOPS) | REQUIREMENT_UNIFORM_INDEXING;
859 
860 	return new ShaderIndexingCase(context, caseName, description, isVertexCase, varType, evalFunc, requirements, vertexShaderSource.c_str(), fragmentShaderSource.c_str());
861 }
862 
863 // MATRIX SUBSCRIPT.
864 
evalSubscriptMat2(ShaderEvalContext & c)865 void evalSubscriptMat2 (ShaderEvalContext& c) { c.color.xy() = c.coords.swizzle(0,1) + 0.5f*c.coords.swizzle(1,2); }
evalSubscriptMat3(ShaderEvalContext & c)866 void evalSubscriptMat3 (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2) + 0.5f*c.coords.swizzle(1,2,3) + 0.25f*c.coords.swizzle(2,3,0); }
evalSubscriptMat4(ShaderEvalContext & c)867 void evalSubscriptMat4 (ShaderEvalContext& c) { c.color = c.coords + 0.5f*c.coords.swizzle(1,2,3,0) + 0.25f*c.coords.swizzle(2,3,0,1) + 0.125f*c.coords.swizzle(3,0,1,2); }
868 
getMatrixSubscriptEvalFunc(DataType dataType)869 static ShaderEvalFunc getMatrixSubscriptEvalFunc (DataType dataType)
870 {
871 	if (dataType == TYPE_FLOAT_MAT2)		return evalSubscriptMat2;
872 	else if (dataType == TYPE_FLOAT_MAT3)	return evalSubscriptMat3;
873 	else if (dataType == TYPE_FLOAT_MAT4)	return evalSubscriptMat4;
874 
875 	DE_FATAL("Invalid data type.");
876 	return NULL;
877 }
878 
createMatrixSubscriptCase(Context & context,const char * caseName,const char * description,bool isVertexCase,DataType varType,IndexAccessType writeAccess,IndexAccessType readAccess)879 static ShaderIndexingCase* createMatrixSubscriptCase (Context& context, const char* caseName, const char* description, bool isVertexCase, DataType varType, IndexAccessType writeAccess, IndexAccessType readAccess)
880 {
881 	std::ostringstream vtx;
882 	std::ostringstream frag;
883 	std::ostringstream& op = isVertexCase ? vtx : frag;
884 
885 	int			matSize		= getDataTypeMatrixNumRows(varType);
886 	const char*	matSizeName	= getIntUniformName(matSize);
887 	DataType	vecType		= getDataTypeFloatVec(matSize);
888 
889 	vtx << "attribute highp vec4 a_position;\n";
890 	vtx << "attribute highp vec4 a_coords;\n";
891 
892 	if (isVertexCase)
893 	{
894 		vtx << "varying mediump vec4 v_color;\n";
895 		frag << "varying mediump vec4 v_color;\n";
896 	}
897 	else
898 	{
899 		vtx << "varying mediump vec4 v_coords;\n";
900 		frag << "varying mediump vec4 v_coords;\n";
901 	}
902 
903 	if (writeAccess == INDEXACCESS_DYNAMIC || readAccess == INDEXACCESS_DYNAMIC)
904 	{
905 		op << "uniform mediump int ui_zero";
906 		if (matSize >= 2) op << ", ui_one";
907 		if (matSize >= 3) op << ", ui_two";
908 		if (matSize >= 4) op << ", ui_three";
909 		op << ";\n";
910 	}
911 
912 	if (writeAccess == INDEXACCESS_DYNAMIC_LOOP || readAccess == INDEXACCESS_DYNAMIC_LOOP)
913 		op << "uniform mediump int " << matSizeName << ";\n";
914 
915 	vtx << "\n";
916 	vtx << "void main()\n";
917 	vtx << "{\n";
918 	vtx << "	gl_Position = a_position;\n";
919 
920 	frag << "\n";
921 	frag << "void main()\n";
922 	frag << "{\n";
923 
924 	// Write matrix.
925 	if (isVertexCase)
926 		op << "	${PRECISION} vec4 coords = a_coords;\n";
927 	else
928 		op << "	${PRECISION} vec4 coords = v_coords;\n";
929 
930 	op << "	${PRECISION} ${MAT_TYPE} tmp;\n";
931 	if (writeAccess == INDEXACCESS_STATIC)
932 	{
933 		op << "	tmp[0] = ${VEC_TYPE}(coords);\n";
934 		if (matSize >= 2) op << "	tmp[1] = ${VEC_TYPE}(coords.yzwx) * 0.5;\n";
935 		if (matSize >= 3) op << "	tmp[2] = ${VEC_TYPE}(coords.zwxy) * 0.25;\n";
936 		if (matSize >= 4) op << "	tmp[3] = ${VEC_TYPE}(coords.wxyz) * 0.125;\n";
937 	}
938 	else if (writeAccess == INDEXACCESS_DYNAMIC)
939 	{
940 		op << "	tmp[ui_zero]  = ${VEC_TYPE}(coords);\n";
941 		if (matSize >= 2) op << "	tmp[ui_one]   = ${VEC_TYPE}(coords.yzwx) * 0.5;\n";
942 		if (matSize >= 3) op << "	tmp[ui_two]   = ${VEC_TYPE}(coords.zwxy) * 0.25;\n";
943 		if (matSize >= 4) op << "	tmp[ui_three] = ${VEC_TYPE}(coords.wxyz) * 0.125;\n";
944 	}
945 	else if (writeAccess == INDEXACCESS_STATIC_LOOP)
946 	{
947 		op << "	for (int i = 0; i < " << matSize << "; i++)\n";
948 		op << "	{\n";
949 		op << "		tmp[i] = ${VEC_TYPE}(coords);\n";
950 		op << "		coords = coords.yzwx * 0.5;\n";
951 		op << "	}\n";
952 	}
953 	else
954 	{
955 		DE_ASSERT(writeAccess == INDEXACCESS_DYNAMIC_LOOP);
956 		op << "	for (int i = 0; i < " << matSizeName << "; i++)\n";
957 		op << "	{\n";
958 		op << "		tmp[i] = ${VEC_TYPE}(coords);\n";
959 		op << "		coords = coords.yzwx * 0.5;\n";
960 		op << "	}\n";
961 	}
962 
963 	// Read matrix.
964 	op << "	${PRECISION} ${VEC_TYPE} res = ${VEC_TYPE}(0.0);\n";
965 	if (readAccess == INDEXACCESS_STATIC)
966 	{
967 		op << "	res += tmp[0];\n";
968 		if (matSize >= 2) op << "	res += tmp[1];\n";
969 		if (matSize >= 3) op << "	res += tmp[2];\n";
970 		if (matSize >= 4) op << "	res += tmp[3];\n";
971 	}
972 	else if (readAccess == INDEXACCESS_DYNAMIC)
973 	{
974 		op << "	res += tmp[ui_zero];\n";
975 		if (matSize >= 2) op << "	res += tmp[ui_one];\n";
976 		if (matSize >= 3) op << "	res += tmp[ui_two];\n";
977 		if (matSize >= 4) op << "	res += tmp[ui_three];\n";
978 	}
979 	else if (readAccess == INDEXACCESS_STATIC_LOOP)
980 	{
981 		op << "	for (int i = 0; i < " << matSize << "; i++)\n";
982 		op << "		res += tmp[i];\n";
983 	}
984 	else
985 	{
986 		DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
987 		op << "	for (int i = 0; i < " << matSizeName << "; i++)\n";
988 		op << "		res += tmp[i];\n";
989 	}
990 
991 	if (isVertexCase)
992 	{
993 		vtx << "	v_color = vec4(res${PADDING});\n";
994 		frag << "	gl_FragColor = v_color;\n";
995 	}
996 	else
997 	{
998 		vtx << "	v_coords = a_coords;\n";
999 		frag << "	gl_FragColor = vec4(res${PADDING});\n";
1000 	}
1001 
1002 	vtx << "}\n";
1003 	frag << "}\n";
1004 
1005 	// Fill in shader templates.
1006 	map<string, string> params;
1007 	params.insert(pair<string, string>("MAT_TYPE", getDataTypeName(varType)));
1008 	params.insert(pair<string, string>("VEC_TYPE", getDataTypeName(vecType)));
1009 	params.insert(pair<string, string>("PRECISION", "mediump"));
1010 
1011 	if (matSize == 2)
1012 		params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
1013 	else if (matSize == 3)
1014 		params.insert(pair<string, string>("PADDING", ", 1.0"));
1015 	else
1016 		params.insert(pair<string, string>("PADDING", ""));
1017 
1018 	StringTemplate vertTemplate(vtx.str().c_str());
1019 	StringTemplate fragTemplate(frag.str().c_str());
1020 	string vertexShaderSource = vertTemplate.specialize(params);
1021 	string fragmentShaderSource = fragTemplate.specialize(params);
1022 
1023 	ShaderEvalFunc evalFunc = getMatrixSubscriptEvalFunc(varType);
1024 	deUint32 requirements = 0;
1025 
1026 	if (readAccess == INDEXACCESS_DYNAMIC || writeAccess == INDEXACCESS_DYNAMIC)
1027 		requirements |= REQUIREMENT_UNIFORM_INDEXING;
1028 
1029 	if (readAccess == INDEXACCESS_DYNAMIC_LOOP || writeAccess == INDEXACCESS_DYNAMIC_LOOP)
1030 		requirements |= (isVertexCase ? REQUIREMENT_VERTEX_UNIFORM_LOOPS : REQUIREMENT_FRAGMENT_UNIFORM_LOOPS) | REQUIREMENT_UNIFORM_INDEXING;
1031 
1032 	return new ShaderIndexingCase(context, caseName, description, isVertexCase, varType, evalFunc, requirements, vertexShaderSource.c_str(), fragmentShaderSource.c_str());
1033 }
1034 
1035 // ShaderIndexingTests.
1036 
ShaderIndexingTests(Context & context)1037 ShaderIndexingTests::ShaderIndexingTests(Context& context)
1038 	: TestCaseGroup(context, "indexing", "Indexing Tests")
1039 {
1040 }
1041 
~ShaderIndexingTests(void)1042 ShaderIndexingTests::~ShaderIndexingTests (void)
1043 {
1044 }
1045 
init(void)1046 void ShaderIndexingTests::init (void)
1047 {
1048 	static const ShaderType s_shaderTypes[] =
1049 	{
1050 		SHADERTYPE_VERTEX,
1051 		SHADERTYPE_FRAGMENT
1052 	};
1053 
1054 	static const DataType s_floatAndVecTypes[] =
1055 	{
1056 		TYPE_FLOAT,
1057 		TYPE_FLOAT_VEC2,
1058 		TYPE_FLOAT_VEC3,
1059 		TYPE_FLOAT_VEC4
1060 	};
1061 
1062 	// Varying array access cases.
1063 	{
1064 		TestCaseGroup* varyingGroup = new TestCaseGroup(m_context, "varying_array", "Varying array access tests.");
1065 		addChild(varyingGroup);
1066 
1067 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
1068 		{
1069 			DataType varType = s_floatAndVecTypes[typeNdx];
1070 			for (int vertAccess = 0; vertAccess < INDEXACCESS_CONST; vertAccess++)
1071 			{
1072 				for (int fragAccess = 0; fragAccess < INDEXACCESS_CONST; fragAccess++)
1073 				{
1074 					const char* vertAccessName = getIndexAccessTypeName((IndexAccessType)vertAccess);
1075 					const char* fragAccessName = getIndexAccessTypeName((IndexAccessType)fragAccess);
1076 					string name = string(getDataTypeName(varType)) + "_" + vertAccessName + "_write_" + fragAccessName + "_read";
1077 					string desc = string("Varying array with ") + vertAccessName + " write in vertex shader and " + fragAccessName + " read in fragment shader.";
1078 					varyingGroup->addChild(createVaryingArrayCase(m_context, name.c_str(), desc.c_str(), varType, (IndexAccessType)vertAccess, (IndexAccessType)fragAccess));
1079 				}
1080 			}
1081 		}
1082 	}
1083 
1084 	// Uniform array access cases.
1085 	{
1086 		TestCaseGroup* uniformGroup = new TestCaseGroup(m_context, "uniform_array", "Uniform array access tests.");
1087 		addChild(uniformGroup);
1088 
1089 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
1090 		{
1091 			DataType varType = s_floatAndVecTypes[typeNdx];
1092 			for (int readAccess = 0; readAccess < INDEXACCESS_CONST; readAccess++)
1093 			{
1094 				const char* readAccessName = getIndexAccessTypeName((IndexAccessType)readAccess);
1095 				for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1096 				{
1097 					ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1098 					const char*	shaderTypeName	= getShaderTypeName(shaderType);
1099 					string		name			= string(getDataTypeName(varType)) + "_" + readAccessName + "_read_" + shaderTypeName;
1100 					string		desc			= string("Uniform array with ") + readAccessName + " read in " + shaderTypeName + " shader.";
1101 					bool isVertexCase = ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1102 					uniformGroup->addChild(createUniformArrayCase(m_context, name.c_str(), desc.c_str(), isVertexCase, varType, (IndexAccessType)readAccess));
1103 				}
1104 			}
1105 		}
1106 	}
1107 
1108 	// Temporary array access cases.
1109 	{
1110 		TestCaseGroup* tmpGroup = new TestCaseGroup(m_context, "tmp_array", "Temporary array access tests.");
1111 		addChild(tmpGroup);
1112 
1113 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
1114 		{
1115 			DataType varType = s_floatAndVecTypes[typeNdx];
1116 			for (int writeAccess = 0; writeAccess < INDEXACCESS_LAST; writeAccess++)
1117 			{
1118 				for (int readAccess = 0; readAccess < INDEXACCESS_CONST; readAccess++)
1119 				{
1120 					const char* writeAccessName = getIndexAccessTypeName((IndexAccessType)writeAccess);
1121 					const char* readAccessName = getIndexAccessTypeName((IndexAccessType)readAccess);
1122 
1123 					for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1124 					{
1125 						ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1126 						const char* shaderTypeName	= getShaderTypeName(shaderType);
1127 						string		name			= string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" + readAccessName + "_read_" + shaderTypeName;
1128 						string		desc			= string("Temporary array with ") + writeAccessName + " write and " + readAccessName + " read in " + shaderTypeName + " shader.";
1129 						bool		isVertexCase	= ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1130 						tmpGroup->addChild(createTmpArrayCase(m_context, name.c_str(), desc.c_str(), isVertexCase, varType, (IndexAccessType)writeAccess, (IndexAccessType)readAccess));
1131 					}
1132 				}
1133 			}
1134 		}
1135 	}
1136 
1137 	// Vector indexing with subscripts.
1138 	{
1139 		TestCaseGroup* vecGroup = new TestCaseGroup(m_context, "vector_subscript", "Vector subscript indexing.");
1140 		addChild(vecGroup);
1141 
1142 		static const DataType s_vectorTypes[] =
1143 		{
1144 			TYPE_FLOAT_VEC2,
1145 			TYPE_FLOAT_VEC3,
1146 			TYPE_FLOAT_VEC4
1147 		};
1148 
1149 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_vectorTypes); typeNdx++)
1150 		{
1151 			DataType varType = s_vectorTypes[typeNdx];
1152 			for (int writeAccess = 0; writeAccess < VECTORACCESS_LAST; writeAccess++)
1153 			{
1154 				for (int readAccess = 0; readAccess < VECTORACCESS_LAST; readAccess++)
1155 				{
1156 					const char* writeAccessName = getVectorAccessTypeName((VectorAccessType)writeAccess);
1157 					const char* readAccessName = getVectorAccessTypeName((VectorAccessType)readAccess);
1158 
1159 					for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1160 					{
1161 						ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1162 						const char* shaderTypeName	= getShaderTypeName(shaderType);
1163 						string		name			= string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" + readAccessName + "_read_" + shaderTypeName;
1164 						string		desc			= string("Vector subscript access with ") + writeAccessName + " write and " + readAccessName + " read in " + shaderTypeName + " shader.";
1165 						bool		isVertexCase	= ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1166 						vecGroup->addChild(createVectorSubscriptCase(m_context, name.c_str(), desc.c_str(), isVertexCase, varType, (VectorAccessType)writeAccess, (VectorAccessType)readAccess));
1167 					}
1168 				}
1169 			}
1170 		}
1171 	}
1172 
1173 	// Matrix indexing with subscripts.
1174 	{
1175 		TestCaseGroup* matGroup = new TestCaseGroup(m_context, "matrix_subscript", "Matrix subscript indexing.");
1176 		addChild(matGroup);
1177 
1178 		static const DataType s_matrixTypes[] =
1179 		{
1180 			TYPE_FLOAT_MAT2,
1181 			TYPE_FLOAT_MAT3,
1182 			TYPE_FLOAT_MAT4
1183 		};
1184 
1185 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_matrixTypes); typeNdx++)
1186 		{
1187 			DataType varType = s_matrixTypes[typeNdx];
1188 			for (int writeAccess = 0; writeAccess < INDEXACCESS_CONST; writeAccess++)
1189 			{
1190 				for (int readAccess = 0; readAccess < INDEXACCESS_CONST; readAccess++)
1191 				{
1192 					const char* writeAccessName = getIndexAccessTypeName((IndexAccessType)writeAccess);
1193 					const char* readAccessName = getIndexAccessTypeName((IndexAccessType)readAccess);
1194 
1195 					for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1196 					{
1197 						ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1198 						const char* shaderTypeName	= getShaderTypeName(shaderType);
1199 						string		name			= string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" + readAccessName + "_read_" + shaderTypeName;
1200 						string		desc			= string("Vector subscript access with ") + writeAccessName + " write and " + readAccessName + " read in " + shaderTypeName + " shader.";
1201 						bool		isVertexCase	= ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1202 						matGroup->addChild(createMatrixSubscriptCase(m_context, name.c_str(), desc.c_str(), isVertexCase, varType, (IndexAccessType)writeAccess, (IndexAccessType)readAccess));
1203 					}
1204 				}
1205 			}
1206 		}
1207 	}
1208 }
1209 
1210 } // Functional
1211 } // gles2
1212 } // deqp
1213