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