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