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