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