• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	/* Must be next to last, since most loop iterations won't include
53 	 * _CONST
54 	 */
55 	INDEXACCESS_CONST,
56 	INDEXACCESS_LAST
57 };
58 
getIndexAccessTypeName(IndexAccessType accessType)59 static const char* getIndexAccessTypeName (IndexAccessType accessType)
60 {
61 	static const char* s_names[INDEXACCESS_LAST] =
62 	{
63 		"static",
64 		"dynamic",
65 		"static_loop",
66 		"dynamic_loop",
67 		"const"
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 
getIntUniformName(int number)134 static const char* getIntUniformName (int number)
135 {
136 	switch (number)
137 	{
138 		case 0:		return "ui_zero";
139 		case 1:		return "ui_one";
140 		case 2:		return "ui_two";
141 		case 3:		return "ui_three";
142 		case 4:		return "ui_four";
143 		case 5:		return "ui_five";
144 		case 6:		return "ui_six";
145 		case 7:		return "ui_seven";
146 		case 8:		return "ui_eight";
147 		case 101:	return "ui_oneHundredOne";
148 		default:
149 			DE_ASSERT(false);
150 			return "";
151 	}
152 }
153 
154 class IndexingTestUniformSetup : public UniformSetup
155 {
156 public:
IndexingTestUniformSetup(const DataType varType,bool usesArray)157 							IndexingTestUniformSetup	(const DataType varType, bool usesArray)
158 								: m_varType(varType)
159 								, m_usesArray(usesArray)
160 							{}
~IndexingTestUniformSetup(void)161 	virtual					~IndexingTestUniformSetup	(void)
162 							{}
163 
164 	virtual void			setup						(ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
165 
166 private:
167 	const DataType			m_varType;
168 	const bool				m_usesArray;
169 };
170 
setup(ShaderRenderCaseInstance & instance,const tcu::Vec4 & constCoords) const171 void IndexingTestUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const
172 {
173 	instance.useUniform(0u, UI_ZERO);
174 	instance.useUniform(1u, UI_ONE);
175 	instance.useUniform(2u, UI_TWO);
176 	instance.useUniform(3u, UI_THREE);
177 	instance.useUniform(4u, UI_FOUR);
178 
179 	if (m_usesArray)
180 	{
181 		Vec4 arr[4];
182 		if (m_varType == TYPE_FLOAT)
183 		{
184 			arr[0] = Vec4(constCoords.x());
185 			arr[1] = Vec4(constCoords.x() * 0.5f);
186 			arr[2] = Vec4(constCoords.x() * 0.25f);
187 			arr[3] = Vec4(constCoords.x() * 0.125f);
188 		}
189 		else if (m_varType == TYPE_FLOAT_VEC2)
190 		{
191 			arr[0] = constCoords.swizzle(0, 1).toWidth<4>();
192 			arr[1] = (constCoords.swizzle(0, 1) * 0.5f).toWidth<4>();
193 			arr[2] = (constCoords.swizzle(0, 1) * 0.25f).toWidth<4>();
194 			arr[3] = (constCoords.swizzle(0, 1) * 0.125f).toWidth<4>();
195 		}
196 		else if (m_varType == TYPE_FLOAT_VEC3)
197 		{
198 			arr[0] = constCoords.swizzle(0, 1, 2).toWidth<4>();
199 			arr[1] = (constCoords.swizzle(0, 1, 2) * 0.5f).toWidth<4>();
200 			arr[2] = (constCoords.swizzle(0, 1, 2) * 0.25f).toWidth<4>();
201 			arr[3] = (constCoords.swizzle(0, 1, 2) * 0.125f).toWidth<4>();
202 		}
203 		else if (m_varType == TYPE_FLOAT_VEC4)
204 		{
205 			arr[0] = constCoords;
206 			arr[1] = constCoords * 0.5f;
207 			arr[2] = constCoords * 0.25f;
208 			arr[3] = constCoords * 0.125f;
209 		}
210 		else
211 			throw tcu::TestError("invalid data type for u_arr");
212 
213 		instance.addUniform(5u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(Vec4) * 4, arr[0].getPtr());
214 	}
215 }
216 
217 // ShaderIndexingCase
218 
219 class ShaderIndexingCase : public ShaderRenderCase
220 {
221 public:
222 								ShaderIndexingCase		(tcu::TestContext&			testCtx,
223 														const std::string&			name,
224 														bool						isVertexCase,
225 														const ShaderEvalFunc		evalFunc,
226 														const std::string&			vertShaderSource,
227 														const std::string&			fragShaderSource,
228 														const DataType				varType,
229 														const bool					usesArray);
230 	virtual						~ShaderIndexingCase		(void);
231 
232 private:
233 								ShaderIndexingCase		(const ShaderIndexingCase&);	// not allowed!
234 	ShaderIndexingCase&			operator=				(const ShaderIndexingCase&);	// not allowed!
235 };
236 
ShaderIndexingCase(tcu::TestContext & testCtx,const std::string & name,const bool isVertexCase,const ShaderEvalFunc evalFunc,const std::string & vertShaderSource,const std::string & fragShaderSource,const DataType varType,const bool usesArray)237 ShaderIndexingCase::ShaderIndexingCase (tcu::TestContext&			testCtx,
238 										const std::string&			name,
239 										const bool					isVertexCase,
240 										const ShaderEvalFunc		evalFunc,
241 										const std::string&			vertShaderSource,
242 										const std::string&			fragShaderSource,
243 										const DataType				varType,
244 										const bool					usesArray)
245 	: ShaderRenderCase(testCtx, name, isVertexCase, evalFunc, new IndexingTestUniformSetup(varType, usesArray), DE_NULL)
246 {
247 	m_vertShaderSource	= vertShaderSource;
248 	m_fragShaderSource	= fragShaderSource;
249 }
250 
~ShaderIndexingCase(void)251 ShaderIndexingCase::~ShaderIndexingCase (void)
252 {
253 }
254 
255 // Test case builders.
256 
createVaryingArrayCase(tcu::TestContext & context,const std::string & caseName,DataType varType,IndexAccessType vertAccess,IndexAccessType fragAccess)257 static de::MovePtr<ShaderIndexingCase> createVaryingArrayCase (tcu::TestContext&	context,
258 															const std::string&		caseName,
259 															DataType				varType,
260 															IndexAccessType			vertAccess,
261 															IndexAccessType			fragAccess)
262 {
263 	std::ostringstream vtx;
264 	vtx << "#version 310 es\n";
265 	vtx << "layout(location = 0) in highp vec4 a_position;\n";
266 	vtx << "layout(location = 1) in highp vec4 a_coords;\n";
267 	if (vertAccess == INDEXACCESS_DYNAMIC)
268 	{
269 		vtx << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
270 		vtx << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
271 		vtx << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
272 		vtx << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
273 	}
274 	else if (vertAccess == INDEXACCESS_DYNAMIC_LOOP)
275 		vtx << "layout(std140, binding = 4) uniform something { mediump int ui_four; };\n";
276 	vtx << "layout(location = 0) out ${PRECISION} ${VAR_TYPE} var[${ARRAY_LEN}];\n";
277 	vtx << "\n";
278 	vtx << "void main()\n";
279 	vtx << "{\n";
280 	vtx << "	gl_Position = a_position;\n";
281 	if (vertAccess == INDEXACCESS_STATIC)
282 	{
283 		vtx << "	var[0] = ${VAR_TYPE}(a_coords);\n";
284 		vtx << "	var[1] = ${VAR_TYPE}(a_coords) * 0.5;\n";
285 		vtx << "	var[2] = ${VAR_TYPE}(a_coords) * 0.25;\n";
286 		vtx << "	var[3] = ${VAR_TYPE}(a_coords) * 0.125;\n";
287 	}
288 	else if (vertAccess == INDEXACCESS_DYNAMIC)
289 	{
290 		vtx << "	var[ui_zero]  = ${VAR_TYPE}(a_coords);\n";
291 		vtx << "	var[ui_one]   = ${VAR_TYPE}(a_coords) * 0.5;\n";
292 		vtx << "	var[ui_two]   = ${VAR_TYPE}(a_coords) * 0.25;\n";
293 		vtx << "	var[ui_three] = ${VAR_TYPE}(a_coords) * 0.125;\n";
294 	}
295 	else if (vertAccess == INDEXACCESS_STATIC_LOOP)
296 	{
297 		vtx << "	${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
298 		vtx << "	for (int i = 0; i < 4; i++)\n";
299 		vtx << "	{\n";
300 		vtx << "		var[i] = ${VAR_TYPE}(coords);\n";
301 		vtx << "		coords = coords * 0.5;\n";
302 		vtx << "	}\n";
303 	}
304 	else
305 	{
306 		DE_ASSERT(vertAccess == INDEXACCESS_DYNAMIC_LOOP);
307 		vtx << "	${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
308 		vtx << "	for (int i = 0; i < ui_four; i++)\n";
309 		vtx << "	{\n";
310 		vtx << "		var[i] = ${VAR_TYPE}(coords);\n";
311 		vtx << "		coords = coords * 0.5;\n";
312 		vtx << "	}\n";
313 	}
314 	vtx << "}\n";
315 
316 	std::ostringstream frag;
317 	frag << "#version 310 es\n";
318 	frag << "precision mediump int;\n";
319 	frag << "layout(location = 0) out mediump vec4 o_color;\n";
320 	if (fragAccess == INDEXACCESS_DYNAMIC)
321 	{
322 		frag << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
323 		frag << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
324 		frag << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
325 		frag << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
326 	}
327 	else if (fragAccess == INDEXACCESS_DYNAMIC_LOOP)
328 		frag << "layout(std140, binding = 4) uniform something4 { mediump int ui_four; };\n";
329 	frag << "layout(location = 0) in ${PRECISION} ${VAR_TYPE} var[${ARRAY_LEN}];\n";
330 	frag << "\n";
331 	frag << "void main()\n";
332 	frag << "{\n";
333 	frag << "	${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
334 	if (fragAccess == INDEXACCESS_STATIC)
335 	{
336 		frag << "	res += var[0];\n";
337 		frag << "	res += var[1];\n";
338 		frag << "	res += var[2];\n";
339 		frag << "	res += var[3];\n";
340 	}
341 	else if (fragAccess == INDEXACCESS_DYNAMIC)
342 	{
343 		frag << "	res += var[ui_zero];\n";
344 		frag << "	res += var[ui_one];\n";
345 		frag << "	res += var[ui_two];\n";
346 		frag << "	res += var[ui_three];\n";
347 	}
348 	else if (fragAccess == INDEXACCESS_STATIC_LOOP)
349 	{
350 		frag << "	for (int i = 0; i < 4; i++)\n";
351 		frag << "		res += var[i];\n";
352 	}
353 	else
354 	{
355 		DE_ASSERT(fragAccess == INDEXACCESS_DYNAMIC_LOOP);
356 		frag << "	for (int i = 0; i < ui_four; i++)\n";
357 		frag << "		res += var[i];\n";
358 	}
359 	frag << "	o_color = vec4(res${PADDING});\n";
360 	frag << "}\n";
361 
362 	// Fill in shader templates.
363 	map<string, string> params;
364 	params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
365 	params.insert(pair<string, string>("ARRAY_LEN", "4"));
366 	params.insert(pair<string, string>("PRECISION", "mediump"));
367 
368 	if (varType == TYPE_FLOAT)
369 		params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
370 	else if (varType == TYPE_FLOAT_VEC2)
371 		params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
372 	else if (varType == TYPE_FLOAT_VEC3)
373 		params.insert(pair<string, string>("PADDING", ", 1.0"));
374 	else
375 		params.insert(pair<string, string>("PADDING", ""));
376 
377 	StringTemplate vertTemplate(vtx.str());
378 	StringTemplate fragTemplate(frag.str());
379 	string vertexShaderSource = vertTemplate.specialize(params);
380 	string fragmentShaderSource = fragTemplate.specialize(params);
381 
382 	ShaderEvalFunc evalFunc = getArrayCoordsEvalFunc(varType);
383 	return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(context, caseName, true, evalFunc, vertexShaderSource, fragmentShaderSource, varType, false));
384 }
385 
createUniformArrayCase(tcu::TestContext & context,const std::string & caseName,bool isVertexCase,DataType varType,IndexAccessType readAccess)386 static de::MovePtr<ShaderIndexingCase> createUniformArrayCase (tcu::TestContext&	context,
387 															const std::string&		caseName,
388 															bool					isVertexCase,
389 															DataType				varType,
390 															IndexAccessType			readAccess)
391 {
392 	std::ostringstream vtx;
393 	std::ostringstream frag;
394 	std::ostringstream& op = isVertexCase ? vtx : frag;
395 
396 	vtx << "#version 310 es\n";
397 	frag << "#version 310 es\n";
398 
399 	vtx << "layout(location = 0) in highp vec4 a_position;\n";
400 	vtx << "layout(location = 1) in highp vec4 a_coords;\n";
401 	frag << "layout(location = 0) out mediump vec4 o_color;\n";
402 
403 	if (isVertexCase)
404 	{
405 		vtx << "layout(location = 0) out mediump vec4 v_color;\n";
406 		frag << "layout(location = 0) in mediump vec4 v_color;\n";
407 	}
408 	else
409 	{
410 		vtx << "layout(location = 0) out mediump vec4 v_coords;\n";
411 		frag << "layout(location = 0) in mediump vec4 v_coords;\n";
412 	}
413 
414 	if (readAccess == INDEXACCESS_DYNAMIC)
415 	{
416 		op << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
417 		op << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
418 		op << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
419 		op << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
420 	}
421 	else if (readAccess == INDEXACCESS_DYNAMIC_LOOP)
422 		op << "layout(std140, binding = 4) uniform something4 { mediump int ui_four; };\n";
423 
424 	op << "layout(std140, binding = 5) uniform something5 { ${PRECISION} ${VAR_TYPE} u_arr[${ARRAY_LEN}]; };\n";
425 
426 	vtx << "\n";
427 	vtx << "void main()\n";
428 	vtx << "{\n";
429 	vtx << "	gl_Position = a_position;\n";
430 
431 	frag << "\n";
432 	frag << "void main()\n";
433 	frag << "{\n";
434 
435 	// Read array.
436 	op << "	${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
437 	if (readAccess == INDEXACCESS_STATIC)
438 	{
439 		op << "	res += u_arr[0];\n";
440 		op << "	res += u_arr[1];\n";
441 		op << "	res += u_arr[2];\n";
442 		op << "	res += u_arr[3];\n";
443 	}
444 	else if (readAccess == INDEXACCESS_DYNAMIC)
445 	{
446 		op << "	res += u_arr[ui_zero];\n";
447 		op << "	res += u_arr[ui_one];\n";
448 		op << "	res += u_arr[ui_two];\n";
449 		op << "	res += u_arr[ui_three];\n";
450 	}
451 	else if (readAccess == INDEXACCESS_STATIC_LOOP)
452 	{
453 		op << "	for (int i = 0; i < 4; i++)\n";
454 		op << "		res += u_arr[i];\n";
455 	}
456 	else
457 	{
458 		DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
459 		op << "	for (int i = 0; i < ui_four; i++)\n";
460 		op << "		res += u_arr[i];\n";
461 	}
462 
463 	if (isVertexCase)
464 	{
465 		vtx << "	v_color = vec4(res${PADDING});\n";
466 		frag << "	o_color = v_color;\n";
467 	}
468 	else
469 	{
470 		vtx << "	v_coords = a_coords;\n";
471 		frag << "	o_color = vec4(res${PADDING});\n";
472 	}
473 
474 	vtx << "}\n";
475 	frag << "}\n";
476 
477 	// Fill in shader templates.
478 	map<string, string> params;
479 	params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
480 	params.insert(pair<string, string>("ARRAY_LEN", "4"));
481 	params.insert(pair<string, string>("PRECISION", "mediump"));
482 
483 	if (varType == TYPE_FLOAT)
484 		params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
485 	else if (varType == TYPE_FLOAT_VEC2)
486 		params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
487 	else if (varType == TYPE_FLOAT_VEC3)
488 		params.insert(pair<string, string>("PADDING", ", 1.0"));
489 	else
490 		params.insert(pair<string, string>("PADDING", ""));
491 
492 	StringTemplate vertTemplate(vtx.str());
493 	StringTemplate fragTemplate(frag.str());
494 	string vertexShaderSource = vertTemplate.specialize(params);
495 	string fragmentShaderSource = fragTemplate.specialize(params);
496 
497 	ShaderEvalFunc evalFunc = getArrayUniformEvalFunc(varType);
498 	return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(context, caseName, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, true));
499 }
500 
createTmpArrayCase(tcu::TestContext & context,const std::string & caseName,bool isVertexCase,DataType varType,IndexAccessType writeAccess,IndexAccessType readAccess)501 static de::MovePtr<ShaderIndexingCase> createTmpArrayCase (tcu::TestContext&	context,
502 														const std::string&		caseName,
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 if (writeAccess != INDEXACCESS_CONST)
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_CONST)
565 	{
566 		// Not using a loop inside the shader because we want it
567 		// unrolled to encourage the shader compiler to store it as
568 		// constant data.
569 		static const char *constructors[] = {
570 			"0.125",
571 			"0.125, 0.25",
572 			"0.125, 0.25, 0.5",
573 			"0.125, 0.25, 0.5, 1.0"
574 		};
575 		const char *constructor_args =
576 			constructors[getDataTypeNumComponents(varType) - 1];
577 
578 		op << "	arr[0] = ${VAR_TYPE}(" << constructor_args << ");\n";
579 		op << "	arr[1] = ${VAR_TYPE}(" << constructor_args << ") * 0.5;\n";
580 		op << "	arr[2] = ${VAR_TYPE}(" << constructor_args << ") * 0.25;\n";
581 		op << "	arr[3] = ${VAR_TYPE}(" << constructor_args << ") * 0.125;\n";
582 
583 		/* Stuff unused values in the rest of the array. */
584 		op << "	int i = 4;\n";
585 		for (int i = 4; i < 40; i++)
586 			op << "	arr[i++] = ${VAR_TYPE}(" << i << ".0);\n";
587 	}
588 	else if (writeAccess == INDEXACCESS_DYNAMIC)
589 	{
590 		op << "	arr[ui_zero]  = ${VAR_TYPE}(coords);\n";
591 		op << "	arr[ui_one]   = ${VAR_TYPE}(coords) * 0.5;\n";
592 		op << "	arr[ui_two]   = ${VAR_TYPE}(coords) * 0.25;\n";
593 		op << "	arr[ui_three] = ${VAR_TYPE}(coords) * 0.125;\n";
594 	}
595 	else if (writeAccess == INDEXACCESS_STATIC_LOOP)
596 	{
597 		op << "	for (int i = 0; i < 4; i++)\n";
598 		op << "	{\n";
599 		op << "		arr[i] = ${VAR_TYPE}(coords);\n";
600 		op << "		coords = coords * 0.5;\n";
601 		op << "	}\n";
602 	}
603 	else
604 	{
605 		DE_ASSERT(writeAccess == INDEXACCESS_DYNAMIC_LOOP);
606 		op << "	for (int i = 0; i < ui_four; i++)\n";
607 		op << "	{\n";
608 		op << "		arr[i] = ${VAR_TYPE}(coords);\n";
609 		op << "		coords = coords * 0.5;\n";
610 		op << "	}\n";
611 	}
612 
613 	// Read array.
614 	op << "	${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
615 	if (readAccess == INDEXACCESS_STATIC)
616 	{
617 		op << "	res += arr[0];\n";
618 		op << "	res += arr[1];\n";
619 		op << "	res += arr[2];\n";
620 		op << "	res += arr[3];\n";
621 	}
622 	else if (readAccess == INDEXACCESS_DYNAMIC)
623 	{
624 		op << "	res += arr[ui_zero];\n";
625 		op << "	res += arr[ui_one];\n";
626 		op << "	res += arr[ui_two];\n";
627 		op << "	res += arr[ui_three];\n";
628 	}
629 	else if (readAccess == INDEXACCESS_STATIC_LOOP)
630 	{
631 		op << "	for (int i = 0; i < 4; i++)\n";
632 		op << "		res += arr[i];\n";
633 	}
634 	else
635 	{
636 		DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
637 		op << "	for (int i = 0; i < ui_four; i++)\n";
638 		op << "		res += arr[i];\n";
639 	}
640 
641 	if (isVertexCase)
642 	{
643 		vtx << "	v_color = vec4(res${PADDING});\n";
644 		frag << "	o_color = v_color;\n";
645 	}
646 	else
647 	{
648 		if (writeAccess != INDEXACCESS_CONST)
649 			vtx << "	v_coords = a_coords;\n";
650 		frag << "	o_color = vec4(res${PADDING});\n";
651 	}
652 
653 	vtx << "}\n";
654 	frag << "}\n";
655 
656 	// Fill in shader templates.
657 	map<string, string> params;
658 	params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
659 	// For const indexing, size the array such that the compiler is
660 	// more likely to optimize the temporary to constants.  40 was
661 	// enough to trigger a compiler failure in Mesa's turnip driver
662 	// without the optimization in place.
663 	if (writeAccess == INDEXACCESS_CONST)
664 		params.insert(pair<string, string>("ARRAY_LEN", "40"));
665 	else
666 		params.insert(pair<string, string>("ARRAY_LEN", "4"));
667 	params.insert(pair<string, string>("PRECISION", "mediump"));
668 
669 	if (varType == TYPE_FLOAT)
670 		params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
671 	else if (varType == TYPE_FLOAT_VEC2)
672 		params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
673 	else if (varType == TYPE_FLOAT_VEC3)
674 		params.insert(pair<string, string>("PADDING", ", 1.0"));
675 	else
676 		params.insert(pair<string, string>("PADDING", ""));
677 
678 	StringTemplate vertTemplate(vtx.str());
679 	StringTemplate fragTemplate(frag.str());
680 	string vertexShaderSource = vertTemplate.specialize(params);
681 	string fragmentShaderSource = fragTemplate.specialize(params);
682 
683 	ShaderEvalFunc evalFunc;
684 	if (writeAccess == INDEXACCESS_CONST)
685 		evalFunc = getArrayUniformEvalFunc(varType);
686 	else
687 		evalFunc = getArrayCoordsEvalFunc(varType);
688 
689 	return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(context, caseName, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, false));
690 }
691 
692 // VECTOR SUBSCRIPT.
693 
evalSubscriptVec2(ShaderEvalContext & c)694 void evalSubscriptVec2 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y()); }
evalSubscriptVec3(ShaderEvalContext & c)695 void evalSubscriptVec3 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y() + 0.25f*c.coords.z()); }
evalSubscriptVec4(ShaderEvalContext & c)696 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()); }
697 
getVectorSubscriptEvalFunc(DataType dataType)698 static ShaderEvalFunc getVectorSubscriptEvalFunc (DataType dataType)
699 {
700 	if (dataType == TYPE_FLOAT_VEC2)		return evalSubscriptVec2;
701 	else if (dataType == TYPE_FLOAT_VEC3)	return evalSubscriptVec3;
702 	else if (dataType == TYPE_FLOAT_VEC4)	return evalSubscriptVec4;
703 
704 	DE_FATAL("Invalid data type.");
705 	return NULL;
706 }
707 
createVectorSubscriptCase(tcu::TestContext & context,const std::string & caseName,bool isVertexCase,DataType varType,VectorAccessType writeAccess,VectorAccessType readAccess)708 static de::MovePtr<ShaderIndexingCase> createVectorSubscriptCase (tcu::TestContext&		context,
709 																const std::string&		caseName,
710 																bool					isVertexCase,
711 																DataType				varType,
712 																VectorAccessType		writeAccess,
713 																VectorAccessType		readAccess)
714 {
715 	std::ostringstream vtx;
716 	std::ostringstream frag;
717 	std::ostringstream& op = isVertexCase ? vtx : frag;
718 
719 	int			vecLen		= getDataTypeScalarSize(varType);
720 	const char*	vecLenName	= getIntUniformName(vecLen);
721 
722 	vtx << "#version 310 es\n";
723 	frag << "#version 310 es\n";
724 
725 	vtx << "layout(location = 0) in highp vec4 a_position;\n";
726 	vtx << "layout(location = 1) in highp vec4 a_coords;\n";
727 	frag << "layout(location = 0) out mediump vec4 o_color;\n";
728 
729 	if (isVertexCase)
730 	{
731 		vtx << "layout(location = 0) out mediump vec3 v_color;\n";
732 		frag << "layout(location = 0) in mediump vec3 v_color;\n";
733 	}
734 	else
735 	{
736 		vtx << "layout(location = 0) out mediump vec4 v_coords;\n";
737 		frag << "layout(location = 0) in mediump vec4 v_coords;\n";
738 	}
739 
740 	if (writeAccess == SUBSCRIPT_DYNAMIC || readAccess == SUBSCRIPT_DYNAMIC)
741 	{
742 		op << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
743 		if (vecLen >= 2) op << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
744 		if (vecLen >= 3) op << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
745 		if (vecLen >= 4) op << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
746 	}
747 
748 	if (writeAccess == SUBSCRIPT_DYNAMIC_LOOP || readAccess == SUBSCRIPT_DYNAMIC_LOOP)
749 		op << "layout(std140, binding = " << vecLen << ") uniform something" << vecLen << " { mediump int " << vecLenName << "; };\n";
750 
751 	vtx << "\n";
752 	vtx << "void main()\n";
753 	vtx << "{\n";
754 	vtx << "	gl_Position = a_position;\n";
755 
756 	frag << "\n";
757 	frag << "void main()\n";
758 	frag << "{\n";
759 
760 	// Write vector.
761 	if (isVertexCase)
762 		op << "	${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
763 	else
764 		op << "	${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(v_coords);\n";
765 
766 	op << "	${PRECISION} ${VAR_TYPE} tmp;\n";
767 	if (writeAccess == DIRECT)
768 		op << "	tmp = coords.${SWIZZLE} * vec4(1.0, 0.5, 0.25, 0.125).${SWIZZLE};\n";
769 	else if (writeAccess == COMPONENT)
770 	{
771 		op << "	tmp.x = coords.x;\n";
772 		if (vecLen >= 2) op << "	tmp.y = coords.y * 0.5;\n";
773 		if (vecLen >= 3) op << "	tmp.z = coords.z * 0.25;\n";
774 		if (vecLen >= 4) op << "	tmp.w = coords.w * 0.125;\n";
775 	}
776 	else if (writeAccess == SUBSCRIPT_STATIC)
777 	{
778 		op << "	tmp[0] = coords.x;\n";
779 		if (vecLen >= 2) op << "	tmp[1] = coords.y * 0.5;\n";
780 		if (vecLen >= 3) op << "	tmp[2] = coords.z * 0.25;\n";
781 		if (vecLen >= 4) op << "	tmp[3] = coords.w * 0.125;\n";
782 	}
783 	else if (writeAccess == SUBSCRIPT_DYNAMIC)
784 	{
785 		op << "	tmp[ui_zero]  = coords.x;\n";
786 		if (vecLen >= 2) op << "	tmp[ui_one]   = coords.y * 0.5;\n";
787 		if (vecLen >= 3) op << "	tmp[ui_two]   = coords.z * 0.25;\n";
788 		if (vecLen >= 4) op << "	tmp[ui_three] = coords.w * 0.125;\n";
789 	}
790 	else if (writeAccess == SUBSCRIPT_STATIC_LOOP)
791 	{
792 		op << "	for (int i = 0; i < " << vecLen << "; i++)\n";
793 		op << "	{\n";
794 		op << "		tmp[i] = coords.x;\n";
795 		op << "		coords = coords.${ROT_SWIZZLE} * 0.5;\n";
796 		op << "	}\n";
797 	}
798 	else
799 	{
800 		DE_ASSERT(writeAccess == SUBSCRIPT_DYNAMIC_LOOP);
801 		op << "	for (int i = 0; i < " << vecLenName << "; i++)\n";
802 		op << "	{\n";
803 		op << "		tmp[i] = coords.x;\n";
804 		op << "		coords = coords.${ROT_SWIZZLE} * 0.5;\n";
805 		op << "	}\n";
806 	}
807 
808 	// Read vector.
809 	op << "	${PRECISION} float res = 0.0;\n";
810 	if (readAccess == DIRECT)
811 		op << "	res = dot(tmp, ${VAR_TYPE}(1.0));\n";
812 	else if (readAccess == COMPONENT)
813 	{
814 		op << "	res += tmp.x;\n";
815 		if (vecLen >= 2) op << "	res += tmp.y;\n";
816 		if (vecLen >= 3) op << "	res += tmp.z;\n";
817 		if (vecLen >= 4) op << "	res += tmp.w;\n";
818 	}
819 	else if (readAccess == SUBSCRIPT_STATIC)
820 	{
821 		op << "	res += tmp[0];\n";
822 		if (vecLen >= 2) op << "	res += tmp[1];\n";
823 		if (vecLen >= 3) op << "	res += tmp[2];\n";
824 		if (vecLen >= 4) op << "	res += tmp[3];\n";
825 	}
826 	else if (readAccess == SUBSCRIPT_DYNAMIC)
827 	{
828 		op << "	res += tmp[ui_zero];\n";
829 		if (vecLen >= 2) op << "	res += tmp[ui_one];\n";
830 		if (vecLen >= 3) op << "	res += tmp[ui_two];\n";
831 		if (vecLen >= 4) op << "	res += tmp[ui_three];\n";
832 	}
833 	else if (readAccess == SUBSCRIPT_STATIC_LOOP)
834 	{
835 		op << "	for (int i = 0; i < " << vecLen << "; i++)\n";
836 		op << "		res += tmp[i];\n";
837 	}
838 	else
839 	{
840 		DE_ASSERT(readAccess == SUBSCRIPT_DYNAMIC_LOOP);
841 		op << "	for (int i = 0; i < " << vecLenName << "; i++)\n";
842 		op << "		res += tmp[i];\n";
843 	}
844 
845 	if (isVertexCase)
846 	{
847 		vtx << "	v_color = vec3(res);\n";
848 		frag << "	o_color = vec4(v_color.rgb, 1.0);\n";
849 	}
850 	else
851 	{
852 		vtx << "	v_coords = a_coords;\n";
853 		frag << "	o_color = vec4(vec3(res), 1.0);\n";
854 	}
855 
856 	vtx << "}\n";
857 	frag << "}\n";
858 
859 	// Fill in shader templates.
860 	static const char* s_swizzles[5]	= { "", "x", "xy", "xyz", "xyzw" };
861 	static const char* s_rotSwizzles[5]	= { "", "x", "yx", "yzx", "yzwx" };
862 
863 	map<string, string> params;
864 	params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
865 	params.insert(pair<string, string>("PRECISION", "mediump"));
866 	params.insert(pair<string, string>("SWIZZLE", s_swizzles[vecLen]));
867 	params.insert(pair<string, string>("ROT_SWIZZLE", s_rotSwizzles[vecLen]));
868 
869 	StringTemplate vertTemplate(vtx.str());
870 	StringTemplate fragTemplate(frag.str());
871 	string vertexShaderSource = vertTemplate.specialize(params);
872 	string fragmentShaderSource = fragTemplate.specialize(params);
873 
874 	ShaderEvalFunc evalFunc = getVectorSubscriptEvalFunc(varType);
875 	return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(context, caseName, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, false));
876 }
877 
878 // MATRIX SUBSCRIPT.
879 
evalSubscriptMat2(ShaderEvalContext & c)880 void evalSubscriptMat2		(ShaderEvalContext& c) { c.color.xy()	= c.coords.swizzle(0,1) + 0.5f*c.coords.swizzle(1,2); }
evalSubscriptMat2x3(ShaderEvalContext & c)881 void evalSubscriptMat2x3	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(0,1,2) + 0.5f*c.coords.swizzle(1,2,3); }
evalSubscriptMat2x4(ShaderEvalContext & c)882 void evalSubscriptMat2x4	(ShaderEvalContext& c) { c.color		= c.coords.swizzle(0,1,2,3) + 0.5f*c.coords.swizzle(1,2,3,0); }
883 
evalSubscriptMat3x2(ShaderEvalContext & c)884 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)885 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)886 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); }
887 
evalSubscriptMat4x2(ShaderEvalContext & c)888 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)889 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)890 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); }
891 
getMatrixSubscriptEvalFunc(DataType dataType)892 static ShaderEvalFunc getMatrixSubscriptEvalFunc (DataType dataType)
893 {
894 	switch (dataType)
895 	{
896 		case TYPE_FLOAT_MAT2:		return evalSubscriptMat2;
897 		case TYPE_FLOAT_MAT2X3:		return evalSubscriptMat2x3;
898 		case TYPE_FLOAT_MAT2X4:		return evalSubscriptMat2x4;
899 		case TYPE_FLOAT_MAT3X2:		return evalSubscriptMat3x2;
900 		case TYPE_FLOAT_MAT3:		return evalSubscriptMat3;
901 		case TYPE_FLOAT_MAT3X4:		return evalSubscriptMat3x4;
902 		case TYPE_FLOAT_MAT4X2:		return evalSubscriptMat4x2;
903 		case TYPE_FLOAT_MAT4X3:		return evalSubscriptMat4x3;
904 		case TYPE_FLOAT_MAT4:		return evalSubscriptMat4;
905 
906 		default:
907 			DE_FATAL("Invalid data type.");
908 			return DE_NULL;
909 	}
910 }
911 
createMatrixSubscriptCase(tcu::TestContext & context,const std::string & caseName,bool isVertexCase,DataType varType,IndexAccessType writeAccess,IndexAccessType readAccess)912 static de::MovePtr<ShaderIndexingCase> createMatrixSubscriptCase (tcu::TestContext&		context,
913 																const std::string&		caseName,
914 																bool					isVertexCase,
915 																DataType				varType,
916 																IndexAccessType			writeAccess,
917 																IndexAccessType			readAccess)
918 {
919 	std::ostringstream vtx;
920 	std::ostringstream frag;
921 	std::ostringstream& op = isVertexCase ? vtx : frag;
922 
923 	int			numCols		= getDataTypeMatrixNumColumns(varType);
924 	int			numRows		= getDataTypeMatrixNumRows(varType);
925 	const char*	matSizeName	= getIntUniformName(numCols);
926 	DataType	vecType		= getDataTypeFloatVec(numRows);
927 
928 	vtx << "#version 310 es\n";
929 	frag << "#version 310 es\n";
930 
931 	vtx << "layout(location = 0) in highp vec4 a_position;\n";
932 	vtx << "layout(location = 1) in highp vec4 a_coords;\n";
933 	frag << "layout(location = 0) out mediump vec4 o_color;\n";
934 
935 	if (isVertexCase)
936 	{
937 		vtx << "layout(location = 0) out mediump vec4 v_color;\n";
938 		frag << "layout(location = 0) in mediump vec4 v_color;\n";
939 	}
940 	else
941 	{
942 		vtx << "layout(location = 0) out mediump vec4 v_coords;\n";
943 		frag << "layout(location = 0) in mediump vec4 v_coords;\n";
944 	}
945 
946 	if (writeAccess == INDEXACCESS_DYNAMIC || readAccess == INDEXACCESS_DYNAMIC)
947 	{
948 		op << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
949 		if (numCols >= 2) op << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
950 		if (numCols >= 3) op << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
951 		if (numCols >= 4) op << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
952 	}
953 
954 	if (writeAccess == INDEXACCESS_DYNAMIC_LOOP || readAccess == INDEXACCESS_DYNAMIC_LOOP)
955 		op << "layout(std140, binding = " << numCols << ") uniform something" << numCols << " { mediump int " << matSizeName << "; };\n";
956 
957 	vtx << "\n";
958 	vtx << "void main()\n";
959 	vtx << "{\n";
960 	vtx << "	gl_Position = a_position;\n";
961 
962 	frag << "\n";
963 	frag << "void main()\n";
964 	frag << "{\n";
965 
966 	// Write matrix.
967 	if (isVertexCase)
968 		op << "	${PRECISION} vec4 coords = a_coords;\n";
969 	else
970 		op << "	${PRECISION} vec4 coords = v_coords;\n";
971 
972 	op << "	${PRECISION} ${MAT_TYPE} tmp;\n";
973 	if (writeAccess == INDEXACCESS_STATIC)
974 	{
975 		op << "	tmp[0] = ${VEC_TYPE}(coords);\n";
976 		if (numCols >= 2) op << "	tmp[1] = ${VEC_TYPE}(coords.yzwx) * 0.5;\n";
977 		if (numCols >= 3) op << "	tmp[2] = ${VEC_TYPE}(coords.zwxy) * 0.25;\n";
978 		if (numCols >= 4) op << "	tmp[3] = ${VEC_TYPE}(coords.wxyz) * 0.125;\n";
979 	}
980 	else if (writeAccess == INDEXACCESS_DYNAMIC)
981 	{
982 		op << "	tmp[ui_zero]  = ${VEC_TYPE}(coords);\n";
983 		if (numCols >= 2) op << "	tmp[ui_one]   = ${VEC_TYPE}(coords.yzwx) * 0.5;\n";
984 		if (numCols >= 3) op << "	tmp[ui_two]   = ${VEC_TYPE}(coords.zwxy) * 0.25;\n";
985 		if (numCols >= 4) op << "	tmp[ui_three] = ${VEC_TYPE}(coords.wxyz) * 0.125;\n";
986 	}
987 	else if (writeAccess == INDEXACCESS_STATIC_LOOP)
988 	{
989 		op << "	for (int i = 0; i < " << numCols << "; i++)\n";
990 		op << "	{\n";
991 		op << "		tmp[i] = ${VEC_TYPE}(coords);\n";
992 		op << "		coords = coords.yzwx * 0.5;\n";
993 		op << "	}\n";
994 	}
995 	else
996 	{
997 		DE_ASSERT(writeAccess == INDEXACCESS_DYNAMIC_LOOP);
998 		op << "	for (int i = 0; i < " << matSizeName << "; i++)\n";
999 		op << "	{\n";
1000 		op << "		tmp[i] = ${VEC_TYPE}(coords);\n";
1001 		op << "		coords = coords.yzwx * 0.5;\n";
1002 		op << "	}\n";
1003 	}
1004 
1005 	// Read matrix.
1006 	op << "	${PRECISION} ${VEC_TYPE} res = ${VEC_TYPE}(0.0);\n";
1007 	if (readAccess == INDEXACCESS_STATIC)
1008 	{
1009 		op << "	res += tmp[0];\n";
1010 		if (numCols >= 2) op << "	res += tmp[1];\n";
1011 		if (numCols >= 3) op << "	res += tmp[2];\n";
1012 		if (numCols >= 4) op << "	res += tmp[3];\n";
1013 	}
1014 	else if (readAccess == INDEXACCESS_DYNAMIC)
1015 	{
1016 		op << "	res += tmp[ui_zero];\n";
1017 		if (numCols >= 2) op << "	res += tmp[ui_one];\n";
1018 		if (numCols >= 3) op << "	res += tmp[ui_two];\n";
1019 		if (numCols >= 4) op << "	res += tmp[ui_three];\n";
1020 	}
1021 	else if (readAccess == INDEXACCESS_STATIC_LOOP)
1022 	{
1023 		op << "	for (int i = 0; i < " << numCols << "; i++)\n";
1024 		op << "		res += tmp[i];\n";
1025 	}
1026 	else
1027 	{
1028 		DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
1029 		op << "	for (int i = 0; i < " << matSizeName << "; i++)\n";
1030 		op << "		res += tmp[i];\n";
1031 	}
1032 
1033 	if (isVertexCase)
1034 	{
1035 		vtx << "	v_color = vec4(res${PADDING});\n";
1036 		frag << "	o_color = v_color;\n";
1037 	}
1038 	else
1039 	{
1040 		vtx << "	v_coords = a_coords;\n";
1041 		frag << "	o_color = vec4(res${PADDING});\n";
1042 	}
1043 
1044 	vtx << "}\n";
1045 	frag << "}\n";
1046 
1047 	// Fill in shader templates.
1048 	map<string, string> params;
1049 	params.insert(pair<string, string>("MAT_TYPE", getDataTypeName(varType)));
1050 	params.insert(pair<string, string>("VEC_TYPE", getDataTypeName(vecType)));
1051 	params.insert(pair<string, string>("PRECISION", "mediump"));
1052 
1053 	if (numRows == 2)
1054 		params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
1055 	else if (numRows == 3)
1056 		params.insert(pair<string, string>("PADDING", ", 1.0"));
1057 	else
1058 		params.insert(pair<string, string>("PADDING", ""));
1059 
1060 	StringTemplate vertTemplate(vtx.str());
1061 	StringTemplate fragTemplate(frag.str());
1062 	string vertexShaderSource = vertTemplate.specialize(params);
1063 	string fragmentShaderSource = fragTemplate.specialize(params);
1064 
1065 	ShaderEvalFunc evalFunc = getMatrixSubscriptEvalFunc(varType);
1066 	return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(context, caseName, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, false));
1067 }
1068 
1069 // ShaderIndexingTests.
1070 
1071 class ShaderIndexingTests : public tcu::TestCaseGroup
1072 {
1073 public:
1074 							ShaderIndexingTests		(tcu::TestContext& context);
1075 	virtual					~ShaderIndexingTests	(void);
1076 
1077 	virtual void			init					(void);
1078 
1079 private:
1080 							ShaderIndexingTests		(const ShaderIndexingTests&);		// not allowed!
1081 	ShaderIndexingTests&	operator=				(const ShaderIndexingTests&);		// not allowed!
1082 };
1083 
ShaderIndexingTests(tcu::TestContext & context)1084 ShaderIndexingTests::ShaderIndexingTests(tcu::TestContext& context)
1085 	: TestCaseGroup(context, "indexing")
1086 {
1087 }
1088 
~ShaderIndexingTests(void)1089 ShaderIndexingTests::~ShaderIndexingTests (void)
1090 {
1091 }
1092 
init(void)1093 void ShaderIndexingTests::init (void)
1094 {
1095 	static const ShaderType s_shaderTypes[] =
1096 	{
1097 		SHADERTYPE_VERTEX,
1098 		SHADERTYPE_FRAGMENT
1099 	};
1100 
1101 	static const DataType s_floatAndVecTypes[] =
1102 	{
1103 		TYPE_FLOAT,
1104 		TYPE_FLOAT_VEC2,
1105 		TYPE_FLOAT_VEC3,
1106 		TYPE_FLOAT_VEC4
1107 	};
1108 
1109 	// Varying array access cases.
1110 	{
1111 		de::MovePtr<TestCaseGroup> varyingGroup(new TestCaseGroup(m_testCtx, "varying_array"));
1112 
1113 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
1114 		{
1115 			DataType varType = s_floatAndVecTypes[typeNdx];
1116 			for (int vertAccess = 0; vertAccess < INDEXACCESS_CONST; vertAccess++)
1117 			{
1118 				for (int fragAccess = 0; fragAccess < INDEXACCESS_CONST; fragAccess++)
1119 				{
1120 					const char* vertAccessName = getIndexAccessTypeName((IndexAccessType)vertAccess);
1121 					const char* fragAccessName = getIndexAccessTypeName((IndexAccessType)fragAccess);
1122 					string name = string(getDataTypeName(varType)) + "_" + vertAccessName + "_write_" + fragAccessName + "_read";
1123 					de::MovePtr<ShaderIndexingCase> testCase(createVaryingArrayCase(m_testCtx, name, varType, (IndexAccessType)vertAccess, (IndexAccessType)fragAccess));
1124 					varyingGroup->addChild(testCase.release());
1125 				}
1126 			}
1127 		}
1128 
1129 		addChild(varyingGroup.release());
1130 	}
1131 
1132 	// Uniform array access cases.
1133 	{
1134 		de::MovePtr<TestCaseGroup> uniformGroup(new TestCaseGroup(m_testCtx, "uniform_array"));
1135 
1136 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
1137 		{
1138 			DataType varType = s_floatAndVecTypes[typeNdx];
1139 			for (int readAccess = 0; readAccess < INDEXACCESS_CONST; readAccess++)
1140 			{
1141 				const char* readAccessName = getIndexAccessTypeName((IndexAccessType)readAccess);
1142 				for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1143 				{
1144 					ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1145 					const char*	shaderTypeName	= getShaderTypeName(shaderType);
1146 					string		name			= string(getDataTypeName(varType)) + "_" + readAccessName + "_read_" + shaderTypeName;
1147 					bool isVertexCase = ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1148 					de::MovePtr<ShaderIndexingCase> testCase(createUniformArrayCase(m_testCtx, name, isVertexCase, varType, (IndexAccessType)readAccess));
1149 					uniformGroup->addChild(testCase.release());
1150 				}
1151 			}
1152 		}
1153 
1154 		addChild(uniformGroup.release());
1155 	}
1156 
1157 	// Temporary array access cases.
1158 	{
1159 		de::MovePtr<TestCaseGroup> tmpGroup(new TestCaseGroup(m_testCtx, "tmp_array"));
1160 
1161 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
1162 		{
1163 			DataType varType = s_floatAndVecTypes[typeNdx];
1164 			for (int writeAccess = 0; writeAccess < INDEXACCESS_LAST; writeAccess++)
1165 			{
1166 				for (int readAccess = 0; readAccess < INDEXACCESS_CONST; readAccess++)
1167 				{
1168 					const char* writeAccessName = getIndexAccessTypeName((IndexAccessType)writeAccess);
1169 					const char* readAccessName = getIndexAccessTypeName((IndexAccessType)readAccess);
1170 
1171 					for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1172 					{
1173 						ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1174 						const char* shaderTypeName	= getShaderTypeName(shaderType);
1175 						string		name			= string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" + readAccessName + "_read_" + shaderTypeName;
1176 						bool		isVertexCase	= ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1177 						de::MovePtr<ShaderIndexingCase> testCase(createTmpArrayCase(m_testCtx, name, isVertexCase, varType, (IndexAccessType)writeAccess, (IndexAccessType)readAccess));
1178 						tmpGroup->addChild(testCase.release());
1179 					}
1180 				}
1181 			}
1182 		}
1183 
1184 		addChild(tmpGroup.release());
1185 	}
1186 
1187 	// Vector indexing with subscripts.
1188 	{
1189 		de::MovePtr<TestCaseGroup> vecGroup(new TestCaseGroup(m_testCtx, "vector_subscript"));
1190 
1191 		static const DataType s_vectorTypes[] =
1192 		{
1193 			TYPE_FLOAT_VEC2,
1194 			TYPE_FLOAT_VEC3,
1195 			TYPE_FLOAT_VEC4
1196 		};
1197 
1198 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_vectorTypes); typeNdx++)
1199 		{
1200 			DataType varType = s_vectorTypes[typeNdx];
1201 			for (int writeAccess = 0; writeAccess < VECTORACCESS_LAST; writeAccess++)
1202 			{
1203 				for (int readAccess = 0; readAccess < VECTORACCESS_LAST; readAccess++)
1204 				{
1205 					const char* writeAccessName = getVectorAccessTypeName((VectorAccessType)writeAccess);
1206 					const char* readAccessName = getVectorAccessTypeName((VectorAccessType)readAccess);
1207 
1208 					for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1209 					{
1210 						ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1211 						const char* shaderTypeName	= getShaderTypeName(shaderType);
1212 						string		name			= string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" + readAccessName + "_read_" + shaderTypeName;
1213 						bool		isVertexCase	= ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1214 						de::MovePtr<ShaderIndexingCase> testCase(createVectorSubscriptCase(m_testCtx, name.c_str(), isVertexCase, varType, (VectorAccessType)writeAccess, (VectorAccessType)readAccess));
1215 						vecGroup->addChild(testCase.release());
1216 					}
1217 				}
1218 			}
1219 		}
1220 
1221 		addChild(vecGroup.release());
1222 	}
1223 
1224 	// Matrix indexing with subscripts.
1225 	{
1226 		de::MovePtr<TestCaseGroup> matGroup(new TestCaseGroup(m_testCtx, "matrix_subscript"));
1227 
1228 		static const DataType s_matrixTypes[] =
1229 		{
1230 			TYPE_FLOAT_MAT2,
1231 			TYPE_FLOAT_MAT2X3,
1232 			TYPE_FLOAT_MAT2X4,
1233 			TYPE_FLOAT_MAT3X2,
1234 			TYPE_FLOAT_MAT3,
1235 			TYPE_FLOAT_MAT3X4,
1236 			TYPE_FLOAT_MAT4X2,
1237 			TYPE_FLOAT_MAT4X3,
1238 			TYPE_FLOAT_MAT4
1239 		};
1240 
1241 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_matrixTypes); typeNdx++)
1242 		{
1243 			DataType varType = s_matrixTypes[typeNdx];
1244 			for (int writeAccess = 0; writeAccess < INDEXACCESS_CONST; writeAccess++)
1245 			{
1246 				for (int readAccess = 0; readAccess < INDEXACCESS_CONST; readAccess++)
1247 				{
1248 					const char* writeAccessName = getIndexAccessTypeName((IndexAccessType)writeAccess);
1249 					const char* readAccessName = getIndexAccessTypeName((IndexAccessType)readAccess);
1250 
1251 					for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1252 					{
1253 						ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1254 						const char* shaderTypeName	= getShaderTypeName(shaderType);
1255 						string		name			= string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" + readAccessName + "_read_" + shaderTypeName;
1256 						bool		isVertexCase	= ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1257 						de::MovePtr<ShaderIndexingCase> testCase(createMatrixSubscriptCase(m_testCtx, name.c_str(), isVertexCase, varType, (IndexAccessType)writeAccess, (IndexAccessType)readAccess));
1258 						matGroup->addChild(testCase.release());
1259 					}
1260 				}
1261 			}
1262 		}
1263 
1264 		addChild(matGroup.release());
1265 	}
1266 }
1267 
1268 } // anonymous
1269 
createIndexingTests(tcu::TestContext & testCtx)1270 tcu::TestCaseGroup* createIndexingTests (tcu::TestContext& testCtx)
1271 {
1272 	return new ShaderIndexingTests(testCtx);
1273 }
1274 
1275 } // sr
1276 } // vkt
1277