1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2018 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 indexing with access chain operations.
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktSpvAsmIndexingTests.hpp"
25 #include "vktSpvAsmComputeShaderCase.hpp"
26 #include "vktSpvAsmComputeShaderTestUtil.hpp"
27 #include "vktSpvAsmGraphicsShaderTestUtil.hpp"
28
29 #include "tcuStringTemplate.hpp"
30 #include "tcuVectorUtil.hpp"
31
32 namespace vkt
33 {
34 namespace SpirVAssembly
35 {
36
37 using namespace vk;
38 using std::map;
39 using std::pair;
40 using std::string;
41 using std::vector;
42 using tcu::IVec3;
43 using tcu::Mat4;
44 using tcu::RGBA;
45 using tcu::StringTemplate;
46 using tcu::UVec4;
47 using tcu::Vec4;
48
49 namespace
50 {
51
52 enum ChainOp
53 {
54 CHAIN_OP_ACCESS_CHAIN = 0,
55 CHAIN_OP_IN_BOUNDS_ACCESS_CHAIN,
56 CHAIN_OP_PTR_ACCESS_CHAIN,
57
58 CHAIN_OP_LAST
59 };
60 static const int idxSizes[] = {16, 32, 64};
61 static const string chainOpTestNames[] = {"opaccesschain", "opinboundsaccesschain", "opptraccesschain"};
62
63 struct InputData
64 {
65 Mat4 matrix[32][32];
66 };
67
addComputeIndexingStructTests(tcu::TestCaseGroup * group)68 void addComputeIndexingStructTests(tcu::TestCaseGroup *group)
69 {
70 tcu::TestContext &testCtx = group->getTestContext();
71 de::MovePtr<tcu::TestCaseGroup> structGroup(new tcu::TestCaseGroup(testCtx, "struct"));
72 de::Random rnd(deStringHash(group->getName()));
73 const int numItems = 128;
74 const int numStructs = 2;
75 const int numInputFloats = (int)sizeof(InputData) / 4 * numStructs;
76 vector<float> inputData;
77 vector<UVec4> indexSelectorData;
78
79 inputData.reserve(numInputFloats);
80 for (uint32_t numIdx = 0; numIdx < numInputFloats; ++numIdx)
81 inputData.push_back(rnd.getFloat());
82
83 indexSelectorData.reserve(numItems);
84 for (uint32_t numIdx = 0; numIdx < numItems; ++numIdx)
85 indexSelectorData.push_back(tcu::randomVector<uint32_t, 4>(rnd, UVec4(0), UVec4(31, 31, 3, 3)));
86
87 for (int chainOpIdx = 0; chainOpIdx < CHAIN_OP_LAST; ++chainOpIdx)
88 {
89 for (int idxSizeIdx = 0; idxSizeIdx < DE_LENGTH_OF_ARRAY(idxSizes); ++idxSizeIdx)
90 {
91 for (int sign = 0; sign < 2; ++sign)
92 {
93 const int idxSize = idxSizes[idxSizeIdx];
94 const string testName =
95 chainOpTestNames[chainOpIdx] + string(sign == 0 ? "_u" : "_s") + de::toString(idxSize);
96 VulkanFeatures vulkanFeatures;
97 map<string, string> specs;
98 vector<float> outputData;
99 ComputeShaderSpec spec;
100 int element = 0;
101
102 // Index an input buffer containing 2D array of 4x4 matrices. The indices are read from another
103 // input and converted to the desired bit size and sign.
104 const StringTemplate shaderSource(
105 " OpCapability Shader\n"
106 " ${intcaps:opt}\n"
107 " ${variablepointercaps:opt}\n"
108 " ${extensions:opt}\n"
109 " %1 = OpExtInstImport \"GLSL.std.450\"\n"
110 " OpMemoryModel Logical GLSL450\n"
111 " OpEntryPoint GLCompute %main \"main\" %gl_GlobalInvocationID\n"
112 " OpExecutionMode %main LocalSize 1 1 1\n"
113 " OpSource GLSL 430\n"
114 " OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId\n"
115 " OpDecorate %_arr_float_uint_128 ArrayStride 4\n"
116 " OpMemberDecorate %Output 0 Offset 0\n"
117 " OpDecorate %Output BufferBlock\n"
118 " OpDecorate %dataOutput DescriptorSet 0\n"
119 " OpDecorate %dataOutput Binding 2\n"
120 " OpDecorate %_arr_mat4v4float_uint_32 ArrayStride 64\n"
121 " OpDecorate %_arr__arr_mat4v4float_uint_32_uint_32 ArrayStride 2048\n"
122 " OpMemberDecorate %InputStruct 0 ColMajor\n"
123 " OpMemberDecorate %InputStruct 0 Offset 0\n"
124 " OpMemberDecorate %InputStruct 0 MatrixStride 16\n"
125 " OpDecorate %InputStructArr ArrayStride 65536\n"
126 " OpDecorate %Input ${inputdecoration}\n"
127 " OpMemberDecorate %Input 0 Offset 0\n"
128 " OpDecorate %dataInput DescriptorSet 0\n"
129 " OpDecorate %dataInput Binding 0\n"
130 " OpDecorate %_ptr_buffer_InputStruct ArrayStride 65536\n"
131 " OpDecorate %_arr_v4uint_uint_128 ArrayStride 16\n"
132 " OpMemberDecorate %DataSelector 0 Offset 0\n"
133 " OpDecorate %DataSelector BufferBlock\n"
134 " OpDecorate %selector DescriptorSet 0\n"
135 " OpDecorate %selector Binding 1\n"
136 " %void = OpTypeVoid\n"
137 " %3 = OpTypeFunction %void\n"
138 " %u32 = OpTypeInt 32 0\n"
139 " %i32 = OpTypeInt 32 1\n"
140 "${intdecl:opt}"
141 " %idx_0 = OpConstant ${idx_int} 0\n"
142 " %idx_1 = OpConstant ${idx_int} 1\n"
143 " %idx_2 = OpConstant ${idx_int} 2\n"
144 " %idx_3 = OpConstant ${idx_int} 3\n"
145 " %_ptr_Function_uint32 = OpTypePointer Function %u32\n"
146 " %v3uint32 = OpTypeVector %u32 3\n"
147 " %_ptr_Input_v3uint32 = OpTypePointer Input %v3uint32\n"
148 " %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint32 Input\n"
149 " %_ptr_Input_uint32 = OpTypePointer Input %u32\n"
150 " %float = OpTypeFloat 32\n"
151 " %uint_128 = OpConstant %u32 128\n"
152 " %uint_32 = OpConstant %u32 32\n"
153 " %uint_2 = OpConstant %u32 2\n"
154 " %_arr_float_uint_128 = OpTypeArray %float %uint_128\n"
155 " %Output = OpTypeStruct %_arr_float_uint_128\n"
156 " %_ptr_Uniform_Output = OpTypePointer Uniform %Output\n"
157 " %dataOutput = OpVariable %_ptr_Uniform_Output Uniform\n"
158 " %v4float = OpTypeVector %float 4\n"
159 " %mat4v4float = OpTypeMatrix %v4float 4\n"
160 " %_arr_mat4v4float_uint_32 = OpTypeArray %mat4v4float %uint_32\n"
161 " %_arr__arr_mat4v4float_uint_32_uint_32 = OpTypeArray %_arr_mat4v4float_uint_32 %uint_32\n"
162 " %InputStruct = OpTypeStruct %_arr__arr_mat4v4float_uint_32_uint_32\n"
163 " %InputStructArr = OpTypeArray %InputStruct %uint_2\n"
164 " %Input = OpTypeStruct %InputStructArr\n"
165 " %_ptr_buffer_Input = OpTypePointer ${inputstorageclass} %Input\n"
166 " %dataInput = OpVariable %_ptr_buffer_Input ${inputstorageclass}\n"
167 " %_ptr_buffer_InputStruct = OpTypePointer ${inputstorageclass} %InputStruct\n"
168 " %v4uint32 = OpTypeVector %u32 4\n"
169 " %_arr_v4uint_uint_128 = OpTypeArray %v4uint32 %uint_128\n"
170 " %DataSelector = OpTypeStruct %_arr_v4uint_uint_128\n"
171 "%_ptr_Uniform_DataSelector = OpTypePointer Uniform %DataSelector\n"
172 " %selector = OpVariable %_ptr_Uniform_DataSelector Uniform\n"
173 " %_ptr_Uniform_uint32 = OpTypePointer Uniform %u32\n"
174 " %_ptr_Uniform_float = OpTypePointer Uniform %float\n"
175 " ${ptr_buffer_float:opt}\n"
176
177 " %main = OpFunction %void None %3\n"
178 " %5 = OpLabel\n"
179 " %i = OpVariable %_ptr_Function_uint32 Function\n"
180 " %14 = OpAccessChain %_ptr_Input_uint32 %gl_GlobalInvocationID %idx_0\n"
181 " %15 = OpLoad %u32 %14\n"
182 " OpStore %i %15\n"
183 " %uint_i = OpLoad %u32 %i\n"
184 " %39 = OpAccessChain %_ptr_Uniform_uint32 %selector %idx_0 %uint_i %idx_0\n"
185 " %40 = OpLoad %u32 %39\n"
186 " %43 = OpAccessChain %_ptr_Uniform_uint32 %selector %idx_0 %uint_i %idx_1\n"
187 " %44 = OpLoad %u32 %43\n"
188 " %47 = OpAccessChain %_ptr_Uniform_uint32 %selector %idx_0 %uint_i %idx_2\n"
189 " %48 = OpLoad %u32 %47\n"
190 " %51 = OpAccessChain %_ptr_Uniform_uint32 %selector %idx_0 %uint_i %idx_3\n"
191 " %52 = OpLoad %u32 %51\n"
192 " %i0 = ${convert} ${idx_int} %40\n"
193 " %i1 = ${convert} ${idx_int} %44\n"
194 " %i2 = ${convert} ${idx_int} %48\n"
195 " %i3 = ${convert} ${idx_int} %52\n"
196 " %inputFirstElement = OpAccessChain %_ptr_buffer_InputStruct %dataInput %idx_0 %idx_0\n"
197 " %54 = ${accesschain}\n"
198 " %55 = OpLoad %float %54\n"
199 " %56 = OpAccessChain %_ptr_Uniform_float %dataOutput %idx_0 %uint_i\n"
200 " OpStore %56 %55\n"
201 " OpReturn\n"
202 " OpFunctionEnd\n");
203
204 switch (chainOpIdx)
205 {
206 case CHAIN_OP_ACCESS_CHAIN:
207 specs["accesschain"] =
208 "OpAccessChain %_ptr_Uniform_float %inputFirstElement %idx_0 %i0 %i1 %i2 %i3\n";
209 specs["inputdecoration"] = "BufferBlock";
210 specs["inputstorageclass"] = "Uniform";
211 break;
212 case CHAIN_OP_IN_BOUNDS_ACCESS_CHAIN:
213 specs["accesschain"] =
214 "OpInBoundsAccessChain %_ptr_Uniform_float %inputFirstElement %idx_0 %i0 %i1 %i2 %i3\n";
215 specs["inputdecoration"] = "BufferBlock";
216 specs["inputstorageclass"] = "Uniform";
217 break;
218 default:
219 DE_ASSERT(chainOpIdx == CHAIN_OP_PTR_ACCESS_CHAIN);
220 specs["accesschain"] =
221 "OpPtrAccessChain %_ptr_StorageBuffer_float %inputFirstElement %idx_1 %idx_0 %i0 %i1 %i2 %i3\n";
222 specs["inputdecoration"] = "Block";
223 specs["inputstorageclass"] = "StorageBuffer";
224 specs["variablepointercaps"] = "OpCapability VariablePointersStorageBuffer";
225 specs["ptr_buffer_float"] = "%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float";
226 specs["extensions"] = "OpExtension \"SPV_KHR_variable_pointers\"\n "
227 "OpExtension \"SPV_KHR_storage_buffer_storage_class\"";
228 element = 1;
229 vulkanFeatures.extVariablePointers.variablePointersStorageBuffer = true;
230 spec.extensions.push_back("VK_KHR_variable_pointers");
231 break;
232 }
233
234 spec.inputs.push_back(BufferSp(new Float32Buffer(inputData)));
235 spec.inputs.push_back(BufferSp(new Buffer<UVec4>(indexSelectorData)));
236
237 outputData.reserve(numItems);
238 for (uint32_t numIdx = 0; numIdx < numItems; ++numIdx)
239 {
240 // Determine the selected output float for the selected indices.
241 const UVec4 vec = indexSelectorData[numIdx];
242 outputData.push_back(inputData[element * sizeof(InputData) / 4 + vec.x() * (32 * 4 * 4) +
243 vec.y() * 4 * 4 + vec.z() * 4 + vec.w()]);
244 }
245
246 if (idxSize == 16)
247 {
248 specs["intcaps"] = "OpCapability Int16";
249 specs["convert"] = "OpSConvert";
250 specs["intdecl"] = " %u16 = OpTypeInt 16 0\n"
251 " %i16 = OpTypeInt 16 1\n";
252 }
253 else if (idxSize == 64)
254 {
255 specs["intcaps"] = "OpCapability Int64";
256 specs["convert"] = "OpSConvert";
257 specs["intdecl"] = " %u64 = OpTypeInt 64 0\n"
258 " %i64 = OpTypeInt 64 1\n";
259 }
260 else
261 {
262 specs["convert"] = "OpBitcast";
263 }
264
265 specs["idx_uint"] = "%u" + de::toString(idxSize);
266 specs["idx_int"] = (sign ? "%i" : "%u") + de::toString(idxSize);
267
268 spec.assembly = shaderSource.specialize(specs);
269 spec.numWorkGroups = IVec3(numItems, 1, 1);
270 spec.requestedVulkanFeatures = vulkanFeatures;
271 spec.inputs[0].setDescriptorType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
272 spec.inputs[1].setDescriptorType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
273
274 spec.outputs.push_back(BufferSp(new Float32Buffer(outputData)));
275
276 if (idxSize == 16)
277 spec.requestedVulkanFeatures.coreFeatures.shaderInt16 = VK_TRUE;
278
279 if (idxSize == 64)
280 spec.requestedVulkanFeatures.coreFeatures.shaderInt64 = VK_TRUE;
281
282 structGroup->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), spec));
283 }
284 }
285 }
286 group->addChild(structGroup.release());
287 }
288
addGraphicsIndexingStructTests(tcu::TestCaseGroup * group)289 void addGraphicsIndexingStructTests(tcu::TestCaseGroup *group)
290 {
291 tcu::TestContext &testCtx = group->getTestContext();
292 de::MovePtr<tcu::TestCaseGroup> structGroup(new tcu::TestCaseGroup(testCtx, "struct"));
293 de::Random rnd(deStringHash(group->getName()));
294 const int numItems = 128;
295 const int numStructs = 2;
296 const int numInputFloats = (int)sizeof(InputData) / 4 * numStructs;
297 RGBA defaultColors[4];
298 vector<float> inputData;
299 vector<UVec4> indexSelectorData;
300
301 inputData.reserve(numInputFloats);
302 for (uint32_t numIdx = 0; numIdx < numInputFloats; ++numIdx)
303 inputData.push_back(rnd.getFloat());
304
305 indexSelectorData.reserve(numItems);
306 for (uint32_t numIdx = 0; numIdx < numItems; ++numIdx)
307 indexSelectorData.push_back(tcu::randomVector<uint32_t, 4>(rnd, UVec4(0), UVec4(31, 31, 3, 3)));
308
309 getDefaultColors(defaultColors);
310
311 for (int chainOpIdx = 0; chainOpIdx < CHAIN_OP_LAST; ++chainOpIdx)
312 {
313 for (int idxSizeIdx = 0; idxSizeIdx < DE_LENGTH_OF_ARRAY(idxSizes); ++idxSizeIdx)
314 {
315 for (int sign = 0; sign < 2; sign++)
316 {
317 const int idxSize = idxSizes[idxSizeIdx];
318 const string testName =
319 chainOpTestNames[chainOpIdx] + string(sign == 0 ? "_u" : "_s") + de::toString(idxSize);
320 VulkanFeatures vulkanFeatures;
321 vector<string> extensions;
322 SpecConstants noSpecConstants;
323 PushConstants noPushConstants;
324 GraphicsInterfaces noInterfaces;
325 map<string, string> specs;
326 map<string, string> fragments;
327 vector<float> outputData;
328 ComputeShaderSpec spec;
329 int element = 0;
330 GraphicsResources resources;
331
332 const StringTemplate preMain(
333 "${intdecl:opt}"
334 " %c_i32_128 = OpConstant %i32 128\n"
335 " %uint_0 = OpConstant ${idx_uint} 0\n"
336 " %uint_128 = OpConstant %u32 128\n"
337 " %uint_32 = OpConstant %u32 32\n"
338 " %uint_1 = OpConstant ${idx_uint} 1\n"
339 " %uint_2 = OpConstant ${idx_uint} 2\n"
340 " %uint_3 = OpConstant ${idx_uint} 3\n"
341 " %_arr_float_uint_128 = OpTypeArray %f32 %uint_128\n"
342 " %Output = OpTypeStruct %_arr_float_uint_128\n"
343 " %_ptr_Uniform_Output = OpTypePointer Uniform %Output\n"
344 " %dataOutput = OpVariable %_ptr_Uniform_Output Uniform\n"
345 " %int_0 = OpConstant ${idx_int} 0\n"
346 " %mat4v4float = OpTypeMatrix %v4f32 4\n"
347 " %_arr_mat4v4float_uint_32 = OpTypeArray %mat4v4float %uint_32\n"
348 " %_arr__arr_mat4v4float_uint_32_uint_32 = OpTypeArray %_arr_mat4v4float_uint_32 %uint_32\n"
349 " %InputStruct = OpTypeStruct %_arr__arr_mat4v4float_uint_32_uint_32\n"
350 " %InputStructArr = OpTypeArray %InputStruct %uint_2\n"
351 " %Input = OpTypeStruct %InputStructArr\n"
352 " %_ptr_buffer_Input = OpTypePointer ${inputstorageclass} %Input\n"
353 " %dataInput = OpVariable %_ptr_buffer_Input ${inputstorageclass}\n"
354 " %_ptr_buffer_InputStruct = OpTypePointer ${inputstorageclass} %InputStruct\n"
355 " %_arr_v4uint_uint_128 = OpTypeArray %v4u32 %uint_128\n"
356 " %DataSelector = OpTypeStruct %_arr_v4uint_uint_128\n"
357 "%_ptr_Uniform_DataSelector = OpTypePointer Uniform %DataSelector\n"
358 " %selector = OpVariable %_ptr_Uniform_DataSelector Uniform\n"
359 " %_ptr_Uniform_uint32 = OpTypePointer Uniform %u32\n"
360 " %_ptr_Uniform_float = OpTypePointer Uniform %f32\n"
361 " ${ptr_buffer_float:opt}\n");
362
363 const StringTemplate decoration("OpDecorate %_arr_float_uint_128 ArrayStride 4\n"
364 "OpMemberDecorate %Output 0 Offset 0\n"
365 "OpDecorate %Output BufferBlock\n"
366 "OpDecorate %dataOutput DescriptorSet 0\n"
367 "OpDecorate %dataOutput Binding 2\n"
368 "OpDecorate %_arr_mat4v4float_uint_32 ArrayStride 64\n"
369 "OpDecorate %_arr__arr_mat4v4float_uint_32_uint_32 ArrayStride 2048\n"
370 "OpMemberDecorate %InputStruct 0 ColMajor\n"
371 "OpMemberDecorate %InputStruct 0 Offset 0\n"
372 "OpMemberDecorate %InputStruct 0 MatrixStride 16\n"
373 "OpDecorate %InputStructArr ArrayStride 65536\n"
374 "OpDecorate %Input ${inputdecoration}\n"
375 "OpMemberDecorate %Input 0 Offset 0\n"
376 "OpDecorate %dataInput DescriptorSet 0\n"
377 "OpDecorate %dataInput Binding 0\n"
378 "OpDecorate %_ptr_buffer_InputStruct ArrayStride 65536\n"
379 "OpDecorate %_arr_v4uint_uint_128 ArrayStride 16\n"
380 "OpMemberDecorate %DataSelector 0 Offset 0\n"
381 "OpDecorate %DataSelector BufferBlock\n"
382 "OpDecorate %selector DescriptorSet 0\n"
383 "OpDecorate %selector Binding 1\n");
384
385 // Index an input buffer containing 2D array of 4x4 matrices. The indices are read from another
386 // input and converted to the desired bit size and sign.
387 const StringTemplate testFun(
388 " %test_code = OpFunction %v4f32 None %v4f32_v4f32_function\n"
389 " %param = OpFunctionParameter %v4f32\n"
390
391 " %entry = OpLabel\n"
392 " %i = OpVariable %fp_i32 Function\n"
393 " OpStore %i %c_i32_0\n"
394 " OpBranch %loop\n"
395
396 " %loop = OpLabel\n"
397 " %15 = OpLoad %i32 %i\n"
398 " %lt = OpSLessThan %bool %15 %c_i32_128\n"
399 " OpLoopMerge %merge %inc None\n"
400 " OpBranchConditional %lt %write %merge\n"
401
402 " %write = OpLabel\n"
403 " %int_i = OpLoad %i32 %i\n"
404 " %39 = OpAccessChain %_ptr_Uniform_uint32 %selector %int_0 %int_i %uint_0\n"
405 " %40 = OpLoad %u32 %39\n"
406 " %43 = OpAccessChain %_ptr_Uniform_uint32 %selector %int_0 %int_i %uint_1\n"
407 " %44 = OpLoad %u32 %43\n"
408 " %47 = OpAccessChain %_ptr_Uniform_uint32 %selector %int_0 %int_i %uint_2\n"
409 " %48 = OpLoad %u32 %47\n"
410 " %51 = OpAccessChain %_ptr_Uniform_uint32 %selector %int_0 %int_i %uint_3\n"
411 " %52 = OpLoad %u32 %51\n"
412 " %i0 = ${convert} ${idx_uint} %40\n"
413 " %i1 = ${convert} ${idx_uint} %44\n"
414 " %i2 = ${convert} ${idx_uint} %48\n"
415 " %i3 = ${convert} ${idx_uint} %52\n"
416 "%inputFirstElement = OpAccessChain %_ptr_buffer_InputStruct %dataInput %uint_0 %uint_0\n"
417 " %54 = ${accesschain}\n"
418 " %55 = OpLoad %f32 %54\n"
419 " %56 = OpAccessChain %_ptr_Uniform_float %dataOutput %int_0 %int_i\n"
420 " OpStore %56 %55\n"
421 " OpBranch %inc\n"
422
423 " %inc = OpLabel\n"
424 " %67 = OpLoad %i32 %i\n"
425 " %69 = OpIAdd %i32 %67 %c_i32_1\n"
426 " OpStore %i %69\n"
427 " OpBranch %loop\n"
428
429 " %merge = OpLabel\n"
430 " OpReturnValue %param\n"
431
432 " OpFunctionEnd\n");
433
434 resources.inputs.push_back(
435 Resource(BufferSp(new Float32Buffer(inputData)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
436 resources.inputs.push_back(
437 Resource(BufferSp(new Buffer<UVec4>(indexSelectorData)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
438
439 if (idxSize == 16)
440 {
441 fragments["capability"] = "OpCapability Int16\n";
442 vulkanFeatures.coreFeatures.shaderInt16 = VK_TRUE;
443 specs["convert"] = "OpUConvert";
444 specs["intdecl"] = " %u16 = OpTypeInt 16 0\n"
445 " %i16 = OpTypeInt 16 1\n";
446 }
447 else if (idxSize == 64)
448 {
449 fragments["capability"] = "OpCapability Int64\n";
450 vulkanFeatures.coreFeatures.shaderInt64 = VK_TRUE;
451 specs["convert"] = "OpUConvert";
452 specs["intdecl"] = " %u64 = OpTypeInt 64 0\n"
453 " %i64 = OpTypeInt 64 1\n";
454 }
455 else
456 {
457 specs["convert"] = "OpCopyObject";
458 }
459
460 specs["idx_uint"] = "%u" + de::toString(idxSize);
461 specs["idx_int"] = (sign ? "%i" : "%u") + de::toString(idxSize);
462
463 switch (chainOpIdx)
464 {
465 case CHAIN_OP_ACCESS_CHAIN:
466 specs["accesschain"] =
467 "OpAccessChain %_ptr_Uniform_float %inputFirstElement %int_0 %i0 %i1 %i2 %i3\n";
468 specs["inputdecoration"] = "BufferBlock";
469 specs["inputstorageclass"] = "Uniform";
470 break;
471 case CHAIN_OP_IN_BOUNDS_ACCESS_CHAIN:
472 specs["accesschain"] =
473 "OpInBoundsAccessChain %_ptr_Uniform_float %inputFirstElement %int_0 %i0 %i1 %i2 %i3\n";
474 specs["inputdecoration"] = "BufferBlock";
475 specs["inputstorageclass"] = "Uniform";
476 break;
477 default:
478 DE_ASSERT(chainOpIdx == CHAIN_OP_PTR_ACCESS_CHAIN);
479 specs["accesschain"] = "OpPtrAccessChain %_ptr_StorageBuffer_float %inputFirstElement %uint_1 "
480 "%int_0 %i0 %i1 %i2 %i3\n";
481 specs["inputdecoration"] = "Block";
482 specs["inputstorageclass"] = "StorageBuffer";
483 specs["ptr_buffer_float"] = "%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %f32";
484 fragments["capability"] += "OpCapability VariablePointersStorageBuffer";
485 fragments["extension"] = "OpExtension \"SPV_KHR_variable_pointers\"\nOpExtension "
486 "\"SPV_KHR_storage_buffer_storage_class\"";
487 extensions.push_back("VK_KHR_variable_pointers");
488 vulkanFeatures.extVariablePointers.variablePointersStorageBuffer = true;
489 element = 1;
490 break;
491 }
492
493 outputData.reserve(numItems);
494 for (uint32_t numIdx = 0; numIdx < numItems; ++numIdx)
495 {
496 // Determine the selected output float for the selected indices.
497 const UVec4 vec = indexSelectorData[numIdx];
498 outputData.push_back(inputData[element * sizeof(InputData) / 4 + vec.x() * (32 * 4 * 4) +
499 vec.y() * 4 * 4 + vec.z() * 4 + vec.w()]);
500 }
501
502 resources.outputs.push_back(
503 Resource(BufferSp(new Float32Buffer(outputData)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
504
505 vulkanFeatures.coreFeatures.vertexPipelineStoresAndAtomics = true;
506 vulkanFeatures.coreFeatures.fragmentStoresAndAtomics = true;
507
508 fragments["pre_main"] = preMain.specialize(specs);
509 fragments["decoration"] = decoration.specialize(specs);
510 fragments["testfun"] = testFun.specialize(specs);
511
512 createTestsForAllStages(testName.c_str(), defaultColors, defaultColors, fragments, noSpecConstants,
513 noPushConstants, resources, noInterfaces, extensions, vulkanFeatures,
514 structGroup.get());
515 }
516 }
517 }
518 group->addChild(structGroup.release());
519 }
520
addGraphicsOutputComponentIndexingTests(tcu::TestCaseGroup * testGroup)521 void addGraphicsOutputComponentIndexingTests(tcu::TestCaseGroup *testGroup)
522 {
523 RGBA defaultColors[4];
524 vector<string> noExtensions;
525 map<string, string> fragments = passthruFragments();
526 const uint32_t numItems = 4;
527 vector<int32_t> inputData;
528 vector<float> outputData;
529 const int32_t pattern[] = {2, 0, 1, 3};
530
531 for (uint32_t itemIdx = 0; itemIdx < numItems; ++itemIdx)
532 {
533 Vec4 output(0.0f);
534 output[pattern[itemIdx]] = 1.0f;
535 outputData.push_back(output.x());
536 outputData.push_back(output.y());
537 outputData.push_back(output.z());
538 outputData.push_back(output.w());
539 inputData.push_back(pattern[itemIdx]);
540 }
541
542 getDefaultColors(defaultColors);
543
544 fragments["pre_main"] = " %a3u32 = OpTypeArray %u32 %c_i32_3\n"
545 " %ip_a3u32 = OpTypePointer Input %a3u32\n"
546 "%v4f32_u32_function = OpTypeFunction %v4f32 %u32\n";
547
548 fragments["interface_op_call"] = "OpFunctionCall %v4f32 %interface_op_func";
549 fragments["interface_op_func"] =
550 "%interface_op_func = OpFunction %v4f32 None %v4f32_u32_function\n"
551 " %io_param1 = OpFunctionParameter %u32\n"
552 " %entry = OpLabel\n"
553 " %ret = OpCompositeConstruct %v4f32 %c_f32_0 %c_f32_0 %c_f32_0 %c_f32_0\n"
554 " OpReturnValue %ret\n"
555 " OpFunctionEnd\n";
556
557 fragments["post_interface_op_vert"] = fragments["post_interface_op_frag"] =
558 "%cpntPtr = OpAccessChain %op_f32 %IF_output %IF_input_val\n"
559 " OpStore %cpntPtr %c_f32_1\n";
560
561 fragments["post_interface_op_tessc"] = "%cpntPtr0 = OpAccessChain %op_f32 %IF_output %c_i32_0 %IF_input_val0\n"
562 " OpStore %cpntPtr0 %c_f32_1\n"
563 "%cpntPtr1 = OpAccessChain %op_f32 %IF_output %c_i32_1 %IF_input_val1\n"
564 " OpStore %cpntPtr1 %c_f32_1\n"
565 "%cpntPtr2 = OpAccessChain %op_f32 %IF_output %c_i32_2 %IF_input_val2\n"
566 " OpStore %cpntPtr2 %c_f32_1\n";
567
568 fragments["post_interface_op_tesse"] = fragments["post_interface_op_geom"] =
569 "%cpntPtr = OpAccessChain %op_f32 %IF_output %IF_input_val0\n"
570 " OpStore %cpntPtr %c_f32_1\n";
571
572 fragments["input_type"] = "u32";
573 fragments["output_type"] = "v4f32";
574
575 GraphicsInterfaces interfaces;
576
577 interfaces.setInputOutput(
578 std::make_pair(IFDataType(1, NUMBERTYPE_UINT32), BufferSp(new Int32Buffer(inputData))),
579 std::make_pair(IFDataType(4, NUMBERTYPE_FLOAT32), BufferSp(new Float32Buffer(outputData))));
580
581 createTestsForAllStages("component", defaultColors, defaultColors, fragments, interfaces, noExtensions, testGroup);
582 }
583
addComputeIndexingNon16BaseAlignmentTests(tcu::TestCaseGroup * group)584 void addComputeIndexingNon16BaseAlignmentTests(tcu::TestCaseGroup *group)
585 {
586 tcu::TestContext &testCtx = group->getTestContext();
587 de::MovePtr<tcu::TestCaseGroup> non16BaseAlignmentGroup(new tcu::TestCaseGroup(testCtx, "non16basealignment"));
588 de::Random rnd(deStringHash(group->getName()));
589 const int floatArraySize = 18;
590 const int numFloatArrays = 32;
591
592 const int numInputFloats = floatArraySize * numFloatArrays;
593 const int numOutputFloats = numFloatArrays;
594 vector<float> inputData;
595 VulkanFeatures vulkanFeatures;
596 vector<float> outputData;
597 ComputeShaderSpec spec;
598 const ChainOp chainOps[] = {CHAIN_OP_ACCESS_CHAIN, CHAIN_OP_PTR_ACCESS_CHAIN};
599
600 // Input is the following structure:
601 //
602 // struct
603 // {
604 // struct
605 // {
606 // float f[18];
607 // } struct1[];
608 // } struct 0;
609 //
610 // Each instance calculates a sum of f[0]..f[17] and outputs the result into float array.
611 string shaderStr = " OpCapability Shader\n"
612 " ${variablepointercaps:opt}\n"
613 " ${extensions:opt}\n"
614 " %1 = OpExtInstImport \"GLSL.std.450\"\n"
615 " OpMemoryModel Logical GLSL450\n"
616 " OpEntryPoint GLCompute %main \"main\" %gl_GlobalInvocationID\n"
617 " OpExecutionMode %main LocalSize 1 1 1\n"
618 " OpSource GLSL 430\n"
619 " OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId\n"
620 " OpDecorate %input_array ArrayStride 4\n"
621 " OpDecorate %output_array ArrayStride 4\n";
622 shaderStr += " OpDecorate %runtimearr_struct1 ArrayStride " +
623 de::toString(floatArraySize * 4) + "\n";
624 shaderStr += " OpDecorate %_ptr_struct1_sb ArrayStride " +
625 de::toString(floatArraySize * 4) + "\n";
626 shaderStr += " OpMemberDecorate %Output 0 Offset 0\n"
627 " OpDecorate %Output Block\n"
628 " OpDecorate %dataOutput DescriptorSet 0\n"
629 " OpDecorate %dataOutput Binding 1\n"
630 " OpMemberDecorate %struct0 0 Offset 0\n"
631 " OpMemberDecorate %struct1 0 Offset 0\n"
632 " OpDecorate %struct0 Block\n"
633 " OpDecorate %dataInput DescriptorSet 0\n"
634 " OpDecorate %dataInput Binding 0\n"
635 " %void = OpTypeVoid\n"
636 " %3 = OpTypeFunction %void\n"
637 " %u32 = OpTypeInt 32 0\n"
638 " %i32 = OpTypeInt 32 1\n"
639 " %_ptr_Function_uint32 = OpTypePointer Function %u32\n"
640 " %v3uint32 = OpTypeVector %u32 3\n"
641 " %_ptr_Input_v3uint32 = OpTypePointer Input %v3uint32\n"
642 " %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint32 Input\n"
643 " %_ptr_Input_uint32 = OpTypePointer Input %u32\n"
644 " %float = OpTypeFloat 32\n";
645 for (uint32_t floatIdx = 0; floatIdx < floatArraySize + 1; ++floatIdx)
646 shaderStr += string("%uint_") + de::toString(floatIdx) + " = OpConstant %u32 " + de::toString(floatIdx) + "\n";
647 shaderStr += " %uint_" + de::toString(numFloatArrays) + " = OpConstant %u32 " +
648 de::toString(numFloatArrays) + "\n";
649 shaderStr += " %input_array = OpTypeArray %float %uint_" + de::toString(floatArraySize) + "\n";
650 shaderStr += " %output_array = OpTypeArray %float %uint_" + de::toString(numFloatArrays) + "\n";
651 shaderStr += " %Output = OpTypeStruct %output_array\n"
652 " %_ptr_sb_Output = OpTypePointer StorageBuffer %Output\n"
653 " %dataOutput = OpVariable %_ptr_sb_Output StorageBuffer\n"
654 " %struct1 = OpTypeStruct %input_array\n"
655 " %runtimearr_struct1 = OpTypeRuntimeArray %struct1\n"
656 " %struct0 = OpTypeStruct %runtimearr_struct1\n"
657 " %_ptr_struct0_sb = OpTypePointer StorageBuffer %struct0\n"
658 " %_ptr_struct1_sb = OpTypePointer StorageBuffer %struct1\n"
659 " %_ptr_float_sb = OpTypePointer StorageBuffer %float\n"
660 " %dataInput = OpVariable %_ptr_struct0_sb StorageBuffer\n"
661 " %main = OpFunction %void None %3\n"
662 " %entry = OpLabel\n"
663 " %base = OpAccessChain %_ptr_struct1_sb %dataInput %uint_0 %uint_0\n"
664 " %invid_ptr = OpAccessChain %_ptr_Input_uint32 %gl_GlobalInvocationID %uint_0\n"
665 " %invid = OpLoad %u32 %invid_ptr\n";
666 for (uint32_t floatIdx = 0; floatIdx < floatArraySize; ++floatIdx)
667 {
668 shaderStr += string("%dataPtr") + de::toString(floatIdx) + " = ${chainop} %invid %uint_0 %uint_" +
669 de::toString(floatIdx) + "\n";
670 if (floatIdx == 0)
671 {
672 shaderStr += "%acc0 = OpLoad %float %dataPtr0\n";
673 }
674 else
675 {
676 shaderStr +=
677 string("%tmp") + de::toString(floatIdx) + " = OpLoad %float %dataPtr" + de::toString(floatIdx) + "\n";
678 shaderStr += string("%acc") + de::toString(floatIdx) + " = OpFAdd %float %tmp" + de::toString(floatIdx) +
679 " %acc" + de::toString(floatIdx - 1) + "\n";
680 }
681 }
682 shaderStr += " %outPtr = OpAccessChain %_ptr_float_sb %dataOutput %uint_0 %invid\n";
683 shaderStr += " OpStore %outPtr %acc" + de::toString(floatArraySize - 1) + "\n";
684 shaderStr += " OpReturn\n"
685 " OpFunctionEnd\n";
686
687 vulkanFeatures.extVariablePointers.variablePointersStorageBuffer = true;
688 spec.extensions.push_back("VK_KHR_variable_pointers");
689
690 inputData.reserve(numInputFloats);
691 for (uint32_t numIdx = 0; numIdx < numInputFloats; ++numIdx)
692 {
693 float f = rnd.getFloat();
694
695 // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
696 f = deFloatFloor(f);
697
698 inputData.push_back(f);
699 }
700
701 spec.inputs.push_back(Resource(BufferSp(new Float32Buffer(inputData)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
702
703 outputData.reserve(numOutputFloats);
704 for (uint32_t outputIdx = 0; outputIdx < numOutputFloats; ++outputIdx)
705 {
706 float f = 0.0f;
707 for (uint32_t arrIdx = 0; arrIdx < floatArraySize; ++arrIdx)
708 f += inputData[outputIdx * floatArraySize + arrIdx];
709 outputData.push_back(f);
710 }
711
712 spec.numWorkGroups = IVec3(numFloatArrays, 1, 1);
713 spec.requestedVulkanFeatures = vulkanFeatures;
714 spec.outputs.push_back(Resource(BufferSp(new Float32Buffer(outputData)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
715
716 for (int chainOpIdx = 0; chainOpIdx < DE_LENGTH_OF_ARRAY(chainOps); ++chainOpIdx)
717 {
718 const ChainOp chainOp = chainOps[chainOpIdx];
719 const string testName = chainOpTestNames[chainOp];
720 map<string, string> specs;
721
722 specs["variablepointercaps"] = "OpCapability VariablePointersStorageBuffer";
723 specs["extensions"] = "OpExtension \"SPV_KHR_variable_pointers\"\n "
724 "OpExtension \"SPV_KHR_storage_buffer_storage_class\"";
725 switch (chainOp)
726 {
727 case CHAIN_OP_ACCESS_CHAIN:
728 specs["chainop"] = "OpAccessChain %_ptr_float_sb %dataInput %uint_0";
729 break;
730 case CHAIN_OP_PTR_ACCESS_CHAIN:
731 specs["chainop"] = "OpPtrAccessChain %_ptr_float_sb %base";
732 break;
733 default:
734 DE_FATAL("Unexpected chain op");
735 break;
736 }
737
738 spec.assembly = StringTemplate(shaderStr).specialize(specs);
739
740 non16BaseAlignmentGroup->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), spec));
741 }
742
743 group->addChild(non16BaseAlignmentGroup.release());
744 }
745
746 } // namespace
747
createIndexingComputeGroup(tcu::TestContext & testCtx)748 tcu::TestCaseGroup *createIndexingComputeGroup(tcu::TestContext &testCtx)
749 {
750 // Compute tests for data indexing.
751 de::MovePtr<tcu::TestCaseGroup> indexingGroup(new tcu::TestCaseGroup(testCtx, "indexing"));
752 // Tests for indexing input data.
753 de::MovePtr<tcu::TestCaseGroup> inputGroup(new tcu::TestCaseGroup(testCtx, "input"));
754
755 addComputeIndexingStructTests(inputGroup.get());
756 addComputeIndexingNon16BaseAlignmentTests(inputGroup.get());
757
758 indexingGroup->addChild(inputGroup.release());
759
760 return indexingGroup.release();
761 }
762
createIndexingGraphicsGroup(tcu::TestContext & testCtx)763 tcu::TestCaseGroup *createIndexingGraphicsGroup(tcu::TestContext &testCtx)
764 {
765 de::MovePtr<tcu::TestCaseGroup> indexingGroup(new tcu::TestCaseGroup(testCtx, "indexing"));
766 de::MovePtr<tcu::TestCaseGroup> inputGroup(new tcu::TestCaseGroup(testCtx, "input"));
767 de::MovePtr<tcu::TestCaseGroup> outputGroup(new tcu::TestCaseGroup(testCtx, "output"));
768
769 addGraphicsIndexingStructTests(inputGroup.get());
770 addGraphicsOutputComponentIndexingTests(outputGroup.get());
771
772 indexingGroup->addChild(inputGroup.release());
773 indexingGroup->addChild(outputGroup.release());
774
775 return indexingGroup.release();
776 }
777
778 } // namespace SpirVAssembly
779 } // namespace vkt
780