xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmIndexingTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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