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