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