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