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