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