Home | History | Annotate | Download | only in spirv_assembly
      1 /*-------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2017 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 different bit sizes.
     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::Mat4;
     45 using tcu::StringTemplate;
     46 
     47 namespace
     48 {
     49 
     50 enum ChainOp
     51 {
     52 	CHAIN_OP_ACCESS_CHAIN = 0,
     53 	CHAIN_OP_IN_BOUNDS_ACCESS_CHAIN,
     54 	CHAIN_OP_PTR_ACCESS_CHAIN,
     55 
     56 	CHAIN_OP_LAST
     57 };
     58 static const int					idxSizes[]				= { 16, 32, 64 };
     59 static const ComputeTestFeatures	computeTestFeatures[]	= { COMPUTE_TEST_USES_INT16, COMPUTE_TEST_USES_NONE, COMPUTE_TEST_USES_INT64 };
     60 static const string					chainOpTestNames[]		= { "opaccesschain", "opinboundsaccesschain", "opptraccesschain" };
     61 
     62 struct InputData
     63 {
     64 	Mat4	matrix[32][32];
     65 };
     66 
     67 void addComputeIndexingTests (tcu::TestCaseGroup* group)
     68 {
     69 	tcu::TestContext&	testCtx			= group->getTestContext();
     70 	de::Random			rnd				(deStringHash(group->getName()));
     71 	const int			numItems		= 128;
     72 	const int			numStructs		= 2;
     73 	const int			numInputFloats	= (int)sizeof(InputData) / 4 * numStructs;
     74 	vector<float>		inputData;
     75 	vector<UVec4>		indexSelectorData;
     76 
     77 	inputData.reserve(numInputFloats);
     78 	for (deUint32 numIdx = 0; numIdx < numInputFloats; ++numIdx)
     79 		inputData.push_back(rnd.getFloat());
     80 
     81 	indexSelectorData.reserve(numItems);
     82 	for (deUint32 numIdx = 0; numIdx < numItems; ++numIdx)
     83 		indexSelectorData.push_back(UVec4(rnd.getUint32() % 32, rnd.getUint32() % 32, rnd.getUint32() % 4, rnd.getUint32() % 4));
     84 
     85 	for (int chainOpIdx = 0; chainOpIdx < CHAIN_OP_LAST; ++chainOpIdx)
     86 	{
     87 		for (int idxSizeIdx = 0; idxSizeIdx < DE_LENGTH_OF_ARRAY(idxSizes); ++idxSizeIdx)
     88 		{
     89 			for (int sign = 0; sign < 2; ++sign)
     90 			{
     91 				const int					idxSize			= idxSizes[idxSizeIdx];
     92 				const string				testName		= chainOpTestNames[chainOpIdx] + string(sign == 0 ? "_u" : "_s") + de::toString(idxSize);
     93 				VulkanFeatures				vulkanFeatures;
     94 				map<string, string>			specs;
     95 				vector<float>				outputData;
     96 				ComputeShaderSpec			spec;
     97 				const ComputeTestFeatures	features		= computeTestFeatures[idxSizeIdx];
     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"] = "OpCopyObject";
    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.inputTypes[0]				= VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
    265 				spec.inputTypes[1]				= VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
    266 
    267 				spec.outputs.push_back(BufferSp(new Float32Buffer(outputData)));
    268 
    269 				group->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), testName.c_str(), spec, features));
    270 			}
    271 		}
    272 	}
    273 }
    274 
    275 void addGraphicsIndexingTests (tcu::TestCaseGroup* group)
    276 {
    277 	de::Random			rnd				(deStringHash(group->getName()));
    278 	const int			numItems		= 128;
    279 	const int			numStructs		= 2;
    280 	const int			numInputFloats	= (int)sizeof(InputData) / 4 * numStructs;
    281 	RGBA				defaultColors[4];
    282 	vector<float>		inputData;
    283 	vector<UVec4>		indexSelectorData;
    284 
    285 	inputData.reserve(numInputFloats);
    286 	for (deUint32 numIdx = 0; numIdx < numInputFloats; ++numIdx)
    287 		inputData.push_back(rnd.getFloat());
    288 
    289 	indexSelectorData.reserve(numItems);
    290 	for (deUint32 numIdx = 0; numIdx < numItems; ++numIdx)
    291 		indexSelectorData.push_back(UVec4(rnd.getUint32() % 32, rnd.getUint32() % 32, rnd.getUint32() % 4, rnd.getUint32() % 4));
    292 
    293 	getDefaultColors(defaultColors);
    294 
    295 	for (int chainOpIdx = 0; chainOpIdx < CHAIN_OP_LAST; ++chainOpIdx)
    296 	{
    297 		for (int idxSizeIdx = 0; idxSizeIdx < DE_LENGTH_OF_ARRAY(idxSizes); ++idxSizeIdx)
    298 		{
    299 			for (int sign = 0; sign < 2; sign++)
    300 			{
    301 				const int					idxSize			= idxSizes[idxSizeIdx];
    302 				const string				testName		= chainOpTestNames[chainOpIdx] + string(sign == 0 ? "_u" : "_s") + de::toString(idxSize);
    303 				VulkanFeatures				vulkanFeatures;
    304 				vector<string>				extensions;
    305 				vector<string>				features;
    306 				vector<deInt32>				noSpecConstants;
    307 				PushConstants				noPushConstants;
    308 				GraphicsInterfaces			noInterfaces;
    309 				map<string, string>			specs;
    310 				map<string, string>			fragments;
    311 				vector<float>				outputData;
    312 				ComputeShaderSpec			spec;
    313 				int							element			= 0;
    314 				GraphicsResources			resources;
    315 
    316 				const StringTemplate		preMain(
    317 					"${intdecl:opt}"
    318 					"                %c_i32_128 = OpConstant %i32 128\n"
    319 					"                   %uint_0 = OpConstant ${idx_uint} 0\n"
    320 					"                 %uint_128 = OpConstant %u32 128\n"
    321 					"                  %uint_32 = OpConstant %u32 32\n"
    322 					"                   %uint_1 = OpConstant ${idx_uint} 1\n"
    323 					"                   %uint_2 = OpConstant ${idx_uint} 2\n"
    324 					"                   %uint_3 = OpConstant ${idx_uint} 3\n"
    325 					"      %_arr_float_uint_128 = OpTypeArray %f32 %uint_128\n"
    326 					"                   %Output = OpTypeStruct %_arr_float_uint_128\n"
    327 					"      %_ptr_Uniform_Output = OpTypePointer Uniform %Output\n"
    328 					"               %dataOutput = OpVariable %_ptr_Uniform_Output Uniform\n"
    329 					"                    %int_0 = OpConstant ${idx_int} 0\n"
    330 					"              %mat4v4float = OpTypeMatrix %v4f32 4\n"
    331 					" %_arr_mat4v4float_uint_32 = OpTypeArray %mat4v4float %uint_32\n"
    332 					" %_arr__arr_mat4v4float_uint_32_uint_32 = OpTypeArray %_arr_mat4v4float_uint_32 %uint_32\n"
    333 					"              %InputStruct = OpTypeStruct %_arr__arr_mat4v4float_uint_32_uint_32\n"
    334 					"           %InputStructArr = OpTypeArray %InputStruct %uint_2\n"
    335 					"                    %Input = OpTypeStruct %InputStructArr\n"
    336 					"        %_ptr_buffer_Input = OpTypePointer ${inputstorageclass} %Input\n"
    337 					"                %dataInput = OpVariable %_ptr_buffer_Input ${inputstorageclass}\n"
    338 					"  %_ptr_buffer_InputStruct = OpTypePointer ${inputstorageclass} %InputStruct\n"
    339 					"     %_arr_v4uint_uint_128 = OpTypeArray %v4u32 %uint_128\n"
    340 					"             %DataSelector = OpTypeStruct %_arr_v4uint_uint_128\n"
    341 					"%_ptr_Uniform_DataSelector = OpTypePointer Uniform %DataSelector\n"
    342 					"                 %selector = OpVariable %_ptr_Uniform_DataSelector Uniform\n"
    343 					"      %_ptr_Uniform_uint32 = OpTypePointer Uniform %u32\n"
    344 					"       %_ptr_Uniform_float = OpTypePointer Uniform %f32\n"
    345 					"       ${ptr_buffer_float:opt}\n");
    346 
    347 
    348 				const StringTemplate		decoration(
    349 					"OpDecorate %_arr_float_uint_128 ArrayStride 4\n"
    350 					"OpMemberDecorate %Output 0 Offset 0\n"
    351 					"OpDecorate %Output BufferBlock\n"
    352 					"OpDecorate %dataOutput DescriptorSet 0\n"
    353 					"OpDecorate %dataOutput Binding 2\n"
    354 					"OpDecorate %_arr_mat4v4float_uint_32 ArrayStride 64\n"
    355 					"OpDecorate %_arr__arr_mat4v4float_uint_32_uint_32 ArrayStride 2048\n"
    356 					"OpMemberDecorate %InputStruct 0 ColMajor\n"
    357 					"OpMemberDecorate %InputStruct 0 Offset 0\n"
    358 					"OpMemberDecorate %InputStruct 0 MatrixStride 16\n"
    359 					"OpDecorate %InputStructArr ArrayStride 65536\n"
    360 					"OpDecorate %Input ${inputdecoration}\n"
    361 					"OpMemberDecorate %Input 0 Offset 0\n"
    362 					"OpDecorate %dataInput DescriptorSet 0\n"
    363 					"OpDecorate %dataInput Binding 0\n"
    364 					"OpDecorate %_ptr_buffer_InputStruct ArrayStride 65536\n"
    365 					"OpDecorate %_arr_v4uint_uint_128 ArrayStride 16\n"
    366 					"OpMemberDecorate %DataSelector 0 Offset 0\n"
    367 					"OpDecorate %DataSelector BufferBlock\n"
    368 					"OpDecorate %selector DescriptorSet 0\n"
    369 					"OpDecorate %selector Binding 1\n");
    370 
    371 				// Index an input buffer containing 2D array of 4x4 matrices. The indices are read from another
    372 				// input and converted to the desired bit size and sign.
    373 				const StringTemplate		testFun(
    374 					"        %test_code = OpFunction %v4f32 None %v4f32_function\n"
    375 					"            %param = OpFunctionParameter %v4f32\n"
    376 
    377 					"            %entry = OpLabel\n"
    378 					"                %i = OpVariable %fp_i32 Function\n"
    379 					"                     OpStore %i %c_i32_0\n"
    380 					"                     OpBranch %loop\n"
    381 
    382 					"             %loop = OpLabel\n"
    383 					"               %15 = OpLoad %i32 %i\n"
    384 					"               %lt = OpSLessThan %bool %15 %c_i32_128\n"
    385 					"                     OpLoopMerge %merge %inc None\n"
    386 					"                     OpBranchConditional %lt %write %merge\n"
    387 
    388 					"            %write = OpLabel\n"
    389 					"            %int_i = OpLoad %i32 %i\n"
    390 					"               %39 = OpAccessChain %_ptr_Uniform_uint32 %selector %int_0 %int_i %uint_0\n"
    391 					"               %40 = OpLoad %u32 %39\n"
    392 					"               %43 = OpAccessChain %_ptr_Uniform_uint32 %selector %int_0 %int_i %uint_1\n"
    393 					"               %44 = OpLoad %u32 %43\n"
    394 					"               %47 = OpAccessChain %_ptr_Uniform_uint32 %selector %int_0 %int_i %uint_2\n"
    395 					"               %48 = OpLoad %u32 %47\n"
    396 					"               %51 = OpAccessChain %_ptr_Uniform_uint32 %selector %int_0 %int_i %uint_3\n"
    397 					"               %52 = OpLoad %u32 %51\n"
    398 					"               %i0 = ${convert} ${idx_uint} %40\n"
    399 					"               %i1 = ${convert} ${idx_uint} %44\n"
    400 					"               %i2 = ${convert} ${idx_uint} %48\n"
    401 					"               %i3 = ${convert} ${idx_uint} %52\n"
    402 					"%inputFirstElement = OpAccessChain %_ptr_buffer_InputStruct %dataInput %uint_0 %uint_0\n"
    403 					"               %54 = ${accesschain}\n"
    404 					"               %55 = OpLoad %f32 %54\n"
    405 					"               %56 = OpAccessChain %_ptr_Uniform_float %dataOutput %int_0 %int_i\n"
    406 					"                     OpStore %56 %55\n"
    407 					"                     OpBranch %inc\n"
    408 
    409 					"              %inc = OpLabel\n"
    410 					"               %67 = OpLoad %i32 %i\n"
    411 					"               %69 = OpIAdd %i32 %67 %c_i32_1\n"
    412 					"                     OpStore %i %69\n"
    413 					"                     OpBranch %loop\n"
    414 
    415 					"            %merge = OpLabel\n"
    416 					"                     OpReturnValue %param\n"
    417 
    418 					"                     OpFunctionEnd\n");
    419 
    420 				resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(inputData))));
    421 				resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Buffer<UVec4>(indexSelectorData))));
    422 
    423 				if (idxSize == 16)
    424 				{
    425 					fragments["capability"] = "OpCapability Int16\n";
    426 					features.push_back("shaderInt16");
    427 					specs["convert"] = "OpUConvert";
    428 					specs["intdecl"] =	"                      %u16 = OpTypeInt 16 0\n"
    429 								"                      %i16 = OpTypeInt 16 1\n";
    430 				}
    431 				else if (idxSize == 64)
    432 				{
    433 					fragments["capability"] = "OpCapability Int64\n";
    434 					features.push_back("shaderInt64");
    435 					specs["convert"] = "OpUConvert";
    436 					specs["intdecl"] =	"                      %u64 = OpTypeInt 64 0\n"
    437 								"                      %i64 = OpTypeInt 64 1\n";
    438 				} else {
    439 					specs["convert"] = "OpCopyObject";
    440 				}
    441 
    442 				specs["idx_uint"] = "%u" + de::toString(idxSize);
    443 				specs["idx_int"] = (sign ? "%i" : "%u") + de::toString(idxSize);
    444 
    445 				switch (chainOpIdx)
    446 				{
    447 					case CHAIN_OP_ACCESS_CHAIN:
    448 						specs["accesschain"]				= "OpAccessChain %_ptr_Uniform_float %inputFirstElement %int_0 %i0 %i1 %i2 %i3\n";
    449 						specs["inputdecoration"]			= "BufferBlock";
    450 						specs["inputstorageclass"]			= "Uniform";
    451 						break;
    452 					case CHAIN_OP_IN_BOUNDS_ACCESS_CHAIN:
    453 						specs["accesschain"]				= "OpInBoundsAccessChain %_ptr_Uniform_float %inputFirstElement %int_0 %i0 %i1 %i2 %i3\n";
    454 						specs["inputdecoration"]			= "BufferBlock";
    455 						specs["inputstorageclass"]			= "Uniform";
    456 						break;
    457 					default:
    458 						DE_ASSERT(chainOpIdx == CHAIN_OP_PTR_ACCESS_CHAIN);
    459 						specs["accesschain"]				= "OpPtrAccessChain %_ptr_StorageBuffer_float %inputFirstElement %uint_1 %int_0 %i0 %i1 %i2 %i3\n";
    460 						specs["inputdecoration"]			= "Block";
    461 						specs["inputstorageclass"]			= "StorageBuffer";
    462 						specs["ptr_buffer_float"]			= "%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %f32";
    463 						fragments["capability"]				+= "OpCapability VariablePointersStorageBuffer";
    464 						fragments["extension"]				= "OpExtension \"SPV_KHR_variable_pointers\"\nOpExtension \"SPV_KHR_storage_buffer_storage_class\"";
    465 						extensions.push_back				("VK_KHR_variable_pointers");
    466 						vulkanFeatures.extVariablePointers	= EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS_STORAGEBUFFER;
    467 						element = 1;
    468 						break;
    469 				};
    470 
    471 				outputData.reserve(numItems);
    472 				for (deUint32 numIdx = 0; numIdx < numItems; ++numIdx)
    473 				{
    474 					// Determine the selected output float for the selected indices.
    475 					const UVec4 vec = indexSelectorData[numIdx];
    476 					outputData.push_back(inputData[element * sizeof(InputData) / 4 + vec.x() * (32 * 4 * 4) + vec.y() * 4 * 4 + vec.z() * 4 + vec.w()]);
    477 				}
    478 
    479 				resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(outputData))));
    480 
    481 				fragments["pre_main"]	= preMain.specialize(specs);
    482 				fragments["decoration"]	= decoration.specialize(specs);
    483 				fragments["testfun"]	= testFun.specialize(specs);
    484 
    485 				createTestsForAllStages(
    486 						testName.c_str(), defaultColors, defaultColors, fragments, noSpecConstants,
    487 						noPushConstants, resources, noInterfaces, extensions, features, vulkanFeatures, group);
    488 			}
    489 		}
    490 	}
    491 }
    492 
    493 } // anonymous
    494 
    495 tcu::TestCaseGroup* createIndexingComputeGroup (tcu::TestContext& testCtx)
    496 {
    497 	de::MovePtr<tcu::TestCaseGroup> group		(new tcu::TestCaseGroup(testCtx, "indexing", "Compute tests for data indexing."));
    498 	addComputeIndexingTests(group.get());
    499 
    500 	return group.release();
    501 }
    502 
    503 tcu::TestCaseGroup* createIndexingGraphicsGroup (tcu::TestContext& testCtx)
    504 {
    505 	de::MovePtr<tcu::TestCaseGroup> group		(new tcu::TestCaseGroup(testCtx, "indexing", "Graphics tests for data indexing."));
    506 	addGraphicsIndexingTests(group.get());
    507 
    508 	return group.release();
    509 }
    510 
    511 } // SpirVAssembly
    512 } // vkt
    513