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