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 vktSparseResourcesShaderIntrinsicsBase.cpp
21 * \brief Sparse Resources Shader Intrinsics Base Classes
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktSparseResourcesShaderIntrinsicsBase.hpp"
25 #include "vkCmdUtil.hpp"
26 #include "vkBarrierUtil.hpp"
27
28 using namespace vk;
29
30 namespace vkt
31 {
32 namespace sparse
33 {
34
getOpTypeImageComponent(const tcu::TextureFormat & format)35 std::string getOpTypeImageComponent (const tcu::TextureFormat& format)
36 {
37 switch (tcu::getTextureChannelClass(format.type))
38 {
39 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
40 return "OpTypeInt 32 0";
41 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
42 return "OpTypeInt 32 1";
43 default:
44 DE_ASSERT(0);
45 return "";
46 }
47 }
48
getImageComponentTypeName(const tcu::TextureFormat & format)49 std::string getImageComponentTypeName (const tcu::TextureFormat& format)
50 {
51 switch (tcu::getTextureChannelClass(format.type))
52 {
53 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
54 return "%type_uint";
55 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
56 return "%type_int";
57 default:
58 DE_ASSERT(0);
59 return "";
60 }
61 }
62
getImageComponentVec4TypeName(const tcu::TextureFormat & format)63 std::string getImageComponentVec4TypeName (const tcu::TextureFormat& format)
64 {
65 switch (tcu::getTextureChannelClass(format.type))
66 {
67 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
68 return "%type_uvec4";
69 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
70 return "%type_ivec4";
71 default:
72 DE_ASSERT(0);
73 return "";
74 }
75 }
76
getOpTypeImageSparse(const ImageType imageType,const tcu::TextureFormat & format,const std::string & componentType,const bool requiresSampler)77 std::string getOpTypeImageSparse (const ImageType imageType,
78 const tcu::TextureFormat& format,
79 const std::string& componentType,
80 const bool requiresSampler)
81 {
82 std::ostringstream src;
83
84 src << "OpTypeImage " << componentType << " ";
85
86 switch (imageType)
87 {
88 case IMAGE_TYPE_1D :
89 src << "1D 0 0 0 ";
90 break;
91 case IMAGE_TYPE_1D_ARRAY :
92 src << "1D 0 1 0 ";
93 break;
94 case IMAGE_TYPE_2D :
95 src << "2D 0 0 0 ";
96 break;
97 case IMAGE_TYPE_2D_ARRAY :
98 src << "2D 0 1 0 ";
99 break;
100 case IMAGE_TYPE_3D :
101 src << "3D 0 0 0 ";
102 break;
103 case IMAGE_TYPE_CUBE :
104 src << "Cube 0 0 0 ";
105 break;
106 case IMAGE_TYPE_CUBE_ARRAY :
107 src << "Cube 0 1 0 ";
108 break;
109 default :
110 DE_ASSERT(0);
111 break;
112 };
113
114 if (requiresSampler)
115 src << "1 ";
116 else
117 src << "2 ";
118
119 switch (format.order)
120 {
121 case tcu::TextureFormat::R:
122 src << "R";
123 break;
124 case tcu::TextureFormat::RG:
125 src << "Rg";
126 break;
127 case tcu::TextureFormat::RGB:
128 src << "Rgb";
129 break;
130 case tcu::TextureFormat::RGBA:
131 src << "Rgba";
132 break;
133 default:
134 DE_ASSERT(0);
135 break;
136 }
137
138 switch (format.type)
139 {
140 case tcu::TextureFormat::SIGNED_INT8:
141 src << "8i";
142 break;
143 case tcu::TextureFormat::SIGNED_INT16:
144 src << "16i";
145 break;
146 case tcu::TextureFormat::SIGNED_INT32:
147 src << "32i";
148 break;
149 case tcu::TextureFormat::UNSIGNED_INT8:
150 src << "8ui";
151 break;
152 case tcu::TextureFormat::UNSIGNED_INT16:
153 src << "16ui";
154 break;
155 case tcu::TextureFormat::UNSIGNED_INT32:
156 src << "32ui";
157 break;
158 default:
159 DE_ASSERT(0);
160 break;
161 };
162
163 return src.str();
164 }
165
getOpTypeImageResidency(const ImageType imageType)166 std::string getOpTypeImageResidency (const ImageType imageType)
167 {
168 std::ostringstream src;
169
170 src << "OpTypeImage %type_uint ";
171
172 switch (imageType)
173 {
174 case IMAGE_TYPE_1D :
175 src << "1D 0 0 0 2 R32ui";
176 break;
177 case IMAGE_TYPE_1D_ARRAY :
178 src << "1D 0 1 0 2 R32ui";
179 break;
180 case IMAGE_TYPE_2D :
181 src << "2D 0 0 0 2 R32ui";
182 break;
183 case IMAGE_TYPE_2D_ARRAY :
184 src << "2D 0 1 0 2 R32ui";
185 break;
186 case IMAGE_TYPE_3D :
187 src << "3D 0 0 0 2 R32ui";
188 break;
189 case IMAGE_TYPE_CUBE :
190 src << "Cube 0 0 0 2 R32ui";
191 break;
192 case IMAGE_TYPE_CUBE_ARRAY :
193 src << "Cube 0 1 0 2 R32ui";
194 break;
195 default :
196 DE_ASSERT(0);
197 break;
198 };
199
200 return src.str();
201 }
202
iterate(void)203 tcu::TestStatus SparseShaderIntrinsicsInstanceBase::iterate (void)
204 {
205 const InstanceInterface& instance = m_context.getInstanceInterface();
206 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
207 VkImageCreateInfo imageSparseInfo;
208 VkImageCreateInfo imageTexelsInfo;
209 VkImageCreateInfo imageResidencyInfo;
210 VkSparseImageMemoryRequirements aspectRequirements;
211 std::vector <deUint32> residencyReferenceData;
212 std::vector<DeviceMemorySp> deviceMemUniquePtrVec;
213
214 // Check if image size does not exceed device limits
215 if (!isImageSizeSupported(instance, physicalDevice, m_imageType, m_imageSize))
216 TCU_THROW(NotSupportedError, "Image size not supported for device");
217
218 // Check if device supports sparse operations for image type
219 if (!checkSparseSupportForImageType(instance, physicalDevice, m_imageType))
220 TCU_THROW(NotSupportedError, "Sparse residency for image type is not supported");
221
222 if (!getPhysicalDeviceFeatures(instance, physicalDevice).shaderResourceResidency)
223 TCU_THROW(NotSupportedError, "Sparse resource residency information not supported in shader code.");
224
225 imageSparseInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
226 imageSparseInfo.pNext = DE_NULL;
227 imageSparseInfo.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
228 imageSparseInfo.imageType = mapImageType(m_imageType);
229 imageSparseInfo.format = mapTextureFormat(m_format);
230 imageSparseInfo.extent = makeExtent3D(getLayerSize(m_imageType, m_imageSize));
231 imageSparseInfo.arrayLayers = getNumLayers(m_imageType, m_imageSize);
232 imageSparseInfo.samples = VK_SAMPLE_COUNT_1_BIT;
233 imageSparseInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
234 imageSparseInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
235 imageSparseInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | imageSparseUsageFlags();
236 imageSparseInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
237 imageSparseInfo.queueFamilyIndexCount = 0u;
238 imageSparseInfo.pQueueFamilyIndices = DE_NULL;
239
240 if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
241 {
242 imageSparseInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
243 }
244
245 {
246 // Assign maximum allowed mipmap levels to image
247 VkImageFormatProperties imageFormatProperties;
248 instance.getPhysicalDeviceImageFormatProperties(physicalDevice,
249 imageSparseInfo.format,
250 imageSparseInfo.imageType,
251 imageSparseInfo.tiling,
252 imageSparseInfo.usage,
253 imageSparseInfo.flags,
254 &imageFormatProperties);
255
256 imageSparseInfo.mipLevels = getImageMaxMipLevels(imageFormatProperties, imageSparseInfo.extent);
257 }
258
259 // Check if device supports sparse operations for image format
260 if (!checkSparseSupportForImageFormat(instance, physicalDevice, imageSparseInfo))
261 TCU_THROW(NotSupportedError, "The image format does not support sparse operations");
262
263 {
264 // Create logical device supporting both sparse and compute/graphics queues
265 QueueRequirementsVec queueRequirements;
266 queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
267 queueRequirements.push_back(QueueRequirements(getQueueFlags(), 1u));
268
269 createDeviceSupportingQueues(queueRequirements);
270 }
271
272 const DeviceInterface& deviceInterface = getDeviceInterface();
273
274 // Create queues supporting sparse binding operations and compute/graphics operations
275 const Queue& sparseQueue = getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0);
276 const Queue& extractQueue = getQueue(getQueueFlags(), 0);
277
278 // Create sparse image
279 const Unique<VkImage> imageSparse(createImage(deviceInterface, getDevice(), &imageSparseInfo));
280
281 // Create sparse image memory bind semaphore
282 const Unique<VkSemaphore> memoryBindSemaphore(createSemaphore(deviceInterface, getDevice()));
283
284 const deUint32 imageSparseSizeInBytes = getImageSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, imageSparseInfo.mipLevels, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
285 const deUint32 imageSizeInPixels = getImageSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, imageSparseInfo.mipLevels) / tcu::getPixelSize(m_format);
286
287 residencyReferenceData.assign(imageSizeInPixels, MEMORY_BLOCK_NOT_BOUND_VALUE);
288
289 {
290 // Get sparse image general memory requirements
291 const VkMemoryRequirements imageMemoryRequirements = getImageMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
292
293 // Check if required image memory size does not exceed device limits
294 if (imageMemoryRequirements.size > getPhysicalDeviceProperties(instance, physicalDevice).limits.sparseAddressSpaceSize)
295 TCU_THROW(NotSupportedError, "Required memory size for sparse resource exceeds device limits");
296
297 DE_ASSERT((imageMemoryRequirements.size % imageMemoryRequirements.alignment) == 0);
298
299 // Get sparse image sparse memory requirements
300 const std::vector<VkSparseImageMemoryRequirements> sparseMemoryRequirements = getImageSparseMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
301
302 DE_ASSERT(sparseMemoryRequirements.size() != 0);
303
304 const deUint32 colorAspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, VK_IMAGE_ASPECT_COLOR_BIT);
305 const deUint32 metadataAspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, VK_IMAGE_ASPECT_METADATA_BIT);
306
307 if (colorAspectIndex == NO_MATCH_FOUND)
308 TCU_THROW(NotSupportedError, "Not supported image aspect - the test supports currently only VK_IMAGE_ASPECT_COLOR_BIT");
309
310 aspectRequirements = sparseMemoryRequirements[colorAspectIndex];
311
312 DE_ASSERT((aspectRequirements.imageMipTailSize % imageMemoryRequirements.alignment) == 0);
313
314 const VkImageAspectFlags aspectMask = aspectRequirements.formatProperties.aspectMask;
315 const VkExtent3D imageGranularity = aspectRequirements.formatProperties.imageGranularity;
316 const deUint32 memoryType = findMatchingMemoryType(instance, physicalDevice, imageMemoryRequirements, MemoryRequirement::Any);
317
318 if (memoryType == NO_MATCH_FOUND)
319 return tcu::TestStatus::fail("No matching memory type found");
320
321 deUint32 pixelOffset = 0u;
322
323 std::vector<VkSparseImageMemoryBind> imageResidencyMemoryBinds;
324 std::vector<VkSparseMemoryBind> imageMipTailBinds;
325
326 // Bind memory for each mipmap level
327 for (deUint32 mipLevelNdx = 0; mipLevelNdx < aspectRequirements.imageMipTailFirstLod; ++mipLevelNdx)
328 {
329 const deUint32 mipLevelSizeInPixels = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx) / tcu::getPixelSize(m_format);
330
331 if (mipLevelNdx % MEMORY_BLOCK_TYPE_COUNT == MEMORY_BLOCK_NOT_BOUND)
332 {
333 pixelOffset += mipLevelSizeInPixels;
334 continue;
335 }
336
337 for (deUint32 pixelNdx = 0u; pixelNdx < mipLevelSizeInPixels; ++pixelNdx)
338 {
339 residencyReferenceData[pixelOffset + pixelNdx] = MEMORY_BLOCK_BOUND_VALUE;
340 }
341
342 pixelOffset += mipLevelSizeInPixels;
343
344 for (deUint32 layerNdx = 0; layerNdx < imageSparseInfo.arrayLayers; ++layerNdx)
345 {
346 const VkExtent3D mipExtent = mipLevelExtents(imageSparseInfo.extent, mipLevelNdx);
347 const tcu::UVec3 sparseBlocks = alignedDivide(mipExtent, imageGranularity);
348 const deUint32 numSparseBlocks = sparseBlocks.x() * sparseBlocks.y() * sparseBlocks.z();
349 const VkImageSubresource subresource = { aspectMask, mipLevelNdx, layerNdx };
350
351 const VkSparseImageMemoryBind imageMemoryBind = makeSparseImageMemoryBind(deviceInterface, getDevice(),
352 imageMemoryRequirements.alignment * numSparseBlocks, memoryType, subresource, makeOffset3D(0u, 0u, 0u), mipExtent);
353
354 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
355
356 imageResidencyMemoryBinds.push_back(imageMemoryBind);
357 }
358 }
359
360 if (aspectRequirements.imageMipTailFirstLod < imageSparseInfo.mipLevels)
361 {
362 if (aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT)
363 {
364 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
365 aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset);
366
367 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
368
369 imageMipTailBinds.push_back(imageMipTailMemoryBind);
370 }
371 else
372 {
373 for (deUint32 layerNdx = 0; layerNdx < imageSparseInfo.arrayLayers; ++layerNdx)
374 {
375 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
376 aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset + layerNdx * aspectRequirements.imageMipTailStride);
377
378 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
379
380 imageMipTailBinds.push_back(imageMipTailMemoryBind);
381 }
382 }
383
384 for (deUint32 pixelNdx = pixelOffset; pixelNdx < residencyReferenceData.size(); ++pixelNdx)
385 {
386 residencyReferenceData[pixelNdx] = MEMORY_BLOCK_BOUND_VALUE;
387 }
388 }
389
390 // Metadata
391 if (metadataAspectIndex != NO_MATCH_FOUND)
392 {
393 const VkSparseImageMemoryRequirements metadataAspectRequirements = sparseMemoryRequirements[metadataAspectIndex];
394
395 const deUint32 metadataBindCount = (metadataAspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT ? 1u : imageSparseInfo.arrayLayers);
396 for (deUint32 bindNdx = 0u; bindNdx < metadataBindCount; ++bindNdx)
397 {
398 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
399 metadataAspectRequirements.imageMipTailSize, memoryType,
400 metadataAspectRequirements.imageMipTailOffset + bindNdx * metadataAspectRequirements.imageMipTailStride,
401 VK_SPARSE_MEMORY_BIND_METADATA_BIT);
402
403 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
404
405 imageMipTailBinds.push_back(imageMipTailMemoryBind);
406 }
407 }
408
409 VkBindSparseInfo bindSparseInfo =
410 {
411 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, //VkStructureType sType;
412 DE_NULL, //const void* pNext;
413 0u, //deUint32 waitSemaphoreCount;
414 DE_NULL, //const VkSemaphore* pWaitSemaphores;
415 0u, //deUint32 bufferBindCount;
416 DE_NULL, //const VkSparseBufferMemoryBindInfo* pBufferBinds;
417 0u, //deUint32 imageOpaqueBindCount;
418 DE_NULL, //const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds;
419 0u, //deUint32 imageBindCount;
420 DE_NULL, //const VkSparseImageMemoryBindInfo* pImageBinds;
421 1u, //deUint32 signalSemaphoreCount;
422 &memoryBindSemaphore.get() //const VkSemaphore* pSignalSemaphores;
423 };
424
425 VkSparseImageMemoryBindInfo imageResidencyBindInfo;
426 VkSparseImageOpaqueMemoryBindInfo imageMipTailBindInfo;
427
428 if (imageResidencyMemoryBinds.size() > 0)
429 {
430 imageResidencyBindInfo.image = *imageSparse;
431 imageResidencyBindInfo.bindCount = static_cast<deUint32>(imageResidencyMemoryBinds.size());
432 imageResidencyBindInfo.pBinds = &imageResidencyMemoryBinds[0];
433
434 bindSparseInfo.imageBindCount = 1u;
435 bindSparseInfo.pImageBinds = &imageResidencyBindInfo;
436 }
437
438 if (imageMipTailBinds.size() > 0)
439 {
440 imageMipTailBindInfo.image = *imageSparse;
441 imageMipTailBindInfo.bindCount = static_cast<deUint32>(imageMipTailBinds.size());
442 imageMipTailBindInfo.pBinds = &imageMipTailBinds[0];
443
444 bindSparseInfo.imageOpaqueBindCount = 1u;
445 bindSparseInfo.pImageOpaqueBinds = &imageMipTailBindInfo;
446 }
447
448 // Submit sparse bind commands for execution
449 VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
450 }
451
452 // Create image to store texels copied from sparse image
453 imageTexelsInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
454 imageTexelsInfo.pNext = DE_NULL;
455 imageTexelsInfo.flags = 0u;
456 imageTexelsInfo.imageType = imageSparseInfo.imageType;
457 imageTexelsInfo.format = imageSparseInfo.format;
458 imageTexelsInfo.extent = imageSparseInfo.extent;
459 imageTexelsInfo.arrayLayers = imageSparseInfo.arrayLayers;
460 imageTexelsInfo.mipLevels = imageSparseInfo.mipLevels;
461 imageTexelsInfo.samples = imageSparseInfo.samples;
462 imageTexelsInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
463 imageTexelsInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
464 imageTexelsInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | imageOutputUsageFlags();
465 imageTexelsInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
466 imageTexelsInfo.queueFamilyIndexCount = 0u;
467 imageTexelsInfo.pQueueFamilyIndices = DE_NULL;
468
469 if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
470 {
471 imageTexelsInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
472 }
473
474 const Unique<VkImage> imageTexels (createImage(deviceInterface, getDevice(), &imageTexelsInfo));
475 const de::UniquePtr<Allocation> imageTexelsAlloc (bindImage(deviceInterface, getDevice(), getAllocator(), *imageTexels, MemoryRequirement::Any));
476
477 // Create image to store residency info copied from sparse image
478 imageResidencyInfo = imageTexelsInfo;
479 imageResidencyInfo.format = mapTextureFormat(m_residencyFormat);
480
481 const Unique<VkImage> imageResidency (createImage(deviceInterface, getDevice(), &imageResidencyInfo));
482 const de::UniquePtr<Allocation> imageResidencyAlloc (bindImage(deviceInterface, getDevice(), getAllocator(), *imageResidency, MemoryRequirement::Any));
483
484 // Create command buffer for compute and transfer oparations
485 const Unique<VkCommandPool> commandPool(makeCommandPool(deviceInterface, getDevice(), extractQueue.queueFamilyIndex));
486 const Unique<VkCommandBuffer> commandBuffer(allocateCommandBuffer(deviceInterface, getDevice(), *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
487
488 std::vector <VkBufferImageCopy> bufferImageSparseCopy(imageSparseInfo.mipLevels);
489
490 {
491 deUint32 bufferOffset = 0u;
492 for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx)
493 {
494 bufferImageSparseCopy[mipLevelNdx] = makeBufferImageCopy(mipLevelExtents(imageSparseInfo.extent, mipLevelNdx), imageSparseInfo.arrayLayers, mipLevelNdx, static_cast<VkDeviceSize>(bufferOffset));
495 bufferOffset += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
496 }
497 }
498
499 // Start recording commands
500 beginCommandBuffer(deviceInterface, *commandBuffer);
501
502 // Create input buffer
503 const VkBufferCreateInfo inputBufferCreateInfo = makeBufferCreateInfo(imageSparseSizeInBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
504 const Unique<VkBuffer> inputBuffer (createBuffer(deviceInterface, getDevice(), &inputBufferCreateInfo));
505 const de::UniquePtr<Allocation> inputBufferAlloc (bindBuffer(deviceInterface, getDevice(), getAllocator(), *inputBuffer, MemoryRequirement::HostVisible));
506
507 // Fill input buffer with reference data
508 std::vector<deUint8> referenceData(imageSparseSizeInBytes);
509
510 for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx)
511 {
512 const deUint32 mipLevelSizeinBytes = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx);
513 const deUint32 bufferOffset = static_cast<deUint32>(bufferImageSparseCopy[mipLevelNdx].bufferOffset);
514
515 for (deUint32 byteNdx = 0u; byteNdx < mipLevelSizeinBytes; ++byteNdx)
516 {
517 referenceData[bufferOffset + byteNdx] = (deUint8)(mipLevelNdx + byteNdx);
518 }
519 }
520
521 deMemcpy(inputBufferAlloc->getHostPtr(), &referenceData[0], imageSparseSizeInBytes);
522 flushAlloc(deviceInterface, getDevice(), *inputBufferAlloc);
523
524 {
525 // Prepare input buffer for data transfer operation
526 const VkBufferMemoryBarrier inputBufferBarrier = makeBufferMemoryBarrier
527 (
528 VK_ACCESS_HOST_WRITE_BIT,
529 VK_ACCESS_TRANSFER_READ_BIT,
530 *inputBuffer,
531 0u,
532 imageSparseSizeInBytes
533 );
534
535 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 0u, DE_NULL);
536 }
537
538 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers);
539
540 {
541 // Prepare sparse image for data transfer operation
542 const VkImageMemoryBarrier imageSparseTransferDstBarrier = makeImageMemoryBarrier
543 (
544 0u,
545 VK_ACCESS_TRANSFER_WRITE_BIT,
546 VK_IMAGE_LAYOUT_UNDEFINED,
547 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
548 *imageSparse,
549 fullImageSubresourceRange,
550 sparseQueue.queueFamilyIndex != extractQueue.queueFamilyIndex ? sparseQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED,
551 sparseQueue.queueFamilyIndex != extractQueue.queueFamilyIndex ? extractQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED
552 );
553
554 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseTransferDstBarrier);
555 }
556
557 // Copy reference data from input buffer to sparse image
558 deviceInterface.cmdCopyBufferToImage(*commandBuffer, *inputBuffer, *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<deUint32>(bufferImageSparseCopy.size()), &bufferImageSparseCopy[0]);
559
560 recordCommands(*commandBuffer, imageSparseInfo, *imageSparse, *imageTexels, *imageResidency);
561
562 const VkBufferCreateInfo bufferTexelsCreateInfo = makeBufferCreateInfo(imageSparseSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
563 const Unique<VkBuffer> bufferTexels (createBuffer(deviceInterface, getDevice(), &bufferTexelsCreateInfo));
564 const de::UniquePtr<Allocation> bufferTexelsAlloc (bindBuffer(deviceInterface, getDevice(), getAllocator(), *bufferTexels, MemoryRequirement::HostVisible));
565
566 // Copy data from texels image to buffer
567 deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageTexels, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *bufferTexels, static_cast<deUint32>(bufferImageSparseCopy.size()), &bufferImageSparseCopy[0]);
568
569 const deUint32 imageResidencySizeInBytes = getImageSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_residencyFormat, imageSparseInfo.mipLevels, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
570
571 const VkBufferCreateInfo bufferResidencyCreateInfo = makeBufferCreateInfo(imageResidencySizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
572 const Unique<VkBuffer> bufferResidency (createBuffer(deviceInterface, getDevice(), &bufferResidencyCreateInfo));
573 const de::UniquePtr<Allocation> bufferResidencyAlloc (bindBuffer(deviceInterface, getDevice(), getAllocator(), *bufferResidency, MemoryRequirement::HostVisible));
574
575 // Copy data from residency image to buffer
576 std::vector <VkBufferImageCopy> bufferImageResidencyCopy(imageSparseInfo.mipLevels);
577
578 {
579 deUint32 bufferOffset = 0u;
580 for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx)
581 {
582 bufferImageResidencyCopy[mipLevelNdx] = makeBufferImageCopy(mipLevelExtents(imageSparseInfo.extent, mipLevelNdx), imageSparseInfo.arrayLayers, mipLevelNdx, static_cast<VkDeviceSize>(bufferOffset));
583 bufferOffset += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_residencyFormat, mipLevelNdx, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
584 }
585 }
586
587 deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageResidency, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *bufferResidency, static_cast<deUint32>(bufferImageResidencyCopy.size()), &bufferImageResidencyCopy[0]);
588
589 {
590 VkBufferMemoryBarrier bufferOutputHostReadBarriers[2];
591
592 bufferOutputHostReadBarriers[0] = makeBufferMemoryBarrier
593 (
594 VK_ACCESS_TRANSFER_WRITE_BIT,
595 VK_ACCESS_HOST_READ_BIT,
596 *bufferTexels,
597 0u,
598 imageSparseSizeInBytes
599 );
600
601 bufferOutputHostReadBarriers[1] = makeBufferMemoryBarrier
602 (
603 VK_ACCESS_TRANSFER_WRITE_BIT,
604 VK_ACCESS_HOST_READ_BIT,
605 *bufferResidency,
606 0u,
607 imageResidencySizeInBytes
608 );
609
610 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 2u, bufferOutputHostReadBarriers, 0u, DE_NULL);
611 }
612
613 // End recording commands
614 endCommandBuffer(deviceInterface, *commandBuffer);
615
616 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT };
617
618 // Submit commands for execution and wait for completion
619 submitCommandsAndWait(deviceInterface, getDevice(), extractQueue.queueHandle, *commandBuffer, 1u, &memoryBindSemaphore.get(), stageBits);
620
621 // Wait for sparse queue to become idle
622 deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
623
624 // Retrieve data from residency buffer to host memory
625 invalidateAlloc(deviceInterface, getDevice(), *bufferResidencyAlloc);
626
627 const deUint32* bufferResidencyData = static_cast<const deUint32*>(bufferResidencyAlloc->getHostPtr());
628
629 deUint32 pixelOffsetNotAligned = 0u;
630 for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; ++mipmapNdx)
631 {
632 const deUint32 mipLevelSizeInBytes = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_residencyFormat, mipmapNdx);
633 const deUint32 pixelOffsetAligned = static_cast<deUint32>(bufferImageResidencyCopy[mipmapNdx].bufferOffset) / tcu::getPixelSize(m_residencyFormat);
634
635 if (deMemCmp(&bufferResidencyData[pixelOffsetAligned], &residencyReferenceData[pixelOffsetNotAligned], mipLevelSizeInBytes) != 0)
636 return tcu::TestStatus::fail("Failed");
637
638 pixelOffsetNotAligned += mipLevelSizeInBytes / tcu::getPixelSize(m_residencyFormat);
639 }
640
641 // Retrieve data from texels buffer to host memory
642 invalidateAlloc(deviceInterface, getDevice(), *bufferTexelsAlloc);
643
644 const deUint8* bufferTexelsData = static_cast<const deUint8*>(bufferTexelsAlloc->getHostPtr());
645
646 for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; ++mipmapNdx)
647 {
648 const deUint32 mipLevelSizeInBytes = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipmapNdx);
649 const deUint32 bufferOffset = static_cast<deUint32>(bufferImageSparseCopy[mipmapNdx].bufferOffset);
650
651 if (mipmapNdx < aspectRequirements.imageMipTailFirstLod)
652 {
653 if (mipmapNdx % MEMORY_BLOCK_TYPE_COUNT == MEMORY_BLOCK_BOUND)
654 {
655 if (deMemCmp(&bufferTexelsData[bufferOffset], &referenceData[bufferOffset], mipLevelSizeInBytes) != 0)
656 return tcu::TestStatus::fail("Failed");
657 }
658 else if (getPhysicalDeviceProperties(instance, physicalDevice).sparseProperties.residencyNonResidentStrict)
659 {
660 std::vector<deUint8> zeroData;
661 zeroData.assign(mipLevelSizeInBytes, 0u);
662
663 if (deMemCmp(&bufferTexelsData[bufferOffset], &zeroData[0], mipLevelSizeInBytes) != 0)
664 return tcu::TestStatus::fail("Failed");
665 }
666 }
667 else
668 {
669 if (deMemCmp(&bufferTexelsData[bufferOffset], &referenceData[bufferOffset], mipLevelSizeInBytes) != 0)
670 return tcu::TestStatus::fail("Failed");
671 }
672 }
673
674 return tcu::TestStatus::pass("Passed");
675 }
676
677 } // sparse
678 } // vkt
679