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
37using namespace std;
38using namespace tcu;
39using namespace glu;
40using namespace deqp::gls;
41
42namespace deqp
43{
44namespace gles2
45{
46namespace Functional
47{
48
49enum 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
63static 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
78enum 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
90static 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
106enum RequirementFlags
107{
108	REQUIREMENT_UNIFORM_INDEXING		= (1<<0),
109	REQUIREMENT_VERTEX_UNIFORM_LOOPS	= (1<<1),
110	REQUIREMENT_FRAGMENT_UNIFORM_LOOPS	= (1<<2),
111};
112
113void evalArrayCoordsFloat		(ShaderEvalContext& c) { c.color.x()	= 1.875f * c.coords.x(); }
114void evalArrayCoordsVec2		(ShaderEvalContext& c) { c.color.xy()	= 1.875f * c.coords.swizzle(0,1); }
115void evalArrayCoordsVec3		(ShaderEvalContext& c) { c.color.xyz()	= 1.875f * c.coords.swizzle(0,1,2); }
116void evalArrayCoordsVec4		(ShaderEvalContext& c) { c.color		= 1.875f * c.coords; }
117
118static 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
129void evalArrayUniformFloat		(ShaderEvalContext& c) { c.color.x()	= 1.875f * c.constCoords.x(); }
130void evalArrayUniformVec2		(ShaderEvalContext& c) { c.color.xy()	= 1.875f * c.constCoords.swizzle(0,1); }
131void evalArrayUniformVec3		(ShaderEvalContext& c) { c.color.xyz()	= 1.875f * c.constCoords.swizzle(0,1,2); }
132void evalArrayUniformVec4		(ShaderEvalContext& c) { c.color		= 1.875f * c.constCoords; }
133
134static 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
147class ShaderIndexingCase : public ShaderRenderCase
148{
149public:
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
155private:
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
166ShaderIndexingCase::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
175ShaderIndexingCase::~ShaderIndexingCase (void)
176{
177}
178
179void 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
198void ShaderIndexingCase::setup (int programID)
199{
200	DE_UNREF(programID);
201}
202
203void 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
256static 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
379static 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
489static 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
679void evalSubscriptVec2 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y()); }
680void evalSubscriptVec3 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y() + 0.25f*c.coords.z()); }
681void 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
683static 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
693static 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
865void evalSubscriptMat2 (ShaderEvalContext& c) { c.color.xy() = c.coords.swizzle(0,1) + 0.5f*c.coords.swizzle(1,2); }
866void 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); }
867void 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
869static 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
879static 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
1037ShaderIndexingTests::ShaderIndexingTests(Context& context)
1038	: TestCaseGroup(context, "indexing", "Indexing Tests")
1039{
1040}
1041
1042ShaderIndexingTests::~ShaderIndexingTests (void)
1043{
1044}
1045
1046void 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