1 /*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 The Khronos Group 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 vktSparseResourcesShaderIntrinsicsStorage.cpp 21 * \brief Sparse Resources Shader Intrinsics for storage images 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vktSparseResourcesShaderIntrinsicsStorage.hpp" 25 26 using namespace vk; 27 28 namespace vkt 29 { 30 namespace sparse 31 { 32 33 tcu::UVec3 computeWorkGroupSize (const tcu::UVec3& gridSize) 34 { 35 const deUint32 maxComputeWorkGroupInvocations = 128u; 36 const tcu::UVec3 maxComputeWorkGroupSize = tcu::UVec3(128u, 128u, 64u); 37 38 const deUint32 xWorkGroupSize = std::min(std::min(gridSize.x(), maxComputeWorkGroupSize.x()), maxComputeWorkGroupInvocations); 39 const deUint32 yWorkGroupSize = std::min(std::min(gridSize.y(), maxComputeWorkGroupSize.y()), maxComputeWorkGroupInvocations / xWorkGroupSize); 40 const deUint32 zWorkGroupSize = std::min(std::min(gridSize.z(), maxComputeWorkGroupSize.z()), maxComputeWorkGroupInvocations / (xWorkGroupSize*yWorkGroupSize)); 41 42 return tcu::UVec3(xWorkGroupSize, yWorkGroupSize, zWorkGroupSize); 43 } 44 45 void SparseShaderIntrinsicsCaseStorage::initPrograms (vk::SourceCollections& programCollection) const 46 { 47 const std::string imageTypeStr = getShaderImageType(m_format, m_imageType); 48 const std::string formatDataStr = getShaderImageDataType(m_format); 49 const std::string formatQualStr = getShaderImageFormatQualifier(m_format); 50 51 const std::string coordString = getShaderImageCoordinates(m_imageType, 52 "%local_int_GlobalInvocationID_x", 53 "%local_ivec2_GlobalInvocationID_xy", 54 "%local_ivec3_GlobalInvocationID_xyz"); 55 // Create compute program 56 std::ostringstream src; 57 58 const std::string typeImgComp = getImageComponentTypeName(m_format); 59 const std::string typeImgCompVec4 = getImageComponentVec4TypeName(m_format); 60 const std::string typeImageSparse = getSparseImageTypeName(); 61 const std::string typeUniformConstImageSparse = getUniformConstSparseImageTypeName(); 62 63 src << "OpCapability Shader\n" 64 << "OpCapability ImageCubeArray\n" 65 << "OpCapability SparseResidency\n" 66 << "OpCapability StorageImageExtendedFormats\n" 67 68 << "%ext_import = OpExtInstImport \"GLSL.std.450\"\n" 69 << "OpMemoryModel Logical GLSL450\n" 70 << "OpEntryPoint GLCompute %func_main \"main\" %input_GlobalInvocationID\n" 71 << "OpExecutionMode %func_main LocalSize 1 1 1\n" 72 << "OpSource GLSL 440\n" 73 74 << "OpName %func_main \"main\"\n" 75 76 << "OpName %input_GlobalInvocationID \"gl_GlobalInvocationID\"\n" 77 << "OpName %input_WorkGroupSize \"gl_WorkGroupSize\"\n" 78 79 << "OpName %uniform_image_sparse \"u_imageSparse\"\n" 80 << "OpName %uniform_image_texels \"u_imageTexels\"\n" 81 << "OpName %uniform_image_residency \"u_imageResidency\"\n" 82 83 << "OpDecorate %input_GlobalInvocationID BuiltIn GlobalInvocationId\n" 84 85 << "OpDecorate %input_WorkGroupSize BuiltIn WorkgroupSize\n" 86 87 << "OpDecorate %constant_uint_grid_x SpecId 1\n" 88 << "OpDecorate %constant_uint_grid_y SpecId 2\n" 89 << "OpDecorate %constant_uint_grid_z SpecId 3\n" 90 91 << "OpDecorate %constant_uint_work_group_size_x SpecId 4\n" 92 << "OpDecorate %constant_uint_work_group_size_y SpecId 5\n" 93 << "OpDecorate %constant_uint_work_group_size_z SpecId 6\n" 94 95 << "OpDecorate %uniform_image_sparse DescriptorSet 0\n" 96 << "OpDecorate %uniform_image_sparse Binding " << BINDING_IMAGE_SPARSE << "\n" 97 98 << "OpDecorate %uniform_image_texels DescriptorSet 0\n" 99 << "OpDecorate %uniform_image_texels Binding " << BINDING_IMAGE_TEXELS << "\n" 100 << "OpDecorate %uniform_image_texels NonReadable\n" 101 102 << "OpDecorate %uniform_image_residency DescriptorSet 0\n" 103 << "OpDecorate %uniform_image_residency Binding " << BINDING_IMAGE_RESIDENCY << "\n" 104 << "OpDecorate %uniform_image_residency NonReadable\n" 105 106 // Declare data types 107 << "%type_bool = OpTypeBool\n" 108 << "%type_int = OpTypeInt 32 1\n" 109 << "%type_uint = OpTypeInt 32 0\n" 110 << "%type_ivec2 = OpTypeVector %type_int 2\n" 111 << "%type_ivec3 = OpTypeVector %type_int 3\n" 112 << "%type_ivec4 = OpTypeVector %type_int 4\n" 113 << "%type_uvec3 = OpTypeVector %type_uint 3\n" 114 << "%type_uvec4 = OpTypeVector %type_uint 4\n" 115 << "%type_struct_int_img_comp_vec4 = OpTypeStruct %type_int " << typeImgCompVec4 << "\n" 116 117 << "%type_input_uint = OpTypePointer Input %type_uint\n" 118 << "%type_input_uvec3 = OpTypePointer Input %type_uvec3\n" 119 120 << "%type_function_int = OpTypePointer Function %type_int\n" 121 << "%type_function_img_comp_vec4 = OpTypePointer Function " << typeImgCompVec4 << "\n" 122 123 << "%type_void = OpTypeVoid\n" 124 << "%type_void_func = OpTypeFunction %type_void\n" 125 126 // Sparse image without sampler type declaration 127 << "%type_image_sparse = " << getOpTypeImageSparse(m_imageType, m_format, typeImgComp, false) << "\n" 128 << "%type_uniformconst_image_sparse = OpTypePointer UniformConstant %type_image_sparse\n" 129 130 // Sparse image with sampler type declaration 131 << "%type_image_sparse_with_sampler = " << getOpTypeImageSparse(m_imageType, m_format, typeImgComp, true) << "\n" 132 << "%type_uniformconst_image_sparse_with_sampler = OpTypePointer UniformConstant %type_image_sparse_with_sampler\n" 133 134 // Residency image type declaration 135 << "%type_image_residency = " << getOpTypeImageResidency(m_imageType) << "\n" 136 << "%type_uniformconst_image_residency = OpTypePointer UniformConstant %type_image_residency\n" 137 138 // Declare sparse image variable 139 << "%uniform_image_sparse = OpVariable " << typeUniformConstImageSparse << " UniformConstant\n" 140 141 // Declare output image variable for storing texels 142 << "%uniform_image_texels = OpVariable %type_uniformconst_image_sparse UniformConstant\n" 143 144 // Declare output image variable for storing residency information 145 << "%uniform_image_residency = OpVariable %type_uniformconst_image_residency UniformConstant\n" 146 147 // Declare input variables 148 << "%input_GlobalInvocationID = OpVariable %type_input_uvec3 Input\n" 149 150 << "%constant_uint_grid_x = OpSpecConstant %type_uint 1\n" 151 << "%constant_uint_grid_y = OpSpecConstant %type_uint 1\n" 152 << "%constant_uint_grid_z = OpSpecConstant %type_uint 1\n" 153 154 << "%constant_uint_work_group_size_x = OpSpecConstant %type_uint 1\n" 155 << "%constant_uint_work_group_size_y = OpSpecConstant %type_uint 1\n" 156 << "%constant_uint_work_group_size_z = OpSpecConstant %type_uint 1\n" 157 << "%input_WorkGroupSize = OpSpecConstantComposite %type_uvec3 %constant_uint_work_group_size_x %constant_uint_work_group_size_y %constant_uint_work_group_size_z\n" 158 159 // Declare constants 160 << "%constant_uint_0 = OpConstant %type_uint 0\n" 161 << "%constant_uint_1 = OpConstant %type_uint 1\n" 162 << "%constant_uint_2 = OpConstant %type_uint 2\n" 163 << "%constant_int_0 = OpConstant %type_int 0\n" 164 << "%constant_int_1 = OpConstant %type_int 1\n" 165 << "%constant_int_2 = OpConstant %type_int 2\n" 166 << "%constant_bool_true = OpConstantTrue %type_bool\n" 167 << "%constant_uint_resident = OpConstant %type_uint " << MEMORY_BLOCK_BOUND_VALUE << "\n" 168 << "%constant_uvec4_resident = OpConstantComposite %type_uvec4 %constant_uint_resident %constant_uint_resident %constant_uint_resident %constant_uint_resident\n" 169 << "%constant_uint_not_resident = OpConstant %type_uint " << MEMORY_BLOCK_NOT_BOUND_VALUE << "\n" 170 << "%constant_uvec4_not_resident = OpConstantComposite %type_uvec4 %constant_uint_not_resident %constant_uint_not_resident %constant_uint_not_resident %constant_uint_not_resident\n" 171 172 // Call main function 173 << "%func_main = OpFunction %type_void None %type_void_func\n" 174 << "%label_func_main = OpLabel\n" 175 176 // Load GlobalInvocationID.xyz into local variables 177 << "%access_GlobalInvocationID_x = OpAccessChain %type_input_uint %input_GlobalInvocationID %constant_uint_0\n" 178 << "%local_uint_GlobalInvocationID_x = OpLoad %type_uint %access_GlobalInvocationID_x\n" 179 << "%local_int_GlobalInvocationID_x = OpBitcast %type_int %local_uint_GlobalInvocationID_x\n" 180 181 << "%access_GlobalInvocationID_y = OpAccessChain %type_input_uint %input_GlobalInvocationID %constant_uint_1\n" 182 << "%local_uint_GlobalInvocationID_y = OpLoad %type_uint %access_GlobalInvocationID_y\n" 183 << "%local_int_GlobalInvocationID_y = OpBitcast %type_int %local_uint_GlobalInvocationID_y\n" 184 185 << "%access_GlobalInvocationID_z = OpAccessChain %type_input_uint %input_GlobalInvocationID %constant_uint_2\n" 186 << "%local_uint_GlobalInvocationID_z = OpLoad %type_uint %access_GlobalInvocationID_z\n" 187 << "%local_int_GlobalInvocationID_z = OpBitcast %type_int %local_uint_GlobalInvocationID_z\n" 188 189 << "%local_ivec2_GlobalInvocationID_xy = OpCompositeConstruct %type_ivec2 %local_int_GlobalInvocationID_x %local_int_GlobalInvocationID_y\n" 190 << "%local_ivec3_GlobalInvocationID_xyz = OpCompositeConstruct %type_ivec3 %local_int_GlobalInvocationID_x %local_int_GlobalInvocationID_y %local_int_GlobalInvocationID_z\n" 191 192 << "%comparison_range_x = OpULessThan %type_bool %local_uint_GlobalInvocationID_x %constant_uint_grid_x\n" 193 << "OpSelectionMerge %label_out_range_x None\n" 194 << "OpBranchConditional %comparison_range_x %label_in_range_x %label_out_range_x\n" 195 << "%label_in_range_x = OpLabel\n" 196 197 << "%comparison_range_y = OpULessThan %type_bool %local_uint_GlobalInvocationID_y %constant_uint_grid_y\n" 198 << "OpSelectionMerge %label_out_range_y None\n" 199 << "OpBranchConditional %comparison_range_y %label_in_range_y %label_out_range_y\n" 200 << "%label_in_range_y = OpLabel\n" 201 202 << "%comparison_range_z = OpULessThan %type_bool %local_uint_GlobalInvocationID_z %constant_uint_grid_z\n" 203 << "OpSelectionMerge %label_out_range_z None\n" 204 << "OpBranchConditional %comparison_range_z %label_in_range_z %label_out_range_z\n" 205 << "%label_in_range_z = OpLabel\n" 206 207 // Load sparse image 208 << "%local_image_sparse = OpLoad " << typeImageSparse << " %uniform_image_sparse\n" 209 210 // Call OpImageSparse* 211 << sparseImageOpString("%local_sparse_op_result", "%type_struct_int_img_comp_vec4", "%local_image_sparse", coordString, "%constant_int_0") << "\n" 212 213 // Load the texel from the sparse image to local variable for OpImageSparse* 214 << "%local_img_comp_vec4 = OpCompositeExtract " << typeImgCompVec4 << " %local_sparse_op_result 1\n" 215 216 // Load residency code for OpImageSparse* 217 << "%local_residency_code = OpCompositeExtract %type_int %local_sparse_op_result 0\n" 218 // End Call OpImageSparse* 219 220 // Load texels image 221 << "%local_image_texels = OpLoad %type_image_sparse %uniform_image_texels\n" 222 223 // Write the texel to output image via OpImageWrite 224 << "OpImageWrite %local_image_texels " << coordString << " %local_img_comp_vec4\n" 225 226 // Load residency info image 227 << "%local_image_residency = OpLoad %type_image_residency %uniform_image_residency\n" 228 229 // Check if loaded texel is placed in resident memory 230 << "%local_texel_resident = OpImageSparseTexelsResident %type_bool %local_residency_code\n" 231 << "OpSelectionMerge %branch_texel_resident None\n" 232 << "OpBranchConditional %local_texel_resident %label_texel_resident %label_texel_not_resident\n" 233 << "%label_texel_resident = OpLabel\n" 234 235 // Loaded texel is in resident memory 236 << "OpImageWrite %local_image_residency " << coordString << " %constant_uvec4_resident\n" 237 238 << "OpBranch %branch_texel_resident\n" 239 << "%label_texel_not_resident = OpLabel\n" 240 241 // Loaded texel is not in resident memory 242 << "OpImageWrite %local_image_residency " << coordString << " %constant_uvec4_not_resident\n" 243 244 << "OpBranch %branch_texel_resident\n" 245 << "%branch_texel_resident = OpLabel\n" 246 247 << "OpBranch %label_out_range_z\n" 248 << "%label_out_range_z = OpLabel\n" 249 250 << "OpBranch %label_out_range_y\n" 251 << "%label_out_range_y = OpLabel\n" 252 253 << "OpBranch %label_out_range_x\n" 254 << "%label_out_range_x = OpLabel\n" 255 256 << "OpReturn\n" 257 << "OpFunctionEnd\n"; 258 259 programCollection.spirvAsmSources.add("compute") << src.str(); 260 } 261 262 std::string SparseCaseOpImageSparseFetch::getSparseImageTypeName (void) const 263 { 264 return "%type_image_sparse_with_sampler"; 265 } 266 267 std::string SparseCaseOpImageSparseFetch::getUniformConstSparseImageTypeName (void) const 268 { 269 return "%type_uniformconst_image_sparse_with_sampler"; 270 } 271 272 std::string SparseCaseOpImageSparseFetch::sparseImageOpString (const std::string& resultVariable, 273 const std::string& resultType, 274 const std::string& image, 275 const std::string& coord, 276 const std::string& mipLevel) const 277 { 278 std::ostringstream src; 279 280 src << resultVariable << " = OpImageSparseFetch " << resultType << " " << image << " " << coord << " Lod " << mipLevel << "\n"; 281 282 return src.str(); 283 } 284 285 std::string SparseCaseOpImageSparseRead::getSparseImageTypeName (void) const 286 { 287 return "%type_image_sparse"; 288 } 289 290 std::string SparseCaseOpImageSparseRead::getUniformConstSparseImageTypeName (void) const 291 { 292 return "%type_uniformconst_image_sparse"; 293 } 294 295 std::string SparseCaseOpImageSparseRead::sparseImageOpString (const std::string& resultVariable, 296 const std::string& resultType, 297 const std::string& image, 298 const std::string& coord, 299 const std::string& mipLevel) const 300 { 301 DE_UNREF(mipLevel); 302 303 std::ostringstream src; 304 305 src << resultVariable << " = OpImageSparseRead " << resultType << " " << image << " " << coord << "\n"; 306 307 return src.str(); 308 } 309 310 class SparseShaderIntrinsicsInstanceStorage : public SparseShaderIntrinsicsInstanceBase 311 { 312 public: 313 SparseShaderIntrinsicsInstanceStorage (Context& context, 314 const SpirVFunction function, 315 const ImageType imageType, 316 const tcu::UVec3& imageSize, 317 const tcu::TextureFormat& format) 318 : SparseShaderIntrinsicsInstanceBase(context, function, imageType, imageSize, format) {} 319 320 VkImageUsageFlags imageOutputUsageFlags (void) const; 321 322 VkQueueFlags getQueueFlags (void) const; 323 324 void recordCommands (const VkCommandBuffer commandBuffer, 325 const VkImageCreateInfo& imageSparseInfo, 326 const VkImage imageSparse, 327 const VkImage imageTexels, 328 const VkImage imageResidency); 329 330 virtual VkDescriptorType imageSparseDescType (void) const = 0; 331 }; 332 333 VkImageUsageFlags SparseShaderIntrinsicsInstanceStorage::imageOutputUsageFlags (void) const 334 { 335 return VK_IMAGE_USAGE_STORAGE_BIT; 336 } 337 338 VkQueueFlags SparseShaderIntrinsicsInstanceStorage::getQueueFlags (void) const 339 { 340 return VK_QUEUE_COMPUTE_BIT; 341 } 342 343 void SparseShaderIntrinsicsInstanceStorage::recordCommands (const VkCommandBuffer commandBuffer, 344 const VkImageCreateInfo& imageSparseInfo, 345 const VkImage imageSparse, 346 const VkImage imageTexels, 347 const VkImage imageResidency) 348 { 349 const InstanceInterface& instance = m_context.getInstanceInterface(); 350 const DeviceInterface& deviceInterface = getDeviceInterface(); 351 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice(); 352 353 // Check if device supports image format for storage image 354 if (!checkImageFormatFeatureSupport(instance, physicalDevice, imageSparseInfo.format, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) 355 TCU_THROW(NotSupportedError, "Device does not support image format for storage image"); 356 357 // Make sure device supports VK_FORMAT_R32_UINT format for storage image 358 if (!checkImageFormatFeatureSupport(instance, physicalDevice, mapTextureFormat(m_residencyFormat), VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) 359 TCU_THROW(TestError, "Device does not support VK_FORMAT_R32_UINT format for storage image"); 360 361 pipelines.resize(imageSparseInfo.mipLevels); 362 descriptorSets.resize(imageSparseInfo.mipLevels); 363 imageSparseViews.resize(imageSparseInfo.mipLevels); 364 imageTexelsViews.resize(imageSparseInfo.mipLevels); 365 imageResidencyViews.resize(imageSparseInfo.mipLevels); 366 367 // Create descriptor set layout 368 DescriptorSetLayoutBuilder descriptorLayerBuilder; 369 370 descriptorLayerBuilder.addSingleBinding(imageSparseDescType(), VK_SHADER_STAGE_COMPUTE_BIT); 371 descriptorLayerBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT); 372 descriptorLayerBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT); 373 374 const Unique<VkDescriptorSetLayout> descriptorSetLayout(descriptorLayerBuilder.build(deviceInterface, getDevice())); 375 376 // Create pipeline layout 377 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(deviceInterface, getDevice(), *descriptorSetLayout)); 378 379 // Create descriptor pool 380 DescriptorPoolBuilder descriptorPoolBuilder; 381 382 descriptorPoolBuilder.addType(imageSparseDescType(), imageSparseInfo.mipLevels); 383 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, imageSparseInfo.mipLevels); 384 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, imageSparseInfo.mipLevels); 385 386 descriptorPool = descriptorPoolBuilder.build(deviceInterface, getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, imageSparseInfo.mipLevels); 387 388 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers); 389 390 { 391 VkImageMemoryBarrier imageShaderAccessBarriers[3]; 392 393 imageShaderAccessBarriers[0] = makeImageMemoryBarrier 394 ( 395 VK_ACCESS_TRANSFER_WRITE_BIT, 396 VK_ACCESS_SHADER_READ_BIT, 397 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 398 VK_IMAGE_LAYOUT_GENERAL, 399 imageSparse, 400 fullImageSubresourceRange 401 ); 402 403 imageShaderAccessBarriers[1] = makeImageMemoryBarrier 404 ( 405 0u, 406 VK_ACCESS_SHADER_WRITE_BIT, 407 VK_IMAGE_LAYOUT_UNDEFINED, 408 VK_IMAGE_LAYOUT_GENERAL, 409 imageTexels, 410 fullImageSubresourceRange 411 ); 412 413 imageShaderAccessBarriers[2] = makeImageMemoryBarrier 414 ( 415 0u, 416 VK_ACCESS_SHADER_WRITE_BIT, 417 VK_IMAGE_LAYOUT_UNDEFINED, 418 VK_IMAGE_LAYOUT_GENERAL, 419 imageResidency, 420 fullImageSubresourceRange 421 ); 422 423 deviceInterface.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 3u, imageShaderAccessBarriers); 424 } 425 426 const VkSpecializationMapEntry specializationMapEntries[6] = 427 { 428 { 1u, 0u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // GridSize.x 429 { 2u, 1u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // GridSize.y 430 { 3u, 2u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // GridSize.z 431 { 4u, 3u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // WorkGroupSize.x 432 { 5u, 4u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // WorkGroupSize.y 433 { 6u, 5u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // WorkGroupSize.z 434 }; 435 436 Unique<VkShaderModule> shaderModule(createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get("compute"), 0u)); 437 438 for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx) 439 { 440 const tcu::UVec3 gridSize = getShaderGridSize(m_imageType, m_imageSize, mipLevelNdx); 441 const tcu::UVec3 workGroupSize = computeWorkGroupSize(gridSize); 442 const tcu::UVec3 specializationData[2] = { gridSize, workGroupSize }; 443 444 const VkSpecializationInfo specializationInfo = 445 { 446 (deUint32)DE_LENGTH_OF_ARRAY(specializationMapEntries), // mapEntryCount 447 specializationMapEntries, // pMapEntries 448 sizeof(specializationData), // dataSize 449 specializationData, // pData 450 }; 451 452 // Create and bind compute pipeline 453 pipelines[mipLevelNdx] = makeVkSharedPtr(makeComputePipeline(deviceInterface, getDevice(), *pipelineLayout, *shaderModule, &specializationInfo)); 454 const VkPipeline computePipeline = **pipelines[mipLevelNdx]; 455 456 deviceInterface.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline); 457 458 // Create descriptor set 459 descriptorSets[mipLevelNdx] = makeVkSharedPtr(makeDescriptorSet(deviceInterface, getDevice(), *descriptorPool, *descriptorSetLayout)); 460 const VkDescriptorSet descriptorSet = **descriptorSets[mipLevelNdx]; 461 462 // Bind resources 463 const VkImageSubresourceRange mipLevelRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevelNdx, 1u, 0u, imageSparseInfo.arrayLayers); 464 465 imageSparseViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageSparse, mapImageViewType(m_imageType), imageSparseInfo.format, mipLevelRange)); 466 const VkDescriptorImageInfo imageSparseDescInfo = makeDescriptorImageInfo(DE_NULL, **imageSparseViews[mipLevelNdx], VK_IMAGE_LAYOUT_GENERAL); 467 468 imageTexelsViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageTexels, mapImageViewType(m_imageType), imageSparseInfo.format, mipLevelRange)); 469 const VkDescriptorImageInfo imageTexelsDescInfo = makeDescriptorImageInfo(DE_NULL, **imageTexelsViews[mipLevelNdx], VK_IMAGE_LAYOUT_GENERAL); 470 471 imageResidencyViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageResidency, mapImageViewType(m_imageType), mapTextureFormat(m_residencyFormat), mipLevelRange)); 472 const VkDescriptorImageInfo imageResidencyDescInfo = makeDescriptorImageInfo(DE_NULL, **imageResidencyViews[mipLevelNdx], VK_IMAGE_LAYOUT_GENERAL); 473 474 DescriptorSetUpdateBuilder descriptorUpdateBuilder; 475 descriptorUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(BINDING_IMAGE_SPARSE), imageSparseDescType(), &imageSparseDescInfo); 476 descriptorUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(BINDING_IMAGE_TEXELS), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageTexelsDescInfo); 477 descriptorUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(BINDING_IMAGE_RESIDENCY), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageResidencyDescInfo); 478 479 descriptorUpdateBuilder.update(deviceInterface, getDevice()); 480 481 deviceInterface.cmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL); 482 483 const deUint32 xWorkGroupCount = gridSize.x() / workGroupSize.x() + (gridSize.x() % workGroupSize.x() ? 1u : 0u); 484 const deUint32 yWorkGroupCount = gridSize.y() / workGroupSize.y() + (gridSize.y() % workGroupSize.y() ? 1u : 0u); 485 const deUint32 zWorkGroupCount = gridSize.z() / workGroupSize.z() + (gridSize.z() % workGroupSize.z() ? 1u : 0u); 486 const tcu::UVec3 maxWorkGroupCount = tcu::UVec3(65535u, 65535u, 65535u); 487 488 if (maxWorkGroupCount.x() < xWorkGroupCount || 489 maxWorkGroupCount.y() < yWorkGroupCount || 490 maxWorkGroupCount.z() < zWorkGroupCount) 491 { 492 TCU_THROW(NotSupportedError, "Image size exceeds compute invocations limit"); 493 } 494 495 deviceInterface.cmdDispatch(commandBuffer, xWorkGroupCount, yWorkGroupCount, zWorkGroupCount); 496 } 497 498 { 499 VkImageMemoryBarrier imageOutputTransferSrcBarriers[2]; 500 501 imageOutputTransferSrcBarriers[0] = makeImageMemoryBarrier 502 ( 503 VK_ACCESS_SHADER_WRITE_BIT, 504 VK_ACCESS_TRANSFER_READ_BIT, 505 VK_IMAGE_LAYOUT_GENERAL, 506 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 507 imageTexels, 508 fullImageSubresourceRange 509 ); 510 511 imageOutputTransferSrcBarriers[1] = makeImageMemoryBarrier 512 ( 513 VK_ACCESS_SHADER_WRITE_BIT, 514 VK_ACCESS_TRANSFER_READ_BIT, 515 VK_IMAGE_LAYOUT_GENERAL, 516 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 517 imageResidency, 518 fullImageSubresourceRange 519 ); 520 521 deviceInterface.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 2u, imageOutputTransferSrcBarriers); 522 } 523 } 524 525 class SparseShaderIntrinsicsInstanceFetch : public SparseShaderIntrinsicsInstanceStorage 526 { 527 public: 528 SparseShaderIntrinsicsInstanceFetch (Context& context, 529 const SpirVFunction function, 530 const ImageType imageType, 531 const tcu::UVec3& imageSize, 532 const tcu::TextureFormat& format) 533 : SparseShaderIntrinsicsInstanceStorage (context, function, imageType, imageSize, format) {} 534 535 VkImageUsageFlags imageSparseUsageFlags (void) const { return VK_IMAGE_USAGE_SAMPLED_BIT; } 536 VkDescriptorType imageSparseDescType (void) const { return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; } 537 }; 538 539 TestInstance* SparseCaseOpImageSparseFetch::createInstance (Context& context) const 540 { 541 return new SparseShaderIntrinsicsInstanceFetch(context, m_function, m_imageType, m_imageSize, m_format); 542 } 543 544 class SparseShaderIntrinsicsInstanceRead : public SparseShaderIntrinsicsInstanceStorage 545 { 546 public: 547 SparseShaderIntrinsicsInstanceRead (Context& context, 548 const SpirVFunction function, 549 const ImageType imageType, 550 const tcu::UVec3& imageSize, 551 const tcu::TextureFormat& format) 552 : SparseShaderIntrinsicsInstanceStorage (context, function, imageType, imageSize, format) {} 553 554 VkImageUsageFlags imageSparseUsageFlags (void) const { return VK_IMAGE_USAGE_STORAGE_BIT; } 555 VkDescriptorType imageSparseDescType (void) const { return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; } 556 }; 557 558 TestInstance* SparseCaseOpImageSparseRead::createInstance (Context& context) const 559 { 560 return new SparseShaderIntrinsicsInstanceRead(context, m_function, m_imageType, m_imageSize, m_format); 561 } 562 563 } // sparse 564 } // vkt 565