1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2016 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Shader indexing (arrays, vector, matrices) tests.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktShaderRenderIndexingTests.hpp"
27 #include "vktShaderRender.hpp"
28 #include "gluShaderUtil.hpp"
29 #include "tcuStringTemplate.hpp"
30 
31 #include <map>
32 
33 using namespace std;
34 using namespace tcu;
35 using namespace glu;
36 
37 namespace vkt
38 {
39 namespace sr
40 {
41 
42 namespace
43 {
44 
45 enum IndexAccessType
46 {
47     INDEXACCESS_STATIC = 0,
48     INDEXACCESS_DYNAMIC,
49     INDEXACCESS_STATIC_LOOP,
50     INDEXACCESS_DYNAMIC_LOOP,
51 
52     /* Must be next to last, since most loop iterations won't include
53      * _CONST
54      */
55     INDEXACCESS_CONST,
56     INDEXACCESS_LAST
57 };
58 
getIndexAccessTypeName(IndexAccessType accessType)59 static const char *getIndexAccessTypeName(IndexAccessType accessType)
60 {
61     static const char *s_names[INDEXACCESS_LAST] = {"static", "dynamic", "static_loop", "dynamic_loop", "const"};
62 
63     DE_ASSERT(deInBounds32((int)accessType, 0, INDEXACCESS_LAST));
64     return s_names[(int)accessType];
65 }
66 
67 enum VectorAccessType
68 {
69     DIRECT = 0,
70     COMPONENT,
71     SUBSCRIPT_STATIC,
72     SUBSCRIPT_DYNAMIC,
73     SUBSCRIPT_STATIC_LOOP,
74     SUBSCRIPT_DYNAMIC_LOOP,
75 
76     VECTORACCESS_LAST
77 };
78 
getVectorAccessTypeName(VectorAccessType accessType)79 static const char *getVectorAccessTypeName(VectorAccessType accessType)
80 {
81     static const char *s_names[VECTORACCESS_LAST] = {"direct",
82                                                      "component",
83                                                      "static_subscript",
84                                                      "dynamic_subscript",
85                                                      "static_loop_subscript",
86                                                      "dynamic_loop_subscript"};
87 
88     DE_ASSERT(deInBounds32((int)accessType, 0, VECTORACCESS_LAST));
89     return s_names[(int)accessType];
90 }
91 
evalArrayCoordsFloat(ShaderEvalContext & c)92 void evalArrayCoordsFloat(ShaderEvalContext &c)
93 {
94     c.color.x() = 1.875f * c.coords.x();
95 }
evalArrayCoordsVec2(ShaderEvalContext & c)96 void evalArrayCoordsVec2(ShaderEvalContext &c)
97 {
98     c.color.xy() = 1.875f * c.coords.swizzle(0, 1);
99 }
evalArrayCoordsVec3(ShaderEvalContext & c)100 void evalArrayCoordsVec3(ShaderEvalContext &c)
101 {
102     c.color.xyz() = 1.875f * c.coords.swizzle(0, 1, 2);
103 }
evalArrayCoordsVec4(ShaderEvalContext & c)104 void evalArrayCoordsVec4(ShaderEvalContext &c)
105 {
106     c.color = 1.875f * c.coords;
107 }
108 
getArrayCoordsEvalFunc(DataType dataType)109 static ShaderEvalFunc getArrayCoordsEvalFunc(DataType dataType)
110 {
111     if (dataType == TYPE_FLOAT)
112         return evalArrayCoordsFloat;
113     else if (dataType == TYPE_FLOAT_VEC2)
114         return evalArrayCoordsVec2;
115     else if (dataType == TYPE_FLOAT_VEC3)
116         return evalArrayCoordsVec3;
117     else if (dataType == TYPE_FLOAT_VEC4)
118         return evalArrayCoordsVec4;
119 
120     DE_FATAL("Invalid data type.");
121     return NULL;
122 }
123 
evalArrayUniformFloat(ShaderEvalContext & c)124 void evalArrayUniformFloat(ShaderEvalContext &c)
125 {
126     c.color.x() = 1.875f * c.constCoords.x();
127 }
evalArrayUniformVec2(ShaderEvalContext & c)128 void evalArrayUniformVec2(ShaderEvalContext &c)
129 {
130     c.color.xy() = 1.875f * c.constCoords.swizzle(0, 1);
131 }
evalArrayUniformVec3(ShaderEvalContext & c)132 void evalArrayUniformVec3(ShaderEvalContext &c)
133 {
134     c.color.xyz() = 1.875f * c.constCoords.swizzle(0, 1, 2);
135 }
evalArrayUniformVec4(ShaderEvalContext & c)136 void evalArrayUniformVec4(ShaderEvalContext &c)
137 {
138     c.color = 1.875f * c.constCoords;
139 }
140 
getArrayUniformEvalFunc(DataType dataType)141 static ShaderEvalFunc getArrayUniformEvalFunc(DataType dataType)
142 {
143     if (dataType == TYPE_FLOAT)
144         return evalArrayUniformFloat;
145     else if (dataType == TYPE_FLOAT_VEC2)
146         return evalArrayUniformVec2;
147     else if (dataType == TYPE_FLOAT_VEC3)
148         return evalArrayUniformVec3;
149     else if (dataType == TYPE_FLOAT_VEC4)
150         return evalArrayUniformVec4;
151 
152     DE_FATAL("Invalid data type.");
153     return NULL;
154 }
155 
getIntUniformName(int number)156 static const char *getIntUniformName(int number)
157 {
158     switch (number)
159     {
160     case 0:
161         return "ui_zero";
162     case 1:
163         return "ui_one";
164     case 2:
165         return "ui_two";
166     case 3:
167         return "ui_three";
168     case 4:
169         return "ui_four";
170     case 5:
171         return "ui_five";
172     case 6:
173         return "ui_six";
174     case 7:
175         return "ui_seven";
176     case 8:
177         return "ui_eight";
178     case 101:
179         return "ui_oneHundredOne";
180     default:
181         DE_ASSERT(false);
182         return "";
183     }
184 }
185 
186 class IndexingTestUniformSetup : public UniformSetup
187 {
188 public:
IndexingTestUniformSetup(const DataType varType,bool usesArray)189     IndexingTestUniformSetup(const DataType varType, bool usesArray) : m_varType(varType), m_usesArray(usesArray)
190     {
191     }
~IndexingTestUniformSetup(void)192     virtual ~IndexingTestUniformSetup(void)
193     {
194     }
195 
196     virtual void setup(ShaderRenderCaseInstance &instance, const tcu::Vec4 &constCoords) const;
197 
198 private:
199     const DataType m_varType;
200     const bool m_usesArray;
201 };
202 
setup(ShaderRenderCaseInstance & instance,const tcu::Vec4 & constCoords) const203 void IndexingTestUniformSetup::setup(ShaderRenderCaseInstance &instance, const tcu::Vec4 &constCoords) const
204 {
205     instance.useUniform(0u, UI_ZERO);
206     instance.useUniform(1u, UI_ONE);
207     instance.useUniform(2u, UI_TWO);
208     instance.useUniform(3u, UI_THREE);
209     instance.useUniform(4u, UI_FOUR);
210 
211     if (m_usesArray)
212     {
213         Vec4 arr[4];
214         if (m_varType == TYPE_FLOAT)
215         {
216             arr[0] = Vec4(constCoords.x());
217             arr[1] = Vec4(constCoords.x() * 0.5f);
218             arr[2] = Vec4(constCoords.x() * 0.25f);
219             arr[3] = Vec4(constCoords.x() * 0.125f);
220         }
221         else if (m_varType == TYPE_FLOAT_VEC2)
222         {
223             arr[0] = constCoords.swizzle(0, 1).toWidth<4>();
224             arr[1] = (constCoords.swizzle(0, 1) * 0.5f).toWidth<4>();
225             arr[2] = (constCoords.swizzle(0, 1) * 0.25f).toWidth<4>();
226             arr[3] = (constCoords.swizzle(0, 1) * 0.125f).toWidth<4>();
227         }
228         else if (m_varType == TYPE_FLOAT_VEC3)
229         {
230             arr[0] = constCoords.swizzle(0, 1, 2).toWidth<4>();
231             arr[1] = (constCoords.swizzle(0, 1, 2) * 0.5f).toWidth<4>();
232             arr[2] = (constCoords.swizzle(0, 1, 2) * 0.25f).toWidth<4>();
233             arr[3] = (constCoords.swizzle(0, 1, 2) * 0.125f).toWidth<4>();
234         }
235         else if (m_varType == TYPE_FLOAT_VEC4)
236         {
237             arr[0] = constCoords;
238             arr[1] = constCoords * 0.5f;
239             arr[2] = constCoords * 0.25f;
240             arr[3] = constCoords * 0.125f;
241         }
242         else
243             throw tcu::TestError("invalid data type for u_arr");
244 
245         instance.addUniform(5u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(Vec4) * 4, arr[0].getPtr());
246     }
247 }
248 
249 // ShaderIndexingCase
250 
251 class ShaderIndexingCase : public ShaderRenderCase
252 {
253 public:
254     ShaderIndexingCase(tcu::TestContext &testCtx, const std::string &name, bool isVertexCase,
255                        const ShaderEvalFunc evalFunc, const std::string &vertShaderSource,
256                        const std::string &fragShaderSource, const DataType varType, const bool usesArray);
257     virtual ~ShaderIndexingCase(void);
258 
259 private:
260     ShaderIndexingCase(const ShaderIndexingCase &);            // not allowed!
261     ShaderIndexingCase &operator=(const ShaderIndexingCase &); // not allowed!
262 };
263 
ShaderIndexingCase(tcu::TestContext & testCtx,const std::string & name,const bool isVertexCase,const ShaderEvalFunc evalFunc,const std::string & vertShaderSource,const std::string & fragShaderSource,const DataType varType,const bool usesArray)264 ShaderIndexingCase::ShaderIndexingCase(tcu::TestContext &testCtx, const std::string &name, const bool isVertexCase,
265                                        const ShaderEvalFunc evalFunc, const std::string &vertShaderSource,
266                                        const std::string &fragShaderSource, const DataType varType,
267                                        const bool usesArray)
268     : ShaderRenderCase(testCtx, name, isVertexCase, evalFunc, new IndexingTestUniformSetup(varType, usesArray), DE_NULL)
269 {
270     m_vertShaderSource = vertShaderSource;
271     m_fragShaderSource = fragShaderSource;
272 }
273 
~ShaderIndexingCase(void)274 ShaderIndexingCase::~ShaderIndexingCase(void)
275 {
276 }
277 
278 // Test case builders.
279 
createVaryingArrayCase(tcu::TestContext & context,const std::string & caseName,DataType varType,IndexAccessType vertAccess,IndexAccessType fragAccess)280 static de::MovePtr<ShaderIndexingCase> createVaryingArrayCase(tcu::TestContext &context, const std::string &caseName,
281                                                               DataType varType, IndexAccessType vertAccess,
282                                                               IndexAccessType fragAccess)
283 {
284     std::ostringstream vtx;
285     vtx << "#version 310 es\n";
286     vtx << "layout(location = 0) in highp vec4 a_position;\n";
287     vtx << "layout(location = 1) in highp vec4 a_coords;\n";
288     if (vertAccess == INDEXACCESS_DYNAMIC)
289     {
290         vtx << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
291         vtx << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
292         vtx << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
293         vtx << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
294     }
295     else if (vertAccess == INDEXACCESS_DYNAMIC_LOOP)
296         vtx << "layout(std140, binding = 4) uniform something { mediump int ui_four; };\n";
297     vtx << "layout(location = 0) out ${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 << "#version 310 es\n";
339     frag << "precision mediump int;\n";
340     frag << "layout(location = 0) out mediump vec4 o_color;\n";
341     if (fragAccess == INDEXACCESS_DYNAMIC)
342     {
343         frag << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
344         frag << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
345         frag << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
346         frag << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
347     }
348     else if (fragAccess == INDEXACCESS_DYNAMIC_LOOP)
349         frag << "layout(std140, binding = 4) uniform something4 { mediump int ui_four; };\n";
350     frag << "layout(location = 0) in ${PRECISION} ${VAR_TYPE} var[${ARRAY_LEN}];\n";
351     frag << "\n";
352     frag << "void main()\n";
353     frag << "{\n";
354     frag << "    ${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
355     if (fragAccess == INDEXACCESS_STATIC)
356     {
357         frag << "    res += var[0];\n";
358         frag << "    res += var[1];\n";
359         frag << "    res += var[2];\n";
360         frag << "    res += var[3];\n";
361     }
362     else if (fragAccess == INDEXACCESS_DYNAMIC)
363     {
364         frag << "    res += var[ui_zero];\n";
365         frag << "    res += var[ui_one];\n";
366         frag << "    res += var[ui_two];\n";
367         frag << "    res += var[ui_three];\n";
368     }
369     else if (fragAccess == INDEXACCESS_STATIC_LOOP)
370     {
371         frag << "    for (int i = 0; i < 4; i++)\n";
372         frag << "        res += var[i];\n";
373     }
374     else
375     {
376         DE_ASSERT(fragAccess == INDEXACCESS_DYNAMIC_LOOP);
377         frag << "    for (int i = 0; i < ui_four; i++)\n";
378         frag << "        res += var[i];\n";
379     }
380     frag << "    o_color = vec4(res${PADDING});\n";
381     frag << "}\n";
382 
383     // Fill in shader templates.
384     map<string, string> params;
385     params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
386     params.insert(pair<string, string>("ARRAY_LEN", "4"));
387     params.insert(pair<string, string>("PRECISION", "mediump"));
388 
389     if (varType == TYPE_FLOAT)
390         params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
391     else if (varType == TYPE_FLOAT_VEC2)
392         params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
393     else if (varType == TYPE_FLOAT_VEC3)
394         params.insert(pair<string, string>("PADDING", ", 1.0"));
395     else
396         params.insert(pair<string, string>("PADDING", ""));
397 
398     StringTemplate vertTemplate(vtx.str());
399     StringTemplate fragTemplate(frag.str());
400     string vertexShaderSource   = vertTemplate.specialize(params);
401     string fragmentShaderSource = fragTemplate.specialize(params);
402 
403     ShaderEvalFunc evalFunc = getArrayCoordsEvalFunc(varType);
404     return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(context, caseName, true, evalFunc, vertexShaderSource,
405                                                                   fragmentShaderSource, varType, false));
406 }
407 
createUniformArrayCase(tcu::TestContext & context,const std::string & caseName,bool isVertexCase,DataType varType,IndexAccessType readAccess)408 static de::MovePtr<ShaderIndexingCase> createUniformArrayCase(tcu::TestContext &context, const std::string &caseName,
409                                                               bool isVertexCase, DataType varType,
410                                                               IndexAccessType readAccess)
411 {
412     std::ostringstream vtx;
413     std::ostringstream frag;
414     std::ostringstream &op = isVertexCase ? vtx : frag;
415 
416     vtx << "#version 310 es\n";
417     frag << "#version 310 es\n";
418 
419     vtx << "layout(location = 0) in highp vec4 a_position;\n";
420     vtx << "layout(location = 1) in highp vec4 a_coords;\n";
421     frag << "layout(location = 0) out mediump vec4 o_color;\n";
422 
423     if (isVertexCase)
424     {
425         vtx << "layout(location = 0) out mediump vec4 v_color;\n";
426         frag << "layout(location = 0) in mediump vec4 v_color;\n";
427     }
428     else
429     {
430         vtx << "layout(location = 0) out mediump vec4 v_coords;\n";
431         frag << "layout(location = 0) in mediump vec4 v_coords;\n";
432     }
433 
434     if (readAccess == INDEXACCESS_DYNAMIC)
435     {
436         op << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
437         op << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
438         op << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
439         op << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
440     }
441     else if (readAccess == INDEXACCESS_DYNAMIC_LOOP)
442         op << "layout(std140, binding = 4) uniform something4 { mediump int ui_four; };\n";
443 
444     op << "layout(std140, binding = 5) uniform something5 { ${PRECISION} ${VAR_TYPE} u_arr[${ARRAY_LEN}]; };\n";
445 
446     vtx << "\n";
447     vtx << "void main()\n";
448     vtx << "{\n";
449     vtx << "    gl_Position = a_position;\n";
450 
451     frag << "\n";
452     frag << "void main()\n";
453     frag << "{\n";
454 
455     // Read array.
456     op << "    ${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
457     if (readAccess == INDEXACCESS_STATIC)
458     {
459         op << "    res += u_arr[0];\n";
460         op << "    res += u_arr[1];\n";
461         op << "    res += u_arr[2];\n";
462         op << "    res += u_arr[3];\n";
463     }
464     else if (readAccess == INDEXACCESS_DYNAMIC)
465     {
466         op << "    res += u_arr[ui_zero];\n";
467         op << "    res += u_arr[ui_one];\n";
468         op << "    res += u_arr[ui_two];\n";
469         op << "    res += u_arr[ui_three];\n";
470     }
471     else if (readAccess == INDEXACCESS_STATIC_LOOP)
472     {
473         op << "    for (int i = 0; i < 4; i++)\n";
474         op << "        res += u_arr[i];\n";
475     }
476     else
477     {
478         DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
479         op << "    for (int i = 0; i < ui_four; i++)\n";
480         op << "        res += u_arr[i];\n";
481     }
482 
483     if (isVertexCase)
484     {
485         vtx << "    v_color = vec4(res${PADDING});\n";
486         frag << "    o_color = v_color;\n";
487     }
488     else
489     {
490         vtx << "    v_coords = a_coords;\n";
491         frag << "    o_color = vec4(res${PADDING});\n";
492     }
493 
494     vtx << "}\n";
495     frag << "}\n";
496 
497     // Fill in shader templates.
498     map<string, string> params;
499     params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
500     params.insert(pair<string, string>("ARRAY_LEN", "4"));
501     params.insert(pair<string, string>("PRECISION", "mediump"));
502 
503     if (varType == TYPE_FLOAT)
504         params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
505     else if (varType == TYPE_FLOAT_VEC2)
506         params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
507     else if (varType == TYPE_FLOAT_VEC3)
508         params.insert(pair<string, string>("PADDING", ", 1.0"));
509     else
510         params.insert(pair<string, string>("PADDING", ""));
511 
512     StringTemplate vertTemplate(vtx.str());
513     StringTemplate fragTemplate(frag.str());
514     string vertexShaderSource   = vertTemplate.specialize(params);
515     string fragmentShaderSource = fragTemplate.specialize(params);
516 
517     ShaderEvalFunc evalFunc = getArrayUniformEvalFunc(varType);
518     return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(
519         context, caseName, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, true));
520 }
521 
createTmpArrayCase(tcu::TestContext & context,const std::string & caseName,bool isVertexCase,DataType varType,IndexAccessType writeAccess,IndexAccessType readAccess)522 static de::MovePtr<ShaderIndexingCase> createTmpArrayCase(tcu::TestContext &context, const std::string &caseName,
523                                                           bool isVertexCase, DataType varType,
524                                                           IndexAccessType writeAccess, IndexAccessType readAccess)
525 {
526     std::ostringstream vtx;
527     std::ostringstream frag;
528     std::ostringstream &op = isVertexCase ? vtx : frag;
529 
530     vtx << "#version 310 es\n";
531     frag << "#version 310 es\n";
532 
533     vtx << "layout(location = 0) in highp vec4 a_position;\n";
534     vtx << "layout(location = 1) in highp vec4 a_coords;\n";
535     frag << "layout(location = 0) out mediump vec4 o_color;\n";
536 
537     if (isVertexCase)
538     {
539         vtx << "layout(location = 0) out mediump vec4 v_color;\n";
540         frag << "layout(location = 0) in mediump vec4 v_color;\n";
541     }
542     else
543     {
544         vtx << "layout(location = 0) out mediump vec4 v_coords;\n";
545         frag << "layout(location = 0) in mediump vec4 v_coords;\n";
546     }
547 
548     if (writeAccess == INDEXACCESS_DYNAMIC || readAccess == INDEXACCESS_DYNAMIC)
549     {
550         op << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
551         op << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
552         op << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
553         op << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
554     }
555 
556     if (writeAccess == INDEXACCESS_DYNAMIC_LOOP || readAccess == INDEXACCESS_DYNAMIC_LOOP)
557         op << "layout(std140, binding = 4) uniform something4 { mediump int ui_four; };\n";
558 
559     vtx << "\n";
560     vtx << "void main()\n";
561     vtx << "{\n";
562     vtx << "    gl_Position = a_position;\n";
563 
564     frag << "\n";
565     frag << "void main()\n";
566     frag << "{\n";
567 
568     // Write array.
569     if (isVertexCase)
570         op << "    ${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
571     else if (writeAccess != INDEXACCESS_CONST)
572         op << "    ${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(v_coords);\n";
573 
574     op << "    ${PRECISION} ${VAR_TYPE} arr[${ARRAY_LEN}];\n";
575     if (writeAccess == INDEXACCESS_STATIC)
576     {
577         op << "    arr[0] = ${VAR_TYPE}(coords);\n";
578         op << "    arr[1] = ${VAR_TYPE}(coords) * 0.5;\n";
579         op << "    arr[2] = ${VAR_TYPE}(coords) * 0.25;\n";
580         op << "    arr[3] = ${VAR_TYPE}(coords) * 0.125;\n";
581     }
582     else if (writeAccess == INDEXACCESS_CONST)
583     {
584         // Not using a loop inside the shader because we want it
585         // unrolled to encourage the shader compiler to store it as
586         // constant data.
587         static const char *constructors[] = {"0.125", "0.125, 0.25", "0.125, 0.25, 0.5", "0.125, 0.25, 0.5, 1.0"};
588         const char *constructor_args      = constructors[getDataTypeNumComponents(varType) - 1];
589 
590         op << "    arr[0] = ${VAR_TYPE}(" << constructor_args << ");\n";
591         op << "    arr[1] = ${VAR_TYPE}(" << constructor_args << ") * 0.5;\n";
592         op << "    arr[2] = ${VAR_TYPE}(" << constructor_args << ") * 0.25;\n";
593         op << "    arr[3] = ${VAR_TYPE}(" << constructor_args << ") * 0.125;\n";
594 
595         /* Stuff unused values in the rest of the array. */
596         op << "    int i = 4;\n";
597         for (int i = 4; i < 40; i++)
598             op << "    arr[i++] = ${VAR_TYPE}(" << i << ".0);\n";
599     }
600     else if (writeAccess == INDEXACCESS_DYNAMIC)
601     {
602         op << "    arr[ui_zero]  = ${VAR_TYPE}(coords);\n";
603         op << "    arr[ui_one]   = ${VAR_TYPE}(coords) * 0.5;\n";
604         op << "    arr[ui_two]   = ${VAR_TYPE}(coords) * 0.25;\n";
605         op << "    arr[ui_three] = ${VAR_TYPE}(coords) * 0.125;\n";
606     }
607     else if (writeAccess == INDEXACCESS_STATIC_LOOP)
608     {
609         op << "    for (int i = 0; i < 4; i++)\n";
610         op << "    {\n";
611         op << "        arr[i] = ${VAR_TYPE}(coords);\n";
612         op << "        coords = coords * 0.5;\n";
613         op << "    }\n";
614     }
615     else
616     {
617         DE_ASSERT(writeAccess == INDEXACCESS_DYNAMIC_LOOP);
618         op << "    for (int i = 0; i < ui_four; i++)\n";
619         op << "    {\n";
620         op << "        arr[i] = ${VAR_TYPE}(coords);\n";
621         op << "        coords = coords * 0.5;\n";
622         op << "    }\n";
623     }
624 
625     // Read array.
626     op << "    ${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
627     if (readAccess == INDEXACCESS_STATIC)
628     {
629         op << "    res += arr[0];\n";
630         op << "    res += arr[1];\n";
631         op << "    res += arr[2];\n";
632         op << "    res += arr[3];\n";
633     }
634     else if (readAccess == INDEXACCESS_DYNAMIC)
635     {
636         op << "    res += arr[ui_zero];\n";
637         op << "    res += arr[ui_one];\n";
638         op << "    res += arr[ui_two];\n";
639         op << "    res += arr[ui_three];\n";
640     }
641     else if (readAccess == INDEXACCESS_STATIC_LOOP)
642     {
643         op << "    for (int i = 0; i < 4; i++)\n";
644         op << "        res += arr[i];\n";
645     }
646     else
647     {
648         DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
649         op << "    for (int i = 0; i < ui_four; i++)\n";
650         op << "        res += arr[i];\n";
651     }
652 
653     if (isVertexCase)
654     {
655         vtx << "    v_color = vec4(res${PADDING});\n";
656         frag << "    o_color = v_color;\n";
657     }
658     else
659     {
660         if (writeAccess != INDEXACCESS_CONST)
661             vtx << "    v_coords = a_coords;\n";
662         frag << "    o_color = vec4(res${PADDING});\n";
663     }
664 
665     vtx << "}\n";
666     frag << "}\n";
667 
668     // Fill in shader templates.
669     map<string, string> params;
670     params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
671     // For const indexing, size the array such that the compiler is
672     // more likely to optimize the temporary to constants.  40 was
673     // enough to trigger a compiler failure in Mesa's turnip driver
674     // without the optimization in place.
675     if (writeAccess == INDEXACCESS_CONST)
676         params.insert(pair<string, string>("ARRAY_LEN", "40"));
677     else
678         params.insert(pair<string, string>("ARRAY_LEN", "4"));
679     params.insert(pair<string, string>("PRECISION", "mediump"));
680 
681     if (varType == TYPE_FLOAT)
682         params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
683     else if (varType == TYPE_FLOAT_VEC2)
684         params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
685     else if (varType == TYPE_FLOAT_VEC3)
686         params.insert(pair<string, string>("PADDING", ", 1.0"));
687     else
688         params.insert(pair<string, string>("PADDING", ""));
689 
690     StringTemplate vertTemplate(vtx.str());
691     StringTemplate fragTemplate(frag.str());
692     string vertexShaderSource   = vertTemplate.specialize(params);
693     string fragmentShaderSource = fragTemplate.specialize(params);
694 
695     ShaderEvalFunc evalFunc;
696     if (writeAccess == INDEXACCESS_CONST)
697         evalFunc = getArrayUniformEvalFunc(varType);
698     else
699         evalFunc = getArrayCoordsEvalFunc(varType);
700 
701     return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(
702         context, caseName, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, false));
703 }
704 
705 // VECTOR SUBSCRIPT.
706 
evalSubscriptVec2(ShaderEvalContext & c)707 void evalSubscriptVec2(ShaderEvalContext &c)
708 {
709     c.color.xyz() = Vec3(c.coords.x() + 0.5f * c.coords.y());
710 }
evalSubscriptVec3(ShaderEvalContext & c)711 void evalSubscriptVec3(ShaderEvalContext &c)
712 {
713     c.color.xyz() = Vec3(c.coords.x() + 0.5f * c.coords.y() + 0.25f * c.coords.z());
714 }
evalSubscriptVec4(ShaderEvalContext & c)715 void evalSubscriptVec4(ShaderEvalContext &c)
716 {
717     c.color.xyz() = Vec3(c.coords.x() + 0.5f * c.coords.y() + 0.25f * c.coords.z() + 0.125f * c.coords.w());
718 }
719 
getVectorSubscriptEvalFunc(DataType dataType)720 static ShaderEvalFunc getVectorSubscriptEvalFunc(DataType dataType)
721 {
722     if (dataType == TYPE_FLOAT_VEC2)
723         return evalSubscriptVec2;
724     else if (dataType == TYPE_FLOAT_VEC3)
725         return evalSubscriptVec3;
726     else if (dataType == TYPE_FLOAT_VEC4)
727         return evalSubscriptVec4;
728 
729     DE_FATAL("Invalid data type.");
730     return NULL;
731 }
732 
createVectorSubscriptCase(tcu::TestContext & context,const std::string & caseName,bool isVertexCase,DataType varType,VectorAccessType writeAccess,VectorAccessType readAccess)733 static de::MovePtr<ShaderIndexingCase> createVectorSubscriptCase(tcu::TestContext &context, const std::string &caseName,
734                                                                  bool isVertexCase, DataType varType,
735                                                                  VectorAccessType writeAccess,
736                                                                  VectorAccessType readAccess)
737 {
738     std::ostringstream vtx;
739     std::ostringstream frag;
740     std::ostringstream &op = isVertexCase ? vtx : frag;
741 
742     int vecLen             = getDataTypeScalarSize(varType);
743     const char *vecLenName = getIntUniformName(vecLen);
744 
745     vtx << "#version 310 es\n";
746     frag << "#version 310 es\n";
747 
748     vtx << "layout(location = 0) in highp vec4 a_position;\n";
749     vtx << "layout(location = 1) in highp vec4 a_coords;\n";
750     frag << "layout(location = 0) out mediump vec4 o_color;\n";
751 
752     if (isVertexCase)
753     {
754         vtx << "layout(location = 0) out mediump vec3 v_color;\n";
755         frag << "layout(location = 0) in mediump vec3 v_color;\n";
756     }
757     else
758     {
759         vtx << "layout(location = 0) out mediump vec4 v_coords;\n";
760         frag << "layout(location = 0) in mediump vec4 v_coords;\n";
761     }
762 
763     if (writeAccess == SUBSCRIPT_DYNAMIC || readAccess == SUBSCRIPT_DYNAMIC)
764     {
765         op << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
766         if (vecLen >= 2)
767             op << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
768         if (vecLen >= 3)
769             op << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
770         if (vecLen >= 4)
771             op << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
772     }
773 
774     if (writeAccess == SUBSCRIPT_DYNAMIC_LOOP || readAccess == SUBSCRIPT_DYNAMIC_LOOP)
775         op << "layout(std140, binding = " << vecLen << ") uniform something" << vecLen << " { mediump int "
776            << 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 << "    o_color = vec4(v_color.rgb, 1.0);\n";
894     }
895     else
896     {
897         vtx << "    v_coords = a_coords;\n";
898         frag << "    o_color = 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());
915     StringTemplate fragTemplate(frag.str());
916     string vertexShaderSource   = vertTemplate.specialize(params);
917     string fragmentShaderSource = fragTemplate.specialize(params);
918 
919     ShaderEvalFunc evalFunc = getVectorSubscriptEvalFunc(varType);
920     return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(
921         context, caseName, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, false));
922 }
923 
924 // MATRIX SUBSCRIPT.
925 
evalSubscriptMat2(ShaderEvalContext & c)926 void evalSubscriptMat2(ShaderEvalContext &c)
927 {
928     c.color.xy() = c.coords.swizzle(0, 1) + 0.5f * c.coords.swizzle(1, 2);
929 }
evalSubscriptMat2x3(ShaderEvalContext & c)930 void evalSubscriptMat2x3(ShaderEvalContext &c)
931 {
932     c.color.xyz() = c.coords.swizzle(0, 1, 2) + 0.5f * c.coords.swizzle(1, 2, 3);
933 }
evalSubscriptMat2x4(ShaderEvalContext & c)934 void evalSubscriptMat2x4(ShaderEvalContext &c)
935 {
936     c.color = c.coords.swizzle(0, 1, 2, 3) + 0.5f * c.coords.swizzle(1, 2, 3, 0);
937 }
938 
evalSubscriptMat3x2(ShaderEvalContext & c)939 void evalSubscriptMat3x2(ShaderEvalContext &c)
940 {
941     c.color.xy() = c.coords.swizzle(0, 1) + 0.5f * c.coords.swizzle(1, 2) + 0.25f * c.coords.swizzle(2, 3);
942 }
evalSubscriptMat3(ShaderEvalContext & c)943 void evalSubscriptMat3(ShaderEvalContext &c)
944 {
945     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);
946 }
evalSubscriptMat3x4(ShaderEvalContext & c)947 void evalSubscriptMat3x4(ShaderEvalContext &c)
948 {
949     c.color = c.coords.swizzle(0, 1, 2, 3) + 0.5f * c.coords.swizzle(1, 2, 3, 0) + 0.25f * c.coords.swizzle(2, 3, 0, 1);
950 }
951 
evalSubscriptMat4x2(ShaderEvalContext & c)952 void evalSubscriptMat4x2(ShaderEvalContext &c)
953 {
954     c.color.xy() = c.coords.swizzle(0, 1) + 0.5f * c.coords.swizzle(1, 2) + 0.25f * c.coords.swizzle(2, 3) +
955                    0.125f * c.coords.swizzle(3, 0);
956 }
evalSubscriptMat4x3(ShaderEvalContext & c)957 void evalSubscriptMat4x3(ShaderEvalContext &c)
958 {
959     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) +
960                     0.125f * c.coords.swizzle(3, 0, 1);
961 }
evalSubscriptMat4(ShaderEvalContext & c)962 void evalSubscriptMat4(ShaderEvalContext &c)
963 {
964     c.color = c.coords + 0.5f * c.coords.swizzle(1, 2, 3, 0) + 0.25f * c.coords.swizzle(2, 3, 0, 1) +
965               0.125f * c.coords.swizzle(3, 0, 1, 2);
966 }
967 
getMatrixSubscriptEvalFunc(DataType dataType)968 static ShaderEvalFunc getMatrixSubscriptEvalFunc(DataType dataType)
969 {
970     switch (dataType)
971     {
972     case TYPE_FLOAT_MAT2:
973         return evalSubscriptMat2;
974     case TYPE_FLOAT_MAT2X3:
975         return evalSubscriptMat2x3;
976     case TYPE_FLOAT_MAT2X4:
977         return evalSubscriptMat2x4;
978     case TYPE_FLOAT_MAT3X2:
979         return evalSubscriptMat3x2;
980     case TYPE_FLOAT_MAT3:
981         return evalSubscriptMat3;
982     case TYPE_FLOAT_MAT3X4:
983         return evalSubscriptMat3x4;
984     case TYPE_FLOAT_MAT4X2:
985         return evalSubscriptMat4x2;
986     case TYPE_FLOAT_MAT4X3:
987         return evalSubscriptMat4x3;
988     case TYPE_FLOAT_MAT4:
989         return evalSubscriptMat4;
990 
991     default:
992         DE_FATAL("Invalid data type.");
993         return DE_NULL;
994     }
995 }
996 
createMatrixSubscriptCase(tcu::TestContext & context,const std::string & caseName,bool isVertexCase,DataType varType,IndexAccessType writeAccess,IndexAccessType readAccess)997 static de::MovePtr<ShaderIndexingCase> createMatrixSubscriptCase(tcu::TestContext &context, const std::string &caseName,
998                                                                  bool isVertexCase, DataType varType,
999                                                                  IndexAccessType writeAccess,
1000                                                                  IndexAccessType readAccess)
1001 {
1002     std::ostringstream vtx;
1003     std::ostringstream frag;
1004     std::ostringstream &op = isVertexCase ? vtx : frag;
1005 
1006     int numCols             = getDataTypeMatrixNumColumns(varType);
1007     int numRows             = getDataTypeMatrixNumRows(varType);
1008     const char *matSizeName = getIntUniformName(numCols);
1009     DataType vecType        = getDataTypeFloatVec(numRows);
1010 
1011     vtx << "#version 310 es\n";
1012     frag << "#version 310 es\n";
1013 
1014     vtx << "layout(location = 0) in highp vec4 a_position;\n";
1015     vtx << "layout(location = 1) in highp vec4 a_coords;\n";
1016     frag << "layout(location = 0) out mediump vec4 o_color;\n";
1017 
1018     if (isVertexCase)
1019     {
1020         vtx << "layout(location = 0) out mediump vec4 v_color;\n";
1021         frag << "layout(location = 0) in mediump vec4 v_color;\n";
1022     }
1023     else
1024     {
1025         vtx << "layout(location = 0) out mediump vec4 v_coords;\n";
1026         frag << "layout(location = 0) in mediump vec4 v_coords;\n";
1027     }
1028 
1029     if (writeAccess == INDEXACCESS_DYNAMIC || readAccess == INDEXACCESS_DYNAMIC)
1030     {
1031         op << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
1032         if (numCols >= 2)
1033             op << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
1034         if (numCols >= 3)
1035             op << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
1036         if (numCols >= 4)
1037             op << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
1038     }
1039 
1040     if (writeAccess == INDEXACCESS_DYNAMIC_LOOP || readAccess == INDEXACCESS_DYNAMIC_LOOP)
1041         op << "layout(std140, binding = " << numCols << ") uniform something" << numCols << " { mediump int "
1042            << matSizeName << "; };\n";
1043 
1044     vtx << "\n";
1045     vtx << "void main()\n";
1046     vtx << "{\n";
1047     vtx << "    gl_Position = a_position;\n";
1048 
1049     frag << "\n";
1050     frag << "void main()\n";
1051     frag << "{\n";
1052 
1053     // Write matrix.
1054     if (isVertexCase)
1055         op << "    ${PRECISION} vec4 coords = a_coords;\n";
1056     else
1057         op << "    ${PRECISION} vec4 coords = v_coords;\n";
1058 
1059     op << "    ${PRECISION} ${MAT_TYPE} tmp;\n";
1060     if (writeAccess == INDEXACCESS_STATIC)
1061     {
1062         op << "    tmp[0] = ${VEC_TYPE}(coords);\n";
1063         if (numCols >= 2)
1064             op << "    tmp[1] = ${VEC_TYPE}(coords.yzwx) * 0.5;\n";
1065         if (numCols >= 3)
1066             op << "    tmp[2] = ${VEC_TYPE}(coords.zwxy) * 0.25;\n";
1067         if (numCols >= 4)
1068             op << "    tmp[3] = ${VEC_TYPE}(coords.wxyz) * 0.125;\n";
1069     }
1070     else if (writeAccess == INDEXACCESS_DYNAMIC)
1071     {
1072         op << "    tmp[ui_zero]  = ${VEC_TYPE}(coords);\n";
1073         if (numCols >= 2)
1074             op << "    tmp[ui_one]   = ${VEC_TYPE}(coords.yzwx) * 0.5;\n";
1075         if (numCols >= 3)
1076             op << "    tmp[ui_two]   = ${VEC_TYPE}(coords.zwxy) * 0.25;\n";
1077         if (numCols >= 4)
1078             op << "    tmp[ui_three] = ${VEC_TYPE}(coords.wxyz) * 0.125;\n";
1079     }
1080     else if (writeAccess == INDEXACCESS_STATIC_LOOP)
1081     {
1082         op << "    for (int i = 0; i < " << numCols << "; i++)\n";
1083         op << "    {\n";
1084         op << "        tmp[i] = ${VEC_TYPE}(coords);\n";
1085         op << "        coords = coords.yzwx * 0.5;\n";
1086         op << "    }\n";
1087     }
1088     else
1089     {
1090         DE_ASSERT(writeAccess == INDEXACCESS_DYNAMIC_LOOP);
1091         op << "    for (int i = 0; i < " << matSizeName << "; i++)\n";
1092         op << "    {\n";
1093         op << "        tmp[i] = ${VEC_TYPE}(coords);\n";
1094         op << "        coords = coords.yzwx * 0.5;\n";
1095         op << "    }\n";
1096     }
1097 
1098     // Read matrix.
1099     op << "    ${PRECISION} ${VEC_TYPE} res = ${VEC_TYPE}(0.0);\n";
1100     if (readAccess == INDEXACCESS_STATIC)
1101     {
1102         op << "    res += tmp[0];\n";
1103         if (numCols >= 2)
1104             op << "    res += tmp[1];\n";
1105         if (numCols >= 3)
1106             op << "    res += tmp[2];\n";
1107         if (numCols >= 4)
1108             op << "    res += tmp[3];\n";
1109     }
1110     else if (readAccess == INDEXACCESS_DYNAMIC)
1111     {
1112         op << "    res += tmp[ui_zero];\n";
1113         if (numCols >= 2)
1114             op << "    res += tmp[ui_one];\n";
1115         if (numCols >= 3)
1116             op << "    res += tmp[ui_two];\n";
1117         if (numCols >= 4)
1118             op << "    res += tmp[ui_three];\n";
1119     }
1120     else if (readAccess == INDEXACCESS_STATIC_LOOP)
1121     {
1122         op << "    for (int i = 0; i < " << numCols << "; i++)\n";
1123         op << "        res += tmp[i];\n";
1124     }
1125     else
1126     {
1127         DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
1128         op << "    for (int i = 0; i < " << matSizeName << "; i++)\n";
1129         op << "        res += tmp[i];\n";
1130     }
1131 
1132     if (isVertexCase)
1133     {
1134         vtx << "    v_color = vec4(res${PADDING});\n";
1135         frag << "    o_color = v_color;\n";
1136     }
1137     else
1138     {
1139         vtx << "    v_coords = a_coords;\n";
1140         frag << "    o_color = vec4(res${PADDING});\n";
1141     }
1142 
1143     vtx << "}\n";
1144     frag << "}\n";
1145 
1146     // Fill in shader templates.
1147     map<string, string> params;
1148     params.insert(pair<string, string>("MAT_TYPE", getDataTypeName(varType)));
1149     params.insert(pair<string, string>("VEC_TYPE", getDataTypeName(vecType)));
1150     params.insert(pair<string, string>("PRECISION", "mediump"));
1151 
1152     if (numRows == 2)
1153         params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
1154     else if (numRows == 3)
1155         params.insert(pair<string, string>("PADDING", ", 1.0"));
1156     else
1157         params.insert(pair<string, string>("PADDING", ""));
1158 
1159     StringTemplate vertTemplate(vtx.str());
1160     StringTemplate fragTemplate(frag.str());
1161     string vertexShaderSource   = vertTemplate.specialize(params);
1162     string fragmentShaderSource = fragTemplate.specialize(params);
1163 
1164     ShaderEvalFunc evalFunc = getMatrixSubscriptEvalFunc(varType);
1165     return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(
1166         context, caseName, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, false));
1167 }
1168 
1169 // ShaderIndexingTests.
1170 
1171 class ShaderIndexingTests : public tcu::TestCaseGroup
1172 {
1173 public:
1174     ShaderIndexingTests(tcu::TestContext &context);
1175     virtual ~ShaderIndexingTests(void);
1176 
1177     virtual void init(void);
1178 
1179 private:
1180     ShaderIndexingTests(const ShaderIndexingTests &);            // not allowed!
1181     ShaderIndexingTests &operator=(const ShaderIndexingTests &); // not allowed!
1182 };
1183 
ShaderIndexingTests(tcu::TestContext & context)1184 ShaderIndexingTests::ShaderIndexingTests(tcu::TestContext &context) : TestCaseGroup(context, "indexing")
1185 {
1186 }
1187 
~ShaderIndexingTests(void)1188 ShaderIndexingTests::~ShaderIndexingTests(void)
1189 {
1190 }
1191 
init(void)1192 void ShaderIndexingTests::init(void)
1193 {
1194     static const ShaderType s_shaderTypes[] = {SHADERTYPE_VERTEX, SHADERTYPE_FRAGMENT};
1195 
1196     static const DataType s_floatAndVecTypes[] = {TYPE_FLOAT, TYPE_FLOAT_VEC2, TYPE_FLOAT_VEC3, TYPE_FLOAT_VEC4};
1197 
1198     // Varying array access cases.
1199     {
1200         de::MovePtr<TestCaseGroup> varyingGroup(new TestCaseGroup(m_testCtx, "varying_array"));
1201 
1202         for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
1203         {
1204             DataType varType = s_floatAndVecTypes[typeNdx];
1205             for (int vertAccess = 0; vertAccess < INDEXACCESS_CONST; vertAccess++)
1206             {
1207                 for (int fragAccess = 0; fragAccess < INDEXACCESS_CONST; fragAccess++)
1208                 {
1209                     const char *vertAccessName = getIndexAccessTypeName((IndexAccessType)vertAccess);
1210                     const char *fragAccessName = getIndexAccessTypeName((IndexAccessType)fragAccess);
1211                     string name =
1212                         string(getDataTypeName(varType)) + "_" + vertAccessName + "_write_" + fragAccessName + "_read";
1213                     de::MovePtr<ShaderIndexingCase> testCase(createVaryingArrayCase(
1214                         m_testCtx, name, varType, (IndexAccessType)vertAccess, (IndexAccessType)fragAccess));
1215                     varyingGroup->addChild(testCase.release());
1216                 }
1217             }
1218         }
1219 
1220         addChild(varyingGroup.release());
1221     }
1222 
1223     // Uniform array access cases.
1224     {
1225         de::MovePtr<TestCaseGroup> uniformGroup(new TestCaseGroup(m_testCtx, "uniform_array"));
1226 
1227         for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
1228         {
1229             DataType varType = s_floatAndVecTypes[typeNdx];
1230             for (int readAccess = 0; readAccess < INDEXACCESS_CONST; readAccess++)
1231             {
1232                 const char *readAccessName = getIndexAccessTypeName((IndexAccessType)readAccess);
1233                 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1234                 {
1235                     ShaderType shaderType      = s_shaderTypes[shaderTypeNdx];
1236                     const char *shaderTypeName = getShaderTypeName(shaderType);
1237                     string name = string(getDataTypeName(varType)) + "_" + readAccessName + "_read_" + shaderTypeName;
1238                     bool isVertexCase = ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1239                     de::MovePtr<ShaderIndexingCase> testCase(
1240                         createUniformArrayCase(m_testCtx, name, isVertexCase, varType, (IndexAccessType)readAccess));
1241                     uniformGroup->addChild(testCase.release());
1242                 }
1243             }
1244         }
1245 
1246         addChild(uniformGroup.release());
1247     }
1248 
1249     // Temporary array access cases.
1250     {
1251         de::MovePtr<TestCaseGroup> tmpGroup(new TestCaseGroup(m_testCtx, "tmp_array"));
1252 
1253         for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
1254         {
1255             DataType varType = s_floatAndVecTypes[typeNdx];
1256             for (int writeAccess = 0; writeAccess < INDEXACCESS_LAST; writeAccess++)
1257             {
1258                 for (int readAccess = 0; readAccess < INDEXACCESS_CONST; readAccess++)
1259                 {
1260                     const char *writeAccessName = getIndexAccessTypeName((IndexAccessType)writeAccess);
1261                     const char *readAccessName  = getIndexAccessTypeName((IndexAccessType)readAccess);
1262 
1263                     for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1264                     {
1265                         ShaderType shaderType      = s_shaderTypes[shaderTypeNdx];
1266                         const char *shaderTypeName = getShaderTypeName(shaderType);
1267                         string name = string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" +
1268                                       readAccessName + "_read_" + shaderTypeName;
1269                         bool isVertexCase = ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1270                         de::MovePtr<ShaderIndexingCase> testCase(
1271                             createTmpArrayCase(m_testCtx, name, isVertexCase, varType, (IndexAccessType)writeAccess,
1272                                                (IndexAccessType)readAccess));
1273                         tmpGroup->addChild(testCase.release());
1274                     }
1275                 }
1276             }
1277         }
1278 
1279         addChild(tmpGroup.release());
1280     }
1281 
1282     // Vector indexing with subscripts.
1283     {
1284         de::MovePtr<TestCaseGroup> vecGroup(new TestCaseGroup(m_testCtx, "vector_subscript"));
1285 
1286         static const DataType s_vectorTypes[] = {TYPE_FLOAT_VEC2, TYPE_FLOAT_VEC3, TYPE_FLOAT_VEC4};
1287 
1288         for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_vectorTypes); typeNdx++)
1289         {
1290             DataType varType = s_vectorTypes[typeNdx];
1291             for (int writeAccess = 0; writeAccess < VECTORACCESS_LAST; writeAccess++)
1292             {
1293                 for (int readAccess = 0; readAccess < VECTORACCESS_LAST; readAccess++)
1294                 {
1295                     const char *writeAccessName = getVectorAccessTypeName((VectorAccessType)writeAccess);
1296                     const char *readAccessName  = getVectorAccessTypeName((VectorAccessType)readAccess);
1297 
1298                     for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1299                     {
1300                         ShaderType shaderType      = s_shaderTypes[shaderTypeNdx];
1301                         const char *shaderTypeName = getShaderTypeName(shaderType);
1302                         string name = string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" +
1303                                       readAccessName + "_read_" + shaderTypeName;
1304                         bool isVertexCase = ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1305                         de::MovePtr<ShaderIndexingCase> testCase(
1306                             createVectorSubscriptCase(m_testCtx, name.c_str(), isVertexCase, varType,
1307                                                       (VectorAccessType)writeAccess, (VectorAccessType)readAccess));
1308                         vecGroup->addChild(testCase.release());
1309                     }
1310                 }
1311             }
1312         }
1313 
1314         addChild(vecGroup.release());
1315     }
1316 
1317     // Matrix indexing with subscripts.
1318     {
1319         de::MovePtr<TestCaseGroup> matGroup(new TestCaseGroup(m_testCtx, "matrix_subscript"));
1320 
1321         static const DataType s_matrixTypes[] = {TYPE_FLOAT_MAT2,   TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT2X4,
1322                                                  TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT3,   TYPE_FLOAT_MAT3X4,
1323                                                  TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT4};
1324 
1325         for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_matrixTypes); typeNdx++)
1326         {
1327             DataType varType = s_matrixTypes[typeNdx];
1328             for (int writeAccess = 0; writeAccess < INDEXACCESS_CONST; writeAccess++)
1329             {
1330                 for (int readAccess = 0; readAccess < INDEXACCESS_CONST; readAccess++)
1331                 {
1332                     const char *writeAccessName = getIndexAccessTypeName((IndexAccessType)writeAccess);
1333                     const char *readAccessName  = getIndexAccessTypeName((IndexAccessType)readAccess);
1334 
1335                     for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1336                     {
1337                         ShaderType shaderType      = s_shaderTypes[shaderTypeNdx];
1338                         const char *shaderTypeName = getShaderTypeName(shaderType);
1339                         string name = string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" +
1340                                       readAccessName + "_read_" + shaderTypeName;
1341                         bool isVertexCase = ((ShaderType)shaderType == SHADERTYPE_VERTEX);
1342                         de::MovePtr<ShaderIndexingCase> testCase(
1343                             createMatrixSubscriptCase(m_testCtx, name.c_str(), isVertexCase, varType,
1344                                                       (IndexAccessType)writeAccess, (IndexAccessType)readAccess));
1345                         matGroup->addChild(testCase.release());
1346                     }
1347                 }
1348             }
1349         }
1350 
1351         addChild(matGroup.release());
1352     }
1353 }
1354 
1355 } // namespace
1356 
createIndexingTests(tcu::TestContext & testCtx)1357 tcu::TestCaseGroup *createIndexingTests(tcu::TestContext &testCtx)
1358 {
1359     return new ShaderIndexingTests(testCtx);
1360 }
1361 
1362 } // namespace sr
1363 } // namespace vkt
1364