1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2017 Google Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief SPIR-V Assembly Tests for the SPV_KHR_variable_pointers extension
22 *//*--------------------------------------------------------------------*/
24 #include "tcuFloat.hpp"
25 #include "tcuRGBA.hpp"
26 #include "tcuStringTemplate.hpp"
27 #include "tcuTestLog.hpp"
28 #include "tcuVectorUtil.hpp"
31 #include "vkDeviceUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkPlatform.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkQueryUtil.hpp"
37 #include "vkRefUtil.hpp"
38 #include "vkStrUtil.hpp"
39 #include "vkTypeUtil.hpp"
41 #include "deRandom.hpp"
42 #include "deStringUtil.hpp"
43 #include "deUniquePtr.hpp"
46 #include "vktSpvAsmComputeShaderCase.hpp"
47 #include "vktSpvAsmComputeShaderTestUtil.hpp"
48 #include "vktSpvAsmGraphicsShaderTestUtil.hpp"
49 #include "vktSpvAsmVariablePointersTests.hpp"
50 #include "vktTestCaseUtil.hpp"
51 #include "vktTestGroupUtil.hpp"
61 namespace SpirVAssembly
72 using tcu::TestStatus;
75 using tcu::StringTemplate;
82 void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
84 T* const typedPtr = (T*)dst;
85 for (int ndx = 0; ndx < numValues; ndx++)
86 typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
89 void addComputeVariablePointersGroup (tcu::TestCaseGroup* group)
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;
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];
109 fillRandomScalars(rnd, -100.f, 100.f, &inputAFloats[0], 2*numMuxes);
110 fillRandomScalars(rnd, -100.f, 100.f, &inputBFloats[0], 2*numMuxes);
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());
118 for (size_t i = 0; i < numMuxes; ++i)
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];
126 const StringTemplate shaderTemplate (
127 "OpCapability Shader\n"
129 "${ExtraCapability}\n"
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"
137 "OpSource GLSL 430\n"
138 "OpName %main \"main\"\n"
139 "OpName %id \"gl_GlobalInvocationID\"\n"
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"
155 + string(getComputeAsmCommonTypes()) +
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"
172 "${ExtraGlobalScopeVars}"
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"
186 // main function is the entry_point
187 "%main = OpFunction %void None %voidf\n"
190 "${ExtraFunctionScopeVars}"
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"
205 "${ExtraSetupComputations}"
209 "%mux_output = OpLoad %f32 ${VarPtrName}\n"
210 " OpStore %outloc_i %mux_output\n"
214 const bool singleInputBuffer[] = { true, false };
215 for (int inputBufferTypeIndex = 0 ; inputBufferTypeIndex < 2; ++inputBufferTypeIndex)
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 ";
225 // Set the proper extension features required for the test
226 if (isSingleInputBuffer)
227 requiredFeatures.extVariablePointers = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS_STORAGEBUFFER;
229 requiredFeatures.extVariablePointers = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS;
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));
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));
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));
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));
338 { // Test storing into Private variables.
339 const char* storageClasses[] = {"Private", "Function"};
340 for (int classId = 0; classId < 2; ++classId)
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));
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));
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));
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)
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));
482 void addGraphicsVariablePointersGroup (tcu::TestCaseGroup* testGroup)
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;
501 extensions.push_back("VK_KHR_variable_pointers");
502 getDefaultColors(defaultColors);
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];
508 fillRandomScalars(rnd, -100.f, 100.f, &inputAFloats[0], 2*numMuxes);
509 fillRandomScalars(rnd, -100.f, 100.f, &inputBFloats[0], 2*numMuxes);
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());
517 for (size_t i = 0; i < numMuxes; ++i)
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];
525 fragments["extension"] = "OpExtension \"SPV_KHR_variable_pointers\"\n"
526 "OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n";
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"
537 " ${ExtraGlobalScopeVars}"
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"
544 " ${ExtraFunctions} ");
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"
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");
572 const StringTemplate testFunction (
573 "%test_code = OpFunction %v4f32 None %v4f32_function\n"
574 "%param = OpFunctionParameter %v4f32\n"
577 "${ExtraFunctionScopeVars}"
579 "%i = OpVariable %fp_i32 Function\n"
581 "%should_run = OpFunctionCall %bool %isUniqueIdZero\n"
582 " OpSelectionMerge %end_if None\n"
583 " OpBranchConditional %should_run %run_test %end_if\n"
585 "%run_test = OpLabel\n"
586 " OpStore %i %c_i32_0\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"
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"
608 // select using a strategy.
611 // load through the variable pointer
612 "%mux_output = OpLoad %f32 ${VarPtrName}\n"
614 // store to the output vector.
615 " OpStore %loc_outdata_i %mux_output\n"
619 " %37 = OpLoad %i32 %i\n"
620 " %39 = OpIAdd %i32 %37 %c_i32_1\n"
624 // Return and FunctionEnd
626 " OpBranch %end_if\n"
627 "%end_if = OpLabel\n"
628 "OpReturnValue %param\n"
631 const bool singleInputBuffer[] = { true, false };
632 for (int inputBufferTypeIndex = 0 ; inputBufferTypeIndex < 2; ++inputBufferTypeIndex)
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 ";
642 // Set the proper extension features required for the test
643 if (isSingleInputBuffer)
644 requiredFeatures.extVariablePointers = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS_STORAGEBUFFER;
646 requiredFeatures.extVariablePointers = EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS;
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;
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";
663 fragments["capability"] = cap;
664 fragments["decoration"] = decoration.specialize(specs);
665 fragments["pre_main"] = preMain.specialize(specs);
666 fragments["testfun"] = testFunction.specialize(specs);
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);
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";
685 fragments["capability"] = cap;
686 fragments["decoration"] = decoration.specialize(specs);
687 fragments["pre_main"] = preMain.specialize(specs);
688 fragments["testfun"] = testFunction.specialize(specs);
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);
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";
715 fragments["capability"] = cap;
716 fragments["decoration"] = decoration.specialize(specs);
717 fragments["pre_main"] = preMain.specialize(specs);
718 fragments["testfun"] = testFunction.specialize(specs);
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);
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";
740 fragments["capability"] = cap;
741 fragments["decoration"] = decoration.specialize(specs);
742 fragments["pre_main"] = preMain.specialize(specs);
743 fragments["testfun"] = testFunction.specialize(specs);
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);
751 { // Test storing into Private variables.
752 const char* storageClasses[] = {"Private", "Function"};
753 for (int classId = 0; classId < 2; ++classId)
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";
770 fragments["capability"] = cap;
771 fragments["decoration"] = decoration.specialize(specs);
772 fragments["pre_main"] = preMain.specialize(specs);
773 fragments["testfun"] = testFunction.specialize(specs);
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);
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";
805 fragments["decoration"] = decoration.specialize(specs);
806 fragments["pre_main"] = preMain.specialize(specs);
807 fragments["testfun"] = testFunction.specialize(specs);
808 fragments["capability"] = cap;
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);
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);
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);
846 tcu::TestCaseGroup* createVariablePointersComputeGroup (tcu::TestContext& testCtx)
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);
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();
856 tcu::TestCaseGroup* createVariablePointersGraphicsGroup (tcu::TestContext& testCtx)
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);
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();