Fix compute.exceed_atomic_counters_limit am: 5b837a5b21
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / spirv_assembly / vktSpvAsmVariablePointersTests.cpp
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief SPIR-V Assembly Tests for the SPV_KHR_variable_pointers extension
22  *//*--------------------------------------------------------------------*/
23
24 #include "tcuFloat.hpp"
25 #include "tcuRGBA.hpp"
26 #include "tcuStringTemplate.hpp"
27 #include "tcuTestLog.hpp"
28 #include "tcuVectorUtil.hpp"
29
30 #include "vkDefs.hpp"
31 #include "vkDeviceUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkPlatform.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkRef.hpp"
37 #include "vkRefUtil.hpp"
38 #include "vkStrUtil.hpp"
39 #include "vkTypeUtil.hpp"
40
41 #include "deRandom.hpp"
42 #include "deStringUtil.hpp"
43 #include "deUniquePtr.hpp"
44 #include "deMath.h"
45
46 #include "vktSpvAsmComputeShaderCase.hpp"
47 #include "vktSpvAsmComputeShaderTestUtil.hpp"
48 #include "vktSpvAsmGraphicsShaderTestUtil.hpp"
49 #include "vktSpvAsmVariablePointersTests.hpp"
50 #include "vktTestCaseUtil.hpp"
51 #include "vktTestGroupUtil.hpp"
52
53 #include <limits>
54 #include <map>
55 #include <string>
56 #include <sstream>
57 #include <utility>
58
59 namespace vkt
60 {
61 namespace SpirVAssembly
62 {
63
64 using namespace vk;
65 using std::map;
66 using std::string;
67 using std::vector;
68 using tcu::IVec3;
69 using tcu::IVec4;
70 using tcu::RGBA;
71 using tcu::TestLog;
72 using tcu::TestStatus;
73 using tcu::Vec4;
74 using de::UniquePtr;
75 using tcu::StringTemplate;
76 using tcu::Vec4;
77
78 namespace
79 {
80
81 template<typename T>
82 void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
83 {
84         T* const typedPtr = (T*)dst;
85         for (int ndx = 0; ndx < numValues; ndx++)
86                 typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
87 }
88
89 // The following structure (outer_struct) is passed as a vector of 64 32-bit floats into some shaders.
90 //
91 // struct struct inner_struct {
92 //   vec4 x[2];
93 //   vec4 y[2];
94 // };
95 //
96 // struct outer_struct {
97 //   inner_struct r[2][2];
98 // };
99 //
100 // This method finds the correct offset from the base of a vector<float32> given the indexes into the structure.
101 // Returns the index in the inclusive range of 0 and 63. Each unit of the offset represents offset by the size of a 32-bit float.
102 deUint32 getBaseOffset( deUint32 indexOuterStruct,
103                                                 deUint32 indexMatrixRow,
104                                                 deUint32 indexMatrixCol,
105                                                 deUint32 indexInnerStruct,
106                                                 deUint32 indexVec4Array,
107                                                 deUint32 indexVec4)
108 {
109         // index into the outer structure must be zero since the outer structure has only 1 member.
110         if(indexOuterStruct != 0)
111                 DE_ASSERT(indexOuterStruct == 0);
112
113         DE_ASSERT(indexMatrixRow < 2);
114         DE_ASSERT(indexMatrixCol < 2);
115         DE_ASSERT(indexInnerStruct < 2);
116         DE_ASSERT(indexVec4Array < 2);
117         DE_ASSERT(indexVec4 < 4);
118
119         deUint32 offset = 0;
120
121         // We have a matrix of 2 rows and 2 columns (total of 4 inner_structs). Each inner_struct contains 16 floats.
122         // So, offset by 1 row means offset by 32 floats, and offset by 1 column means offset by 16 floats.
123         offset += indexMatrixRow * 32;
124         offset += indexMatrixCol * 16;
125
126         // The inner structure contains 2 members, each having 8 floats.
127         // So offset by 1 in the inner struct means offset by 8 floats.
128         offset += indexInnerStruct * 8;
129
130         // Each member (x|y) have 2 vectors of 4 floats. So, offset by 1 int the vec4 array means an offset by 4 floats.
131         offset += indexVec4Array * 4;
132
133         // Each vec4 contains 4 floats, so each offset in the vec4 means offset by 1 float.
134         offset += indexVec4;
135
136         return offset;
137 }
138
139 // The following structure (input_buffer) is passed as a vector of 128 32-bit floats into some shaders.
140 //
141 // struct struct inner_struct {
142 //   vec4 x[2];
143 //   vec4 y[2];
144 // };
145 //
146 // struct outer_struct {
147 //   inner_struct r[2][2];
148 // };
149 //
150 // struct input_buffer {
151 //   outer_struct a;
152 //   outer_struct b;
153 // }
154 //
155 // This method finds the correct offset from the base of a vector<float32> given the indexes into the structure.
156 // Returns the index in the inclusive range of 0 and 127.
157 deUint32 getBaseOffsetForSingleInputBuffer(     deUint32 indexOuterStruct,
158                                                                                         deUint32 indexMatrixRow,
159                                                                                         deUint32 indexMatrixCol,
160                                                                                         deUint32 indexInnerStruct,
161                                                                                         deUint32 indexVec4Array,
162                                                                                         deUint32 indexVec4)
163 {
164         DE_ASSERT(indexOuterStruct < 2);
165         DE_ASSERT(indexMatrixRow < 2);
166         DE_ASSERT(indexMatrixCol < 2);
167         DE_ASSERT(indexInnerStruct < 2);
168         DE_ASSERT(indexVec4Array < 2);
169         DE_ASSERT(indexVec4 < 4);
170
171         // Get the offset assuming you have only one outer_struct. (use index 0 for outer_struct)
172         deUint32 offset = getBaseOffset(0, indexMatrixRow, indexMatrixCol, indexInnerStruct, indexVec4Array, indexVec4);
173
174         // If the second outer structure (b) is chosen in the input_buffer, we need to add an offset of 64 since
175         // each outer_struct contains 64 floats.
176         if (indexOuterStruct == 1)
177                 offset += 64;
178
179         return offset;
180 }
181
182 void addVariablePointersComputeGroup (tcu::TestCaseGroup* group)
183 {
184         tcu::TestContext&                               testCtx                                 = group->getTestContext();
185         de::Random                                              rnd                                             (deStringHash(group->getName()));
186         const int                                               seed                                    = testCtx.getCommandLine().getBaseSeed();
187         const int                                               numMuxes                                = 100;
188         std::string                                             inputArraySize                  = "200";
189         vector<float>                                   inputAFloats                    (2*numMuxes, 0);
190         vector<float>                                   inputBFloats                    (2*numMuxes, 0);
191         vector<float>                                   inputSFloats                    (numMuxes, 0);
192         vector<float>                                   AmuxAOutputFloats               (numMuxes, 0);
193         vector<float>                                   AmuxBOutputFloats               (numMuxes, 0);
194         vector<float>                                   incrAmuxAOutputFloats   (numMuxes, 0);
195         vector<float>                                   incrAmuxBOutputFloats   (numMuxes, 0);
196         VulkanFeatures                                  requiredFeatures;
197
198         // Each output entry is chosen as follows: ( 0 <= i < numMuxes)
199         // 1) For tests with one input buffer:  output[i] = (s[i] < 0) ? A[2*i] : A[2*i+1];
200         // 2) For tests with two input buffers: output[i] = (s[i] < 0) ? A[i]   : B[i];
201
202         fillRandomScalars(rnd, -100.f, 100.f, &inputAFloats[0], 2*numMuxes);
203         fillRandomScalars(rnd, -100.f, 100.f, &inputBFloats[0], 2*numMuxes);
204
205         // We want to guarantee that the S input has some positive and some negative values.
206         // We choose random negative numbers for the first half, random positive numbers for the second half, and then shuffle.
207         fillRandomScalars(rnd, -100.f, -1.f , &inputSFloats[0], numMuxes / 2);
208         fillRandomScalars(rnd, 1.f   , 100.f, &inputSFloats[numMuxes / 2], numMuxes / 2);
209         de::Random(seed).shuffle(inputSFloats.begin(), inputSFloats.end());
210
211         for (size_t i = 0; i < numMuxes; ++i)
212         {
213                 AmuxAOutputFloats[i]     = (inputSFloats[i] < 0) ? inputAFloats[2*i]     : inputAFloats[2*i+1];
214                 AmuxBOutputFloats[i]     = (inputSFloats[i] < 0) ? inputAFloats[i]               : inputBFloats[i];
215                 incrAmuxAOutputFloats[i] = (inputSFloats[i] < 0) ? 1 + inputAFloats[2*i] : 1 + inputAFloats[2*i+1];
216                 incrAmuxBOutputFloats[i] = (inputSFloats[i] < 0) ? 1 + inputAFloats[i]   : 1 + inputBFloats[i];
217         }
218
219         const StringTemplate shaderTemplate (
220                 "OpCapability Shader\n"
221
222                 "${ExtraCapability}\n"
223
224                 "OpExtension \"SPV_KHR_variable_pointers\"\n"
225                 "OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n"
226                 "OpMemoryModel Logical GLSL450\n"
227                 "OpEntryPoint GLCompute %main \"main\" %id\n"
228                 "OpExecutionMode %main LocalSize 1 1 1\n"
229
230                 "OpSource GLSL 430\n"
231                 "OpName %main           \"main\"\n"
232                 "OpName %id             \"gl_GlobalInvocationID\"\n"
233
234                 // Decorations
235                 "OpDecorate %id BuiltIn GlobalInvocationId\n"
236                 "OpDecorate %indata_a DescriptorSet 0\n"
237                 "OpDecorate %indata_a Binding 0\n"
238                 "OpDecorate %indata_b DescriptorSet 0\n"
239                 "OpDecorate %indata_b Binding 1\n"
240                 "OpDecorate %indata_s DescriptorSet 0\n"
241                 "OpDecorate %indata_s Binding 2\n"
242                 "OpDecorate %outdata DescriptorSet 0\n"
243                 "OpDecorate %outdata Binding 3\n"
244                 "OpDecorate %f32arr ArrayStride 4\n"
245                 "OpDecorate %sb_f32ptr ArrayStride 4\n"
246                 "OpDecorate %buf Block\n"
247                 "OpMemberDecorate %buf 0 Offset 0\n"
248
249                 + string(getComputeAsmCommonTypes()) +
250
251                 "%sb_f32ptr                             = OpTypePointer StorageBuffer %f32\n"
252                 "%buf                                   = OpTypeStruct %f32arr\n"
253                 "%bufptr                                = OpTypePointer StorageBuffer %buf\n"
254                 "%indata_a                              = OpVariable %bufptr StorageBuffer\n"
255                 "%indata_b                              = OpVariable %bufptr StorageBuffer\n"
256                 "%indata_s                              = OpVariable %bufptr StorageBuffer\n"
257                 "%outdata                               = OpVariable %bufptr StorageBuffer\n"
258                 "%id                                    = OpVariable %uvec3ptr Input\n"
259                 "%zero                              = OpConstant %i32 0\n"
260                 "%one                                   = OpConstant %i32 1\n"
261                 "%fzero                                 = OpConstant %f32 0\n"
262                 "%fone                                  = OpConstant %f32 1\n"
263
264                 "${ExtraTypes}"
265
266                 "${ExtraGlobalScopeVars}"
267
268                 // We're going to put the "selector" function here.
269                 // This function type is needed tests that use OpFunctionCall.
270                 "%selector_func_type    = OpTypeFunction %sb_f32ptr %bool %sb_f32ptr %sb_f32ptr\n"
271                 "%choose_input_func             = OpFunction %sb_f32ptr None %selector_func_type\n"
272                 "%is_neg_param                  = OpFunctionParameter %bool\n"
273                 "%first_ptr_param               = OpFunctionParameter %sb_f32ptr\n"
274                 "%second_ptr_param              = OpFunctionParameter %sb_f32ptr\n"
275                 "%selector_func_begin   = OpLabel\n"
276                 "%result_ptr                    = OpSelect %sb_f32ptr %is_neg_param %first_ptr_param %second_ptr_param\n"
277                 "OpReturnValue %result_ptr\n"
278                 "OpFunctionEnd\n"
279
280                 // main function is the entry_point
281                 "%main                                  = OpFunction %void None %voidf\n"
282                 "%label                                 = OpLabel\n"
283
284                 "${ExtraFunctionScopeVars}"
285
286                 "%idval                                 = OpLoad %uvec3 %id\n"
287                 "%i                                             = OpCompositeExtract %u32 %idval 0\n"
288                 "%two_i                                 = OpIAdd %u32 %i %i\n"
289                 "%two_i_plus_1                  = OpIAdd %u32 %two_i %one\n"
290                 "%inloc_a_i                             = OpAccessChain %sb_f32ptr %indata_a %zero %i\n"
291                 "%inloc_b_i                             = OpAccessChain %sb_f32ptr %indata_b %zero %i\n"
292                 "%inloc_s_i             = OpAccessChain %sb_f32ptr %indata_s %zero %i\n"
293                 "%outloc_i              = OpAccessChain %sb_f32ptr %outdata  %zero %i\n"
294                 "%inloc_a_2i                    = OpAccessChain %sb_f32ptr %indata_a %zero %two_i\n"
295                 "%inloc_a_2i_plus_1             = OpAccessChain %sb_f32ptr %indata_a %zero %two_i_plus_1\n"
296                 "%inval_s_i                             = OpLoad %f32 %inloc_s_i\n"
297                 "%is_neg                                = OpFOrdLessThan %bool %inval_s_i %fzero\n"
298
299                 "${ExtraSetupComputations}"
300
301                 "${ResultStrategy}"
302
303                 "%mux_output                    = OpLoad %f32 ${VarPtrName}\n"
304                 "                                                 OpStore %outloc_i %mux_output\n"
305                 "                                                 OpReturn\n"
306                 "                                                 OpFunctionEnd\n");
307
308         const bool singleInputBuffer[]  = { true, false };
309         for (int inputBufferTypeIndex = 0 ; inputBufferTypeIndex < 2; ++inputBufferTypeIndex)
310         {
311                 const bool isSingleInputBuffer                  = singleInputBuffer[inputBufferTypeIndex];
312                 const string extraCap                                   = isSingleInputBuffer   ? "OpCapability VariablePointersStorageBuffer\n" : "OpCapability VariablePointers\n";
313                 const vector<float>& expectedOutput             = isSingleInputBuffer   ? AmuxAOutputFloats              : AmuxBOutputFloats;
314                 const vector<float>& expectedIncrOutput = isSingleInputBuffer   ? incrAmuxAOutputFloats  : incrAmuxBOutputFloats;
315                 const string bufferType                                 = isSingleInputBuffer   ? "single_buffer"        : "two_buffers";
316                 const string muxInput1                                  = isSingleInputBuffer   ? " %inloc_a_2i "                : " %inloc_a_i ";
317                 const string muxInput2                                  = isSingleInputBuffer   ? " %inloc_a_2i_plus_1 " : " %inloc_b_i ";
318
319                 // Set the proper extension features required for the test
320                 if (isSingleInputBuffer)
321                         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS_STORAGEBUFFER;
322                 else
323                         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS;
324
325                 { // Variable Pointer Reads (using OpSelect)
326                         ComputeShaderSpec                               spec;
327                         map<string, string>                             specs;
328                         string name                                             = "reads_opselect_" + bufferType;
329                         specs["ExtraCapability"]                = extraCap;
330                         specs["ExtraTypes"]                             = "";
331                         specs["ExtraGlobalScopeVars"]   = "";
332                         specs["ExtraFunctionScopeVars"] = "";
333                         specs["ExtraSetupComputations"] = "";
334                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
335                         specs["ResultStrategy"]                 = "%mux_output_var_ptr  = OpSelect %sb_f32ptr %is_neg" + muxInput1 + muxInput2 + "\n";
336                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
337                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
338                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
339                         spec.assembly                                   = shaderTemplate.specialize(specs);
340                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
341                         spec.requestedVulkanFeatures    = requiredFeatures;
342                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
343                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
344                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
345                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
346                         spec.extensions.push_back("VK_KHR_variable_pointers");
347                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
348                 }
349                 { // Variable Pointer Reads (using OpFunctionCall)
350                         ComputeShaderSpec                               spec;
351                         map<string, string>                             specs;
352                         string name                                             = "reads_opfunctioncall_" + bufferType;
353                         specs["ExtraCapability"]                = extraCap;
354                         specs["ExtraTypes"]                             = "";
355                         specs["ExtraGlobalScopeVars"]   = "";
356                         specs["ExtraFunctionScopeVars"] = "";
357                         specs["ExtraSetupComputations"] = "";
358                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
359                         specs["ResultStrategy"]                 = "%mux_output_var_ptr = OpFunctionCall %sb_f32ptr %choose_input_func %is_neg" + muxInput1 + muxInput2 + "\n";
360                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
361                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
362                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
363                         spec.assembly                                   = shaderTemplate.specialize(specs);
364                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
365                         spec.requestedVulkanFeatures    = requiredFeatures;
366                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
367                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
368                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
369                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
370                         spec.extensions.push_back("VK_KHR_variable_pointers");
371                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
372                 }
373                 { // Variable Pointer Reads (using OpPhi)
374                         ComputeShaderSpec                               spec;
375                         map<string, string>                             specs;
376                         string name                                             = "reads_opphi_" + bufferType;
377                         specs["ExtraCapability"]                = extraCap;
378                         specs["ExtraTypes"]                             = "";
379                         specs["ExtraGlobalScopeVars"]   = "";
380                         specs["ExtraFunctionScopeVars"] = "";
381                         specs["ExtraSetupComputations"] = "";
382                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
383                         specs["ResultStrategy"]                 =
384                                 "                                                         OpSelectionMerge %end_label None\n"
385                                 "                                                         OpBranchConditional %is_neg %take_mux_input_1 %take_mux_input_2\n"
386                                 "%take_mux_input_1                      = OpLabel\n"
387                                 "                                                         OpBranch %end_label\n"
388                                 "%take_mux_input_2                      = OpLabel\n"
389                                 "                                                     OpBranch %end_label\n"
390                                 "%end_label                                     = OpLabel\n"
391                                 "%mux_output_var_ptr            = OpPhi %sb_f32ptr" + muxInput1 + "%take_mux_input_1" + muxInput2 + "%take_mux_input_2\n";
392                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
393                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
394                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
395                         spec.assembly                                   = shaderTemplate.specialize(specs);
396                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
397                         spec.requestedVulkanFeatures    = requiredFeatures;
398                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
399                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
400                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
401                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
402                         spec.extensions.push_back("VK_KHR_variable_pointers");
403                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
404                 }
405                 { // Variable Pointer Reads (using OpCopyObject)
406                         ComputeShaderSpec                               spec;
407                         map<string, string>                             specs;
408                         string name                                             = "reads_opcopyobject_" + bufferType;
409                         specs["ExtraCapability"]                = extraCap;
410                         specs["ExtraTypes"]                             = "";
411                         specs["ExtraGlobalScopeVars"]   = "";
412                         specs["ExtraFunctionScopeVars"] = "";
413                         specs["ExtraSetupComputations"] = "";
414                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
415                         specs["ResultStrategy"]                 =
416                                 "%mux_input_1_copy                      = OpCopyObject %sb_f32ptr" + muxInput1 + "\n"
417                                 "%mux_input_2_copy                      = OpCopyObject %sb_f32ptr" + muxInput2 + "\n"
418                                 "%mux_output_var_ptr            = OpSelect %sb_f32ptr %is_neg %mux_input_1_copy %mux_input_2_copy\n";
419                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
420                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
421                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
422                         spec.assembly                                   = shaderTemplate.specialize(specs);
423                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
424                         spec.requestedVulkanFeatures    = requiredFeatures;
425                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
426                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
427                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
428                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
429                         spec.extensions.push_back("VK_KHR_variable_pointers");
430                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
431                 }
432                 { // Test storing into Private variables.
433                         const char* storageClasses[]            = {"Private", "Function"};
434                         for (int classId = 0; classId < 2; ++classId)
435                         {
436                                 ComputeShaderSpec                               spec;
437                                 map<string, string>                             specs;
438                                 std::string storageClass                = storageClasses[classId];
439                                 std::string name                                = "stores_" + string(de::toLower(storageClass)) + "_" + bufferType;
440                                 std::string description                 = "Test storing variable pointer into " + storageClass + " variable.";
441                                 std::string extraVariable               = "%mux_output_copy     = OpVariable %sb_f32ptrptr " + storageClass + "\n";
442                                 specs["ExtraTypes"]                             = "%sb_f32ptrptr = OpTypePointer " + storageClass + " %sb_f32ptr\n";
443                                 specs["ExtraCapability"]                = extraCap;
444                                 specs["ExtraGlobalScopeVars"]   = (classId == 0) ? extraVariable : "";
445                                 specs["ExtraFunctionScopeVars"] = (classId == 1) ? extraVariable : "";
446                                 specs["ExtraSetupComputations"] = "";
447                                 specs["VarPtrName"]                             = "%mux_output_var_ptr";
448                                 specs["ResultStrategy"]                 =
449                                         "%opselect_result                       = OpSelect %sb_f32ptr %is_neg" + muxInput1 + muxInput2 + "\n"
450                                         "                                                         OpStore %mux_output_copy %opselect_result\n"
451                                         "%mux_output_var_ptr            = OpLoad %sb_f32ptr %mux_output_copy\n";
452                                 spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
453                                 spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
454                                 spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
455                                 spec.assembly                                   = shaderTemplate.specialize(specs);
456                                 spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
457                                 spec.requestedVulkanFeatures    = requiredFeatures;
458                                 spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
459                                 spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
460                                 spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
461                                 spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
462                                 spec.extensions.push_back("VK_KHR_variable_pointers");
463                                 group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), description.c_str(), spec));
464                         }
465                 }
466                 { // Variable Pointer Reads (Using OpPtrAccessChain)
467                         ComputeShaderSpec                               spec;
468                         map<string, string>                             specs;
469                         std::string name                                = "reads_opptraccesschain_" + bufferType;
470                         std::string in_1                                = isSingleInputBuffer ? " %a_2i_ptr "            : " %a_i_ptr ";
471                         std::string in_2                                = isSingleInputBuffer ? " %a_2i_plus_1_ptr " : " %b_i_ptr ";
472                         specs["ExtraTypes"]                             = "";
473                         specs["ExtraCapability"]                = extraCap;
474                         specs["ExtraGlobalScopeVars"]   = "";
475                         specs["ExtraFunctionScopeVars"] = "";
476                         specs["ExtraSetupComputations"] = "";
477                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
478                         specs["ResultStrategy"]                 =
479                                         "%a_ptr                                 = OpAccessChain %sb_f32ptr %indata_a %zero %zero\n"
480                                         "%b_ptr                                 = OpAccessChain %sb_f32ptr %indata_b %zero %zero\n"
481                                         "%s_ptr                                 = OpAccessChain %sb_f32ptr %indata_s %zero %zero\n"
482                                         "%out_ptr               = OpAccessChain %sb_f32ptr %outdata  %zero %zero\n"
483                                         "%a_i_ptr               = OpPtrAccessChain %sb_f32ptr %a_ptr %i\n"
484                                         "%b_i_ptr               = OpPtrAccessChain %sb_f32ptr %b_ptr %i\n"
485                                         "%s_i_ptr               = OpPtrAccessChain %sb_f32ptr %s_ptr %i\n"
486                                         "%a_2i_ptr              = OpPtrAccessChain %sb_f32ptr %a_ptr %two_i\n"
487                                         "%a_2i_plus_1_ptr       = OpPtrAccessChain %sb_f32ptr %a_ptr %two_i_plus_1\n"
488                                         "%mux_output_var_ptr    = OpSelect %sb_f32ptr %is_neg " + in_1 + in_2 + "\n";
489                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
490                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
491                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
492                         spec.assembly                                   = shaderTemplate.specialize(specs);
493                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
494                         spec.requestedVulkanFeatures    = requiredFeatures;
495                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
496                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
497                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
498                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
499                         spec.extensions.push_back("VK_KHR_variable_pointers");
500                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
501                 }
502                 {   // Variable Pointer Writes
503                         ComputeShaderSpec                               spec;
504                         map<string, string>                             specs;
505                         std::string     name                            = "writes_" + bufferType;
506                         specs["ExtraCapability"]                = extraCap;
507                         specs["ExtraTypes"]                             = "";
508                         specs["ExtraGlobalScopeVars"]   = "";
509                         specs["ExtraFunctionScopeVars"] = "";
510                         specs["ExtraSetupComputations"] = "";
511                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
512                         specs["ResultStrategy"]                 = "%mux_output_var_ptr = OpSelect %sb_f32ptr %is_neg" + muxInput1 + muxInput2 + "\n" +
513                                                                                           "               %val = OpLoad %f32 %mux_output_var_ptr\n"
514                                                                                           "        %val_plus_1 = OpFAdd %f32 %val %fone\n"
515                                                                                           "                                              OpStore %mux_output_var_ptr %val_plus_1\n";
516                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
517                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
518                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
519                         spec.assembly                                   = shaderTemplate.specialize(specs);
520                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
521                         spec.requestedVulkanFeatures    = requiredFeatures;
522                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
523                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
524                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
525                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedIncrOutput)));
526                         spec.extensions.push_back("VK_KHR_variable_pointers");
527                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
528                 }
529
530                 // If we only have VariablePointersStorageBuffer, then the extension does not apply to Workgroup storage class.
531                 // Therefore the Workgroup tests apply to cases where the VariablePointers capability is used (when 2 input buffers are used).
532                 if (!isSingleInputBuffer)
533                 {
534                         // VariablePointers on Workgroup
535                         ComputeShaderSpec                               spec;
536                         map<string, string>                             specs;
537                         std::string name                                = "workgroup_" + bufferType;
538                         specs["ExtraCapability"]                = extraCap;
539                         specs["ExtraTypes"]                             =
540                                         "%c_i32_N                               = OpConstant %i32 " + inputArraySize + " \n"
541                                         "%f32arr_N                              = OpTypeArray %f32 %c_i32_N\n"
542                                         "%f32arr_wrkgrp_ptr             = OpTypePointer Workgroup %f32arr_N\n"
543                                         "%f32_wrkgrp_ptr                = OpTypePointer Workgroup %f32\n";
544                         specs["ExtraGlobalScopeVars"]   =
545                                         "%AW                                    = OpVariable %f32arr_wrkgrp_ptr Workgroup\n"
546                                         "%BW                                    = OpVariable %f32arr_wrkgrp_ptr Workgroup\n";
547                         specs["ExtraFunctionScopeVars"] = "";
548                         specs["ExtraSetupComputations"] =
549                                         "%loc_AW_i                              = OpAccessChain %f32_wrkgrp_ptr %AW %i\n"
550                                         "%loc_BW_i                              = OpAccessChain %f32_wrkgrp_ptr %BW %i\n"
551                                         "%inval_a_i                             = OpLoad %f32 %inloc_a_i\n"
552                                         "%inval_b_i                             = OpLoad %f32 %inloc_b_i\n"
553                                         "%inval_a_2i                    = OpLoad %f32 %inloc_a_2i\n"
554                                         "%inval_a_2i_plus_1             = OpLoad %f32 %inloc_a_2i_plus_1\n";
555                         specs["VarPtrName"]                             = "%output_var_ptr";
556                         specs["ResultStrategy"]                 =
557                                         "                                                 OpStore %loc_AW_i %inval_a_i\n"
558                                         "                                                 OpStore %loc_BW_i %inval_b_i\n"
559                                         "%output_var_ptr                = OpSelect %f32_wrkgrp_ptr %is_neg %loc_AW_i %loc_BW_i\n";
560                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
561                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
562                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
563                         spec.assembly                                   = shaderTemplate.specialize(specs);
564                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
565                         spec.requestedVulkanFeatures    = requiredFeatures;
566                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
567                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
568                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
569                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
570                         spec.extensions.push_back("VK_KHR_variable_pointers");
571                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
572                 }
573         }
574 }
575
576 void addComplexTypesVariablePointersComputeGroup (tcu::TestCaseGroup* group)
577 {
578         tcu::TestContext&                               testCtx                                 = group->getTestContext();
579         const int                                               numFloats                               = 64;
580         vector<float>                                   inputA                                  (numFloats, 0);
581         vector<float>                                   inputB                                  (numFloats, 0);
582         vector<float>                                   inputC                                  (2*numFloats, 0);
583         vector<float>                                   expectedOutput                  (1, 0);
584         VulkanFeatures                                  requiredFeatures;
585
586         // These tests exercise variable pointers into various levels of the following data-structures.
587         //
588         // struct struct inner_struct {
589         //   vec4 x[2]; // array of 2 vectors. Each vector is 4 floats.
590         //   vec4 y[2]; // array of 2 vectors. Each vector is 4 floats.
591         // };
592         //
593         // struct outer_struct {
594         //   inner_struct r[2][2];
595         // };
596         //
597         // struct input_buffer {
598         //   outer_struct a;
599         //   outer_struct b;
600         // }
601         //
602         // inputA is of type outer_struct.
603         // inputB is of type outer_struct.
604         // inputC is of type input_buffer.
605         //
606         // inputA and inputB are of the same size. When testing variable pointers pointing to
607         // two different input buffers, we use inputA and inputB.
608         //
609         // inputC is twice the size of inputA. When testing the VariablePointersStorageBuffer capability,
610         // the variable pointer must be confined to a single buffer. These tests will use inputC.
611         //
612         // The inner_struct contains 16 floats.
613         // The outer_struct contains 64 floats.
614         // The input_buffer contains 128 floats.
615         // Populate the first input (inputA) to contain:  {0, 4, ... , 252}
616         // Populate the second input (inputB) to contain: {3, 7, ... , 255}
617         // Populate the third input (inputC) to contain:  {0, 4, ... , 252, 3, 7, ... , 255}
618         // Note that the first half of inputC is the same as inputA and the second half is the same as inputB.
619         for (size_t i = 0; i < numFloats; ++i)
620         {
621                 inputA[i] = 4*float(i) / 255;
622                 inputB[i] = ((4*float(i)) + 3) / 255;
623                 inputC[i] = inputA[i];
624                 inputC[i + numFloats] = inputB[i];
625         }
626
627         // In the following tests we use variable pointers to point to different types:
628         // nested structures, matrices of structures, arrays of structures, arrays of vectors, vectors of scalars, and scalars.
629         // outer_structure.inner_structure[?][?].x[?][?];
630         //   ^                    ^        ^  ^  ^ ^  ^
631         //
632         // For tests with 2 input buffers:
633         // 1. inputA                                            or      inputB                                                  = nested structure
634         // 2. inputA.r                                          or      inputB.r                                                = matrices of structures
635         // 3. inputA.r[?]                                       or      inputB.r[?]                                             = arrays of structures
636         // 4. inputA.r[?][?]                            or      inputB.r[?][?]                                  = structures
637         // 5. inputA.r[?][?].(x|y)                      or      inputB.r[?][?].(x|y)                    = arrays of vectors
638         // 6. inputA.r[?][?].(x|y)[?]           or      inputB.r[?][?].(x|y)[?]                 = vectors of scalars
639         // 7. inputA.r[?][?].(x|y)[?][?]        or      inputB.r[?][?].(x|y)[?][?]              = scalars
640         // For tests with 1 input buffer:
641         // 1. inputC.a                                          or      inputC.b                                                = nested structure
642         // 2. inputC.a.r                                        or      inputC.b.r                                              = matrices of structures
643         // 3. inputC.a.r[?]                                     or      inputC.b.r[?]                                   = arrays of structures
644         // 4. inputC.a.r[?][?]                          or      inputC.b.r[?][?]                                = structures
645         // 5. inputC.a.r[?][?].(x|y)            or      inputC.b.r[?][?].(x|y)                  = arrays of vectors
646         // 6. inputC.a.r[?][?].(x|y)[?]         or      inputC.b.r[?][?].(x|y)[?]               = vectors of scalars
647         // 7. inputC.a.r[?][?].(x|y)[?][?]      or      inputC.b.r[?][?].(x|y)[?][?]    = scalars
648         const int numLevels = 7;
649
650         const string decorations (
651                 // Decorations
652                 "OpDecorate %id BuiltIn GlobalInvocationId              \n"
653                 "OpDecorate %inputA DescriptorSet 0                             \n"
654                 "OpDecorate %inputB DescriptorSet 0                             \n"
655                 "OpDecorate %inputC DescriptorSet 0                             \n"
656                 "OpDecorate %outdata DescriptorSet 0                    \n"
657                 "OpDecorate %inputA Binding 0                                   \n"
658                 "OpDecorate %inputB Binding 1                                   \n"
659                 "OpDecorate %inputC Binding 2                                   \n"
660                 "OpDecorate %outdata Binding 3                                  \n"
661
662                 // Set the Block decoration
663                 "OpDecorate %outer_struct       Block                           \n"
664                 "OpDecorate %input_buffer       Block                           \n"
665                 "OpDecorate %output_buffer      Block                           \n"
666
667                 // Set the Offsets
668                 "OpMemberDecorate %output_buffer 0 Offset 0             \n"
669                 "OpMemberDecorate %input_buffer  0 Offset 0             \n"
670                 "OpMemberDecorate %input_buffer  1 Offset 256   \n"
671                 "OpMemberDecorate %outer_struct  0 Offset 0             \n"
672                 "OpMemberDecorate %inner_struct  0 Offset 0             \n"
673                 "OpMemberDecorate %inner_struct  1 Offset 32    \n"
674
675                 // Set the ArrayStrides
676                 "OpDecorate %arr2_v4float        ArrayStride 16         \n"
677                 "OpDecorate %arr2_inner_struct   ArrayStride 64         \n"
678                 "OpDecorate %mat2x2_inner_struct ArrayStride 128        \n"
679                 "OpDecorate %outer_struct_ptr    ArrayStride 256        \n"
680                 "OpDecorate %v4f32_ptr           ArrayStride 16         \n"
681         );
682
683         const string types (
684                 ///////////////
685                 // CONSTANTS //
686                 ///////////////
687                 "%c_bool_true                   = OpConstantTrue        %bool                                                   \n"
688                 "%c_bool_false                  = OpConstantFalse       %bool                                                   \n"
689                 "%c_i32_0                               = OpConstant            %i32            0                                       \n"
690                 "%c_i32_1                               = OpConstant            %i32            1                                       \n"
691                 "%c_i32_2                               = OpConstant            %i32            2                                       \n"
692                 "%c_i32_3                               = OpConstant            %i32            3                                       \n"
693                 "%c_u32_2                               = OpConstant            %u32            2                                       \n"
694
695                 ///////////
696                 // TYPES //
697                 ///////////
698                 "%v4f32                 = OpTypeVector %f32 4                               \n"
699
700                 // struct struct inner_struct {
701                 //   vec4 x[2]; // array of 2 vectors
702                 //   vec4 y[2]; // array of 2 vectors
703                 // };
704                 "%arr2_v4float                  = OpTypeArray %v4f32 %c_u32_2                                           \n"
705                 "%inner_struct                  = OpTypeStruct %arr2_v4float %arr2_v4float                      \n"
706
707                 // struct outer_struct {
708                 //   inner_struct r[2][2];
709                 // };
710                 "%arr2_inner_struct             = OpTypeArray %inner_struct %c_u32_2                            \n"
711                 "%mat2x2_inner_struct   = OpTypeArray %arr2_inner_struct %c_u32_2                       \n"
712                 "%outer_struct                  = OpTypeStruct %mat2x2_inner_struct                                     \n"
713
714                 // struct input_buffer {
715                 //   outer_struct a;
716                 //   outer_struct b;
717                 // }
718                 "%input_buffer                  = OpTypeStruct %outer_struct %outer_struct                      \n"
719
720                 // struct output_struct {
721                 //   float out;
722                 // }
723                 "%output_buffer                 = OpTypeStruct %f32                                                                     \n"
724
725                 ///////////////////
726                 // POINTER TYPES //
727                 ///////////////////
728                 "%output_buffer_ptr             = OpTypePointer StorageBuffer %output_buffer            \n"
729                 "%input_buffer_ptr              = OpTypePointer StorageBuffer %input_buffer                     \n"
730                 "%outer_struct_ptr              = OpTypePointer StorageBuffer %outer_struct                     \n"
731                 "%mat2x2_ptr                    = OpTypePointer StorageBuffer %mat2x2_inner_struct      \n"
732                 "%arr2_ptr                              = OpTypePointer StorageBuffer %arr2_inner_struct        \n"
733                 "%inner_struct_ptr              = OpTypePointer StorageBuffer %inner_struct                     \n"
734                 "%arr_v4f32_ptr                 = OpTypePointer StorageBuffer %arr2_v4float                     \n"
735                 "%v4f32_ptr                             = OpTypePointer StorageBuffer %v4f32                            \n"
736                 "%sb_f32ptr                             = OpTypePointer StorageBuffer %f32                                      \n"
737
738                 ///////////////
739                 // VARIABLES //
740                 ///////////////
741                 "%id                                    = OpVariable %uvec3ptr                  Input                           \n"
742                 "%inputA                                = OpVariable %outer_struct_ptr  StorageBuffer           \n"
743                 "%inputB                                = OpVariable %outer_struct_ptr  StorageBuffer           \n"
744                 "%inputC                                = OpVariable %input_buffer_ptr  StorageBuffer           \n"
745                 "%outdata                               = OpVariable %output_buffer_ptr StorageBuffer           \n"
746         );
747
748         const StringTemplate shaderTemplate (
749                 "OpCapability Shader\n"
750
751                 "${extra_capability}\n"
752
753                 "OpExtension \"SPV_KHR_variable_pointers\"\n"
754                 "OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n"
755                 "OpMemoryModel Logical GLSL450\n"
756                 "OpEntryPoint GLCompute %main \"main\" %id\n"
757                 "OpExecutionMode %main LocalSize 1 1 1\n"
758
759                 "OpSource GLSL 430\n"
760                 "OpName %main           \"main\"\n"
761                 "OpName %id             \"gl_GlobalInvocationID\"\n"
762
763                 + decorations
764
765                 + string(getComputeAsmCommonTypes())
766
767                 + types +
768
769                 // These selector functions return variable pointers.
770                 // These functions are used by tests that use OpFunctionCall to obtain the variable pointer
771                 "%selector_func_type    = OpTypeFunction ${selected_type} %bool ${selected_type} ${selected_type}\n"
772                 "%choose_input_func             = OpFunction ${selected_type} None %selector_func_type\n"
773                 "%choose_first_param    = OpFunctionParameter %bool\n"
774                 "%first_param                   = OpFunctionParameter ${selected_type}\n"
775                 "%second_param                  = OpFunctionParameter ${selected_type}\n"
776                 "%selector_func_begin   = OpLabel\n"
777                 "%result_ptr                    = OpSelect ${selected_type} %choose_first_param %first_param %second_param\n"
778                 "OpReturnValue %result_ptr\n"
779                 "OpFunctionEnd\n"
780
781                 // main function is the entry_point
782                 "%main                                  = OpFunction %void None %voidf\n"
783                 "%label                                 = OpLabel\n"
784
785                 // Here are the 2 nested structures within InputC.
786                 "%inputC_a                              = OpAccessChain %outer_struct_ptr %inputC %c_i32_0\n"
787                 "%inputC_b                              = OpAccessChain %outer_struct_ptr %inputC %c_i32_1\n"
788
789                 // Define the 2 pointers from which we're going to choose one.
790                 "${a_loc} \n"
791                 "${b_loc} \n"
792
793                 // Choose between the 2 pointers / variable pointers.
794                 "${selection_strategy} \n"
795
796                 // OpAccessChain into the variable pointer until you get to the float.
797                 "%result_loc                    = OpAccessChain %sb_f32ptr %var_ptr  ${remaining_indexes} \n"
798
799                 // Now load from the result_loc
800                 "%result_val                    = OpLoad %f32 %result_loc \n"
801
802                 // Store the chosen value to the output buffer.
803                 "%outdata_loc                   = OpAccessChain %sb_f32ptr %outdata %c_i32_0\n"
804                 "                                                 OpStore %outdata_loc %result_val\n"
805                 "                                                 OpReturn\n"
806                 "                                                 OpFunctionEnd\n");
807
808         for (int isSingleInputBuffer = 0 ; isSingleInputBuffer < 2; ++isSingleInputBuffer)
809         {
810                 // Set the proper extension features required for the test
811                 if (isSingleInputBuffer)
812                         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS_STORAGEBUFFER;
813                 else
814                         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS;
815
816                 for (int selectInputA = 0; selectInputA < 2; ++selectInputA)
817                 {
818                         const string extraCap                                   = isSingleInputBuffer   ? "OpCapability VariablePointersStorageBuffer\n" : "OpCapability VariablePointers\n";
819                         const vector<float>& selectedInput              = isSingleInputBuffer   ? inputC                                                                                 : (selectInputA ? inputA : inputB);
820                         const string bufferType                                 = isSingleInputBuffer   ? "single_buffer_"                                                               : "two_buffers_";
821                         const string baseA                                              = isSingleInputBuffer   ? "%inputC_a"                                                                    : "%inputA";
822                         const string baseB                                              = isSingleInputBuffer   ? "%inputC_b"                                                                    : "%inputB";
823                         const string selectedInputStr                   = selectInputA                  ? "first_input"                                                                  : "second_input";
824                         const string spirvSelectInputA                  = selectInputA                  ? "%c_bool_true"                                                                 : "%c_bool_false";
825                         const int outerStructIndex                              = isSingleInputBuffer   ? (selectInputA ? 0 : 1)                                                 : 0;
826
827                         // The indexes chosen at each level. At any level, any given offset is exercised.
828                         // outerStructIndex is 0 for inputA and inputB (because outer_struct has only 1 member).
829                         // outerStructIndex is 0 for member <a> of inputC and 1 for member <b>.
830                         const int indexesForLevel[numLevels][6]= {{outerStructIndex, 0, 0, 0, 0, 1},
831                                                                                                           {outerStructIndex, 1, 0, 1, 0, 2},
832                                                                                                           {outerStructIndex, 0, 1, 0, 1, 3},
833                                                                                                           {outerStructIndex, 1, 1, 1, 0, 0},
834                                                                                                           {outerStructIndex, 0, 0, 1, 1, 1},
835                                                                                                           {outerStructIndex, 1, 0, 0, 0, 2},
836                                                                                                           {outerStructIndex, 1, 1, 1, 1, 3}};
837
838                         const string indexLevelNames[]          = {"_outer_struct_", "_matrices_", "_arrays_", "_inner_structs_", "_vec4arr_", "_vec4_", "_float_"};
839                         const string inputALocations[]          = {     "",
840                                                                                                 "%a_loc = OpAccessChain %mat2x2_ptr       " + baseA + " %c_i32_0",
841                                                                                                 "%a_loc = OpAccessChain %arr2_ptr         " + baseA + " %c_i32_0 %c_i32_0",
842                                                                                                 "%a_loc = OpAccessChain %inner_struct_ptr " + baseA + " %c_i32_0 %c_i32_1 %c_i32_1",
843                                                                                                 "%a_loc = OpAccessChain %arr_v4f32_ptr    " + baseA + " %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
844                                                                                                 "%a_loc = OpAccessChain %v4f32_ptr        " + baseA + " %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
845                                                                                                 "%a_loc = OpAccessChain %sb_f32ptr        " + baseA + " %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3"};
846
847                         const string inputBLocations[]          = {     "",
848                                                                                                 "%b_loc = OpAccessChain %mat2x2_ptr       " + baseB + " %c_i32_0",
849                                                                                                 "%b_loc = OpAccessChain %arr2_ptr         " + baseB + " %c_i32_0 %c_i32_0",
850                                                                                                 "%b_loc = OpAccessChain %inner_struct_ptr " + baseB + " %c_i32_0 %c_i32_1 %c_i32_1",
851                                                                                                 "%b_loc = OpAccessChain %arr_v4f32_ptr    " + baseB + " %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
852                                                                                                 "%b_loc = OpAccessChain %v4f32_ptr        " + baseB + " %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
853                                                                                                 "%b_loc = OpAccessChain %sb_f32ptr        " + baseB + " %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3"};
854
855                         const string inputAPtrAccessChain[]     = {     "",
856                                                                                                 "%a_loc = OpPtrAccessChain %mat2x2_ptr       " + baseA + " %c_i32_0 %c_i32_0",
857                                                                                                 "%a_loc = OpPtrAccessChain %arr2_ptr         " + baseA + " %c_i32_0 %c_i32_0 %c_i32_0",
858                                                                                                 "%a_loc = OpPtrAccessChain %inner_struct_ptr " + baseA + " %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1",
859                                                                                                 "%a_loc = OpPtrAccessChain %arr_v4f32_ptr    " + baseA + " %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
860                                                                                                 "%a_loc = OpPtrAccessChain %v4f32_ptr        " + baseA + " %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
861                                                                                                 // Next case emulates:
862                                                                                                 // %a_loc = OpPtrAccessChain %sb_f32ptr          baseA     %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3
863                                                                                                 // But rewrite it to exercise OpPtrAccessChain with a non-zero first index:
864                                                                                                 //    %a_loc_arr is a pointer to an array that we want to index with 1.
865                                                                                                 // But instead of just using OpAccessChain with first index 1, use OpAccessChain with index 0 to
866                                                                                                 // get a pointer to the first element, then send that into OpPtrAccessChain with index 1.
867                                                                                                 "%a_loc_arr = OpPtrAccessChain %arr_v4f32_ptr " + baseA + " %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 "
868                                                                                                 "%a_loc_first_elem = OpAccessChain %v4f32_ptr %a_loc_arr %c_i32_0 "
869                                                                                                 "%a_loc = OpPtrAccessChain %sb_f32ptr %a_loc_first_elem %c_i32_1 %c_i32_3"};
870
871                         const string inputBPtrAccessChain[]     = {     "",
872                                                                                                 "%b_loc = OpPtrAccessChain %mat2x2_ptr       " + baseB + " %c_i32_0 %c_i32_0",
873                                                                                                 "%b_loc = OpPtrAccessChain %arr2_ptr         " + baseB + " %c_i32_0 %c_i32_0 %c_i32_0",
874                                                                                                 "%b_loc = OpPtrAccessChain %inner_struct_ptr " + baseB + " %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1",
875                                                                                                 "%b_loc = OpPtrAccessChain %arr_v4f32_ptr    " + baseB + " %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
876                                                                                                 "%b_loc = OpPtrAccessChain %v4f32_ptr        " + baseB + " %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
877                                                                                                 // Next case emulates:
878                                                                                                 // %b_loc = OpPtrAccessChain %sb_f32ptr          basseB     %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3
879                                                                                                 // But rewrite it to exercise OpPtrAccessChain with a non-zero first index:
880                                                                                                 //    %b_loc_arr is a pointer to an array that we want to index with 1.
881                                                                                                 // But instead of just using OpAccessChain with first index 1, use OpAccessChain with index 0 to
882                                                                                                 // get a pointer to the first element, then send that into OpPtrAccessChain with index 1.
883                                                                                                 "%b_loc_arr = OpPtrAccessChain %arr_v4f32_ptr " + baseB + " %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 "
884                                                                                                 "%b_loc_first_elem = OpAccessChain %v4f32_ptr %b_loc_arr %c_i32_0 "
885                                                                                                 "%b_loc = OpPtrAccessChain %sb_f32ptr %b_loc_first_elem %c_i32_1 %c_i32_3"};
886
887
888                         const string remainingIndexesAtLevel[]= {"%c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
889                                                                                                          "%c_i32_1 %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_2",
890                                                                                                          "%c_i32_1 %c_i32_0 %c_i32_1 %c_i32_3",
891                                                                                                          "%c_i32_1 %c_i32_0 %c_i32_0",
892                                                                                                          "%c_i32_1 %c_i32_1",
893                                                                                                          "%c_i32_2",
894                                                                                                          ""};
895
896                         const string pointerTypeAtLevel[] = {"%outer_struct_ptr", "%mat2x2_ptr", "%arr2_ptr", "%inner_struct_ptr", "%arr_v4f32_ptr", "%v4f32_ptr", "%sb_f32ptr"};
897                         const string baseANameAtLevel[]   = {baseA, "%a_loc", "%a_loc", "%a_loc", "%a_loc", "%a_loc", "%a_loc"};
898                         const string baseBNameAtLevel[]   = {baseB, "%b_loc", "%b_loc", "%b_loc", "%b_loc", "%b_loc", "%b_loc"};
899
900                         for (int indexLevel = 0; indexLevel < numLevels; ++indexLevel)
901                         {
902                                 const int baseOffset    = getBaseOffsetForSingleInputBuffer(indexesForLevel[indexLevel][0],
903                                                                                                                                                         indexesForLevel[indexLevel][1],
904                                                                                                                                                         indexesForLevel[indexLevel][2],
905                                                                                                                                                         indexesForLevel[indexLevel][3],
906                                                                                                                                                         indexesForLevel[indexLevel][4],
907                                                                                                                                                         indexesForLevel[indexLevel][5]);
908                                 // Use OpSelect to choose between 2 pointers
909                                 {
910                                         ComputeShaderSpec                               spec;
911                                         map<string, string>                             specs;
912                                         string opCodeForTests                   = "opselect";
913                                         string name                                             = opCodeForTests + indexLevelNames[indexLevel] + bufferType + selectedInputStr;
914                                         specs["extra_capability"]               = extraCap;
915                                         specs["selected_type"]                  = pointerTypeAtLevel[indexLevel];
916                                         specs["select_inputA"]                  = spirvSelectInputA;
917                                         specs["a_loc"]                                  = inputALocations[indexLevel];
918                                         specs["b_loc"]                                  = inputBLocations[indexLevel];
919                                         specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
920                                         specs["selection_strategy"]             = "%var_ptr     = OpSelect "
921                                                                                                                 + pointerTypeAtLevel[indexLevel] + " "
922                                                                                                                 + spirvSelectInputA + " "
923                                                                                                                 + baseANameAtLevel[indexLevel] + " "
924                                                                                                                 + baseBNameAtLevel[indexLevel] + "\n";
925                                         expectedOutput[0]                               = selectedInput[baseOffset];
926                                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
927                                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
928                                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
929                                         spec.assembly                                   = shaderTemplate.specialize(specs);
930                                         spec.numWorkGroups                              = IVec3(1, 1, 1);
931                                         spec.requestedVulkanFeatures    = requiredFeatures;
932                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputA)));
933                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputB)));
934                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputC)));
935                                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
936                                         spec.extensions.push_back("VK_KHR_variable_pointers");
937                                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
938                                 }
939
940                                 // Use OpFunctionCall to choose between 2 pointers
941                                 {
942                                         ComputeShaderSpec                               spec;
943                                         map<string, string>                             specs;
944                                         string opCodeForTests                   = "opfunctioncall";
945                                         string name                                             = opCodeForTests + indexLevelNames[indexLevel] + bufferType + selectedInputStr;
946                                         specs["extra_capability"]               = extraCap;
947                                         specs["selected_type"]                  = pointerTypeAtLevel[indexLevel];
948                                         specs["select_inputA"]                  = spirvSelectInputA;
949                                         specs["a_loc"]                                  = inputALocations[indexLevel];
950                                         specs["b_loc"]                                  = inputBLocations[indexLevel];
951                                         specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
952                                         specs["selection_strategy"]             = "%var_ptr     = OpFunctionCall "
953                                                                                                                 + pointerTypeAtLevel[indexLevel]
954                                                                                                                 + " %choose_input_func "
955                                                                                                                 + spirvSelectInputA + " "
956                                                                                                                 + baseANameAtLevel[indexLevel] + " "
957                                                                                                                 + baseBNameAtLevel[indexLevel] + "\n";
958                                         expectedOutput[0]                               = selectedInput[baseOffset];
959                                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
960                                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
961                                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
962                                         spec.assembly                                   = shaderTemplate.specialize(specs);
963                                         spec.numWorkGroups                              = IVec3(1, 1, 1);
964                                         spec.requestedVulkanFeatures    = requiredFeatures;
965                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputA)));
966                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputB)));
967                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputC)));
968                                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
969                                         spec.extensions.push_back("VK_KHR_variable_pointers");
970                                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
971                                 }
972
973                                 // Use OpPhi to choose between 2 pointers
974                                 {
975
976                                         ComputeShaderSpec                               spec;
977                                         map<string, string>                             specs;
978                                         string opCodeForTests                   = "opphi";
979                                         string name                                             = opCodeForTests + indexLevelNames[indexLevel] + bufferType + selectedInputStr;
980                                         specs["extra_capability"]               = extraCap;
981                                         specs["selected_type"]                  = pointerTypeAtLevel[indexLevel];
982                                         specs["select_inputA"]                  = spirvSelectInputA;
983                                         specs["a_loc"]                                  = inputALocations[indexLevel];
984                                         specs["b_loc"]                                  = inputBLocations[indexLevel];
985                                         specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
986                                         specs["selection_strategy"]             =
987                                                                         "                                 OpSelectionMerge %end_label None\n"
988                                                                         "                                 OpBranchConditional " + spirvSelectInputA + " %take_input_a %take_input_b\n"
989                                                                         "%take_input_a  = OpLabel\n"
990                                                                         "                                 OpBranch %end_label\n"
991                                                                         "%take_input_b  = OpLabel\n"
992                                                                         "                             OpBranch %end_label\n"
993                                                                         "%end_label             = OpLabel\n"
994                                                                         "%var_ptr               = OpPhi "
995                                                                                                                 + pointerTypeAtLevel[indexLevel] + " "
996                                                                                                                 + baseANameAtLevel[indexLevel]
997                                                                                                                 + " %take_input_a "
998                                                                                                                 + baseBNameAtLevel[indexLevel]
999                                                                                                                 + " %take_input_b\n";
1000                                         expectedOutput[0]                               = selectedInput[baseOffset];
1001                                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1002                                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1003                                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1004                                         spec.assembly                                   = shaderTemplate.specialize(specs);
1005                                         spec.numWorkGroups                              = IVec3(1, 1, 1);
1006                                         spec.requestedVulkanFeatures    = requiredFeatures;
1007                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputA)));
1008                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputB)));
1009                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputC)));
1010                                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
1011                                         spec.extensions.push_back("VK_KHR_variable_pointers");
1012                                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
1013                                 }
1014
1015                                 // Use OpCopyObject to get variable pointers
1016                                 {
1017                                         ComputeShaderSpec                               spec;
1018                                         map<string, string>                             specs;
1019                                         string opCodeForTests                   = "opcopyobject";
1020                                         string name                                             = opCodeForTests + indexLevelNames[indexLevel] + bufferType + selectedInputStr;
1021                                         specs["extra_capability"]               = extraCap;
1022                                         specs["selected_type"]                  = pointerTypeAtLevel[indexLevel];
1023                                         specs["select_inputA"]                  = spirvSelectInputA;
1024                                         specs["a_loc"]                                  = inputALocations[indexLevel];
1025                                         specs["b_loc"]                                  = inputBLocations[indexLevel];
1026                                         specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
1027                                         specs["selection_strategy"]             =
1028                                                                                 "%in_a_copy = OpCopyObject " + pointerTypeAtLevel[indexLevel] + " " + baseANameAtLevel[indexLevel] + "\n"
1029                                                                                 "%in_b_copy = OpCopyObject " + pointerTypeAtLevel[indexLevel] + " " + baseBNameAtLevel[indexLevel] + "\n"
1030                                                                                 "%var_ptr       = OpSelect " + pointerTypeAtLevel[indexLevel] + " " + spirvSelectInputA + " %in_a_copy %in_b_copy\n";
1031                                         expectedOutput[0]                               = selectedInput[baseOffset];
1032                                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1033                                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1034                                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1035                                         spec.assembly                                   = shaderTemplate.specialize(specs);
1036                                         spec.numWorkGroups                              = IVec3(1, 1, 1);
1037                                         spec.requestedVulkanFeatures    = requiredFeatures;
1038                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputA)));
1039                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputB)));
1040                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputC)));
1041                                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
1042                                         spec.extensions.push_back("VK_KHR_variable_pointers");
1043                                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
1044                                 }
1045
1046                                 // Use OpPtrAccessChain to get variable pointers
1047                                 {
1048                                         ComputeShaderSpec                               spec;
1049                                         map<string, string>                             specs;
1050                                         string opCodeForTests                   = "opptraccesschain";
1051                                         string name                                             = opCodeForTests + indexLevelNames[indexLevel] + bufferType + selectedInputStr;
1052                                         specs["extra_capability"]               = extraCap;
1053                                         specs["selected_type"]                  = pointerTypeAtLevel[indexLevel];
1054                                         specs["select_inputA"]                  = spirvSelectInputA;
1055                                         specs["a_loc"]                                  = inputAPtrAccessChain[indexLevel];
1056                                         specs["b_loc"]                                  = inputBPtrAccessChain[indexLevel];
1057                                         specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
1058                                         specs["selection_strategy"]             = "%var_ptr     = OpSelect "
1059                                                                                                                 + pointerTypeAtLevel[indexLevel] + " "
1060                                                                                                                 + spirvSelectInputA + " "
1061                                                                                                                 + baseANameAtLevel[indexLevel] + " "
1062                                                                                                                 + baseBNameAtLevel[indexLevel] + "\n";
1063                                         expectedOutput[0]                               = selectedInput[baseOffset];
1064                                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1065                                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1066                                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1067                                         spec.assembly                                   = shaderTemplate.specialize(specs);
1068                                         spec.numWorkGroups                              = IVec3(1, 1, 1);
1069                                         spec.requestedVulkanFeatures    = requiredFeatures;
1070                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputA)));
1071                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputB)));
1072                                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputC)));
1073                                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
1074                                         spec.extensions.push_back("VK_KHR_variable_pointers");
1075                                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
1076                                 }
1077                         }
1078                 }
1079         }
1080 }
1081
1082 void addNullptrVariablePointersComputeGroup (tcu::TestCaseGroup* group)
1083 {
1084         tcu::TestContext&                               testCtx                                 = group->getTestContext();
1085         float                                                   someFloat                               = 78;
1086         vector<float>                                   input                                   (1, someFloat);
1087         vector<float>                                   expectedOutput                  (1, someFloat);
1088         VulkanFeatures                                  requiredFeatures;
1089
1090         // Requires the variable pointers feature.
1091         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS;
1092
1093         const string decorations (
1094                 // Decorations
1095                 "OpDecorate %id BuiltIn GlobalInvocationId              \n"
1096                 "OpDecorate %input DescriptorSet 0                              \n"
1097                 "OpDecorate %outdata DescriptorSet 0                    \n"
1098                 "OpDecorate %input Binding 0                                    \n"
1099                 "OpDecorate %outdata Binding 1                                  \n"
1100
1101                 // Set the Block decoration
1102                 "OpDecorate %float_struct       Block                           \n"
1103
1104                 // Set the Offsets
1105                 "OpMemberDecorate %float_struct 0 Offset 0              \n"
1106         );
1107
1108         const string types (
1109                 ///////////
1110                 // TYPES //
1111                 ///////////
1112                 // struct float_struct {
1113                 //   float x;
1114                 // };
1115                 "%float_struct          = OpTypeStruct %f32                                                                                     \n"
1116
1117                 ///////////////////
1118                 // POINTER TYPES //
1119                 ///////////////////
1120                 "%float_struct_ptr      = OpTypePointer StorageBuffer %float_struct                                     \n"
1121                 "%sb_f32ptr                     = OpTypePointer StorageBuffer %f32                                                      \n"
1122                 "%func_f32ptrptr        = OpTypePointer Function %sb_f32ptr                                                     \n"
1123
1124                 ///////////////
1125                 // CONSTANTS //
1126                 ///////////////
1127                 "%c_bool_true           = OpConstantTrue        %bool                                                                   \n"
1128                 "%c_i32_0                       = OpConstant            %i32            0                                                       \n"
1129                 "%c_null_ptr            = OpConstantNull        %sb_f32ptr                                                              \n"
1130
1131                 ///////////////
1132                 // VARIABLES //
1133                 ///////////////
1134                 "%id                            = OpVariable %uvec3ptr                  Input                                           \n"
1135                 "%input                         = OpVariable %float_struct_ptr  StorageBuffer                           \n"
1136                 "%outdata                       = OpVariable %float_struct_ptr  StorageBuffer                           \n"
1137         );
1138
1139         const StringTemplate shaderTemplate (
1140                 "OpCapability Shader\n"
1141                 "OpCapability VariablePointers\n"
1142
1143                 "OpExtension \"SPV_KHR_variable_pointers\"\n"
1144                 "OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n"
1145                 "OpMemoryModel Logical GLSL450\n"
1146                 "OpEntryPoint GLCompute %main \"main\" %id\n"
1147                 "OpExecutionMode %main LocalSize 1 1 1\n"
1148
1149                 "OpSource GLSL 430\n"
1150                 "OpName %main           \"main\"\n"
1151                 "OpName %id             \"gl_GlobalInvocationID\"\n"
1152
1153                 + decorations
1154
1155                 + string(getComputeAsmCommonTypes())
1156
1157                 + types +
1158
1159                 // main function is the entry_point
1160                 "%main                                  = OpFunction %void None %voidf\n"
1161                 "%label                                 = OpLabel\n"
1162
1163                 // Note that the Variable Pointers extension allows creation
1164                 // of a pointer variable with storage class of Private or Function.
1165                 "%f32_ptr_var               = OpVariable %func_f32ptrptr Function %c_null_ptr\n"
1166
1167                 "%input_loc                             = OpAccessChain %sb_f32ptr %input %c_i32_0\n"
1168                 "%output_loc                    = OpAccessChain %sb_f32ptr %outdata %c_i32_0\n"
1169
1170                 "${NullptrTestingStrategy}\n"
1171
1172                 "                                                 OpReturn\n"
1173                 "                                                 OpFunctionEnd\n");
1174
1175         // f32_ptr_var has been inintialized to NULL.
1176         // Now set it to point to the float variable that holds the input value
1177         {
1178                 ComputeShaderSpec                               spec;
1179                 map<string, string>                             specs;
1180                 string name                                             = "opvariable_initialized_null";
1181                 specs["NullptrTestingStrategy"] =
1182                                                         "                  OpStore %f32_ptr_var %input_loc       \n"
1183                                                         "%loaded_f32_ptr = OpLoad  %sb_f32ptr   %f32_ptr_var    \n"
1184                                                         "%loaded_f32     = OpLoad  %f32         %loaded_f32_ptr \n"
1185                                                         "                  OpStore %output_loc  %loaded_f32     \n";
1186
1187                 spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1188                 spec.assembly                                   = shaderTemplate.specialize(specs);
1189                 spec.numWorkGroups                              = IVec3(1, 1, 1);
1190                 spec.requestedVulkanFeatures    = requiredFeatures;
1191                 spec.inputs.push_back(BufferSp(new Float32Buffer(input)));
1192                 spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
1193                 spec.extensions.push_back("VK_KHR_variable_pointers");
1194                 group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
1195         }
1196         // Use OpSelect to choose between nullptr and valid pointer. Since we can't dereference nullptr,
1197         // it is forced to always choose the valid pointer.
1198         {
1199                 ComputeShaderSpec                               spec;
1200                 map<string, string>                             specs;
1201                 string name                                             = "opselect_null_or_valid_ptr";
1202                 specs["NullptrTestingStrategy"] =
1203                                                         "%selected_ptr = OpSelect %sb_f32ptr %c_bool_true %input_loc %c_null_ptr\n"
1204                                                         "%loaded_var = OpLoad %f32 %selected_ptr\n"
1205                                                         "OpStore %output_loc %loaded_var\n";
1206
1207                 spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1208                 spec.assembly                                   = shaderTemplate.specialize(specs);
1209                 spec.numWorkGroups                              = IVec3(1, 1, 1);
1210                 spec.requestedVulkanFeatures    = requiredFeatures;
1211                 spec.inputs.push_back(BufferSp(new Float32Buffer(input)));
1212                 spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
1213                 spec.extensions.push_back("VK_KHR_variable_pointers");
1214                 group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
1215         }
1216 }
1217
1218 void addVariablePointersGraphicsGroup (tcu::TestCaseGroup* testGroup)
1219 {
1220         tcu::TestContext&                               testCtx                                 = testGroup->getTestContext();
1221         de::Random                                              rnd                                             (deStringHash(testGroup->getName()));
1222         map<string, string>                             fragments;
1223         RGBA                                                    defaultColors[4];
1224         vector<string>                                  extensions;
1225         const int                                               seed                                    = testCtx.getCommandLine().getBaseSeed();
1226         const int                                               numMuxes                                = 100;
1227         const std::string                               numMuxesStr                             = "100";
1228         vector<float>                                   inputAFloats                    (2*numMuxes, 0);
1229         vector<float>                                   inputBFloats                    (2*numMuxes, 0);
1230         vector<float>                                   inputSFloats                    (numMuxes, 0);
1231         vector<float>                                   AmuxAOutputFloats               (numMuxes, 0);
1232         vector<float>                                   AmuxBOutputFloats               (numMuxes, 0);
1233         vector<float>                                   incrAmuxAOutputFloats   (numMuxes, 0);
1234         vector<float>                                   incrAmuxBOutputFloats   (numMuxes, 0);
1235         VulkanFeatures                                  requiredFeatures;
1236
1237         extensions.push_back("VK_KHR_variable_pointers");
1238         getDefaultColors(defaultColors);
1239
1240         // Each output entry is chosen as follows: ( 0 <= i < numMuxes)
1241         // 1) For tests with one input buffer:  output[i] = (s[i] < 0) ? A[2*i] : A[2*i+1];
1242         // 2) For tests with two input buffers: output[i] = (s[i] < 0) ? A[i]   : B[i];
1243
1244         fillRandomScalars(rnd, -100.f, 100.f, &inputAFloats[0], 2*numMuxes);
1245         fillRandomScalars(rnd, -100.f, 100.f, &inputBFloats[0], 2*numMuxes);
1246
1247         // We want to guarantee that the S input has some positive and some negative values.
1248         // We choose random negative numbers for the first half, random positive numbers for the second half, and then shuffle.
1249         fillRandomScalars(rnd, -100.f, -1.f , &inputSFloats[0], numMuxes / 2);
1250         fillRandomScalars(rnd, 1.f   , 100.f, &inputSFloats[numMuxes / 2], numMuxes / 2);
1251         de::Random(seed).shuffle(inputSFloats.begin(), inputSFloats.end());
1252
1253         for (size_t i = 0; i < numMuxes; ++i)
1254         {
1255                 AmuxAOutputFloats[i]     = (inputSFloats[i] < 0) ? inputAFloats[2*i]     : inputAFloats[2*i+1];
1256                 AmuxBOutputFloats[i]     = (inputSFloats[i] < 0) ? inputAFloats[i]               : inputBFloats[i];
1257                 incrAmuxAOutputFloats[i] = (inputSFloats[i] < 0) ? 1 + inputAFloats[2*i] : 1 + inputAFloats[2*i+1];
1258                 incrAmuxBOutputFloats[i] = (inputSFloats[i] < 0) ? 1 + inputAFloats[i]   : 1 + inputBFloats[i];
1259         }
1260
1261         fragments["extension"]          = "OpExtension \"SPV_KHR_variable_pointers\"\n"
1262                                                                   "OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n";
1263
1264         const StringTemplate preMain            (
1265                 "%c_i32_limit = OpConstant %i32 " + numMuxesStr + "\n"
1266                 "     %sb_f32 = OpTypePointer StorageBuffer %f32\n"
1267                 "     %ra_f32 = OpTypeRuntimeArray %f32\n"
1268                 "        %buf = OpTypeStruct %ra_f32\n"
1269                 "     %sb_buf = OpTypePointer StorageBuffer %buf\n"
1270
1271                 " ${ExtraTypes}"
1272
1273                 " ${ExtraGlobalScopeVars}"
1274
1275                 "   %indata_a = OpVariable %sb_buf StorageBuffer\n"
1276                 "   %indata_b = OpVariable %sb_buf StorageBuffer\n"
1277                 "   %indata_s = OpVariable %sb_buf StorageBuffer\n"
1278                 "    %outdata = OpVariable %sb_buf StorageBuffer\n"
1279
1280                 " ${ExtraFunctions} ");
1281
1282         const std::string selectorFunction      (
1283                 // We're going to put the "selector" function here.
1284                 // This function type is needed for tests that use OpFunctionCall.
1285                 "%selector_func_type    = OpTypeFunction %sb_f32 %bool %sb_f32 %sb_f32\n"
1286                 "%choose_input_func             = OpFunction %sb_f32 None %selector_func_type\n"
1287                 "%is_neg_param                  = OpFunctionParameter %bool\n"
1288                 "%first_ptr_param               = OpFunctionParameter %sb_f32\n"
1289                 "%second_ptr_param              = OpFunctionParameter %sb_f32\n"
1290                 "%selector_func_begin   = OpLabel\n"
1291                 "%result_ptr                    = OpSelect %sb_f32 %is_neg_param %first_ptr_param %second_ptr_param\n"
1292                 "OpReturnValue %result_ptr\n"
1293                 "OpFunctionEnd\n");
1294
1295         const StringTemplate decoration         (
1296                 "OpMemberDecorate %buf 0 Offset 0\n"
1297                 "OpDecorate %buf Block\n"
1298                 "OpDecorate %ra_f32 ArrayStride 4\n"
1299                 "OpDecorate %sb_f32 ArrayStride 4\n"
1300                 "OpDecorate %indata_a DescriptorSet 0\n"
1301                 "OpDecorate %indata_b DescriptorSet 0\n"
1302                 "OpDecorate %indata_s DescriptorSet 0\n"
1303                 "OpDecorate %outdata  DescriptorSet 0\n"
1304                 "OpDecorate %indata_a Binding 0\n"
1305                 "OpDecorate %indata_b Binding 1\n"
1306                 "OpDecorate %indata_s Binding 2\n"
1307                 "OpDecorate %outdata  Binding 3\n");
1308
1309         const StringTemplate testFunction       (
1310                 "%test_code             = OpFunction %v4f32 None %v4f32_function\n"
1311                 "%param                 = OpFunctionParameter %v4f32\n"
1312                 "%entry                 = OpLabel\n"
1313
1314                 "${ExtraFunctionScopeVars}"
1315
1316                 "%i                             = OpVariable %fp_i32 Function\n"
1317
1318                 "%should_run    = OpFunctionCall %bool %isUniqueIdZero\n"
1319                 "                 OpSelectionMerge %end_if None\n"
1320                 "                 OpBranchConditional %should_run %run_test %end_if\n"
1321
1322                 "%run_test      = OpLabel\n"
1323                 "                               OpStore %i %c_i32_0\n"
1324                 "                               OpBranch %loop\n"
1325                 // loop header
1326                 "%loop                  = OpLabel\n"
1327                 "%15                    = OpLoad %i32 %i\n"
1328                 "%lt                    = OpSLessThan %bool %15 %c_i32_limit\n"
1329                 "                               OpLoopMerge %merge %inc None\n"
1330                 "                               OpBranchConditional %lt %write %merge\n"
1331                 // loop body
1332                 "%write                         = OpLabel\n"
1333                 "%30                            = OpLoad %i32 %i\n"
1334                 "%two_i                         = OpIAdd %i32 %30 %30\n"
1335                 "%two_i_plus_1          = OpIAdd %i32 %two_i %c_i32_1\n"
1336                 "%loc_s_i                       = OpAccessChain %sb_f32 %indata_s %c_i32_0 %30\n"
1337                 "%loc_a_i                       = OpAccessChain %sb_f32 %indata_a %c_i32_0 %30\n"
1338                 "%loc_b_i                       = OpAccessChain %sb_f32 %indata_b %c_i32_0 %30\n"
1339                 "%loc_a_2i                      = OpAccessChain %sb_f32 %indata_a %c_i32_0 %two_i\n"
1340                 "%loc_a_2i_plus_1       = OpAccessChain %sb_f32 %indata_a %c_i32_0 %two_i_plus_1\n"
1341                 "%loc_outdata_i         = OpAccessChain %sb_f32 %outdata  %c_i32_0 %30\n"
1342                 "%val_s_i                       = OpLoad %f32 %loc_s_i\n"
1343                 "%is_neg                        = OpFOrdLessThan %bool %val_s_i %c_f32_0\n"
1344
1345                 // select using a strategy.
1346                 "${ResultStrategy}"
1347
1348                 // load through the variable pointer
1349                 "%mux_output    = OpLoad %f32 ${VarPtrName}\n"
1350
1351                 // store to the output vector.
1352                 "                               OpStore %loc_outdata_i %mux_output\n"
1353                 "                               OpBranch %inc\n"
1354                 // ++i
1355                 "  %inc                 = OpLabel\n"
1356                 "   %37                 = OpLoad %i32 %i\n"
1357                 "   %39                 = OpIAdd %i32 %37 %c_i32_1\n"
1358                 "         OpStore %i %39\n"
1359                 "         OpBranch %loop\n"
1360
1361                 // Return and FunctionEnd
1362                 "%merge                 = OpLabel\n"
1363                 "                 OpBranch %end_if\n"
1364                 "%end_if                = OpLabel\n"
1365                 "OpReturnValue %param\n"
1366                 "OpFunctionEnd\n");
1367
1368         const bool singleInputBuffer[] = { true, false };
1369         for (int inputBufferTypeIndex = 0 ; inputBufferTypeIndex < 2; ++inputBufferTypeIndex)
1370         {
1371                 const bool isSingleInputBuffer                  = singleInputBuffer[inputBufferTypeIndex];
1372                 const string cap                                                = isSingleInputBuffer   ? "OpCapability VariablePointersStorageBuffer\n" : "OpCapability VariablePointers\n";
1373                 const vector<float>& expectedOutput             = isSingleInputBuffer   ? AmuxAOutputFloats              : AmuxBOutputFloats;
1374                 const vector<float>& expectedIncrOutput = isSingleInputBuffer   ? incrAmuxAOutputFloats  : incrAmuxBOutputFloats;
1375                 const string bufferType                                 = isSingleInputBuffer   ? "single_buffer"                : "two_buffers";
1376                 const string muxInput1                                  = isSingleInputBuffer   ? " %loc_a_2i "                  : " %loc_a_i ";
1377                 const string muxInput2                                  = isSingleInputBuffer   ? " %loc_a_2i_plus_1 "   : " %loc_b_i ";
1378
1379                 // Set the proper extension features required for the test
1380                 if (isSingleInputBuffer)
1381                         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS_STORAGEBUFFER;
1382                 else
1383                         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS;
1384
1385                 // All of the following tests write their results into an output SSBO, therefore they require the following features.
1386                 requiredFeatures.coreFeatures.vertexPipelineStoresAndAtomics = DE_TRUE;
1387                 requiredFeatures.coreFeatures.fragmentStoresAndAtomics           = DE_TRUE;
1388
1389                 { // Variable Pointer Reads (using OpSelect)
1390                         GraphicsResources                               resources;
1391                         map<string, string>                             specs;
1392                         string name                                             = "reads_opselect_" + bufferType;
1393                         specs["ExtraTypes"]                             = "";
1394                         specs["ExtraGlobalScopeVars"]   = "";
1395                         specs["ExtraFunctionScopeVars"] = "";
1396                         specs["ExtraFunctions"]                 = "";
1397                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
1398                         specs["ResultStrategy"]                 = "%mux_output_var_ptr  = OpSelect %sb_f32 %is_neg" + muxInput1 + muxInput2 + "\n";
1399
1400                         fragments["capability"]                 = cap;
1401                         fragments["decoration"]                 = decoration.specialize(specs);
1402                         fragments["pre_main"]                   = preMain.specialize(specs);
1403                         fragments["testfun"]                    = testFunction.specialize(specs);
1404
1405                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
1406                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
1407                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
1408                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
1409                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
1410                 }
1411                 { // Variable Pointer Reads (using OpFunctionCall)
1412                         GraphicsResources                               resources;
1413                         map<string, string>                             specs;
1414                         string name                                             = "reads_opfunctioncall_" + bufferType;
1415                         specs["ExtraTypes"]                             = "";
1416                         specs["ExtraGlobalScopeVars"]   = "";
1417                         specs["ExtraFunctionScopeVars"] = "";
1418                         specs["ExtraFunctions"]                 = selectorFunction;
1419                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
1420                         specs["ResultStrategy"]                 = "%mux_output_var_ptr = OpFunctionCall %sb_f32 %choose_input_func %is_neg" + muxInput1 + muxInput2 + "\n";
1421
1422                         fragments["capability"]                 = cap;
1423                         fragments["decoration"]                 = decoration.specialize(specs);
1424                         fragments["pre_main"]                   = preMain.specialize(specs);
1425                         fragments["testfun"]                    = testFunction.specialize(specs);
1426
1427                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
1428                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
1429                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
1430                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
1431                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
1432                 }
1433                 { // Variable Pointer Reads (using OpPhi)
1434                         GraphicsResources                               resources;
1435                         map<string, string>                             specs;
1436                         string name                                             = "reads_opphi_" + bufferType;
1437                         specs["ExtraTypes"]                             = "";
1438                         specs["ExtraGlobalScopeVars"]   = "";
1439                         specs["ExtraFunctionScopeVars"] = "";
1440                         specs["ExtraFunctions"]                 = "";
1441                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
1442                         specs["ResultStrategy"]                 =
1443                                 "                                                         OpSelectionMerge %end_label None\n"
1444                                 "                                                         OpBranchConditional %is_neg %take_mux_input_1 %take_mux_input_2\n"
1445                                 "%take_mux_input_1                      = OpLabel\n"
1446                                 "                                                         OpBranch %end_label\n"
1447                                 "%take_mux_input_2                      = OpLabel\n"
1448                                 "                                                     OpBranch %end_label\n"
1449                                 "%end_label                                     = OpLabel\n"
1450                                 "%mux_output_var_ptr            = OpPhi %sb_f32" + muxInput1 + "%take_mux_input_1" + muxInput2 + "%take_mux_input_2\n";
1451
1452                         fragments["capability"]                 = cap;
1453                         fragments["decoration"]                 = decoration.specialize(specs);
1454                         fragments["pre_main"]                   = preMain.specialize(specs);
1455                         fragments["testfun"]                    = testFunction.specialize(specs);
1456
1457                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
1458                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
1459                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
1460                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
1461                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
1462                 }
1463                 { // Variable Pointer Reads (using OpCopyObject)
1464                         GraphicsResources                               resources;
1465                         map<string, string>                             specs;
1466                         string name                                             = "reads_opcopyobject_" + bufferType;
1467                         specs["ExtraTypes"]                             = "";
1468                         specs["ExtraGlobalScopeVars"]   = "";
1469                         specs["ExtraFunctionScopeVars"] = "";
1470                         specs["ExtraFunctions"]                 = "";
1471                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
1472                         specs["ResultStrategy"]                 =
1473                                 "%mux_input_1_copy                      = OpCopyObject %sb_f32" + muxInput1 + "\n"
1474                                 "%mux_input_2_copy                      = OpCopyObject %sb_f32" + muxInput2 + "\n"
1475                                 "%mux_output_var_ptr            = OpSelect %sb_f32 %is_neg %mux_input_1_copy %mux_input_2_copy\n";
1476
1477                         fragments["capability"]                 = cap;
1478                         fragments["decoration"]                 = decoration.specialize(specs);
1479                         fragments["pre_main"]                   = preMain.specialize(specs);
1480                         fragments["testfun"]                    = testFunction.specialize(specs);
1481
1482                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
1483                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
1484                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
1485                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
1486                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
1487                 }
1488                 { // Test storing into Private variables.
1489                         const char* storageClasses[]            = {"Private", "Function"};
1490                         for (int classId = 0; classId < 2; ++classId)
1491                         {
1492                                 GraphicsResources                               resources;
1493                                 map<string, string>                             specs;
1494                                 std::string storageClass                = storageClasses[classId];
1495                                 std::string name                                = "stores_" + string(de::toLower(storageClass)) + "_" + bufferType;
1496                                 std::string extraVariable               = "%mux_output_copy     = OpVariable %sb_f32ptrptr " + storageClass + "\n";
1497                                 specs["ExtraTypes"]                             = "%sb_f32ptrptr = OpTypePointer " + storageClass + " %sb_f32\n";
1498                                 specs["ExtraGlobalScopeVars"]   = (classId == 0) ? extraVariable : "";
1499                                 specs["ExtraFunctionScopeVars"] = (classId == 1) ? extraVariable : "";
1500                                 specs["ExtraFunctions"]                 = "";
1501                                 specs["VarPtrName"]                             = "%mux_output_var_ptr";
1502                                 specs["ResultStrategy"]                 =
1503                                         "%opselect_result                       = OpSelect %sb_f32 %is_neg" + muxInput1 + muxInput2 + "\n"
1504                                         "                                                         OpStore %mux_output_copy %opselect_result\n"
1505                                         "%mux_output_var_ptr            = OpLoad %sb_f32 %mux_output_copy\n";
1506
1507                                 fragments["capability"]                 = cap;
1508                                 fragments["decoration"]                 = decoration.specialize(specs);
1509                                 fragments["pre_main"]                   = preMain.specialize(specs);
1510                                 fragments["testfun"]                    = testFunction.specialize(specs);
1511
1512                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
1513                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
1514                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
1515                                 resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
1516                                 createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
1517                         }
1518                 }
1519                 { // Variable Pointer Reads (using OpPtrAccessChain)
1520                         GraphicsResources                               resources;
1521                         map<string, string>                             specs;
1522                         std::string name                                = "reads_opptraccesschain_" + bufferType;
1523                         std::string in_1                                = isSingleInputBuffer ? " %a_2i_ptr "            : " %a_i_ptr ";
1524                         std::string in_2                                = isSingleInputBuffer ? " %a_2i_plus_1_ptr " : " %b_i_ptr ";
1525                         specs["ExtraTypes"]                             = "";
1526                         specs["ExtraGlobalScopeVars"]   = "";
1527                         specs["ExtraFunctionScopeVars"] = "";
1528                         specs["ExtraFunctions"]                 = "";
1529                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
1530                         specs["ResultStrategy"]                 =
1531                                         "%a_ptr                                 = OpAccessChain %sb_f32 %indata_a %c_i32_0 %c_i32_0\n"
1532                                         "%b_ptr                                 = OpAccessChain %sb_f32 %indata_b %c_i32_0 %c_i32_0\n"
1533                                         "%s_ptr                                 = OpAccessChain %sb_f32 %indata_s %c_i32_0 %c_i32_0\n"
1534                                         "%out_ptr               = OpAccessChain %sb_f32 %outdata  %c_i32_0 %c_i32_0\n"
1535                                         "%a_i_ptr               = OpPtrAccessChain %sb_f32 %a_ptr %30\n"
1536                                         "%b_i_ptr               = OpPtrAccessChain %sb_f32 %b_ptr %30\n"
1537                                         "%s_i_ptr               = OpPtrAccessChain %sb_f32 %s_ptr %30\n"
1538                                         "%a_2i_ptr              = OpPtrAccessChain %sb_f32 %a_ptr %two_i\n"
1539                                         "%a_2i_plus_1_ptr       = OpPtrAccessChain %sb_f32 %a_ptr %two_i_plus_1\n"
1540                                         "%mux_output_var_ptr    = OpSelect %sb_f32 %is_neg " + in_1 + in_2 + "\n";
1541
1542                         fragments["decoration"]                 = decoration.specialize(specs);
1543                         fragments["pre_main"]                   = preMain.specialize(specs);
1544                         fragments["testfun"]                    = testFunction.specialize(specs);
1545                         fragments["capability"]                 = cap;
1546
1547                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
1548                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
1549                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
1550                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
1551                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
1552                 }
1553                 {   // Variable Pointer Writes
1554                         GraphicsResources                               resources;
1555                         map<string, string>                             specs;
1556                         std::string     name                            = "writes_" + bufferType;
1557                         specs["ExtraTypes"]                             = "";
1558                         specs["ExtraGlobalScopeVars"]   = "";
1559                         specs["ExtraFunctionScopeVars"] = "";
1560                         specs["ExtraFunctions"]                 = "";
1561                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
1562                         specs["ResultStrategy"]                 =
1563                                            "%mux_output_var_ptr = OpSelect %sb_f32 %is_neg" + muxInput1 + muxInput2 + "\n" +
1564                                            "               %val = OpLoad %f32 %mux_output_var_ptr\n"
1565                                            "        %val_plus_1 = OpFAdd %f32 %val %c_f32_1\n"
1566                                            "                                      OpStore %mux_output_var_ptr %val_plus_1\n";
1567                         fragments["capability"]                 = cap;
1568                         fragments["decoration"]                 = decoration.specialize(specs);
1569                         fragments["pre_main"]                   = preMain.specialize(specs);
1570                         fragments["testfun"]                    = testFunction.specialize(specs);
1571
1572                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
1573                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
1574                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
1575                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedIncrOutput))));
1576                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
1577                 }
1578         }
1579 }
1580
1581 // Modifies the 'red channel' of the input color to the given float value.
1582 // Returns the modified color.
1583 void getExpectedOutputColor(RGBA (&inputColors)[4], RGBA (&expectedOutputColors)[4], float val)
1584 {
1585         Vec4 inColor0 = inputColors[0].toVec();
1586         Vec4 inColor1 = inputColors[1].toVec();
1587         Vec4 inColor2 = inputColors[2].toVec();
1588         Vec4 inColor3 = inputColors[3].toVec();
1589         inColor0[0] = val;
1590         inColor1[0] = val;
1591         inColor2[0] = val;
1592         inColor3[0] = val;
1593         expectedOutputColors[0] = RGBA(inColor0);
1594         expectedOutputColors[1] = RGBA(inColor1);
1595         expectedOutputColors[2] = RGBA(inColor2);
1596         expectedOutputColors[3] = RGBA(inColor3);
1597 }
1598
1599 void addTwoInputBufferReadOnlyVariablePointersGraphicsGroup (tcu::TestCaseGroup* testGroup)
1600 {
1601         const int                                               numFloatsPerInput               = 64;
1602         vector<float>                                   inputA                                  (numFloatsPerInput, 0);
1603         vector<float>                                   inputB                                  (numFloatsPerInput, 0);
1604         deUint32                                                baseOffset                              = -1;
1605         VulkanFeatures                                  requiredFeatures;
1606         map<string, string>                             fragments;
1607         RGBA                                                    defaultColors[4];
1608         RGBA                                                    expectedColors[4];
1609         vector<string>                                  extensions;
1610
1611         getDefaultColors(defaultColors);
1612
1613         // Set the proper extension features required for the tests.
1614         requiredFeatures.extVariablePointers = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS;
1615
1616         // Set the required extension.
1617         extensions.push_back("VK_KHR_variable_pointers");
1618
1619         // These tests exercise variable pointers into various levels of the following data-structure:
1620         // struct struct inner_struct {
1621         //   vec4 x[2]; // array of 2 vectors. Each vector is 4 floats.
1622         //   vec4 y[2]; // array of 2 vectors. Each vector is 4 floats.
1623         // };
1624         //
1625         // struct outer_struct {
1626         //   inner_struct r[2][2];
1627         // };
1628         //
1629         // The inner_struct contains 16 floats, and the outer_struct contains 64 floats.
1630         // Therefore the input can be an array of 64 floats.
1631
1632         // Populate the first input (inputA) to contain:  {0, 4, ... , 252} / 255.f
1633         // Populate the second input (inputB) to contain: {3, 7, ... , 255} / 255.f
1634         for (size_t i = 0; i < numFloatsPerInput; ++i)
1635         {
1636                 inputA[i] = 4*float(i) / 255;
1637                 inputB[i] = ((4*float(i)) + 3) / 255;
1638         }
1639
1640         // In the following tests we use variable pointers to point to different types:
1641         // nested structures, matrices of structures, arrays of structures, arrays of vectors, vectors of scalars, and scalars.
1642         // outer_structure.inner_structure[?][?].x[?][?];
1643         //   ^                    ^        ^  ^  ^ ^  ^
1644         //
1645         // 1. inputA                                            or      inputB                                          = nested structure
1646         // 2. inputA.r                                          or      inputB.r                                        = matrices of structures
1647         // 3. inputA.r[?]                                       or      inputB.r[?]                                     = arrays of structures
1648         // 4. inputA.r[?][?]                            or      inputB.r[?][?]                          = structures
1649         // 5. inputA.r[?][?].(x|y)                      or      inputB.r[?][?].(x|y)            = arrays of vectors
1650         // 6. inputA.r[?][?].(x|y)[?]           or      inputB.r[?][?].(x|y)[?]         = vectors of scalars
1651         // 7. inputA.r[?][?].(x|y)[?][?]        or      inputB.r[?][?].(x|y)[?][?]      = scalars
1652         const int numLevels     = 7;
1653
1654         fragments["capability"]         =       "OpCapability VariablePointers                                                  \n";
1655         fragments["extension"]          =       "OpExtension \"SPV_KHR_variable_pointers\"                              \n"
1656                                                                         "OpExtension \"SPV_KHR_storage_buffer_storage_class\"   \n";
1657
1658         const StringTemplate decoration         (
1659                 // Set the Offsets
1660                 "OpMemberDecorate                       %outer_struct 0 Offset 0        \n"
1661                 "OpMemberDecorate                       %inner_struct 0 Offset 0        \n"
1662                 "OpMemberDecorate                       %inner_struct 1 Offset 32       \n"
1663
1664                 // Set the ArrayStrides
1665                 "OpDecorate %arr2_v4float        ArrayStride 16                 \n"
1666                 "OpDecorate %arr2_inner_struct   ArrayStride 64                 \n"
1667                 "OpDecorate %mat2x2_inner_struct ArrayStride 128                \n"
1668                 "OpDecorate %sb_buf              ArrayStride 256                \n"
1669                 "OpDecorate %v4f32_ptr           ArrayStride 16                 \n"
1670
1671                 "OpDecorate                                     %outer_struct Block                     \n"
1672
1673                 "OpDecorate %in_a                       DescriptorSet 0                         \n"
1674                 "OpDecorate %in_b                       DescriptorSet 0                         \n"
1675                 "OpDecorate %in_a                       Binding 0                                       \n"
1676                 "OpDecorate %in_b                       Binding 1                                       \n"
1677         );
1678
1679         const StringTemplate preMain            (
1680                 ///////////
1681                 // TYPES //
1682                 ///////////
1683
1684                 // struct struct inner_struct {
1685                 //   vec4 x[2]; // array of 2 vectors
1686                 //   vec4 y[2]; // array of 2 vectors
1687                 // };
1688                 "%arr2_v4float                  = OpTypeArray %v4f32 %c_u32_2                                           \n"
1689                 "%inner_struct                  = OpTypeStruct %arr2_v4float %arr2_v4float                      \n"
1690
1691                 // struct outer_struct {
1692                 //   inner_struct r[2][2];
1693                 // };
1694                 "%arr2_inner_struct             = OpTypeArray %inner_struct %c_u32_2                            \n"
1695                 "%mat2x2_inner_struct   = OpTypeArray %arr2_inner_struct %c_u32_2                       \n"
1696                 "%outer_struct                  = OpTypeStruct %mat2x2_inner_struct                                     \n"
1697
1698                 ///////////////////
1699                 // POINTER TYPES //
1700                 ///////////////////
1701                 "%sb_buf                                = OpTypePointer StorageBuffer %outer_struct                     \n"
1702                 "%mat2x2_ptr                    = OpTypePointer StorageBuffer %mat2x2_inner_struct      \n"
1703                 "%arr2_ptr                              = OpTypePointer StorageBuffer %arr2_inner_struct        \n"
1704                 "%inner_struct_ptr              = OpTypePointer StorageBuffer %inner_struct                     \n"
1705                 "%arr_v4f32_ptr                 = OpTypePointer StorageBuffer %arr2_v4float                     \n"
1706                 "%v4f32_ptr                             = OpTypePointer StorageBuffer %v4f32                            \n"
1707                 "%sb_f32ptr                             = OpTypePointer StorageBuffer %f32                                      \n"
1708
1709                 ///////////////
1710                 // VARIABLES //
1711                 ///////////////
1712                 "%in_a                                  = OpVariable %sb_buf StorageBuffer                                      \n"
1713                 "%in_b                                  = OpVariable %sb_buf StorageBuffer                                      \n"
1714
1715                 ///////////////
1716                 // CONSTANTS //
1717                 ///////////////
1718                 "%c_bool_true                   = OpConstantTrue %bool                                                          \n"
1719                 "%c_bool_false                  = OpConstantFalse %bool                                                         \n"
1720
1721                 //////////////////////
1722                 // HELPER FUNCTIONS //
1723                 //////////////////////
1724                 "${helper_functions} \n"
1725         );
1726
1727         const StringTemplate selectorFunctions  (
1728                 // This selector function returns a variable pointer.
1729                 // These functions are used by tests that use OpFunctionCall to obtain the variable pointer.
1730                 "%selector_func_type    = OpTypeFunction ${selected_type} %bool ${selected_type} ${selected_type}\n"
1731                 "%choose_input_func             = OpFunction ${selected_type} None %selector_func_type\n"
1732                 "%choose_first_param    = OpFunctionParameter %bool\n"
1733                 "%first_param                   = OpFunctionParameter ${selected_type}\n"
1734                 "%second_param                  = OpFunctionParameter ${selected_type}\n"
1735                 "%selector_func_begin   = OpLabel\n"
1736                 "%result_ptr                    = OpSelect ${selected_type} %choose_first_param %first_param %second_param\n"
1737                 "                                                 OpReturnValue %result_ptr\n"
1738                 "                                                 OpFunctionEnd\n"
1739         );
1740
1741         const StringTemplate testFunction       (
1742                 "%test_code             = OpFunction %v4f32 None %v4f32_function\n"
1743                 "%param                 = OpFunctionParameter %v4f32\n"
1744                 "%entry                 = OpLabel\n"
1745
1746                 // Define the 2 pointers from which we're going to choose one.
1747                 "${a_loc} \n"
1748                 "${b_loc} \n"
1749
1750                 // Choose between the 2 pointers / variable pointers
1751                 "${selection_strategy} \n"
1752
1753                 // OpAccessChain into the variable pointer until you get to the float.
1754                 "%result_loc    = OpAccessChain %sb_f32ptr %var_ptr  ${remaining_indexes} \n"
1755
1756                 // Now load from the result_loc
1757                 "%result_val    = OpLoad %f32 %result_loc\n"
1758
1759                 // Modify the 'RED channel' of the output color to the chosen value
1760                 "%output_color  = OpCompositeInsert %v4f32 %result_val %param 0 \n"
1761
1762                 // Return and FunctionEnd
1763                 "OpReturnValue %output_color\n"
1764                 "OpFunctionEnd\n");
1765
1766         // When select is 0, the variable pointer should point to a value in the first input (inputA).
1767         // When select is 1, the variable pointer should point to a value in the second input (inputB).
1768         for (int selectInputA = 0; selectInputA < 2; ++selectInputA)
1769         {
1770                 const string selectedInputStr           = selectInputA ? "first_input"  : "second_input";
1771                 const string spirvSelectInputA          = selectInputA ? "%c_bool_true" : "%c_bool_false";
1772                 vector<float>& selectedInput            = selectInputA ? inputA                 : inputB;
1773
1774                 // The indexes chosen at each level. At any level, any given offset is exercised.
1775                 // The first index is always zero as the outer structure has only 1 member.
1776                 const int indexesForLevel[numLevels][6]= {{0, 0, 0, 0, 0, 1},
1777                                                                                                   {0, 1, 0, 1, 0, 2},
1778                                                                                                   {0, 0, 1, 0, 1, 3},
1779                                                                                                   {0, 1, 1, 1, 0, 0},
1780                                                                                                   {0, 0, 0, 1, 1, 1},
1781                                                                                                   {0, 1, 0, 0, 0, 2},
1782                                                                                                   {0, 1, 1, 1, 1, 3}};
1783
1784                 const string indexLevelNames[]          = {"_outer_struct_", "_matrices_", "_arrays_", "_inner_structs_", "_vec4arr_", "_vec4_", "_float_"};
1785                 const string inputALocations[]          = {     "",
1786                                                                                         "%a_loc = OpAccessChain %mat2x2_ptr       %in_a %c_i32_0",
1787                                                                                         "%a_loc = OpAccessChain %arr2_ptr         %in_a %c_i32_0 %c_i32_0",
1788                                                                                         "%a_loc = OpAccessChain %inner_struct_ptr %in_a %c_i32_0 %c_i32_1 %c_i32_1",
1789                                                                                         "%a_loc = OpAccessChain %arr_v4f32_ptr    %in_a %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
1790                                                                                         "%a_loc = OpAccessChain %v4f32_ptr        %in_a %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
1791                                                                                         "%a_loc = OpAccessChain %sb_f32ptr        %in_a %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3"};
1792
1793                 const string inputBLocations[]          = {     "",
1794                                                                                         "%b_loc = OpAccessChain %mat2x2_ptr       %in_b %c_i32_0",
1795                                                                                         "%b_loc = OpAccessChain %arr2_ptr         %in_b %c_i32_0 %c_i32_0",
1796                                                                                         "%b_loc = OpAccessChain %inner_struct_ptr %in_b %c_i32_0 %c_i32_1 %c_i32_1",
1797                                                                                         "%b_loc = OpAccessChain %arr_v4f32_ptr    %in_b %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
1798                                                                                         "%b_loc = OpAccessChain %v4f32_ptr        %in_b %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
1799                                                                                         "%b_loc = OpAccessChain %sb_f32ptr        %in_b %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3"};
1800
1801                 const string inputAPtrAccessChain[]     = {     "",
1802                                                                                         "%a_loc = OpPtrAccessChain %mat2x2_ptr       %in_a %c_i32_0 %c_i32_0",
1803                                                                                         "%a_loc = OpPtrAccessChain %arr2_ptr         %in_a %c_i32_0 %c_i32_0 %c_i32_0",
1804                                                                                         "%a_loc = OpPtrAccessChain %inner_struct_ptr %in_a %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1",
1805                                                                                         "%a_loc = OpPtrAccessChain %arr_v4f32_ptr    %in_a %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
1806                                                                                         "%a_loc = OpPtrAccessChain %v4f32_ptr        %in_a %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
1807                                                                                         // Next case emulates:
1808                                                                                         // %a_loc = OpPtrAccessChain %sb_f32ptr      %in_a %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3
1809                                                                                         // But rewrite it to exercise OpPtrAccessChain with a non-zero first index:
1810                                                                                         //    %a_loc_arr is a pointer to an array that we want to index with 1.
1811                                                                                         // But instead of just using OpAccessChain with first index 1, use OpAccessChain with index 0 to
1812                                                                                         // get a pointer to the first element, then send that into OpPtrAccessChain with index 1.
1813                                                                                         "%a_loc_arr = OpPtrAccessChain %arr_v4f32_ptr %in_a %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 "
1814                                                                                         "%a_loc_first_elem = OpAccessChain %v4f32_ptr %a_loc_arr %c_i32_0 "
1815                                                                                         "%a_loc = OpPtrAccessChain %sb_f32ptr %a_loc_first_elem %c_i32_1 %c_i32_3"};
1816
1817                 const string inputBPtrAccessChain[]     = {     "",
1818                                                                                         "%b_loc = OpPtrAccessChain %mat2x2_ptr       %in_b %c_i32_0 %c_i32_0",
1819                                                                                         "%b_loc = OpPtrAccessChain %arr2_ptr         %in_b %c_i32_0 %c_i32_0 %c_i32_0",
1820                                                                                         "%b_loc = OpPtrAccessChain %inner_struct_ptr %in_b %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1",
1821                                                                                         "%b_loc = OpPtrAccessChain %arr_v4f32_ptr    %in_b %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
1822                                                                                         "%b_loc = OpPtrAccessChain %v4f32_ptr        %in_b %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
1823                                                                                         // Next case emulates:
1824                                                                                         // %b_loc = OpPtrAccessChain %sb_f32ptr      %in_b %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3
1825                                                                                         // But rewrite it to exercise OpPtrAccessChain with a non-zero first index:
1826                                                                                         //    %b_loc_arr is a pointer to an array that we want to index with 1.
1827                                                                                         // But instead of just using OpAccessChain with first index 1, use OpAccessChain with index 0 to
1828                                                                                         // get a pointer to the first element, then send that into OpPtrAccessChain with index 1.
1829                                                                                         "%b_loc_arr = OpPtrAccessChain %arr_v4f32_ptr %in_b %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 "
1830                                                                                         "%b_loc_first_elem = OpAccessChain %v4f32_ptr %b_loc_arr %c_i32_0 "
1831                                                                                         "%b_loc = OpPtrAccessChain %sb_f32ptr %b_loc_first_elem %c_i32_1 %c_i32_3"};
1832
1833
1834                 const string remainingIndexesAtLevel[]= {"%c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
1835                                                                                                  "%c_i32_1 %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_2",
1836                                                                                                  "%c_i32_1 %c_i32_0 %c_i32_1 %c_i32_3",
1837                                                                                                  "%c_i32_1 %c_i32_0 %c_i32_0",
1838                                                                                                  "%c_i32_1 %c_i32_1",
1839                                                                                                  "%c_i32_2",
1840                                                                                                  ""};
1841
1842                 const string pointerTypeAtLevel[]       = {"%sb_buf", "%mat2x2_ptr", "%arr2_ptr", "%inner_struct_ptr", "%arr_v4f32_ptr", "%v4f32_ptr", "%sb_f32ptr"};
1843                 const string baseANameAtLevel[]         = {"%in_a", "%a_loc", "%a_loc", "%a_loc", "%a_loc", "%a_loc", "%a_loc"};
1844                 const string baseBNameAtLevel[]                 = {"%in_b", "%b_loc", "%b_loc", "%b_loc", "%b_loc", "%b_loc", "%b_loc"};
1845
1846                 for (int indexLevel = 0; indexLevel < numLevels; ++indexLevel)
1847                 {
1848                         baseOffset                                              = getBaseOffset(indexesForLevel[indexLevel][0],
1849                                                                                                                         indexesForLevel[indexLevel][1],
1850                                                                                                                         indexesForLevel[indexLevel][2],
1851                                                                                                                         indexesForLevel[indexLevel][3],
1852                                                                                                                         indexesForLevel[indexLevel][4],
1853                                                                                                                         indexesForLevel[indexLevel][5]);
1854
1855                         // Use OpSelect to choose between 2 pointers
1856                         {
1857                                 GraphicsResources                               resources;
1858                                 map<string, string>                             specs;
1859                                 string opCodeForTests                   = "opselect";
1860                                 string name                                             = opCodeForTests + indexLevelNames[indexLevel] + selectedInputStr;
1861                                 specs["select_inputA"]                  = spirvSelectInputA;
1862                                 specs["helper_functions"]               = "";
1863                                 specs["a_loc"]                                  = inputALocations[indexLevel];
1864                                 specs["b_loc"]                                  = inputBLocations[indexLevel];
1865                                 specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
1866                                 specs["selection_strategy"]             = "%var_ptr     = OpSelect " +
1867                                                                                                         pointerTypeAtLevel[indexLevel] + " " +
1868                                                                                                         spirvSelectInputA + " " +
1869                                                                                                         baseANameAtLevel[indexLevel] + " " +
1870                                                                                                         baseBNameAtLevel[indexLevel] + "\n";
1871                                 fragments["decoration"]                 = decoration.specialize(specs);
1872                                 fragments["pre_main"]                   = preMain.specialize(specs);
1873                                 fragments["testfun"]                    = testFunction.specialize(specs);
1874                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputA))));
1875                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputB))));
1876                                 getExpectedOutputColor(defaultColors, expectedColors, selectedInput[baseOffset]);
1877                                 createTestsForAllStages(name.c_str(), defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
1878                         }
1879                         // Use OpCopyObject to get variable pointers
1880                         {
1881                                 GraphicsResources                               resources;
1882                                 map<string, string>                             specs;
1883                                 string opCodeForTests                   = "opcopyobject";
1884                                 string name                                             = opCodeForTests + indexLevelNames[indexLevel] + selectedInputStr;
1885                                 specs["select_inputA"]                  = spirvSelectInputA;
1886                                 specs["helper_functions"]               = "";
1887                                 specs["a_loc"]                                  = inputALocations[indexLevel];
1888                                 specs["b_loc"]                                  = inputBLocations[indexLevel];
1889                                 specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
1890                                 specs["selection_strategy"]             =
1891                                                                         "%in_a_copy = OpCopyObject " + pointerTypeAtLevel[indexLevel] + " " + baseANameAtLevel[indexLevel] + "\n"
1892                                                                         "%in_b_copy = OpCopyObject " + pointerTypeAtLevel[indexLevel] + " " + baseBNameAtLevel[indexLevel] + "\n"
1893                                                                         "%var_ptr       = OpSelect " + pointerTypeAtLevel[indexLevel] + " " + spirvSelectInputA + " %in_a_copy %in_b_copy\n";
1894                                 fragments["decoration"]                 = decoration.specialize(specs);
1895                                 fragments["pre_main"]                   = preMain.specialize(specs);
1896                                 fragments["testfun"]                    = testFunction.specialize(specs);
1897                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputA))));
1898                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputB))));
1899                                 getExpectedOutputColor(defaultColors, expectedColors, selectedInput[baseOffset]);
1900                                 createTestsForAllStages(name.c_str(), defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
1901                         }
1902                         // Use OpPhi to choose between 2 pointers
1903                         {
1904                                 GraphicsResources                               resources;
1905                                 map<string, string>                             specs;
1906                                 string opCodeForTests                   = "opphi";
1907                                 string name                                             = opCodeForTests + indexLevelNames[indexLevel] + selectedInputStr;
1908                                 specs["select_inputA"]                  = spirvSelectInputA;
1909                                 specs["helper_functions"]               = "";
1910                                 specs["a_loc"]                                  = inputALocations[indexLevel];
1911                                 specs["b_loc"]                                  = inputBLocations[indexLevel];
1912                                 specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
1913                                 specs["selection_strategy"]             =
1914                                                                 "                                 OpSelectionMerge %end_label None\n"
1915                                                                 "                                 OpBranchConditional " + spirvSelectInputA + " %take_input_a %take_input_b\n"
1916                                                                 "%take_input_a  = OpLabel\n"
1917                                                                 "                                 OpBranch %end_label\n"
1918                                                                 "%take_input_b  = OpLabel\n"
1919                                                                 "                             OpBranch %end_label\n"
1920                                                                 "%end_label             = OpLabel\n"
1921                                                                 "%var_ptr               = OpPhi "
1922                                                                                                         + pointerTypeAtLevel[indexLevel] + " "
1923                                                                                                         + baseANameAtLevel[indexLevel]
1924                                                                                                         + " %take_input_a "
1925                                                                                                         + baseBNameAtLevel[indexLevel]
1926                                                                                                         + " %take_input_b\n";
1927                                 fragments["decoration"]                 = decoration.specialize(specs);
1928                                 fragments["pre_main"]                   = preMain.specialize(specs);
1929                                 fragments["testfun"]                    = testFunction.specialize(specs);
1930                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputA))));
1931                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputB))));
1932                                 getExpectedOutputColor(defaultColors, expectedColors, selectedInput[baseOffset]);
1933                                 createTestsForAllStages(name.c_str(), defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
1934                         }
1935                         // Use OpFunctionCall to choose between 2 pointers
1936                         {
1937                                 GraphicsResources                               resources;
1938                                 map<string, string>                             functionSpecs;
1939                                 map<string, string>                             specs;
1940                                 string opCodeForTests                   = "opfunctioncall";
1941                                 string name                                             = opCodeForTests + indexLevelNames[indexLevel] + selectedInputStr;
1942                                 functionSpecs["selected_type"]  = pointerTypeAtLevel[indexLevel];
1943                                 specs["helper_functions"]               = selectorFunctions.specialize(functionSpecs);
1944                                 specs["select_inputA"]                  = spirvSelectInputA;
1945                                 specs["a_loc"]                                  = inputALocations[indexLevel];
1946                                 specs["b_loc"]                                  = inputBLocations[indexLevel];
1947                                 specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
1948                                 specs["selection_strategy"]             = "%var_ptr     = OpFunctionCall "
1949                                                                                                         + pointerTypeAtLevel[indexLevel]
1950                                                                                                         + " %choose_input_func "
1951                                                                                                         + spirvSelectInputA + " "
1952                                                                                                         + baseANameAtLevel[indexLevel] + " "
1953                                                                                                         + baseBNameAtLevel[indexLevel] + "\n";
1954                                 fragments["decoration"]                 = decoration.specialize(specs);
1955                                 fragments["pre_main"]                   = preMain.specialize(specs);
1956                                 fragments["testfun"]                    = testFunction.specialize(specs);
1957                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputA))));
1958                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputB))));
1959                                 getExpectedOutputColor(defaultColors, expectedColors, selectedInput[baseOffset]);
1960                                 createTestsForAllStages(name.c_str(), defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
1961                         }
1962                         // Use OpPtrAccessChain to get variable pointers
1963                         {
1964                                 GraphicsResources                               resources;
1965                                 map<string, string>                             specs;
1966                                 string opCodeForTests                   = "opptraccesschain";
1967                                 string name                                             = opCodeForTests + indexLevelNames[indexLevel] + selectedInputStr;
1968                                 specs["select_inputA"]                  = spirvSelectInputA;
1969                                 specs["helper_functions"]               = "";
1970                                 specs["a_loc"]                                  = inputAPtrAccessChain[indexLevel];
1971                                 specs["b_loc"]                                  = inputBPtrAccessChain[indexLevel];
1972                                 specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
1973                                 specs["selection_strategy"]             = "%var_ptr     = OpSelect "
1974                                                                                                         + pointerTypeAtLevel[indexLevel] + " "
1975                                                                                                         + spirvSelectInputA + " "
1976                                                                                                         + baseANameAtLevel[indexLevel] + " "
1977                                                                                                         + baseBNameAtLevel[indexLevel] + "\n";
1978                                 fragments["decoration"]                 = decoration.specialize(specs);
1979                                 fragments["pre_main"]                   = preMain.specialize(specs);
1980                                 fragments["testfun"]                    = testFunction.specialize(specs);
1981                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputA))));
1982                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputB))));
1983                                 getExpectedOutputColor(defaultColors, expectedColors, selectedInput[baseOffset]);
1984                                 createTestsForAllStages(name.c_str(), defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
1985                         }
1986                 }
1987         }
1988 }
1989
1990 void addSingleInputBufferReadOnlyVariablePointersGraphicsGroup (tcu::TestCaseGroup* testGroup)
1991 {
1992         const int                                               numFloatsPerInnerStruct = 64;
1993         vector<float>                                   inputBuffer                             (2 * numFloatsPerInnerStruct, 0);
1994         deUint32                                                baseOffset                              = -1;
1995         VulkanFeatures                                  requiredFeatures;
1996         map<string, string>                             fragments;
1997         RGBA                                                    defaultColors[4];
1998         RGBA                                                    expectedColors[4];
1999         vector<string>                                  extensions;
2000
2001         // Set the proper extension features required for the tests.
2002         // The following tests use variable pointers confined withing a single buffer.
2003         requiredFeatures.extVariablePointers = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS_STORAGEBUFFER;
2004
2005         // Set the required extension.
2006         extensions.push_back("VK_KHR_variable_pointers");
2007
2008         getDefaultColors(defaultColors);
2009
2010         // These tests exercise variable pointers into various levels of the following data-structure:
2011         // struct struct inner_struct {
2012         //   vec4 x[2]; // array of 2 vectors. Each vector is 4 floats.
2013         //   vec4 y[2]; // array of 2 vectors. Each vector is 4 floats.
2014         // };
2015         //
2016         // struct outer_struct {
2017         //   inner_struct r[2][2];
2018         // };
2019         //
2020         // struct input_buffer {
2021         //   outer_struct a;
2022         //   outer_struct b;
2023         // }
2024         //
2025         // The inner_struct contains 16 floats, and the outer_struct contains 64 floats.
2026         // Therefore the input_buffer can be an array of 128 floats.
2027
2028         // Populate input_buffer's first member (a) to contain:  {0, 4, ... , 252} / 255.f
2029         // Populate input_buffer's second member (b) to contain: {3, 7, ... , 255} / 255.f
2030         for (size_t i = 0; i < numFloatsPerInnerStruct; ++i)
2031         {
2032                 inputBuffer[i] = 4*float(i) / 255;
2033                 inputBuffer[i + numFloatsPerInnerStruct] = ((4*float(i)) + 3) / 255;
2034         }
2035
2036         // In the following tests we use variable pointers to point to different types:
2037         // nested structures, matrices of structures, arrays of structures, arrays of vectors, vectors of scalars, and scalars.
2038         // outer_struct.inner_struct[?][?].x[?][?];
2039         //   ^              ^        ^  ^  ^ ^  ^
2040         //
2041         // 1. inputBuffer.a                                             or      inputBuffer.b                                           = nested structure
2042         // 2. inputBuffer.a.r                                   or      inputBuffer.b.r                                         = matrices of structures
2043         // 3. inputBuffer.a.r[?]                                or      inputBuffer.b.r[?]                                      = arrays of structures
2044         // 4. inputBuffer.a.r[?][?]                             or      inputBuffer.b.r[?][?]                           = structures
2045         // 5. inputBuffer.a.r[?][?].(x|y)               or      inputBuffer.b.r[?][?].(x|y)                     = arrays of vectors
2046         // 6. inputBuffer.a.r[?][?].(x|y)[?]    or      inputBuffer.b.r[?][?].(x|y)[?]          = vectors of scalars
2047         // 7. inputBuffer.a.r[?][?].(x|y)[?][?] or      inputBuffer.b.r[?][?].(x|y)[?][?]       = scalars
2048         const int numLevels     =       7;
2049
2050         fragments["capability"]         =       "OpCapability VariablePointersStorageBuffer                             \n";
2051         fragments["extension"]          =       "OpExtension \"SPV_KHR_variable_pointers\"                              \n"
2052                                                                         "OpExtension \"SPV_KHR_storage_buffer_storage_class\"   \n";
2053         const StringTemplate decoration         (
2054                 // Set the ArrayStrides
2055                 "OpDecorate %arr2_v4float        ArrayStride 16                 \n"
2056                 "OpDecorate %arr2_inner_struct   ArrayStride 64                 \n"
2057                 "OpDecorate %mat2x2_inner_struct ArrayStride 128                \n"
2058                 "OpDecorate %outer_struct_ptr    ArrayStride 256                \n"
2059                 "OpDecorate %v4f32_ptr           ArrayStride 16                 \n"
2060
2061                 // Set the Offsets
2062                 "OpMemberDecorate                       %input_buffer 0 Offset 0        \n"
2063                 "OpMemberDecorate                       %input_buffer 1 Offset 256      \n"
2064                 "OpMemberDecorate                       %outer_struct 0 Offset 0        \n"
2065                 "OpMemberDecorate                       %inner_struct 0 Offset 0        \n"
2066                 "OpMemberDecorate                       %inner_struct 1 Offset 32       \n"
2067
2068                 "OpDecorate                                     %input_buffer Block                     \n"
2069
2070                 "OpDecorate %input                      DescriptorSet 0                         \n"
2071                 "OpDecorate %input                      Binding 0                                       \n"
2072         );
2073
2074         const StringTemplate preMain            (
2075                 ///////////
2076                 // TYPES //
2077                 ///////////
2078
2079                 // struct struct inner_struct {
2080                 //   vec4 x[2]; // array of 2 vectors
2081                 //   vec4 y[2]; // array of 2 vectors
2082                 // };
2083                 "%arr2_v4float                  = OpTypeArray %v4f32 %c_u32_2                                           \n"
2084                 "%inner_struct                  = OpTypeStruct %arr2_v4float %arr2_v4float                      \n"
2085
2086                 // struct outer_struct {
2087                 //   inner_struct r[2][2];
2088                 // };
2089                 "%arr2_inner_struct             = OpTypeArray %inner_struct %c_u32_2                            \n"
2090                 "%mat2x2_inner_struct   = OpTypeArray %arr2_inner_struct %c_u32_2                       \n"
2091                 "%outer_struct                  = OpTypeStruct %mat2x2_inner_struct                                     \n"
2092
2093                 // struct input_buffer {
2094                 //   outer_struct a;
2095                 //   outer_struct b;
2096                 // }
2097                 "%input_buffer                  = OpTypeStruct %outer_struct %outer_struct                      \n"
2098
2099                 ///////////////////
2100                 // POINTER TYPES //
2101                 ///////////////////
2102                 "%input_buffer_ptr              = OpTypePointer StorageBuffer %input_buffer                     \n"
2103                 "%outer_struct_ptr              = OpTypePointer StorageBuffer %outer_struct                     \n"
2104                 "%mat2x2_ptr                    = OpTypePointer StorageBuffer %mat2x2_inner_struct      \n"
2105                 "%arr2_ptr                              = OpTypePointer StorageBuffer %arr2_inner_struct        \n"
2106                 "%inner_struct_ptr              = OpTypePointer StorageBuffer %inner_struct                     \n"
2107                 "%arr_v4f32_ptr                 = OpTypePointer StorageBuffer %arr2_v4float                     \n"
2108                 "%v4f32_ptr                             = OpTypePointer StorageBuffer %v4f32                            \n"
2109                 "%sb_f32ptr                             = OpTypePointer StorageBuffer %f32                                      \n"
2110
2111                 ///////////////
2112                 // VARIABLES //
2113                 ///////////////
2114                 "%input                                 = OpVariable %input_buffer_ptr StorageBuffer            \n"
2115
2116                 ///////////////
2117                 // CONSTANTS //
2118                 ///////////////
2119                 "%c_bool_true                   = OpConstantTrue %bool                                                          \n"
2120                 "%c_bool_false                  = OpConstantFalse %bool                                                         \n"
2121
2122                 //////////////////////
2123                 // HELPER FUNCTIONS //
2124                 //////////////////////
2125                 "${helper_functions} \n"
2126         );
2127
2128         const StringTemplate selectorFunctions  (
2129                 // These selector functions return variable pointers.
2130                 // These functions are used by tests that use OpFunctionCall to obtain the variable pointer
2131                 "%selector_func_type    = OpTypeFunction ${selected_type} %bool ${selected_type} ${selected_type}\n"
2132                 "%choose_input_func             = OpFunction ${selected_type} None %selector_func_type\n"
2133                 "%choose_first_param    = OpFunctionParameter %bool\n"
2134                 "%first_param                   = OpFunctionParameter ${selected_type}\n"
2135                 "%second_param                  = OpFunctionParameter ${selected_type}\n"
2136                 "%selector_func_begin   = OpLabel\n"
2137                 "%result_ptr                    = OpSelect ${selected_type} %choose_first_param %first_param %second_param\n"
2138                 "OpReturnValue %result_ptr\n"
2139                 "OpFunctionEnd\n"
2140         );
2141
2142         const StringTemplate testFunction       (
2143                 "%test_code             = OpFunction %v4f32 None %v4f32_function\n"
2144                 "%param                 = OpFunctionParameter %v4f32\n"
2145                 "%entry                 = OpLabel\n"
2146
2147                 // Here are the 2 nested structures:
2148                 "%in_a                  = OpAccessChain %outer_struct_ptr %input %c_i32_0\n"
2149                 "%in_b                  = OpAccessChain %outer_struct_ptr %input %c_i32_1\n"
2150
2151                 // Define the 2 pointers from which we're going to choose one.
2152                 "${a_loc} \n"
2153                 "${b_loc} \n"
2154
2155                 // Choose between the 2 pointers / variable pointers
2156                 "${selection_strategy} \n"
2157
2158                 // OpAccessChain into the variable pointer until you get to the float.
2159                 "%result_loc    = OpAccessChain %sb_f32ptr %var_ptr  ${remaining_indexes} \n"
2160
2161
2162                 // Now load from the result_loc
2163                 "%result_val    = OpLoad %f32 %result_loc\n"
2164
2165                 // Modify the 'RED channel' of the output color to the chosen value
2166                 "%output_color  = OpCompositeInsert %v4f32 %result_val %param 0 \n"
2167
2168                 // Return and FunctionEnd
2169                 "OpReturnValue %output_color\n"
2170                 "OpFunctionEnd\n");
2171
2172         // When select is 0, the variable pointer should point to a value in the first input_buffer member (a).
2173         // When select is 1, the variable pointer should point to a value in the second input_buffer member (b).
2174         // Since the 2 members of the input_buffer (a and b) are of type outer_struct, we can conveniently use
2175         // the same indexing scheme that we used for the 2-input-buffer tests.
2176         for (int selectInputA = 0; selectInputA < 2; ++selectInputA)
2177         {
2178                 const string selectedInputStr   = selectInputA ? "first_input"  : "second_input";
2179                 const string spirvSelectInputA  = selectInputA ? "%c_bool_true" : "%c_bool_false";
2180                 const int outerStructIndex              = selectInputA ? 0                              : 1;
2181
2182                 // The indexes chosen at each level. At any level, any given offset is exercised.
2183                 // outerStructIndex is 0 for member (a) and 1 for member (b).
2184                 const int indexesForLevel[numLevels][6]= {{outerStructIndex, 0, 0, 0, 0, 1},
2185                                                                                                   {outerStructIndex, 1, 0, 1, 0, 2},
2186                                                                                                   {outerStructIndex, 0, 1, 0, 1, 3},
2187                                                                                                   {outerStructIndex, 1, 1, 1, 0, 0},
2188                                                                                                   {outerStructIndex, 0, 0, 1, 1, 1},
2189                                                                                                   {outerStructIndex, 1, 0, 0, 0, 2},
2190                                                                                                   {outerStructIndex, 1, 1, 1, 1, 3}};
2191
2192                 const string indexLevelNames[]          = {"_outer_struct_", "_matrices_", "_arrays_", "_inner_structs_", "_vec4arr_", "_vec4_", "_float_"};
2193                 const string inputALocations[]          = {     "",
2194                                                                                         "%a_loc = OpAccessChain %mat2x2_ptr       %in_a %c_i32_0",
2195                                                                                         "%a_loc = OpAccessChain %arr2_ptr         %in_a %c_i32_0 %c_i32_0",
2196                                                                                         "%a_loc = OpAccessChain %inner_struct_ptr %in_a %c_i32_0 %c_i32_1 %c_i32_1",
2197                                                                                         "%a_loc = OpAccessChain %arr_v4f32_ptr    %in_a %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
2198                                                                                         "%a_loc = OpAccessChain %v4f32_ptr        %in_a %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
2199                                                                                         "%a_loc = OpAccessChain %sb_f32ptr        %in_a %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3"};
2200
2201                 const string inputBLocations[]          = {     "",
2202                                                                                         "%b_loc = OpAccessChain %mat2x2_ptr       %in_b %c_i32_0",
2203                                                                                         "%b_loc = OpAccessChain %arr2_ptr         %in_b %c_i32_0 %c_i32_0",
2204                                                                                         "%b_loc = OpAccessChain %inner_struct_ptr %in_b %c_i32_0 %c_i32_1 %c_i32_1",
2205                                                                                         "%b_loc = OpAccessChain %arr_v4f32_ptr    %in_b %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
2206                                                                                         "%b_loc = OpAccessChain %v4f32_ptr        %in_b %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
2207                                                                                         "%b_loc = OpAccessChain %sb_f32ptr        %in_b %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3"};
2208
2209                 const string inputAPtrAccessChain[]     = {     "",
2210                                                                                         "%a_loc = OpPtrAccessChain %mat2x2_ptr       %in_a %c_i32_0 %c_i32_0",
2211                                                                                         "%a_loc = OpPtrAccessChain %arr2_ptr         %in_a %c_i32_0 %c_i32_0 %c_i32_0",
2212                                                                                         "%a_loc = OpPtrAccessChain %inner_struct_ptr %in_a %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1",
2213                                                                                         "%a_loc = OpPtrAccessChain %arr_v4f32_ptr    %in_a %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
2214                                                                                         "%a_loc = OpPtrAccessChain %v4f32_ptr        %in_a %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
2215                                                                                         // Next case emulates:
2216                                                                                         // %a_loc = OpPtrAccessChain %sb_f32ptr      %in_a %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3
2217                                                                                         // But rewrite it to exercise OpPtrAccessChain with a non-zero first index:
2218                                                                                         //    %a_loc_arr is a pointer to an array that we want to index with 1.
2219                                                                                         // But instead of just using OpAccessChain with first index 1, use OpAccessChain with index 0 to
2220                                                                                         // get a pointer to the first element, then send that into OpPtrAccessChain with index 1.
2221                                                                                         "%a_loc_arr = OpPtrAccessChain %arr_v4f32_ptr %in_a %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 "
2222                                                                                         "%a_loc_first_elem = OpAccessChain %v4f32_ptr %a_loc_arr %c_i32_0 "
2223                                                                                         "%a_loc = OpPtrAccessChain %sb_f32ptr %a_loc_first_elem %c_i32_1 %c_i32_3"};
2224
2225                 const string inputBPtrAccessChain[]     = {     "",
2226                                                                                         "%b_loc = OpPtrAccessChain %mat2x2_ptr       %in_b %c_i32_0 %c_i32_0",
2227                                                                                         "%b_loc = OpPtrAccessChain %arr2_ptr         %in_b %c_i32_0 %c_i32_0 %c_i32_0",
2228                                                                                         "%b_loc = OpPtrAccessChain %inner_struct_ptr %in_b %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1",
2229                                                                                         "%b_loc = OpPtrAccessChain %arr_v4f32_ptr    %in_b %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
2230                                                                                         "%b_loc = OpPtrAccessChain %v4f32_ptr        %in_b %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_0 %c_i32_0",
2231                                                                                         // Next case emulates:
2232                                                                                         // %b_loc = OpPtrAccessChain %sb_f32ptr      %in_b %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_1 %c_i32_3
2233                                                                                         // But rewrite it to exercise OpPtrAccessChain with a non-zero first index:
2234                                                                                         //    %b_loc_arr is a pointer to an array that we want to index with 1.
2235                                                                                         // But instead of just using OpAccessChain with first index 1, use OpAccessChain with index 0 to
2236                                                                                         // get a pointer to the first element, then send that into OpPtrAccessChain with index 1.
2237                                                                                         "%b_loc_arr = OpPtrAccessChain %arr_v4f32_ptr %in_b %c_i32_0 %c_i32_0 %c_i32_1 %c_i32_1 %c_i32_1 "
2238                                                                                         "%b_loc_first_elem = OpAccessChain %v4f32_ptr %b_loc_arr %c_i32_0 "
2239                                                                                         "%b_loc = OpPtrAccessChain %sb_f32ptr %b_loc_first_elem %c_i32_1 %c_i32_3"};
2240
2241
2242                 const string remainingIndexesAtLevel[]= {"%c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_0 %c_i32_1",
2243                                                                                                  "%c_i32_1 %c_i32_0 %c_i32_1 %c_i32_0 %c_i32_2",
2244                                                                                                  "%c_i32_1 %c_i32_0 %c_i32_1 %c_i32_3",
2245                                                                                                  "%c_i32_1 %c_i32_0 %c_i32_0",
2246                                                                                                  "%c_i32_1 %c_i32_1",
2247                                                                                                  "%c_i32_2",
2248                                                                                                  ""};
2249
2250                 const string pointerTypeAtLevel[] = {"%outer_struct_ptr", "%mat2x2_ptr", "%arr2_ptr", "%inner_struct_ptr", "%arr_v4f32_ptr", "%v4f32_ptr", "%sb_f32ptr"};
2251                 const string baseANameAtLevel[]   = {"%in_a", "%a_loc", "%a_loc", "%a_loc", "%a_loc", "%a_loc", "%a_loc"};
2252                 const string baseBNameAtLevel[]   = {"%in_b", "%b_loc", "%b_loc", "%b_loc", "%b_loc", "%b_loc", "%b_loc"};
2253
2254                 for (int indexLevel = 0; indexLevel < numLevels; ++indexLevel)
2255                 {
2256                         // Use OpSelect to choose between 2 pointers
2257                         {
2258                                 GraphicsResources                               resources;
2259                                 map<string, string>                             specs;
2260                                 string opCodeForTests                   = "opselect";
2261                                 string name                                             = opCodeForTests + indexLevelNames[indexLevel] + selectedInputStr;
2262                                 specs["select_inputA"]                  = spirvSelectInputA;
2263                                 specs["helper_functions"]               = "";
2264                                 specs["a_loc"]                                  = inputALocations[indexLevel];
2265                                 specs["b_loc"]                                  = inputBLocations[indexLevel];
2266                                 specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
2267                                 specs["selection_strategy"]             = "%var_ptr     = OpSelect " +
2268                                                                                                         pointerTypeAtLevel[indexLevel] + " " +
2269                                                                                                         spirvSelectInputA + " " +
2270                                                                                                         baseANameAtLevel[indexLevel] + " " +
2271                                                                                                         baseBNameAtLevel[indexLevel] + "\n";
2272                                 baseOffset                                              = getBaseOffsetForSingleInputBuffer(indexesForLevel[indexLevel][0],
2273                                                                                                                                                                         indexesForLevel[indexLevel][1],
2274                                                                                                                                                                         indexesForLevel[indexLevel][2],
2275                                                                                                                                                                         indexesForLevel[indexLevel][3],
2276                                                                                                                                                                         indexesForLevel[indexLevel][4],
2277                                                                                                                                                                         indexesForLevel[indexLevel][5]);
2278                                 fragments["decoration"]                 = decoration.specialize(specs);
2279                                 fragments["pre_main"]                   = preMain.specialize(specs);
2280                                 fragments["testfun"]                    = testFunction.specialize(specs);
2281                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBuffer))));
2282                                 getExpectedOutputColor(defaultColors, expectedColors, inputBuffer[baseOffset]);
2283                                 createTestsForAllStages(name.c_str(), defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
2284                         }
2285                         // Use OpCopyObject to get variable pointers
2286                         {
2287                                 GraphicsResources                               resources;
2288                                 map<string, string>                             specs;
2289                                 string opCodeForTests                   = "opcopyobject";
2290                                 string name                                             = opCodeForTests + indexLevelNames[indexLevel] + selectedInputStr;
2291                                 specs["select_inputA"]                  = spirvSelectInputA;
2292                                 specs["helper_functions"]               = "";
2293                                 specs["a_loc"]                                  = inputALocations[indexLevel];
2294                                 specs["b_loc"]                                  = inputBLocations[indexLevel];
2295                                 specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
2296                                 specs["selection_strategy"]             =
2297                                                                         "%in_a_copy = OpCopyObject " + pointerTypeAtLevel[indexLevel] + " " + baseANameAtLevel[indexLevel] + "\n"
2298                                                                         "%in_b_copy = OpCopyObject " + pointerTypeAtLevel[indexLevel] + " " + baseBNameAtLevel[indexLevel] + "\n"
2299                                                                         "%var_ptr       = OpSelect " + pointerTypeAtLevel[indexLevel] + " " + spirvSelectInputA + " %in_a_copy %in_b_copy\n";
2300                                 baseOffset                                              = getBaseOffsetForSingleInputBuffer(indexesForLevel[indexLevel][0],
2301                                                                                                                                                                         indexesForLevel[indexLevel][1],
2302                                                                                                                                                                         indexesForLevel[indexLevel][2],
2303                                                                                                                                                                         indexesForLevel[indexLevel][3],
2304                                                                                                                                                                         indexesForLevel[indexLevel][4],
2305                                                                                                                                                                         indexesForLevel[indexLevel][5]);
2306                                 fragments["decoration"]                 = decoration.specialize(specs);
2307                                 fragments["pre_main"]                   = preMain.specialize(specs);
2308                                 fragments["testfun"]                    = testFunction.specialize(specs);
2309                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBuffer))));
2310                                 getExpectedOutputColor(defaultColors, expectedColors, inputBuffer[baseOffset]);
2311                                 createTestsForAllStages(name.c_str(), defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
2312                         }
2313                         // Use OpPhi to choose between 2 pointers
2314                         {
2315                                 GraphicsResources                               resources;
2316                                 map<string, string>                             specs;
2317                                 string opCodeForTests                   = "opphi";
2318                                 string name                                             = opCodeForTests + indexLevelNames[indexLevel] + selectedInputStr;
2319                                 specs["select_inputA"]                  = spirvSelectInputA;
2320                                 specs["helper_functions"]               = "";
2321                                 specs["a_loc"]                                  = inputALocations[indexLevel];
2322                                 specs["b_loc"]                                  = inputBLocations[indexLevel];
2323                                 specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
2324                                 specs["selection_strategy"]             =
2325                                                                 "                                 OpSelectionMerge %end_label None\n"
2326                                                                 "                                 OpBranchConditional " + spirvSelectInputA + " %take_input_a %take_input_b\n"
2327                                                                 "%take_input_a  = OpLabel\n"
2328                                                                 "                                 OpBranch %end_label\n"
2329                                                                 "%take_input_b  = OpLabel\n"
2330                                                                 "                             OpBranch %end_label\n"
2331                                                                 "%end_label             = OpLabel\n"
2332                                                                 "%var_ptr               = OpPhi "
2333                                                                                                         + pointerTypeAtLevel[indexLevel] + " "
2334                                                                                                         + baseANameAtLevel[indexLevel]
2335                                                                                                         + " %take_input_a "
2336                                                                                                         + baseBNameAtLevel[indexLevel]
2337                                                                                                         + " %take_input_b\n";
2338                                 baseOffset                                              = getBaseOffsetForSingleInputBuffer(indexesForLevel[indexLevel][0],
2339                                                                                                                                                                         indexesForLevel[indexLevel][1],
2340                                                                                                                                                                         indexesForLevel[indexLevel][2],
2341                                                                                                                                                                         indexesForLevel[indexLevel][3],
2342                                                                                                                                                                         indexesForLevel[indexLevel][4],
2343                                                                                                                                                                         indexesForLevel[indexLevel][5]);
2344                                 fragments["decoration"]                 = decoration.specialize(specs);
2345                                 fragments["pre_main"]                   = preMain.specialize(specs);
2346                                 fragments["testfun"]                    = testFunction.specialize(specs);
2347                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBuffer))));
2348                                 getExpectedOutputColor(defaultColors, expectedColors, inputBuffer[baseOffset]);
2349                                 createTestsForAllStages(name.c_str(), defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
2350                         }
2351                         // Use OpFunctionCall to choose between 2 pointers
2352                         {
2353                                 GraphicsResources                               resources;
2354                                 map<string, string>                             functionSpecs;
2355                                 map<string, string>                             specs;
2356                                 string opCodeForTests                   = "opfunctioncall";
2357                                 string name                                             = opCodeForTests + indexLevelNames[indexLevel] + selectedInputStr;
2358                                 //string selectedType                           = "%mat2x2_ptr";
2359                                 functionSpecs["selected_type"]  = pointerTypeAtLevel[indexLevel];
2360                                 specs["helper_functions"]               = selectorFunctions.specialize(functionSpecs);
2361                                 specs["select_inputA"]                  = spirvSelectInputA;
2362                                 specs["a_loc"]                                  = inputALocations[indexLevel];
2363                                 specs["b_loc"]                                  = inputBLocations[indexLevel];
2364                                 specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
2365                                 specs["selection_strategy"]             = "%var_ptr     = OpFunctionCall "
2366                                                                                                         + pointerTypeAtLevel[indexLevel]
2367                                                                                                         + " %choose_input_func "
2368                                                                                                         + spirvSelectInputA + " "
2369                                                                                                         + baseANameAtLevel[indexLevel] + " "
2370                                                                                                         + baseBNameAtLevel[indexLevel] + "\n";
2371                                 baseOffset                                              = getBaseOffsetForSingleInputBuffer(indexesForLevel[indexLevel][0],
2372                                                                                                                                                                         indexesForLevel[indexLevel][1],
2373                                                                                                                                                                         indexesForLevel[indexLevel][2],
2374                                                                                                                                                                         indexesForLevel[indexLevel][3],
2375                                                                                                                                                                         indexesForLevel[indexLevel][4],
2376                                                                                                                                                                         indexesForLevel[indexLevel][5]);
2377                                 fragments["decoration"]                 = decoration.specialize(specs);
2378                                 fragments["pre_main"]                   = preMain.specialize(specs);
2379                                 fragments["testfun"]                    = testFunction.specialize(specs);
2380                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBuffer))));
2381                                 getExpectedOutputColor(defaultColors, expectedColors, inputBuffer[baseOffset]);
2382                                 createTestsForAllStages(name.c_str(), defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
2383                         }
2384                         // Use OpPtrAccessChain to get variable pointers
2385                         {
2386                                 GraphicsResources                               resources;
2387                                 map<string, string>                             specs;
2388                                 string opCodeForTests                   = "opptraccesschain";
2389                                 string name                                             = opCodeForTests + indexLevelNames[indexLevel] + selectedInputStr;
2390                                 specs["select_inputA"]                  = spirvSelectInputA;
2391                                 specs["helper_functions"]               = "";
2392                                 specs["a_loc"]                                  = inputAPtrAccessChain[indexLevel];
2393                                 specs["b_loc"]                                  = inputBPtrAccessChain[indexLevel];
2394                                 specs["remaining_indexes"]              = remainingIndexesAtLevel[indexLevel];
2395                                 specs["selection_strategy"]             = "%var_ptr     = OpSelect "
2396                                                                                                         + pointerTypeAtLevel[indexLevel] + " "
2397                                                                                                         + spirvSelectInputA + " "
2398                                                                                                         + baseANameAtLevel[indexLevel] + " "
2399                                                                                                         + baseBNameAtLevel[indexLevel] + "\n";
2400                                 baseOffset                                              = getBaseOffsetForSingleInputBuffer(indexesForLevel[indexLevel][0],
2401                                                                                                                                                                         indexesForLevel[indexLevel][1],
2402                                                                                                                                                                         indexesForLevel[indexLevel][2],
2403                                                                                                                                                                         indexesForLevel[indexLevel][3],
2404                                                                                                                                                                         indexesForLevel[indexLevel][4],
2405                                                                                                                                                                         indexesForLevel[indexLevel][5]);
2406                                 fragments["decoration"]                 = decoration.specialize(specs);
2407                                 fragments["pre_main"]                   = preMain.specialize(specs);
2408                                 fragments["testfun"]                    = testFunction.specialize(specs);
2409                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBuffer))));
2410                                 getExpectedOutputColor(defaultColors, expectedColors, inputBuffer[baseOffset]);
2411                                 createTestsForAllStages(name.c_str(), defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
2412                         }
2413                 }
2414         }
2415 }
2416
2417 void addNullptrVariablePointersGraphicsGroup (tcu::TestCaseGroup* testGroup)
2418 {
2419         float                                                   someFloat                               = 78 / 255.f;
2420         vector<float>                                   input                                   (1, someFloat);
2421         vector<float>                                   expectedOutput                  (1, someFloat);
2422         VulkanFeatures                                  requiredFeatures;
2423         map<string, string>                             fragments;
2424         RGBA                                                    defaultColors[4];
2425         RGBA                                                    expectedColors[4];
2426         vector<string>                                  extensions;
2427
2428         getDefaultColors(defaultColors);
2429         getExpectedOutputColor(defaultColors, expectedColors, someFloat);
2430
2431         // Set the required extension.
2432         extensions.push_back("VK_KHR_variable_pointers");
2433
2434         // Requires the variable pointers feature.
2435         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS;
2436
2437         fragments["capability"]         =       "OpCapability VariablePointers                                                  \n";
2438         fragments["extension"]          =       "OpExtension \"SPV_KHR_variable_pointers\"                              \n"
2439                                                                         "OpExtension \"SPV_KHR_storage_buffer_storage_class\"   \n";
2440         const StringTemplate decoration         (
2441                 // Decorations
2442                 "OpDecorate %input DescriptorSet 0                              \n"
2443                 "OpDecorate %input Binding 0                                    \n"
2444
2445                 // Set the Block decoration
2446                 "OpDecorate %float_struct       Block                           \n"
2447
2448                 // Set the Offsets
2449                 "OpMemberDecorate %float_struct 0 Offset 0              \n"
2450         );
2451
2452         const StringTemplate preMain            (
2453                 // struct float_struct {
2454                 //   float x;
2455                 // };
2456                 "%float_struct          = OpTypeStruct %f32                                                                                     \n"
2457
2458                 // POINTER TYPES
2459                 "%float_struct_ptr      = OpTypePointer StorageBuffer %float_struct                                     \n"
2460                 "%sb_f32ptr                     = OpTypePointer StorageBuffer %f32                                                      \n"
2461                 "%func_f32ptrptr        = OpTypePointer Function %sb_f32ptr                                                     \n"
2462
2463                 // CONSTANTS
2464                 "%c_bool_true           = OpConstantTrue        %bool                                                                   \n"
2465                 "%c_null_ptr            = OpConstantNull        %sb_f32ptr                                                              \n"
2466
2467                 // VARIABLES
2468                 "%input                         = OpVariable %float_struct_ptr  StorageBuffer                           \n"
2469                 "%float_var                     = OpVariable %sb_f32ptr                 StorageBuffer %c_null_ptr       \n"
2470         );
2471
2472         const StringTemplate testFunction       (
2473                 "%test_code             = OpFunction %v4f32 None %v4f32_function\n"
2474                 "%param                 = OpFunctionParameter %v4f32\n"
2475                 "%entry                 = OpLabel\n"
2476
2477                 // Note that the Variable Pointers extension allows creation
2478                 // of a pointer variable with storage class of Private or Function.
2479                 "%f32_ptr_var   = OpVariable %func_f32ptrptr Function %c_null_ptr\n"
2480
2481                 "%input_loc             = OpAccessChain %sb_f32ptr %input %c_i32_0\n"
2482
2483                 // Null testing strategy
2484                 "${NullptrTestingStrategy}\n"
2485                 // Modify the 'RED channel' of the output color to the chosen value
2486                 "%output_color  = OpCompositeInsert %v4f32 %result_val %param 0 \n"
2487                 // Return and FunctionEnd
2488                 "OpReturnValue %output_color\n"
2489                 "OpFunctionEnd\n");
2490
2491         // float_var has been inintialized to NULL.
2492         // Now set it to the input variable and return it as output
2493         {
2494                 GraphicsResources                               resources;
2495                 map<string, string>                             specs;
2496                 specs["NullptrTestingStrategy"] =
2497                                                         "                  OpStore %f32_ptr_var %input_loc      \n"
2498                                                         "%loaded_f32_ptr = OpLoad  %sb_f32ptr   %f32_ptr_var    \n"
2499                                                         "%result_val     = OpLoad  %f32         %loaded_f32_ptr \n";
2500                 fragments["decoration"]                 = decoration.specialize(specs);
2501                 fragments["pre_main"]                   = preMain.specialize(specs);
2502                 fragments["testfun"]                    = testFunction.specialize(specs);
2503                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(input))));
2504                 createTestsForAllStages("opvariable_initialized_null", defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
2505         }
2506         // Use OpSelect to choose between nullptr and a valid pointer. Since we can't dereference nullptr,
2507         // it is forced to always choose the valid pointer.
2508         {
2509                 GraphicsResources                               resources;
2510                 map<string, string>                             specs;
2511                 specs["NullptrTestingStrategy"] = "%selected_ptr  = OpSelect %sb_f32ptr %c_bool_true %input_loc %c_null_ptr\n"
2512                                                                                   "%result_val    = OpLoad %f32 %selected_ptr\n";
2513                 fragments["decoration"]                 = decoration.specialize(specs);
2514                 fragments["pre_main"]                   = preMain.specialize(specs);
2515                 fragments["testfun"]                    = testFunction.specialize(specs);
2516                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(input))));
2517                 createTestsForAllStages("opselect_null_or_valid_ptr", defaultColors, expectedColors, fragments, resources, extensions, testGroup, requiredFeatures);
2518         }
2519 }
2520
2521 } // anonymous
2522
2523 tcu::TestCaseGroup* createVariablePointersComputeGroup (tcu::TestContext& testCtx)
2524 {
2525         de::MovePtr<tcu::TestCaseGroup> group   (new tcu::TestCaseGroup(testCtx, "variable_pointers", "Compute tests for SPV_KHR_variable_pointers extension"));
2526         addTestGroup(group.get(), "compute", "Test the variable pointer extension using a compute shader", addVariablePointersComputeGroup);
2527         addTestGroup(group.get(),
2528                                  "complex_types_compute",
2529                                  "Testing Variable Pointers pointing to various types in different input buffers",
2530                                  addComplexTypesVariablePointersComputeGroup);
2531         addTestGroup(group.get(),
2532                                  "nullptr_compute",
2533                                  "Test the usage of nullptr using the variable pointers extension in a compute shader",
2534                                  addNullptrVariablePointersComputeGroup);
2535
2536         return group.release();
2537 }
2538
2539 tcu::TestCaseGroup* createVariablePointersGraphicsGroup (tcu::TestContext& testCtx)
2540 {
2541         de::MovePtr<tcu::TestCaseGroup> group   (new tcu::TestCaseGroup(testCtx, "variable_pointers", "Graphics tests for SPV_KHR_variable_pointers extension"));
2542
2543         addTestGroup(group.get(), "graphics", "Testing Variable Pointers in graphics pipeline", addVariablePointersGraphicsGroup);
2544         addTestGroup(group.get(),
2545                                  "multi_buffer_read_only_graphics",
2546                                  "Testing Variable Pointers pointing to different input buffers in graphics pipeline (no SSBO writes)",
2547                                  addTwoInputBufferReadOnlyVariablePointersGraphicsGroup);
2548         addTestGroup(group.get(),
2549                                  "single_buffer_read_only_graphics",
2550                                  "Testing Variable Pointers confined to a single input buffer in graphics pipeline (no SSBO writes)",
2551                                  addSingleInputBufferReadOnlyVariablePointersGraphicsGroup);
2552         addTestGroup(group.get(),
2553                                  "nullptr_graphics",
2554                                  "Test the usage of nullptr using the variable pointers extension in graphics pipeline",
2555                                  addNullptrVariablePointersGraphicsGroup);
2556
2557         return group.release();
2558 }
2559
2560 } // SpirVAssembly
2561 } // vkt