Home | History | Annotate | Download | only in spirv_assembly
      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
    765