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