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