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	INDEXACCESS_LAST
57};
58
59static 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
73enum 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
85static 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
101enum RequirementFlags
102{
103	REQUIREMENT_UNIFORM_INDEXING		= (1<<0),
104	REQUIREMENT_VERTEX_UNIFORM_LOOPS	= (1<<1),
105	REQUIREMENT_FRAGMENT_UNIFORM_LOOPS	= (1<<2),
106};
107
108void evalArrayCoordsFloat		(ShaderEvalContext& c) { c.color.x()	= 1.875f * c.coords.x(); }
109void evalArrayCoordsVec2		(ShaderEvalContext& c) { c.color.xy()	= 1.875f * c.coords.swizzle(0,1); }
110void evalArrayCoordsVec3		(ShaderEvalContext& c) { c.color.xyz()	= 1.875f * c.coords.swizzle(0,1,2); }
111void evalArrayCoordsVec4		(ShaderEvalContext& c) { c.color		= 1.875f * c.coords; }
112
113static 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
124void evalArrayUniformFloat		(ShaderEvalContext& c) { c.color.x()	= 1.875f * c.constCoords.x(); }
125void evalArrayUniformVec2		(ShaderEvalContext& c) { c.color.xy()	= 1.875f * c.constCoords.swizzle(0,1); }
126void evalArrayUniformVec3		(ShaderEvalContext& c) { c.color.xyz()	= 1.875f * c.constCoords.swizzle(0,1,2); }
127void evalArrayUniformVec4		(ShaderEvalContext& c) { c.color		= 1.875f * c.constCoords; }
128
129static 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
142class ShaderIndexingCase : public ShaderRenderCase
143{
144public:
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
150private:
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
161ShaderIndexingCase::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
170ShaderIndexingCase::~ShaderIndexingCase (void)
171{
172}
173
174void 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
193void ShaderIndexingCase::setup (int programID)
194{
195	DE_UNREF(programID);
196}
197
198void 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
251static 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
374static 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
484static 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
634void evalSubscriptVec2 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y()); }
635void evalSubscriptVec3 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y() + 0.25f*c.coords.z()); }
636void 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
638static 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
648static 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
820void evalSubscriptMat2 (ShaderEvalContext& c) { c.color.xy() = c.coords.swizzle(0,1) + 0.5f*c.coords.swizzle(1,2); }
821void 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); }
822void 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
824static 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
834static 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
992ShaderIndexingTests::ShaderIndexingTests(Context& context)
993	: TestCaseGroup(context, "indexing", "Indexing Tests")
994{
995}
996
997ShaderIndexingTests::~ShaderIndexingTests (void)
998{
999}
1000
1001void 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