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