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