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