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