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