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