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