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 vktSparseResourcesMipmapSparseResidency.cpp
21 * \brief Sparse partially resident images with mipmaps tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktSparseResourcesMipmapSparseResidency.hpp"
25 #include "vktSparseResourcesTestsUtil.hpp"
26 #include "vktSparseResourcesBase.hpp"
27 #include "vktTestCaseUtil.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkRef.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkMemUtil.hpp"
35 #include "vkBuilderUtil.hpp"
36 #include "vkImageUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkTypeUtil.hpp"
39
40 #include "deUniquePtr.hpp"
41 #include "deStringUtil.hpp"
42
43 #include <string>
44 #include <vector>
45
46 using namespace vk;
47
48 namespace vkt
49 {
50 namespace sparse
51 {
52 namespace
53 {
54
alignedDivide(const VkExtent3D & extent,const VkExtent3D & divisor)55 tcu::UVec3 alignedDivide (const VkExtent3D& extent, const VkExtent3D& divisor)
56 {
57 tcu::UVec3 result;
58
59 result.x() = extent.width / divisor.width + ((extent.width % divisor.width) ? 1u : 0u);
60 result.y() = extent.height / divisor.height + ((extent.height % divisor.height) ? 1u : 0u);
61 result.z() = extent.depth / divisor.depth + ((extent.depth % divisor.depth) ? 1u : 0u);
62
63 return result;
64 }
65
66 class MipmapSparseResidencyCase : public TestCase
67 {
68 public:
69 MipmapSparseResidencyCase (tcu::TestContext& testCtx,
70 const std::string& name,
71 const std::string& description,
72 const ImageType imageType,
73 const tcu::UVec3& imageSize,
74 const tcu::TextureFormat& format);
75
76 TestInstance* createInstance (Context& context) const;
77
78 private:
79 const ImageType m_imageType;
80 const tcu::UVec3 m_imageSize;
81 const tcu::TextureFormat m_format;
82 };
83
MipmapSparseResidencyCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const ImageType imageType,const tcu::UVec3 & imageSize,const tcu::TextureFormat & format)84 MipmapSparseResidencyCase::MipmapSparseResidencyCase (tcu::TestContext& testCtx,
85 const std::string& name,
86 const std::string& description,
87 const ImageType imageType,
88 const tcu::UVec3& imageSize,
89 const tcu::TextureFormat& format)
90 : TestCase (testCtx, name, description)
91 , m_imageType (imageType)
92 , m_imageSize (imageSize)
93 , m_format (format)
94 {
95 }
96
97 class MipmapSparseResidencyInstance : public SparseResourcesBaseInstance
98 {
99 public:
100 MipmapSparseResidencyInstance (Context& context,
101 const ImageType imageType,
102 const tcu::UVec3& imageSize,
103 const tcu::TextureFormat& format);
104
105 tcu::TestStatus iterate (void);
106
107 private:
108
109 const ImageType m_imageType;
110 const tcu::UVec3 m_imageSize;
111 const tcu::TextureFormat m_format;
112 };
113
MipmapSparseResidencyInstance(Context & context,const ImageType imageType,const tcu::UVec3 & imageSize,const tcu::TextureFormat & format)114 MipmapSparseResidencyInstance::MipmapSparseResidencyInstance (Context& context,
115 const ImageType imageType,
116 const tcu::UVec3& imageSize,
117 const tcu::TextureFormat& format)
118 : SparseResourcesBaseInstance (context)
119 , m_imageType (imageType)
120 , m_imageSize (imageSize)
121 , m_format (format)
122 {
123 }
124
125
iterate(void)126 tcu::TestStatus MipmapSparseResidencyInstance::iterate (void)
127 {
128 const InstanceInterface& instance = m_context.getInstanceInterface();
129 const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
130 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
131 const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(instance, physicalDevice);
132
133 // Check if device support sparse operations for image type
134 switch (mapImageType(m_imageType))
135 {
136 case VK_IMAGE_TYPE_2D:
137 {
138 if (deviceFeatures.sparseResidencyImage2D == false)
139 return tcu::TestStatus(QP_TEST_RESULT_NOT_SUPPORTED, "Sparse residency for 2D Image not supported");
140 }
141 break;
142 case VK_IMAGE_TYPE_3D:
143 {
144 if (deviceFeatures.sparseResidencyImage3D == false)
145 return tcu::TestStatus(QP_TEST_RESULT_NOT_SUPPORTED, "Sparse residency for 3D Image not supported");
146
147 }
148 break;
149 default:
150 return tcu::TestStatus(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported image type");
151 };
152
153 // Check if device support sparse operations for image format
154 const std::vector<VkSparseImageFormatProperties> sparseImageFormatPropVec =
155 getPhysicalDeviceSparseImageFormatProperties(instance, physicalDevice, mapTextureFormat(m_format), mapImageType(m_imageType),
156 VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_IMAGE_TILING_OPTIMAL);
157
158 if (sparseImageFormatPropVec.size() == 0)
159 {
160 return tcu::TestStatus(QP_TEST_RESULT_NOT_SUPPORTED, "The image format does not support sparse operations");
161 }
162
163 // Check if image size does not exceed device limits
164 const VkPhysicalDeviceProperties deviceProperties = getPhysicalDeviceProperties(instance, physicalDevice);
165
166 if (isImageSizeSupported(m_imageType, m_imageSize, deviceProperties.limits) == false)
167 {
168 return tcu::TestStatus(QP_TEST_RESULT_NOT_SUPPORTED, "Image size not supported for device");
169 }
170
171 QueueRequirementsVec queueRequirements;
172 queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
173 queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u));
174
175 // Create logical device supporting both sparse and transfer queues
176 if (!createDeviceSupportingQueues(queueRequirements))
177 {
178 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Could not create device supporting sparse and compute queue");
179 }
180
181 const VkPhysicalDeviceMemoryProperties deviceMemoryProperties = getPhysicalDeviceMemoryProperties(instance, physicalDevice);
182
183 // Create memory allocator for logical device
184 const de::UniquePtr<Allocator> allocator(new SimpleAllocator(deviceInterface, *m_logicalDevice, deviceMemoryProperties));
185
186 // Create queue supporting sparse binding operations
187 const Queue& sparseQueue = getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0);
188
189 // Create queue supporting compute and transfer operations
190 const Queue& computeQueue = getQueue(VK_QUEUE_COMPUTE_BIT, 0);
191
192 VkImageCreateInfo imageSparseInfo;
193
194 imageSparseInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; //VkStructureType sType;
195 imageSparseInfo.pNext = DE_NULL; //const void* pNext;
196 imageSparseInfo.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT; //VkImageCreateFlags flags;
197 imageSparseInfo.imageType = mapImageType(m_imageType); //VkImageType imageType;
198 imageSparseInfo.format = mapTextureFormat(m_format); //VkFormat format;
199 imageSparseInfo.extent = makeExtent3D(getLayerSize(m_imageType, m_imageSize)); //VkExtent3D extent;
200 imageSparseInfo.arrayLayers = getNumLayers(m_imageType, m_imageSize); //deUint32 arrayLayers;
201 imageSparseInfo.samples = VK_SAMPLE_COUNT_1_BIT; //VkSampleCountFlagBits samples;
202 imageSparseInfo.tiling = VK_IMAGE_TILING_OPTIMAL; //VkImageTiling tiling;
203 imageSparseInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //VkImageLayout initialLayout;
204 imageSparseInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT |
205 VK_IMAGE_USAGE_TRANSFER_SRC_BIT; //VkImageUsageFlags usage;
206 imageSparseInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; //VkSharingMode sharingMode;
207 imageSparseInfo.queueFamilyIndexCount = 0u; //deUint32 queueFamilyIndexCount;
208 imageSparseInfo.pQueueFamilyIndices = DE_NULL; //const deUint32* pQueueFamilyIndices;
209
210 if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
211 {
212 imageSparseInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
213 }
214
215 VkImageFormatProperties imageFormatProperties;
216 instance.getPhysicalDeviceImageFormatProperties(physicalDevice,
217 imageSparseInfo.format,
218 imageSparseInfo.imageType,
219 imageSparseInfo.tiling,
220 imageSparseInfo.usage,
221 imageSparseInfo.flags,
222 &imageFormatProperties);
223
224
225 imageSparseInfo.mipLevels = getImageMaxMipLevels(imageFormatProperties, imageSparseInfo);
226
227 // Allow sharing of sparse image by two different queue families (if necessary)
228 const deUint32 queueFamilyIndices[] = { sparseQueue.queueFamilyIndex, computeQueue.queueFamilyIndex };
229
230 if (sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex)
231 {
232 imageSparseInfo.sharingMode = VK_SHARING_MODE_CONCURRENT; //VkSharingMode sharingMode;
233 imageSparseInfo.queueFamilyIndexCount = 2u; //deUint32 queueFamilyIndexCount;
234 imageSparseInfo.pQueueFamilyIndices = queueFamilyIndices; //const deUint32* pQueueFamilyIndices;
235 }
236
237 // Create sparse image
238 const Unique<VkImage> imageSparse(createImage(deviceInterface, *m_logicalDevice, &imageSparseInfo));
239
240 // Get sparse image general memory requirements
241 const VkMemoryRequirements imageSparseMemRequirements = getImageMemoryRequirements(deviceInterface, *m_logicalDevice, *imageSparse);
242
243 // Check if required image memory size does not exceed device limits
244 if (imageSparseMemRequirements.size > deviceProperties.limits.sparseAddressSpaceSize)
245 {
246 return tcu::TestStatus(QP_TEST_RESULT_NOT_SUPPORTED, "Required memory size for sparse resource exceeds device limits");
247 }
248
249 DE_ASSERT((imageSparseMemRequirements.size % imageSparseMemRequirements.alignment) == 0);
250
251 // Get sparse image sparse memory requirements
252 deUint32 sparseMemRequirementsCount = 0;
253
254 deviceInterface.getImageSparseMemoryRequirements(*m_logicalDevice, *imageSparse, &sparseMemRequirementsCount, DE_NULL);
255
256 DE_ASSERT(sparseMemRequirementsCount != 0);
257
258 std::vector<VkSparseImageMemoryRequirements> sparseMemoryRequirements;
259 sparseMemoryRequirements.resize(sparseMemRequirementsCount);
260
261 deviceInterface.getImageSparseMemoryRequirements(*m_logicalDevice, *imageSparse, &sparseMemRequirementsCount, &sparseMemoryRequirements[0]);
262
263 deUint32 colorAspectIndex = NO_MATCH_FOUND;
264
265 // Check if image includes color aspect
266 for (deUint32 memoryReqNdx = 0; memoryReqNdx < sparseMemRequirementsCount; ++memoryReqNdx)
267 {
268 if (sparseMemoryRequirements[memoryReqNdx].formatProperties.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)
269 {
270 colorAspectIndex = memoryReqNdx;
271 break;
272 }
273 }
274
275 if (colorAspectIndex == NO_MATCH_FOUND)
276 {
277 return tcu::TestStatus(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported image aspect - the test supports currently only VK_IMAGE_ASPECT_COLOR_BIT");
278 }
279
280 const VkSparseImageMemoryRequirements aspectRequirements = sparseMemoryRequirements[colorAspectIndex];
281 const VkImageAspectFlags aspectMask = aspectRequirements.formatProperties.aspectMask;
282 const VkExtent3D imageGranularity = aspectRequirements.formatProperties.imageGranularity;
283
284 DE_ASSERT((aspectRequirements.imageMipTailSize % imageSparseMemRequirements.alignment) == 0);
285
286 typedef de::SharedPtr< Unique<VkDeviceMemory> > DeviceMemoryUniquePtr;
287
288 std::vector<VkSparseImageMemoryBind> imageResidencyMemoryBinds;
289 std::vector<VkSparseMemoryBind> imageMipTailMemoryBinds;
290 std::vector<DeviceMemoryUniquePtr> deviceMemUniquePtrVec;
291 const deUint32 memoryType = findMatchingMemoryType(deviceMemoryProperties, imageSparseMemRequirements, MemoryRequirement::Any);
292
293 if (memoryType == NO_MATCH_FOUND)
294 {
295 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "No matching memory type found");
296 }
297
298 // Bind memory for each layer
299 for (deUint32 layerNdx = 0; layerNdx < imageSparseInfo.arrayLayers; ++layerNdx)
300 {
301 for (deUint32 mipLevelNdx = 0; mipLevelNdx < aspectRequirements.imageMipTailFirstLod; ++mipLevelNdx)
302 {
303 const VkExtent3D mipExtent = mipLevelExtents(imageSparseInfo.extent, mipLevelNdx);
304 const tcu::UVec3 sparseBlocks = alignedDivide(mipExtent, imageGranularity);
305 const deUint32 numSparseBlocks = sparseBlocks.x() * sparseBlocks.y() * sparseBlocks.z();
306
307 const VkMemoryAllocateInfo allocInfo =
308 {
309 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType;
310 DE_NULL, // const void* pNext;
311 imageSparseMemRequirements.alignment * numSparseBlocks, // VkDeviceSize allocationSize;
312 memoryType, // deUint32 memoryTypeIndex;
313 };
314
315 VkDeviceMemory deviceMemory = 0;
316 VK_CHECK(deviceInterface.allocateMemory(*m_logicalDevice, &allocInfo, DE_NULL, &deviceMemory));
317
318 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(deviceMemory), Deleter<VkDeviceMemory>(deviceInterface, *m_logicalDevice, DE_NULL))));
319
320 VkSparseImageMemoryBind imageMemoryBind;
321
322 imageMemoryBind.subresource.aspectMask = aspectMask;
323 imageMemoryBind.subresource.mipLevel = mipLevelNdx;
324 imageMemoryBind.subresource.arrayLayer = layerNdx;
325 imageMemoryBind.memory = deviceMemory;
326 imageMemoryBind.memoryOffset = 0u;
327 imageMemoryBind.flags = 0u;
328 imageMemoryBind.offset = makeOffset3D(0u, 0u, 0u);
329 imageMemoryBind.extent = mipExtent;
330
331 imageResidencyMemoryBinds.push_back(imageMemoryBind);
332 }
333
334 if (!(aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) && aspectRequirements.imageMipTailFirstLod < imageSparseInfo.mipLevels)
335 {
336 const VkMemoryAllocateInfo allocInfo =
337 {
338 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType;
339 DE_NULL, // const void* pNext;
340 aspectRequirements.imageMipTailSize, // VkDeviceSize allocationSize;
341 memoryType, // deUint32 memoryTypeIndex;
342 };
343
344 VkDeviceMemory deviceMemory = 0;
345 VK_CHECK(deviceInterface.allocateMemory(*m_logicalDevice, &allocInfo, DE_NULL, &deviceMemory));
346
347 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(deviceMemory), Deleter<VkDeviceMemory>(deviceInterface, *m_logicalDevice, DE_NULL))));
348
349 VkSparseMemoryBind imageMipTailMemoryBind;
350
351 imageMipTailMemoryBind.resourceOffset = aspectRequirements.imageMipTailOffset + layerNdx * aspectRequirements.imageMipTailStride;
352 imageMipTailMemoryBind.size = aspectRequirements.imageMipTailSize;
353 imageMipTailMemoryBind.memory = deviceMemory;
354 imageMipTailMemoryBind.memoryOffset = 0u;
355 imageMipTailMemoryBind.flags = 0u;
356
357 imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
358 }
359 }
360
361 if ((aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) && aspectRequirements.imageMipTailFirstLod < imageSparseInfo.mipLevels)
362 {
363 const VkMemoryAllocateInfo allocInfo =
364 {
365 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType;
366 DE_NULL, // const void* pNext;
367 aspectRequirements.imageMipTailSize, // VkDeviceSize allocationSize;
368 memoryType, // deUint32 memoryTypeIndex;
369 };
370
371 VkDeviceMemory deviceMemory = 0;
372 VK_CHECK(deviceInterface.allocateMemory(*m_logicalDevice, &allocInfo, DE_NULL, &deviceMemory));
373
374 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(deviceMemory), Deleter<VkDeviceMemory>(deviceInterface, *m_logicalDevice, DE_NULL))));
375
376 VkSparseMemoryBind imageMipTailMemoryBind;
377
378 imageMipTailMemoryBind.resourceOffset = aspectRequirements.imageMipTailOffset;
379 imageMipTailMemoryBind.size = aspectRequirements.imageMipTailSize;
380 imageMipTailMemoryBind.memory = deviceMemory;
381 imageMipTailMemoryBind.memoryOffset = 0u;
382 imageMipTailMemoryBind.flags = 0u;
383
384 imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
385 }
386
387 const Unique<VkSemaphore> imageMemoryBindSemaphore(makeSemaphore(deviceInterface, *m_logicalDevice));
388
389 VkBindSparseInfo bindSparseInfo =
390 {
391 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, //VkStructureType sType;
392 DE_NULL, //const void* pNext;
393 0u, //deUint32 waitSemaphoreCount;
394 DE_NULL, //const VkSemaphore* pWaitSemaphores;
395 0u, //deUint32 bufferBindCount;
396 DE_NULL, //const VkSparseBufferMemoryBindInfo* pBufferBinds;
397 0u, //deUint32 imageOpaqueBindCount;
398 DE_NULL, //const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds;
399 0u, //deUint32 imageBindCount;
400 DE_NULL, //const VkSparseImageMemoryBindInfo* pImageBinds;
401 1u, //deUint32 signalSemaphoreCount;
402 &imageMemoryBindSemaphore.get() //const VkSemaphore* pSignalSemaphores;
403 };
404
405 VkSparseImageMemoryBindInfo imageResidencyBindInfo;
406 VkSparseImageOpaqueMemoryBindInfo imageMipTailBindInfo;
407
408 if (imageResidencyMemoryBinds.size() > 0)
409 {
410 imageResidencyBindInfo.image = *imageSparse;
411 imageResidencyBindInfo.bindCount = static_cast<deUint32>(imageResidencyMemoryBinds.size());
412 imageResidencyBindInfo.pBinds = &imageResidencyMemoryBinds[0];
413
414 bindSparseInfo.imageBindCount = 1u;
415 bindSparseInfo.pImageBinds = &imageResidencyBindInfo;
416 }
417
418 if (imageMipTailMemoryBinds.size() > 0)
419 {
420 imageMipTailBindInfo.image = *imageSparse;
421 imageMipTailBindInfo.bindCount = static_cast<deUint32>(imageMipTailMemoryBinds.size());
422 imageMipTailBindInfo.pBinds = &imageMipTailMemoryBinds[0];
423
424 bindSparseInfo.imageOpaqueBindCount = 1u;
425 bindSparseInfo.pImageOpaqueBinds = &imageMipTailBindInfo;
426 }
427
428 // Submit sparse bind commands for execution
429 VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
430
431 // Create command buffer for compute and transfer oparations
432 const Unique<VkCommandPool> commandPool(makeCommandPool(deviceInterface, *m_logicalDevice, computeQueue.queueFamilyIndex));
433 const Unique<VkCommandBuffer> commandBuffer(makeCommandBuffer(deviceInterface, *m_logicalDevice, *commandPool));
434
435 // Start recording commands
436 beginCommandBuffer(deviceInterface, *commandBuffer);
437
438 const deUint32 imageSizeInBytes = getImageSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, imageSparseInfo.mipLevels);
439 const VkBufferCreateInfo inputBufferCreateInfo = makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
440
441 const de::UniquePtr<Buffer> inputBuffer(new Buffer(deviceInterface, *m_logicalDevice, *allocator, inputBufferCreateInfo, MemoryRequirement::HostVisible));
442
443 std::vector<deUint8> referenceData;
444 referenceData.resize(imageSizeInBytes);
445
446 for (deUint32 valueNdx = 0; valueNdx < imageSizeInBytes; ++valueNdx)
447 {
448 referenceData[valueNdx] = static_cast<deUint8>((valueNdx % imageSparseMemRequirements.alignment) + 1u);
449 }
450
451 deMemcpy(inputBuffer->getAllocation().getHostPtr(), &referenceData[0], imageSizeInBytes);
452
453 flushMappedMemoryRange(deviceInterface, *m_logicalDevice, inputBuffer->getAllocation().getMemory(), inputBuffer->getAllocation().getOffset(), imageSizeInBytes);
454
455 const VkBufferMemoryBarrier inputBufferBarrier
456 = makeBufferMemoryBarrier(
457 VK_ACCESS_HOST_WRITE_BIT,
458 VK_ACCESS_TRANSFER_READ_BIT,
459 inputBuffer->get(),
460 0u,
461 imageSizeInBytes);
462
463 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers);
464
465 const VkImageMemoryBarrier imageSparseTransferDstBarrier
466 = makeImageMemoryBarrier(
467 0u,
468 VK_ACCESS_TRANSFER_WRITE_BIT,
469 VK_IMAGE_LAYOUT_UNDEFINED,
470 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
471 *imageSparse,
472 fullImageSubresourceRange);
473
474 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 1u, &imageSparseTransferDstBarrier);
475
476 std::vector <VkBufferImageCopy> bufferImageCopy;
477 bufferImageCopy.resize(imageSparseInfo.mipLevels);
478
479 VkDeviceSize bufferOffset = 0;
480 for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; mipmapNdx++)
481 {
482 bufferImageCopy[mipmapNdx] = makeBufferImageCopy(mipLevelExtents(imageSparseInfo.extent, mipmapNdx), imageSparseInfo.arrayLayers, mipmapNdx, bufferOffset);
483
484 bufferOffset += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipmapNdx);
485 }
486
487 deviceInterface.cmdCopyBufferToImage(*commandBuffer, inputBuffer->get(), *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<deUint32>(bufferImageCopy.size()), &bufferImageCopy[0]);
488
489 const VkImageMemoryBarrier imageSparseTransferSrcBarrier
490 = makeImageMemoryBarrier(
491 VK_ACCESS_TRANSFER_WRITE_BIT,
492 VK_ACCESS_TRANSFER_READ_BIT,
493 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
494 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
495 *imageSparse,
496 fullImageSubresourceRange);
497
498 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseTransferSrcBarrier);
499
500 const VkBufferCreateInfo outputBufferCreateInfo = makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
501 const de::UniquePtr<Buffer> outputBuffer(new Buffer(deviceInterface, *m_logicalDevice, *allocator, outputBufferCreateInfo, MemoryRequirement::HostVisible));
502
503 deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outputBuffer->get(), static_cast<deUint32>(bufferImageCopy.size()), &bufferImageCopy[0]);
504
505 const VkBufferMemoryBarrier outputBufferBarrier
506 = makeBufferMemoryBarrier(
507 VK_ACCESS_TRANSFER_WRITE_BIT,
508 VK_ACCESS_HOST_READ_BIT,
509 outputBuffer->get(),
510 0u,
511 imageSizeInBytes);
512
513 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferBarrier, 0u, DE_NULL);
514
515 // End recording commands
516 endCommandBuffer(deviceInterface, *commandBuffer);
517
518 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT };
519
520 // Submit commands for execution and wait for completion
521 submitCommandsAndWait(deviceInterface, *m_logicalDevice, computeQueue.queueHandle, *commandBuffer, 1u, &imageMemoryBindSemaphore.get(), stageBits);
522
523 // Retrieve data from buffer to host memory
524 const Allocation& allocation = outputBuffer->getAllocation();
525
526 invalidateMappedMemoryRange(deviceInterface, *m_logicalDevice, allocation.getMemory(), allocation.getOffset(), imageSizeInBytes);
527
528 const deUint8* outputData = static_cast<const deUint8*>(allocation.getHostPtr());
529 tcu::TestStatus testStatus = tcu::TestStatus::pass("Passed");
530
531 if (deMemCmp(outputData, &referenceData[0], imageSizeInBytes) != 0)
532 {
533 testStatus = tcu::TestStatus::fail("Failed");
534 }
535
536 // Wait for sparse queue to become idle
537 deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
538
539 return testStatus;
540 }
541
createInstance(Context & context) const542 TestInstance* MipmapSparseResidencyCase::createInstance (Context& context) const
543 {
544 return new MipmapSparseResidencyInstance(context, m_imageType, m_imageSize, m_format);
545 }
546
547 } // anonymous ns
548
createMipmapSparseResidencyTests(tcu::TestContext & testCtx)549 tcu::TestCaseGroup* createMipmapSparseResidencyTests (tcu::TestContext& testCtx)
550 {
551 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "mipmap_sparse_residency", "Mipmap Sparse Residency"));
552
553 static const deUint32 sizeCountPerImageType = 3u;
554
555 struct ImageParameters
556 {
557 ImageType imageType;
558 tcu::UVec3 imageSizes[sizeCountPerImageType];
559 };
560
561 static const ImageParameters imageParametersArray[] =
562 {
563 { IMAGE_TYPE_2D, { tcu::UVec3(512u, 256u, 1u), tcu::UVec3(1024u, 128u, 1u), tcu::UVec3(11u, 137u, 1u) } },
564 { IMAGE_TYPE_2D_ARRAY, { tcu::UVec3(512u, 256u, 6u), tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u, 137u, 3u) } },
565 { IMAGE_TYPE_CUBE, { tcu::UVec3(512u, 256u, 1u), tcu::UVec3(1024u, 128u, 1u), tcu::UVec3(11u, 137u, 1u) } },
566 { IMAGE_TYPE_CUBE_ARRAY, { tcu::UVec3(512u, 256u, 6u), tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u, 137u, 3u) } },
567 { IMAGE_TYPE_3D, { tcu::UVec3(256u, 256u, 16u), tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u, 137u, 3u) } }
568 };
569
570 static const tcu::TextureFormat formats[] =
571 {
572 tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::SIGNED_INT32),
573 tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::SIGNED_INT16),
574 tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::SIGNED_INT8),
575 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32),
576 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT16),
577 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8)
578 };
579
580 for (deInt32 imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageParametersArray); ++imageTypeNdx)
581 {
582 const ImageType imageType = imageParametersArray[imageTypeNdx].imageType;
583 de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str(), ""));
584
585 for (deInt32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
586 {
587 const tcu::TextureFormat& format = formats[formatNdx];
588 de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, getShaderImageFormatQualifier(format).c_str(), ""));
589
590 for (deInt32 imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(imageParametersArray[imageTypeNdx].imageSizes); ++imageSizeNdx)
591 {
592 const tcu::UVec3 imageSize = imageParametersArray[imageTypeNdx].imageSizes[imageSizeNdx];
593
594 std::ostringstream stream;
595 stream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
596
597 formatGroup->addChild(new MipmapSparseResidencyCase(testCtx, stream.str(), "", imageType, imageSize, format));
598 }
599 imageTypeGroup->addChild(formatGroup.release());
600 }
601 testGroup->addChild(imageTypeGroup.release());
602 }
603
604 return testGroup.release();
605 }
606
607 } // sparse
608 } // vkt
609