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