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