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