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