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