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