cc6bf0bafb4f101a22df7484a08854521fc44b00
[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 void addComputeVariablePointersGroup (tcu::TestCaseGroup* group)
90 {
91         tcu::TestContext&                               testCtx                                 = group->getTestContext();
92         de::Random                                              rnd                                             (deStringHash(group->getName()));
93         const int                                               seed                                    = testCtx.getCommandLine().getBaseSeed();
94         const int                                               numMuxes                                = 100;
95         std::string                                             inputArraySize                  = "200";
96         vector<float>                                   inputAFloats                    (2*numMuxes, 0);
97         vector<float>                                   inputBFloats                    (2*numMuxes, 0);
98         vector<float>                                   inputSFloats                    (numMuxes, 0);
99         vector<float>                                   AmuxAOutputFloats               (numMuxes, 0);
100         vector<float>                                   AmuxBOutputFloats               (numMuxes, 0);
101         vector<float>                                   incrAmuxAOutputFloats   (numMuxes, 0);
102         vector<float>                                   incrAmuxBOutputFloats   (numMuxes, 0);
103         VulkanFeatures                                  requiredFeatures;
104
105         // Each output entry is chosen as follows: ( 0 <= i < numMuxes)
106         // 1) For tests with one input buffer:  output[i] = (s[i] < 0) ? A[2*i] : A[2*i+1];
107         // 2) For tests with two input buffers: output[i] = (s[i] < 0) ? A[i]   : B[i];
108
109         fillRandomScalars(rnd, -100.f, 100.f, &inputAFloats[0], 2*numMuxes);
110         fillRandomScalars(rnd, -100.f, 100.f, &inputBFloats[0], 2*numMuxes);
111
112         // We want to guarantee that the S input has some positive and some negative values.
113         // We choose random negative numbers for the first half, random positive numbers for the second half, and then shuffle.
114         fillRandomScalars(rnd, -100.f, -1.f , &inputSFloats[0], numMuxes / 2);
115         fillRandomScalars(rnd, 1.f   , 100.f, &inputSFloats[numMuxes / 2], numMuxes / 2);
116         de::Random(seed).shuffle(inputSFloats.begin(), inputSFloats.end());
117
118         for (size_t i = 0; i < numMuxes; ++i)
119         {
120                 AmuxAOutputFloats[i]     = (inputSFloats[i] < 0) ? inputAFloats[2*i]     : inputAFloats[2*i+1];
121                 AmuxBOutputFloats[i]     = (inputSFloats[i] < 0) ? inputAFloats[i]               : inputBFloats[i];
122                 incrAmuxAOutputFloats[i] = (inputSFloats[i] < 0) ? 1 + inputAFloats[2*i] : 1+ inputAFloats[2*i+1];
123                 incrAmuxBOutputFloats[i] = (inputSFloats[i] < 0) ? 1 + inputAFloats[i]   : 1 + inputBFloats[i];
124         }
125
126         const StringTemplate shaderTemplate (
127                 "OpCapability Shader\n"
128
129                 "${ExtraCapability}\n"
130
131                 "OpExtension \"SPV_KHR_variable_pointers\"\n"
132                 "OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n"
133                 "OpMemoryModel Logical GLSL450\n"
134                 "OpEntryPoint GLCompute %main \"main\" %id\n"
135                 "OpExecutionMode %main LocalSize 1 1 1\n"
136
137                 "OpSource GLSL 430\n"
138                 "OpName %main           \"main\"\n"
139                 "OpName %id             \"gl_GlobalInvocationID\"\n"
140
141                 // Decorations
142                 "OpDecorate %id BuiltIn GlobalInvocationId\n"
143                 "OpDecorate %indata_a DescriptorSet 0\n"
144                 "OpDecorate %indata_a Binding 0\n"
145                 "OpDecorate %indata_b DescriptorSet 0\n"
146                 "OpDecorate %indata_b Binding 1\n"
147                 "OpDecorate %indata_s DescriptorSet 0\n"
148                 "OpDecorate %indata_s Binding 2\n"
149                 "OpDecorate %outdata DescriptorSet 0\n"
150                 "OpDecorate %outdata Binding 3\n"
151                 "OpDecorate %f32arr ArrayStride 4\n"
152                 "OpDecorate %buf Block\n"
153                 "OpMemberDecorate %buf 0 Offset 0\n"
154
155                 + string(getComputeAsmCommonTypes()) +
156
157                 "%sb_f32ptr                             = OpTypePointer StorageBuffer %f32\n"
158                 "%buf                                   = OpTypeStruct %f32arr\n"
159                 "%bufptr                                = OpTypePointer StorageBuffer %buf\n"
160                 "%indata_a                              = OpVariable %bufptr StorageBuffer\n"
161                 "%indata_b                              = OpVariable %bufptr StorageBuffer\n"
162                 "%indata_s                              = OpVariable %bufptr StorageBuffer\n"
163                 "%outdata                               = OpVariable %bufptr StorageBuffer\n"
164                 "%id                                    = OpVariable %uvec3ptr Input\n"
165                 "%zero                              = OpConstant %i32 0\n"
166                 "%one                                   = OpConstant %i32 1\n"
167                 "%fzero                                 = OpConstant %f32 0\n"
168                 "%fone                                  = OpConstant %f32 1\n"
169
170                 "${ExtraTypes}"
171
172                 "${ExtraGlobalScopeVars}"
173
174                 // We're going to put the "selector" function here.
175                 // This function type is needed tests that use OpFunctionCall.
176                 "%selector_func_type    = OpTypeFunction %sb_f32ptr %bool %sb_f32ptr %sb_f32ptr\n"
177                 "%choose_input_func             = OpFunction %sb_f32ptr None %selector_func_type\n"
178                 "%is_neg_param                  = OpFunctionParameter %bool\n"
179                 "%first_ptr_param               = OpFunctionParameter %sb_f32ptr\n"
180                 "%second_ptr_param              = OpFunctionParameter %sb_f32ptr\n"
181                 "%selector_func_begin   = OpLabel\n"
182                 "%result_ptr                    = OpSelect %sb_f32ptr %is_neg_param %first_ptr_param %second_ptr_param\n"
183                 "OpReturnValue %result_ptr\n"
184                 "OpFunctionEnd\n"
185
186                 // main function is the entry_point
187                 "%main                                  = OpFunction %void None %voidf\n"
188                 "%label                                 = OpLabel\n"
189
190                 "${ExtraFunctionScopeVars}"
191
192                 "%idval                                 = OpLoad %uvec3 %id\n"
193                 "%i                                             = OpCompositeExtract %u32 %idval 0\n"
194                 "%two_i                                 = OpIAdd %u32 %i %i\n"
195                 "%two_i_plus_1                  = OpIAdd %u32 %two_i %one\n"
196                 "%inloc_a_i                             = OpAccessChain %sb_f32ptr %indata_a %zero %i\n"
197                 "%inloc_b_i                             = OpAccessChain %sb_f32ptr %indata_b %zero %i\n"
198                 "%inloc_s_i             = OpAccessChain %sb_f32ptr %indata_s %zero %i\n"
199                 "%outloc_i              = OpAccessChain %sb_f32ptr %outdata  %zero %i\n"
200                 "%inloc_a_2i                    = OpAccessChain %sb_f32ptr %indata_a %zero %two_i\n"
201                 "%inloc_a_2i_plus_1             = OpAccessChain %sb_f32ptr %indata_a %zero %two_i_plus_1\n"
202                 "%inval_s_i                             = OpLoad %f32 %inloc_s_i\n"
203                 "%is_neg                                = OpFOrdLessThan %bool %inval_s_i %fzero\n"
204
205                 "${ExtraSetupComputations}"
206
207                 "${ResultStrategy}"
208
209                 "%mux_output                    = OpLoad %f32 ${VarPtrName}\n"
210                 "                                                 OpStore %outloc_i %mux_output\n"
211                 "                                                 OpReturn\n"
212                 "                                                 OpFunctionEnd\n");
213
214         const bool singleInputBuffer[]  = { true, false };
215         for (int inputBufferTypeIndex = 0 ; inputBufferTypeIndex < 2; ++inputBufferTypeIndex)
216         {
217                 const bool isSingleInputBuffer                  = singleInputBuffer[inputBufferTypeIndex];
218                 const string extraCap                                   = isSingleInputBuffer   ? "OpCapability VariablePointersStorageBuffer\n" : "OpCapability VariablePointers\n";
219                 const vector<float>& expectedOutput             = isSingleInputBuffer   ? AmuxAOutputFloats              : AmuxBOutputFloats;
220                 const vector<float>& expectedIncrOutput = isSingleInputBuffer   ? incrAmuxAOutputFloats  : incrAmuxBOutputFloats;
221                 const string bufferType                                 = isSingleInputBuffer   ? "single_buffer"        : "two_buffers";
222                 const string muxInput1                                  = isSingleInputBuffer   ? " %inloc_a_2i "                : " %inloc_a_i ";
223                 const string muxInput2                                  = isSingleInputBuffer   ? " %inloc_a_2i_plus_1 " : " %inloc_b_i ";
224
225                 // Set the proper extension features required for the test
226                 if (isSingleInputBuffer)
227                         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS_STORAGEBUFFER;
228                 else
229                         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS;
230
231                 { // Variable Pointer Reads (using OpSelect)
232                         ComputeShaderSpec                               spec;
233                         map<string, string>                             specs;
234                         string name                                             = "reads_opselect_" + bufferType;
235                         specs["ExtraCapability"]                = extraCap;
236                         specs["ExtraTypes"]                             = "";
237                         specs["ExtraGlobalScopeVars"]   = "";
238                         specs["ExtraFunctionScopeVars"] = "";
239                         specs["ExtraSetupComputations"] = "";
240                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
241                         specs["ResultStrategy"]                 = "%mux_output_var_ptr  = OpSelect %sb_f32ptr %is_neg" + muxInput1 + muxInput2 + "\n";
242                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
243                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
244                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
245                         spec.assembly                                   = shaderTemplate.specialize(specs);
246                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
247                         spec.requestedVulkanFeatures    = requiredFeatures;
248                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
249                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
250                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
251                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
252                         spec.extensions.push_back("VK_KHR_variable_pointers");
253                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
254                 }
255                 { // Variable Pointer Reads (using OpFunctionCall)
256                         ComputeShaderSpec                               spec;
257                         map<string, string>                             specs;
258                         string name                                             = "reads_opfunctioncall_" + bufferType;
259                         specs["ExtraCapability"]                = extraCap;
260                         specs["ExtraTypes"]                             = "";
261                         specs["ExtraGlobalScopeVars"]   = "";
262                         specs["ExtraFunctionScopeVars"] = "";
263                         specs["ExtraSetupComputations"] = "";
264                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
265                         specs["ResultStrategy"]                 = "%mux_output_var_ptr = OpFunctionCall %sb_f32ptr %choose_input_func %is_neg" + muxInput1 + muxInput2 + "\n";
266                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
267                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
268                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
269                         spec.assembly                                   = shaderTemplate.specialize(specs);
270                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
271                         spec.requestedVulkanFeatures    = requiredFeatures;
272                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
273                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
274                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
275                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
276                         spec.extensions.push_back("VK_KHR_variable_pointers");
277                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
278                 }
279                 { // Variable Pointer Reads (using OpPhi)
280                         ComputeShaderSpec                               spec;
281                         map<string, string>                             specs;
282                         string name                                             = "reads_opphi_" + bufferType;
283                         specs["ExtraCapability"]                = extraCap;
284                         specs["ExtraTypes"]                             = "";
285                         specs["ExtraGlobalScopeVars"]   = "";
286                         specs["ExtraFunctionScopeVars"] = "";
287                         specs["ExtraSetupComputations"] = "";
288                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
289                         specs["ResultStrategy"]                 =
290                                 "                                                         OpSelectionMerge %end_label None\n"
291                                 "                                                         OpBranchConditional %is_neg %take_mux_input_1 %take_mux_input_2\n"
292                                 "%take_mux_input_1                      = OpLabel\n"
293                                 "                                                         OpBranch %end_label\n"
294                                 "%take_mux_input_2                      = OpLabel\n"
295                                 "                                                     OpBranch %end_label\n"
296                                 "%end_label                                     = OpLabel\n"
297                                 "%mux_output_var_ptr            = OpPhi %sb_f32ptr" + muxInput1 + "%take_mux_input_1" + muxInput2 + "%take_mux_input_2\n";
298                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
299                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
300                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
301                         spec.assembly                                   = shaderTemplate.specialize(specs);
302                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
303                         spec.requestedVulkanFeatures    = requiredFeatures;
304                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
305                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
306                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
307                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
308                         spec.extensions.push_back("VK_KHR_variable_pointers");
309                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
310                 }
311                 { // Variable Pointer Reads (using OpCopyObject)
312                         ComputeShaderSpec                               spec;
313                         map<string, string>                             specs;
314                         string name                                             = "reads_opcopyobject_" + bufferType;
315                         specs["ExtraCapability"]                = extraCap;
316                         specs["ExtraTypes"]                             = "";
317                         specs["ExtraGlobalScopeVars"]   = "";
318                         specs["ExtraFunctionScopeVars"] = "";
319                         specs["ExtraSetupComputations"] = "";
320                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
321                         specs["ResultStrategy"]                 =
322                                 "%mux_input_1_copy                      = OpCopyObject %sb_f32ptr" + muxInput1 + "\n"
323                                 "%mux_input_2_copy                      = OpCopyObject %sb_f32ptr" + muxInput2 + "\n"
324                                 "%mux_output_var_ptr            = OpSelect %sb_f32ptr %is_neg %mux_input_1_copy %mux_input_2_copy\n";
325                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
326                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
327                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
328                         spec.assembly                                   = shaderTemplate.specialize(specs);
329                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
330                         spec.requestedVulkanFeatures    = requiredFeatures;
331                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
332                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
333                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
334                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
335                         spec.extensions.push_back("VK_KHR_variable_pointers");
336                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
337                 }
338                 { // Test storing into Private variables.
339                         const char* storageClasses[]            = {"Private", "Function"};
340                         for (int classId = 0; classId < 2; ++classId)
341                         {
342                                 ComputeShaderSpec                               spec;
343                                 map<string, string>                             specs;
344                                 std::string storageClass                = storageClasses[classId];
345                                 std::string name                                = "stores_" + string(de::toLower(storageClass)) + "_" + bufferType;
346                                 std::string description                 = "Test storing variable pointer into " + storageClass + " variable.";
347                                 std::string extraVariable               = "%mux_output_copy     = OpVariable %sb_f32ptrptr " + storageClass + "\n";
348                                 specs["ExtraTypes"]                             = "%sb_f32ptrptr = OpTypePointer " + storageClass + " %sb_f32ptr\n";
349                                 specs["ExtraCapability"]                = extraCap;
350                                 specs["ExtraGlobalScopeVars"]   = (classId == 0) ? extraVariable : "";
351                                 specs["ExtraFunctionScopeVars"] = (classId == 1) ? extraVariable : "";
352                                 specs["ExtraSetupComputations"] = "";
353                                 specs["VarPtrName"]                             = "%mux_output_var_ptr";
354                                 specs["ResultStrategy"]                 =
355                                         "%opselect_result                       = OpSelect %sb_f32ptr %is_neg" + muxInput1 + muxInput2 + "\n"
356                                         "                                                         OpStore %mux_output_copy %opselect_result\n"
357                                         "%mux_output_var_ptr            = OpLoad %sb_f32ptr %mux_output_copy\n";
358                                 spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
359                                 spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
360                                 spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
361                                 spec.assembly                                   = shaderTemplate.specialize(specs);
362                                 spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
363                                 spec.requestedVulkanFeatures    = requiredFeatures;
364                                 spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
365                                 spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
366                                 spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
367                                 spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
368                                 spec.extensions.push_back("VK_KHR_variable_pointers");
369                                 group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), description.c_str(), spec));
370                         }
371                 }
372                 { // Variable Pointer Reads (Using OpPtrAccessChain)
373                         ComputeShaderSpec                               spec;
374                         map<string, string>                             specs;
375                         std::string name                                = "reads_opptraccesschain_" + bufferType;
376                         std::string in_1                                = isSingleInputBuffer ? " %a_2i_ptr "            : " %a_i_ptr ";
377                         std::string in_2                                = isSingleInputBuffer ? " %a_2i_plus_1_ptr " : " %b_i_ptr ";
378                         specs["ExtraTypes"]                             = "";
379                         specs["ExtraCapability"]                = extraCap;
380                         specs["ExtraGlobalScopeVars"]   = "";
381                         specs["ExtraFunctionScopeVars"] = "";
382                         specs["ExtraSetupComputations"] = "";
383                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
384                         specs["ResultStrategy"]                 =
385                                         "%a_ptr                                 = OpAccessChain %sb_f32ptr %indata_a %zero %zero\n"
386                                         "%b_ptr                                 = OpAccessChain %sb_f32ptr %indata_b %zero %zero\n"
387                                         "%s_ptr                                 = OpAccessChain %sb_f32ptr %indata_s %zero %zero\n"
388                                         "%out_ptr               = OpAccessChain %sb_f32ptr %outdata  %zero %zero\n"
389                                         "%a_i_ptr               = OpPtrAccessChain %sb_f32ptr %a_ptr %i\n"
390                                         "%b_i_ptr               = OpPtrAccessChain %sb_f32ptr %b_ptr %i\n"
391                                         "%s_i_ptr               = OpPtrAccessChain %sb_f32ptr %s_ptr %i\n"
392                                         "%a_2i_ptr              = OpPtrAccessChain %sb_f32ptr %a_ptr %two_i\n"
393                                         "%a_2i_plus_1_ptr       = OpPtrAccessChain %sb_f32ptr %a_ptr %two_i_plus_1\n"
394                                         "%mux_output_var_ptr    = OpSelect %sb_f32ptr %is_neg " + in_1 + in_2 + "\n";
395                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
396                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
397                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
398                         spec.assembly                                   = shaderTemplate.specialize(specs);
399                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
400                         spec.requestedVulkanFeatures    = requiredFeatures;
401                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
402                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
403                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
404                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
405                         spec.extensions.push_back("VK_KHR_variable_pointers");
406                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
407                 }
408                 {   // Variable Pointer Writes
409                         ComputeShaderSpec                               spec;
410                         map<string, string>                             specs;
411                         std::string     name                            = "writes_" + bufferType;
412                         specs["ExtraCapability"]                = extraCap;
413                         specs["ExtraTypes"]                             = "";
414                         specs["ExtraGlobalScopeVars"]   = "";
415                         specs["ExtraFunctionScopeVars"] = "";
416                         specs["ExtraSetupComputations"] = "";
417                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
418                         specs["ResultStrategy"]                 = "%mux_output_var_ptr = OpSelect %sb_f32ptr %is_neg" + muxInput1 + muxInput2 + "\n" +
419                                                                                           "               %val = OpLoad %f32 %mux_output_var_ptr\n"
420                                                                                           "        %val_plus_1 = OpFAdd %f32 %val %fone\n"
421                                                                                           "                                              OpStore %mux_output_var_ptr %val_plus_1\n";
422                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
423                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
424                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
425                         spec.assembly                                   = shaderTemplate.specialize(specs);
426                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
427                         spec.requestedVulkanFeatures    = requiredFeatures;
428                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
429                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
430                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
431                         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedIncrOutput)));
432                         spec.extensions.push_back("VK_KHR_variable_pointers");
433                         group->addChild(new SpvAsmComputeShaderCase(testCtx, name.c_str(), name.c_str(), spec));
434                 }
435
436                 // If we only have VariablePointersStorageBuffer, then the extension does not apply to Workgroup storage class.
437                 // Therefore the Workgroup tests apply to cases where the VariablePointers capability is used (when 2 input buffers are used).
438                 if (!isSingleInputBuffer)
439                 {
440                         // VariablePointers on Workgroup
441                         ComputeShaderSpec                               spec;
442                         map<string, string>                             specs;
443                         std::string name                                = "workgroup_" + bufferType;
444                         specs["ExtraCapability"]                = extraCap;
445                         specs["ExtraTypes"]                             =
446                                         "%c_i32_N                               = OpConstant %i32 " + inputArraySize + " \n"
447                                         "%f32arr_N                              = OpTypeArray %f32 %c_i32_N\n"
448                                         "%f32arr_wrkgrp_ptr             = OpTypePointer Workgroup %f32arr_N\n"
449                                         "%f32_wrkgrp_ptr                = OpTypePointer Workgroup %f32\n";
450                         specs["ExtraGlobalScopeVars"]   =
451                                         "%AW                                    = OpVariable %f32arr_wrkgrp_ptr Workgroup\n"
452                                         "%BW                                    = OpVariable %f32arr_wrkgrp_ptr Workgroup\n";
453                         specs["ExtraFunctionScopeVars"] = "";
454                         specs["ExtraSetupComputations"] =
455                                         "%loc_AW_i                              = OpAccessChain %f32_wrkgrp_ptr %AW %i\n"
456                                         "%loc_BW_i                              = OpAccessChain %f32_wrkgrp_ptr %BW %i\n"
457                                         "%inval_a_i                             = OpLoad %f32 %inloc_a_i\n"
458                                         "%inval_b_i                             = OpLoad %f32 %inloc_b_i\n"
459                                         "%inval_a_2i                    = OpLoad %f32 %inloc_a_2i\n"
460                                         "%inval_a_2i_plus_1             = OpLoad %f32 %inloc_a_2i_plus_1\n";
461                         specs["VarPtrName"]                             = "%output_var_ptr";
462                         specs["ResultStrategy"]                 =
463                                         "                                                 OpStore %loc_AW_i %inval_a_i\n"
464                                         "                                                 OpStore %loc_BW_i %inval_b_i\n"
465                                         "%output_var_ptr                = OpSelect %f32_wrkgrp_ptr %is_neg %loc_AW_i %loc_BW_i\n";
466                         spec.inputTypes[0]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
467                         spec.inputTypes[1]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
468                         spec.inputTypes[2]                              = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
469                         spec.assembly                                   = shaderTemplate.specialize(specs);
470                         spec.numWorkGroups                              = IVec3(numMuxes, 1, 1);
471                         spec.requestedVulkanFeatures    = requiredFeatures;
472                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputAFloats)));
473                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputBFloats)));
474                         spec.inputs.push_back(BufferSp(new Float32Buffer(inputSFloats)));
475                         spec.outputs.push_back(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         }
480 }
481
482 void addGraphicsVariablePointersGroup (tcu::TestCaseGroup* testGroup)
483 {
484         tcu::TestContext&                               testCtx                                 = testGroup->getTestContext();
485         de::Random                                              rnd                                             (deStringHash(testGroup->getName()));
486         map<string, string>                             fragments;
487         RGBA                                                    defaultColors[4];
488         vector<string>                                  extensions;
489         const int                                               seed                                    = testCtx.getCommandLine().getBaseSeed();
490         const int                                               numMuxes                                = 100;
491         const std::string                               numMuxesStr                             = "100";
492         vector<float>                                   inputAFloats                    (2*numMuxes, 0);
493         vector<float>                                   inputBFloats                    (2*numMuxes, 0);
494         vector<float>                                   inputSFloats                    (numMuxes, 0);
495         vector<float>                                   AmuxAOutputFloats               (numMuxes, 0);
496         vector<float>                                   AmuxBOutputFloats               (numMuxes, 0);
497         vector<float>                                   incrAmuxAOutputFloats   (numMuxes, 0);
498         vector<float>                                   incrAmuxBOutputFloats   (numMuxes, 0);
499         VulkanFeatures                                  requiredFeatures;
500
501         extensions.push_back("VK_KHR_variable_pointers");
502         getDefaultColors(defaultColors);
503
504         // Each output entry is chosen as follows: ( 0 <= i < numMuxes)
505         // 1) For tests with one input buffer:  output[i] = (s[i] < 0) ? A[2*i] : A[2*i+1];
506         // 2) For tests with two input buffers: output[i] = (s[i] < 0) ? A[i]   : B[i];
507
508         fillRandomScalars(rnd, -100.f, 100.f, &inputAFloats[0], 2*numMuxes);
509         fillRandomScalars(rnd, -100.f, 100.f, &inputBFloats[0], 2*numMuxes);
510
511         // We want to guarantee that the S input has some positive and some negative values.
512         // We choose random negative numbers for the first half, random positive numbers for the second half, and then shuffle.
513         fillRandomScalars(rnd, -100.f, -1.f , &inputSFloats[0], numMuxes / 2);
514         fillRandomScalars(rnd, 1.f   , 100.f, &inputSFloats[numMuxes / 2], numMuxes / 2);
515         de::Random(seed).shuffle(inputSFloats.begin(), inputSFloats.end());
516
517         for (size_t i = 0; i < numMuxes; ++i)
518         {
519                 AmuxAOutputFloats[i]     = (inputSFloats[i] < 0) ? inputAFloats[2*i]     : inputAFloats[2*i+1];
520                 AmuxBOutputFloats[i]     = (inputSFloats[i] < 0) ? inputAFloats[i]               : inputBFloats[i];
521                 incrAmuxAOutputFloats[i] = (inputSFloats[i] < 0) ? 1 + inputAFloats[2*i] : 1 + inputAFloats[2*i+1];
522                 incrAmuxBOutputFloats[i] = (inputSFloats[i] < 0) ? 1 + inputAFloats[i]   : 1 + inputBFloats[i];
523         }
524
525         fragments["extension"]          = "OpExtension \"SPV_KHR_variable_pointers\"\n"
526                                                                   "OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n";
527
528         const StringTemplate preMain            (
529                 "%c_i32_limit = OpConstant %i32 " + numMuxesStr + "\n"
530                 "     %sb_f32 = OpTypePointer StorageBuffer %f32\n"
531                 "     %ra_f32 = OpTypeRuntimeArray %f32\n"
532                 "        %buf = OpTypeStruct %ra_f32\n"
533                 "     %sb_buf = OpTypePointer StorageBuffer %buf\n"
534
535                 " ${ExtraTypes}"
536
537                 " ${ExtraGlobalScopeVars}"
538
539                 "   %indata_a = OpVariable %sb_buf StorageBuffer\n"
540                 "   %indata_b = OpVariable %sb_buf StorageBuffer\n"
541                 "   %indata_s = OpVariable %sb_buf StorageBuffer\n"
542                 "    %outdata = OpVariable %sb_buf StorageBuffer\n"
543
544                 " ${ExtraFunctions} ");
545
546         const std::string selectorFunction      (
547                 // We're going to put the "selector" function here.
548                 // This function type is needed for tests that use OpFunctionCall.
549                 "%selector_func_type    = OpTypeFunction %sb_f32 %bool %sb_f32 %sb_f32\n"
550                 "%choose_input_func             = OpFunction %sb_f32 None %selector_func_type\n"
551                 "%is_neg_param                  = OpFunctionParameter %bool\n"
552                 "%first_ptr_param               = OpFunctionParameter %sb_f32\n"
553                 "%second_ptr_param              = OpFunctionParameter %sb_f32\n"
554                 "%selector_func_begin   = OpLabel\n"
555                 "%result_ptr                    = OpSelect %sb_f32 %is_neg_param %first_ptr_param %second_ptr_param\n"
556                 "OpReturnValue %result_ptr\n"
557                 "OpFunctionEnd\n");
558
559         const StringTemplate decoration         (
560                 "OpMemberDecorate %buf 0 Offset 0\n"
561                 "OpDecorate %buf Block\n"
562                 "OpDecorate %ra_f32 ArrayStride 4\n"
563                 "OpDecorate %indata_a DescriptorSet 0\n"
564                 "OpDecorate %indata_b DescriptorSet 0\n"
565                 "OpDecorate %indata_s DescriptorSet 0\n"
566                 "OpDecorate %outdata  DescriptorSet 0\n"
567                 "OpDecorate %indata_a Binding 0\n"
568                 "OpDecorate %indata_b Binding 1\n"
569                 "OpDecorate %indata_s Binding 2\n"
570                 "OpDecorate %outdata  Binding 3\n");
571
572         const StringTemplate testFunction       (
573                 "%test_code             = OpFunction %v4f32 None %v4f32_function\n"
574                 "%param                 = OpFunctionParameter %v4f32\n"
575                 "%entry                 = OpLabel\n"
576
577                 "${ExtraFunctionScopeVars}"
578
579                 "%i                             = OpVariable %fp_i32 Function\n"
580
581                 "%should_run    = OpFunctionCall %bool %isUniqueIdZero\n"
582                 "                 OpSelectionMerge %end_if None\n"
583                 "                 OpBranchConditional %should_run %run_test %end_if\n"
584
585                 "%run_test      = OpLabel\n"
586                 "                               OpStore %i %c_i32_0\n"
587                 "                               OpBranch %loop\n"
588                 // loop header
589                 "%loop                  = OpLabel\n"
590                 "%15                    = OpLoad %i32 %i\n"
591                 "%lt                    = OpSLessThan %bool %15 %c_i32_limit\n"
592                 "                               OpLoopMerge %merge %inc None\n"
593                 "                               OpBranchConditional %lt %write %merge\n"
594                 // loop body
595                 "%write                         = OpLabel\n"
596                 "%30                            = OpLoad %i32 %i\n"
597                 "%two_i                         = OpIAdd %i32 %30 %30\n"
598                 "%two_i_plus_1          = OpIAdd %i32 %two_i %c_i32_1\n"
599                 "%loc_s_i                       = OpAccessChain %sb_f32 %indata_s %c_i32_0 %30\n"
600                 "%loc_a_i                       = OpAccessChain %sb_f32 %indata_a %c_i32_0 %30\n"
601                 "%loc_b_i                       = OpAccessChain %sb_f32 %indata_b %c_i32_0 %30\n"
602                 "%loc_a_2i                      = OpAccessChain %sb_f32 %indata_a %c_i32_0 %two_i\n"
603                 "%loc_a_2i_plus_1       = OpAccessChain %sb_f32 %indata_a %c_i32_0 %two_i_plus_1\n"
604                 "%loc_outdata_i         = OpAccessChain %sb_f32 %outdata  %c_i32_0 %30\n"
605                 "%val_s_i                       = OpLoad %f32 %loc_s_i\n"
606                 "%is_neg                        = OpFOrdLessThan %bool %val_s_i %c_f32_0\n"
607
608                 // select using a strategy.
609                 "${ResultStrategy}"
610
611                 // load through the variable pointer
612                 "%mux_output    = OpLoad %f32 ${VarPtrName}\n"
613
614                 // store to the output vector.
615                 "                               OpStore %loc_outdata_i %mux_output\n"
616                 "                               OpBranch %inc\n"
617                 // ++i
618                 "  %inc                 = OpLabel\n"
619                 "   %37                 = OpLoad %i32 %i\n"
620                 "   %39                 = OpIAdd %i32 %37 %c_i32_1\n"
621                 "         OpStore %i %39\n"
622                 "         OpBranch %loop\n"
623
624                 // Return and FunctionEnd
625                 "%merge                 = OpLabel\n"
626                 "                 OpBranch %end_if\n"
627                 "%end_if                = OpLabel\n"
628                 "OpReturnValue %param\n"
629                 "OpFunctionEnd\n");
630
631         const bool singleInputBuffer[] = { true, false };
632         for (int inputBufferTypeIndex = 0 ; inputBufferTypeIndex < 2; ++inputBufferTypeIndex)
633         {
634                 const bool isSingleInputBuffer                  = singleInputBuffer[inputBufferTypeIndex];
635                 const string cap                                                = isSingleInputBuffer   ? "OpCapability VariablePointersStorageBuffer\n" : "OpCapability VariablePointers\n";
636                 const vector<float>& expectedOutput             = isSingleInputBuffer   ? AmuxAOutputFloats              : AmuxBOutputFloats;
637                 const vector<float>& expectedIncrOutput = isSingleInputBuffer   ? incrAmuxAOutputFloats  : incrAmuxBOutputFloats;
638                 const string bufferType                                 = isSingleInputBuffer   ? "single_buffer"                : "two_buffers";
639                 const string muxInput1                                  = isSingleInputBuffer   ? " %loc_a_2i "                  : " %loc_a_i ";
640                 const string muxInput2                                  = isSingleInputBuffer   ? " %loc_a_2i_plus_1 "   : " %loc_b_i ";
641
642                 // Set the proper extension features required for the test
643                 if (isSingleInputBuffer)
644                         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS_STORAGEBUFFER;
645                 else
646                         requiredFeatures.extVariablePointers    = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS;
647
648                 // All of the following tests write their results into an output SSBO, therefore they require the following features.
649                 requiredFeatures.coreFeatures.vertexPipelineStoresAndAtomics = DE_TRUE;
650                 requiredFeatures.coreFeatures.fragmentStoresAndAtomics           = DE_TRUE;
651
652                 { // Variable Pointer Reads (using OpSelect)
653                         GraphicsResources                               resources;
654                         map<string, string>                             specs;
655                         string name                                             = "reads_opselect_" + bufferType;
656                         specs["ExtraTypes"]                             = "";
657                         specs["ExtraGlobalScopeVars"]   = "";
658                         specs["ExtraFunctionScopeVars"] = "";
659                         specs["ExtraFunctions"]                 = "";
660                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
661                         specs["ResultStrategy"]                 = "%mux_output_var_ptr  = OpSelect %sb_f32 %is_neg" + muxInput1 + muxInput2 + "\n";
662
663                         fragments["capability"]                 = cap;
664                         fragments["decoration"]                 = decoration.specialize(specs);
665                         fragments["pre_main"]                   = preMain.specialize(specs);
666                         fragments["testfun"]                    = testFunction.specialize(specs);
667
668                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
669                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
670                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
671                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
672                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
673                 }
674                 { // Variable Pointer Reads (using OpFunctionCall)
675                         GraphicsResources                               resources;
676                         map<string, string>                             specs;
677                         string name                                             = "reads_opfunctioncall_" + bufferType;
678                         specs["ExtraTypes"]                             = "";
679                         specs["ExtraGlobalScopeVars"]   = "";
680                         specs["ExtraFunctionScopeVars"] = "";
681                         specs["ExtraFunctions"]                 = selectorFunction;
682                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
683                         specs["ResultStrategy"]                 = "%mux_output_var_ptr = OpFunctionCall %sb_f32 %choose_input_func %is_neg" + muxInput1 + muxInput2 + "\n";
684
685                         fragments["capability"]                 = cap;
686                         fragments["decoration"]                 = decoration.specialize(specs);
687                         fragments["pre_main"]                   = preMain.specialize(specs);
688                         fragments["testfun"]                    = testFunction.specialize(specs);
689
690                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
691                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
692                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
693                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
694                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
695                 }
696                 { // Variable Pointer Reads (using OpPhi)
697                         GraphicsResources                               resources;
698                         map<string, string>                             specs;
699                         string name                                             = "reads_opphi_" + bufferType;
700                         specs["ExtraTypes"]                             = "";
701                         specs["ExtraGlobalScopeVars"]   = "";
702                         specs["ExtraFunctionScopeVars"] = "";
703                         specs["ExtraFunctions"]                 = "";
704                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
705                         specs["ResultStrategy"]                 =
706                                 "                                                         OpSelectionMerge %end_label None\n"
707                                 "                                                         OpBranchConditional %is_neg %take_mux_input_1 %take_mux_input_2\n"
708                                 "%take_mux_input_1                      = OpLabel\n"
709                                 "                                                         OpBranch %end_label\n"
710                                 "%take_mux_input_2                      = OpLabel\n"
711                                 "                                                     OpBranch %end_label\n"
712                                 "%end_label                                     = OpLabel\n"
713                                 "%mux_output_var_ptr            = OpPhi %sb_f32" + muxInput1 + "%take_mux_input_1" + muxInput2 + "%take_mux_input_2\n";
714
715                         fragments["capability"]                 = cap;
716                         fragments["decoration"]                 = decoration.specialize(specs);
717                         fragments["pre_main"]                   = preMain.specialize(specs);
718                         fragments["testfun"]                    = testFunction.specialize(specs);
719
720                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
721                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
722                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
723                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
724                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
725                 }
726                 { // Variable Pointer Reads (using OpCopyObject)
727                         GraphicsResources                               resources;
728                         map<string, string>                             specs;
729                         string name                                             = "reads_opcopyobject_" + bufferType;
730                         specs["ExtraTypes"]                             = "";
731                         specs["ExtraGlobalScopeVars"]   = "";
732                         specs["ExtraFunctionScopeVars"] = "";
733                         specs["ExtraFunctions"]                 = "";
734                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
735                         specs["ResultStrategy"]                 =
736                                 "%mux_input_1_copy                      = OpCopyObject %sb_f32" + muxInput1 + "\n"
737                                 "%mux_input_2_copy                      = OpCopyObject %sb_f32" + muxInput2 + "\n"
738                                 "%mux_output_var_ptr            = OpSelect %sb_f32 %is_neg %mux_input_1_copy %mux_input_2_copy\n";
739
740                         fragments["capability"]                 = cap;
741                         fragments["decoration"]                 = decoration.specialize(specs);
742                         fragments["pre_main"]                   = preMain.specialize(specs);
743                         fragments["testfun"]                    = testFunction.specialize(specs);
744
745                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
746                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
747                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
748                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
749                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
750                 }
751                 { // Test storing into Private variables.
752                         const char* storageClasses[]            = {"Private", "Function"};
753                         for (int classId = 0; classId < 2; ++classId)
754                         {
755                                 GraphicsResources                               resources;
756                                 map<string, string>                             specs;
757                                 std::string storageClass                = storageClasses[classId];
758                                 std::string name                                = "stores_" + string(de::toLower(storageClass)) + "_" + bufferType;
759                                 std::string extraVariable               = "%mux_output_copy     = OpVariable %sb_f32ptrptr " + storageClass + "\n";
760                                 specs["ExtraTypes"]                             = "%sb_f32ptrptr = OpTypePointer " + storageClass + " %sb_f32\n";
761                                 specs["ExtraGlobalScopeVars"]   = (classId == 0) ? extraVariable : "";
762                                 specs["ExtraFunctionScopeVars"] = (classId == 1) ? extraVariable : "";
763                                 specs["ExtraFunctions"]                 = "";
764                                 specs["VarPtrName"]                             = "%mux_output_var_ptr";
765                                 specs["ResultStrategy"]                 =
766                                         "%opselect_result                       = OpSelect %sb_f32 %is_neg" + muxInput1 + muxInput2 + "\n"
767                                         "                                                         OpStore %mux_output_copy %opselect_result\n"
768                                         "%mux_output_var_ptr            = OpLoad %sb_f32 %mux_output_copy\n";
769
770                                 fragments["capability"]                 = cap;
771                                 fragments["decoration"]                 = decoration.specialize(specs);
772                                 fragments["pre_main"]                   = preMain.specialize(specs);
773                                 fragments["testfun"]                    = testFunction.specialize(specs);
774
775                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
776                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
777                                 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
778                                 resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
779                                 createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
780                         }
781                 }
782                 { // Variable Pointer Reads (using OpPtrAccessChain)
783                         GraphicsResources                               resources;
784                         map<string, string>                             specs;
785                         std::string name                                = "reads_opptraccesschain_" + bufferType;
786                         std::string in_1                                = isSingleInputBuffer ? " %a_2i_ptr "            : " %a_i_ptr ";
787                         std::string in_2                                = isSingleInputBuffer ? " %a_2i_plus_1_ptr " : " %b_i_ptr ";
788                         specs["ExtraTypes"]                             = "";
789                         specs["ExtraGlobalScopeVars"]   = "";
790                         specs["ExtraFunctionScopeVars"] = "";
791                         specs["ExtraFunctions"]                 = "";
792                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
793                         specs["ResultStrategy"]                 =
794                                         "%a_ptr                                 = OpAccessChain %sb_f32 %indata_a %c_i32_0 %c_i32_0\n"
795                                         "%b_ptr                                 = OpAccessChain %sb_f32 %indata_b %c_i32_0 %c_i32_0\n"
796                                         "%s_ptr                                 = OpAccessChain %sb_f32 %indata_s %c_i32_0 %c_i32_0\n"
797                                         "%out_ptr               = OpAccessChain %sb_f32 %outdata  %c_i32_0 %c_i32_0\n"
798                                         "%a_i_ptr               = OpPtrAccessChain %sb_f32 %a_ptr %30\n"
799                                         "%b_i_ptr               = OpPtrAccessChain %sb_f32 %b_ptr %30\n"
800                                         "%s_i_ptr               = OpPtrAccessChain %sb_f32 %s_ptr %30\n"
801                                         "%a_2i_ptr              = OpPtrAccessChain %sb_f32 %a_ptr %two_i\n"
802                                         "%a_2i_plus_1_ptr       = OpPtrAccessChain %sb_f32 %a_ptr %two_i_plus_1\n"
803                                         "%mux_output_var_ptr    = OpSelect %sb_f32 %is_neg " + in_1 + in_2 + "\n";
804
805                         fragments["decoration"]                 = decoration.specialize(specs);
806                         fragments["pre_main"]                   = preMain.specialize(specs);
807                         fragments["testfun"]                    = testFunction.specialize(specs);
808                         fragments["capability"]                 = cap;
809
810                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
811                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
812                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
813                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedOutput))));
814                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
815                 }
816                 {   // Variable Pointer Writes
817                         GraphicsResources                               resources;
818                         map<string, string>                             specs;
819                         std::string     name                            = "writes_" + bufferType;
820                         specs["ExtraTypes"]                             = "";
821                         specs["ExtraGlobalScopeVars"]   = "";
822                         specs["ExtraFunctionScopeVars"] = "";
823                         specs["ExtraFunctions"]                 = "";
824                         specs["VarPtrName"]                             = "%mux_output_var_ptr";
825                         specs["ResultStrategy"]                 =
826                                            "%mux_output_var_ptr = OpSelect %sb_f32 %is_neg" + muxInput1 + muxInput2 + "\n" +
827                                            "               %val = OpLoad %f32 %mux_output_var_ptr\n"
828                                            "        %val_plus_1 = OpFAdd %f32 %val %c_f32_1\n"
829                                            "                                      OpStore %mux_output_var_ptr %val_plus_1\n";
830                         fragments["capability"]                 = cap;
831                         fragments["decoration"]                 = decoration.specialize(specs);
832                         fragments["pre_main"]                   = preMain.specialize(specs);
833                         fragments["testfun"]                    = testFunction.specialize(specs);
834
835                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputAFloats))));
836                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputBFloats))));
837                         resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputSFloats))));
838                         resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(expectedIncrOutput))));
839                         createTestsForAllStages(name.c_str(), defaultColors, defaultColors, fragments, resources, extensions, testGroup, requiredFeatures);
840                 }
841         }
842 }
843
844 } // anonymous
845
846 tcu::TestCaseGroup* createVariablePointersComputeGroup (tcu::TestContext& testCtx)
847 {
848         de::MovePtr<tcu::TestCaseGroup> group   (new tcu::TestCaseGroup(testCtx, "variable_pointers", "Compute tests for SPV_KHR_variable_pointers extension"));
849         addTestGroup(group.get(), "compute", "Test the variable pointer extension using a compute shader", addComputeVariablePointersGroup);
850
851         // \todo [2017-03-17 ehsann] A couple of things to do:
852         // * Add more tests (similar to existing ones) using data types other than Float.
853         return group.release();
854 }
855
856 tcu::TestCaseGroup* createVariablePointersGraphicsGroup (tcu::TestContext& testCtx)
857 {
858         de::MovePtr<tcu::TestCaseGroup> group   (new tcu::TestCaseGroup(testCtx, "variable_pointers", "Graphics tests for SPV_KHR_variable_pointers extension"));
859         addTestGroup(group.get(), "graphics", "Testing Variable Pointers in graphics pipeline", addGraphicsVariablePointersGroup);
860
861         // \todo [2017-03-17 ehsann] A couple of things to do:
862         // * Add more tests (similar to existing ones) using data types other than Float.
863         return group.release();
864 }
865
866 } // SpirVAssembly
867 } // vkt