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