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