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