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