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