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