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