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