Fixes sparse image padding tests
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / sparse_resources / vktSparseResourcesImageSparseBinding.cpp
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  vktSparseResourcesImageSparseBinding.cpp
21  * \brief Sparse fully resident images with mipmaps tests
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktSparseResourcesBufferSparseBinding.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 "vkBarrierUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkCmdUtil.hpp"
41
42 #include "deUniquePtr.hpp"
43 #include "deStringUtil.hpp"
44 #include "tcuTextureUtil.hpp"
45
46 #include <string>
47 #include <vector>
48
49 using namespace vk;
50
51 namespace vkt
52 {
53 namespace sparse
54 {
55 namespace
56 {
57
58 class ImageSparseBindingCase : public TestCase
59 {
60 public:
61         ImageSparseBindingCase                  (tcu::TestContext&      testCtx,
62                                                                          const std::string&     name,
63                                                                          const std::string&     description,
64                                                                          const ImageType        imageType,
65                                                                          const tcu::UVec3&      imageSize,
66                                                                          const VkFormat         format,
67                                                                          const bool                     useDeviceGroups = false);
68
69         TestInstance*   createInstance  (Context&                       context) const;
70         virtual void    checkSupport                    (Context&                                       context) const;
71
72 private:
73         const bool                      m_useDeviceGroups;
74         const ImageType         m_imageType;
75         const tcu::UVec3        m_imageSize;
76         const VkFormat          m_format;
77 };
78
79 ImageSparseBindingCase::ImageSparseBindingCase (tcu::TestContext&       testCtx,
80                                                                                                 const std::string&      name,
81                                                                                                 const std::string&      description,
82                                                                                                 const ImageType         imageType,
83                                                                                                 const tcu::UVec3&       imageSize,
84                                                                                                 const VkFormat          format,
85                                                                                                 const bool                      useDeviceGroups)
86
87         : TestCase                      (testCtx, name, description)
88         , m_useDeviceGroups     (useDeviceGroups)
89         , m_imageType           (imageType)
90         , m_imageSize           (imageSize)
91         , m_format                      (format)
92 {
93 }
94
95 void ImageSparseBindingCase::checkSupport (Context& context) const
96 {
97         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SPARSE_BINDING);
98
99         if (!isImageSizeSupported(context.getInstanceInterface(), context.getPhysicalDevice(), m_imageType, m_imageSize))
100                 TCU_THROW(NotSupportedError, "Image size not supported for device");
101 }
102
103 class ImageSparseBindingInstance : public SparseResourcesBaseInstance
104 {
105 public:
106         ImageSparseBindingInstance      (Context&                       context,
107                                                                  const ImageType        imageType,
108                                                                  const tcu::UVec3&      imageSize,
109                                                                  const VkFormat         format,
110                                                                  const bool                     useDeviceGroups);
111
112         tcu::TestStatus iterate         (void);
113
114 private:
115         const bool                      m_useDeviceGroups;
116         const ImageType         m_imageType;
117         const tcu::UVec3        m_imageSize;
118         const VkFormat          m_format;
119 };
120
121 ImageSparseBindingInstance::ImageSparseBindingInstance (Context&                        context,
122                                                                                                                 const ImageType         imageType,
123                                                                                                                 const tcu::UVec3&       imageSize,
124                                                                                                                 const VkFormat          format,
125                                                                                                                 const bool                      useDeviceGroups)
126
127         : SparseResourcesBaseInstance   (context, useDeviceGroups)
128         , m_useDeviceGroups                             (useDeviceGroups)
129         , m_imageType                                   (imageType)
130         , m_imageSize                                   (imageSize)
131         , m_format                                              (format)
132 {
133 }
134
135 tcu::TestStatus ImageSparseBindingInstance::iterate (void)
136 {
137         const InstanceInterface&        instance                = m_context.getInstanceInterface();
138
139         {
140                 // Create logical device supporting both sparse and compute queues
141                 QueueRequirementsVec queueRequirements;
142                 queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
143                 queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u));
144
145                 createDeviceSupportingQueues(queueRequirements);
146         }
147
148         const VkPhysicalDevice          physicalDevice  = getPhysicalDevice();
149         VkImageCreateInfo                       imageSparseInfo;
150         std::vector<DeviceMemorySp>     deviceMemUniquePtrVec;
151
152         const DeviceInterface&                  deviceInterface         = getDeviceInterface();
153         const Queue&                                    sparseQueue                     = getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0);
154         const Queue&                                    computeQueue            = getQueue(VK_QUEUE_COMPUTE_BIT, 0);
155         const PlanarFormatDescription   formatDescription       = getPlanarFormatDescription(m_format);
156
157         // Go through all physical devices
158         for (deUint32 physDevID = 0; physDevID < m_numPhysicalDevices; ++physDevID)
159         {
160                 const deUint32  firstDeviceID   = physDevID;
161                 const deUint32  secondDeviceID  = (firstDeviceID + 1) % m_numPhysicalDevices;
162
163                 imageSparseInfo.sType                                   = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;                                  //VkStructureType               sType;
164                 imageSparseInfo.pNext                                   = DE_NULL;                                                                                              //const void*                   pNext;
165                 imageSparseInfo.flags                                   = VK_IMAGE_CREATE_SPARSE_BINDING_BIT;                                   //VkImageCreateFlags    flags;
166                 imageSparseInfo.imageType                               = mapImageType(m_imageType);                                                    //VkImageType                   imageType;
167                 imageSparseInfo.format                                  = m_format;                                                                                             //VkFormat                              format;
168                 imageSparseInfo.extent                                  = makeExtent3D(getLayerSize(m_imageType, m_imageSize)); //VkExtent3D                    extent;
169                 imageSparseInfo.arrayLayers                             = getNumLayers(m_imageType, m_imageSize);                               //deUint32                              arrayLayers;
170                 imageSparseInfo.samples                                 = VK_SAMPLE_COUNT_1_BIT;                                                                //VkSampleCountFlagBits samples;
171                 imageSparseInfo.tiling                                  = VK_IMAGE_TILING_OPTIMAL;                                                              //VkImageTiling                 tiling;
172                 imageSparseInfo.initialLayout                   = VK_IMAGE_LAYOUT_UNDEFINED;                                                    //VkImageLayout                 initialLayout;
173                 imageSparseInfo.usage                                   = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
174                                                                                                   VK_IMAGE_USAGE_TRANSFER_DST_BIT;                                              //VkImageUsageFlags             usage;
175                 imageSparseInfo.sharingMode                             = VK_SHARING_MODE_EXCLUSIVE;                                                    //VkSharingMode                 sharingMode;
176                 imageSparseInfo.queueFamilyIndexCount   = 0u;                                                                                                   //deUint32                              queueFamilyIndexCount;
177                 imageSparseInfo.pQueueFamilyIndices             = DE_NULL;                                                                                              //const deUint32*               pQueueFamilyIndices;
178
179                 if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
180                 {
181                         imageSparseInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
182                 }
183
184                 if (!checkSparseSupportForImageFormat(instance, physicalDevice, imageSparseInfo))
185                         TCU_THROW(NotSupportedError, "The image format does not support sparse operations");
186
187                 {
188                         VkImageFormatProperties imageFormatProperties;
189                         if (instance.getPhysicalDeviceImageFormatProperties(physicalDevice,
190                                 imageSparseInfo.format,
191                                 imageSparseInfo.imageType,
192                                 imageSparseInfo.tiling,
193                                 imageSparseInfo.usage,
194                                 imageSparseInfo.flags,
195                                 &imageFormatProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
196                         {
197                                 TCU_THROW(NotSupportedError, "Image format does not support sparse operations");
198                         }
199
200                         imageSparseInfo.mipLevels = getMipmapCount(m_format, formatDescription, imageFormatProperties, imageSparseInfo.extent);
201                 }
202
203                 // Create sparse image
204                 const Unique<VkImage> imageSparse(createImage(deviceInterface, getDevice(), &imageSparseInfo));
205
206                 // Create sparse image memory bind semaphore
207                 const Unique<VkSemaphore> imageMemoryBindSemaphore(createSemaphore(deviceInterface, getDevice()));
208
209                 // Get sparse image general memory requirements
210                 const VkMemoryRequirements imageMemoryRequirements = getImageMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
211
212                 // Check if required image memory size does not exceed device limits
213                 if (imageMemoryRequirements.size > getPhysicalDeviceProperties(instance, getPhysicalDevice(secondDeviceID)).limits.sparseAddressSpaceSize)
214                         TCU_THROW(NotSupportedError, "Required memory size for sparse resource exceeds device limits");
215
216                 DE_ASSERT((imageMemoryRequirements.size % imageMemoryRequirements.alignment) == 0);
217
218                 {
219                         std::vector<VkSparseMemoryBind> sparseMemoryBinds;
220                         const deUint32                                  numSparseBinds  = static_cast<deUint32>(imageMemoryRequirements.size / imageMemoryRequirements.alignment);
221                         const deUint32                                  memoryType              = findMatchingMemoryType(instance, getPhysicalDevice(secondDeviceID), imageMemoryRequirements, MemoryRequirement::Any);
222
223                         if (memoryType == NO_MATCH_FOUND)
224                                 return tcu::TestStatus::fail("No matching memory type found");
225
226                         if (firstDeviceID != secondDeviceID)
227                         {
228                                 VkPeerMemoryFeatureFlags        peerMemoryFeatureFlags = (VkPeerMemoryFeatureFlags)0;
229                                 const deUint32                          heapIndex = getHeapIndexForMemoryType(instance, getPhysicalDevice(secondDeviceID), memoryType);
230                                 deviceInterface.getDeviceGroupPeerMemoryFeatures(getDevice(), heapIndex, firstDeviceID, secondDeviceID, &peerMemoryFeatureFlags);
231
232                                 if (((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT) == 0) ||
233                                         ((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_COPY_DST_BIT) == 0))
234                                 {
235                                         TCU_THROW(NotSupportedError, "Peer memory does not support COPY_SRC and COPY_DST");
236                                 }
237                         }
238
239                         for (deUint32 sparseBindNdx = 0; sparseBindNdx < numSparseBinds; ++sparseBindNdx)
240                         {
241                                 const VkSparseMemoryBind sparseMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
242                                         imageMemoryRequirements.alignment, memoryType, imageMemoryRequirements.alignment * sparseBindNdx);
243
244                                 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(sparseMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
245
246                                 sparseMemoryBinds.push_back(sparseMemoryBind);
247                         }
248
249                         const VkSparseImageOpaqueMemoryBindInfo opaqueBindInfo = makeSparseImageOpaqueMemoryBindInfo(*imageSparse, static_cast<deUint32>(sparseMemoryBinds.size()), sparseMemoryBinds.data());
250
251                         const VkDeviceGroupBindSparseInfo devGroupBindSparseInfo =
252                         {
253                                 VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR,    //VkStructureType                                                       sType;
254                                 DE_NULL,                                                                                                //const void*                                                           pNext;
255                                 firstDeviceID,                                                                                  //deUint32                                                                      resourceDeviceIndex;
256                                 secondDeviceID,                                                                                 //deUint32                                                                      memoryDeviceIndex;
257                         };
258
259                         const VkBindSparseInfo bindSparseInfo =
260                         {
261                                 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,                                             //VkStructureType                                                       sType;
262                                 m_useDeviceGroups ? &devGroupBindSparseInfo : DE_NULL,  //const void*                                                           pNext;
263                                 0u,                                                                                                             //deUint32                                                                      waitSemaphoreCount;
264                                 DE_NULL,                                                                                                //const VkSemaphore*                                            pWaitSemaphores;
265                                 0u,                                                                                                             //deUint32                                                                      bufferBindCount;
266                                 DE_NULL,                                                                                                //const VkSparseBufferMemoryBindInfo*           pBufferBinds;
267                                 1u,                                                                                                             //deUint32                                                                      imageOpaqueBindCount;
268                                 &opaqueBindInfo,                                                                                //const VkSparseImageOpaqueMemoryBindInfo*      pImageOpaqueBinds;
269                                 0u,                                                                                                             //deUint32                                                                      imageBindCount;
270                                 DE_NULL,                                                                                                //const VkSparseImageMemoryBindInfo*            pImageBinds;
271                                 1u,                                                                                                             //deUint32                                                                      signalSemaphoreCount;
272                                 &imageMemoryBindSemaphore.get()                                                 //const VkSemaphore*                                            pSignalSemaphores;
273                         };
274
275                         // Submit sparse bind commands for execution
276                         VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
277                 }
278
279                 deUint32 imageSizeInBytes = 0;
280
281                 for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
282                         for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; ++mipmapNdx)
283                                 imageSizeInBytes += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, formatDescription, planeNdx, mipmapNdx, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
284
285                 std::vector<VkBufferImageCopy> bufferImageCopy(formatDescription.numPlanes * imageSparseInfo.mipLevels);
286                 {
287                         deUint32 bufferOffset = 0;
288                         for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
289                         {
290                                 const VkImageAspectFlags aspect = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
291
292                                 for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; ++mipmapNdx)
293                                 {
294                                         bufferImageCopy[planeNdx*imageSparseInfo.mipLevels + mipmapNdx] =
295                                         {
296                                                 bufferOffset,                                                                                                                                           //      VkDeviceSize                            bufferOffset;
297                                                 0u,                                                                                                                                                                     //      deUint32                                        bufferRowLength;
298                                                 0u,                                                                                                                                                                     //      deUint32                                        bufferImageHeight;
299                                                 makeImageSubresourceLayers(aspect, mipmapNdx, 0u, imageSparseInfo.arrayLayers),         //      VkImageSubresourceLayers        imageSubresource;
300                                                 makeOffset3D(0, 0, 0),                                                                                                                          //      VkOffset3D                                      imageOffset;
301                                                 vk::getPlaneExtent(formatDescription, imageSparseInfo.extent, planeNdx, mipmapNdx)      //      VkExtent3D                                      imageExtent;
302                                         };
303                                         bufferOffset += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, formatDescription, planeNdx, mipmapNdx, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
304                                 }
305                         }
306                 }
307
308                 // Create command buffer for compute and transfer operations
309                 const Unique<VkCommandPool>             commandPool(makeCommandPool(deviceInterface, getDevice(), computeQueue.queueFamilyIndex));
310                 const Unique<VkCommandBuffer>   commandBuffer(allocateCommandBuffer(deviceInterface, getDevice(), *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
311
312                 // Start recording commands
313                 beginCommandBuffer(deviceInterface, *commandBuffer);
314
315                 const VkBufferCreateInfo                inputBufferCreateInfo   = makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
316                 const Unique<VkBuffer>                  inputBuffer                             (createBuffer(deviceInterface, getDevice(), &inputBufferCreateInfo));
317                 const de::UniquePtr<Allocation> inputBufferAlloc                (bindBuffer(deviceInterface, getDevice(), getAllocator(), *inputBuffer, MemoryRequirement::HostVisible));
318
319                 std::vector<deUint8>                    referenceData(imageSizeInBytes);
320                 for (deUint32 valueNdx = 0; valueNdx < imageSizeInBytes; ++valueNdx)
321                 {
322                         referenceData[valueNdx] = static_cast<deUint8>((valueNdx % imageMemoryRequirements.alignment) + 1u);
323                 }
324
325                 {
326                         deMemcpy(inputBufferAlloc->getHostPtr(), referenceData.data(), imageSizeInBytes);
327                         flushAlloc(deviceInterface, getDevice(), *inputBufferAlloc);
328
329                         const VkBufferMemoryBarrier inputBufferBarrier = makeBufferMemoryBarrier (
330                                 VK_ACCESS_HOST_WRITE_BIT,
331                                 VK_ACCESS_TRANSFER_READ_BIT,
332                                 *inputBuffer,
333                                 0u,
334                                 imageSizeInBytes
335                         );
336                         deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 0u, DE_NULL);
337                 }
338
339                 {
340                         std::vector<VkImageMemoryBarrier> imageSparseTransferDstBarriers;
341
342                         for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
343                         {
344                                 const VkImageAspectFlags aspect = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
345
346                                 imageSparseTransferDstBarriers.push_back( makeImageMemoryBarrier (
347                                         0u,
348                                         VK_ACCESS_TRANSFER_WRITE_BIT,
349                                         VK_IMAGE_LAYOUT_UNDEFINED,
350                                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
351                                         *imageSparse,
352                                         makeImageSubresourceRange(aspect, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers),
353                                         sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? sparseQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED,
354                                         sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? computeQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED
355                                 ));
356                         }
357                         deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, static_cast<deUint32>(imageSparseTransferDstBarriers.size()), imageSparseTransferDstBarriers.data());
358                 }
359
360                 deviceInterface.cmdCopyBufferToImage(*commandBuffer, *inputBuffer, *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<deUint32>(bufferImageCopy.size()), bufferImageCopy.data());
361
362                 {
363                         std::vector<VkImageMemoryBarrier> imageSparseTransferSrcBarriers;
364
365                         for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
366                         {
367                                 const VkImageAspectFlags aspect = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
368
369                                 imageSparseTransferSrcBarriers.push_back( makeImageMemoryBarrier (
370                                         VK_ACCESS_TRANSFER_WRITE_BIT,
371                                         VK_ACCESS_TRANSFER_READ_BIT,
372                                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
373                                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
374                                         *imageSparse,
375                                         makeImageSubresourceRange(aspect, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers)
376                                 ));
377                         }
378
379                         deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, static_cast<deUint32>(imageSparseTransferSrcBarriers.size()), imageSparseTransferSrcBarriers.data());
380                 }
381
382                 const VkBufferCreateInfo                outputBufferCreateInfo  = makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
383                 const Unique<VkBuffer>                  outputBuffer                    (createBuffer(deviceInterface, getDevice(), &outputBufferCreateInfo));
384                 const de::UniquePtr<Allocation> outputBufferAlloc               (bindBuffer(deviceInterface, getDevice(), getAllocator(), *outputBuffer, MemoryRequirement::HostVisible));
385
386                 deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *outputBuffer, static_cast<deUint32>(bufferImageCopy.size()), bufferImageCopy.data());
387
388                 {
389                         const VkBufferMemoryBarrier outputBufferBarrier = makeBufferMemoryBarrier
390                         (
391                                 VK_ACCESS_TRANSFER_WRITE_BIT,
392                                 VK_ACCESS_HOST_READ_BIT,
393                                 *outputBuffer,
394                                 0u,
395                                 imageSizeInBytes
396                         );
397
398                         deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferBarrier, 0u, DE_NULL);
399                 }
400
401                 // End recording commands
402                 endCommandBuffer(deviceInterface, *commandBuffer);
403
404                 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT };
405
406                 // Submit commands for execution and wait for completion
407                 submitCommandsAndWait(deviceInterface, getDevice(), computeQueue.queueHandle, *commandBuffer, 1u, &imageMemoryBindSemaphore.get(), stageBits,
408                         0, DE_NULL, m_useDeviceGroups, firstDeviceID);
409
410                 // Retrieve data from buffer to host memory
411                 invalidateAlloc(deviceInterface, getDevice(), *outputBufferAlloc);
412
413                 // Wait for sparse queue to become idle
414                 deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
415
416                 const deUint8*  outputData              = static_cast<const deUint8*>(outputBufferAlloc->getHostPtr());
417                 bool                    ignoreLsb6Bits  = areLsb6BitsDontCare(imageSparseInfo.format);
418                 bool                    ignoreLsb4Bits  = areLsb4BitsDontCare(imageSparseInfo.format);
419
420                 for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
421                 {
422                         for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; ++mipmapNdx)
423                         {
424                                 const deUint32  mipLevelSizeInBytes             = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, formatDescription, planeNdx, mipmapNdx);
425                                 const deUint32  bufferOffset                    = static_cast<deUint32>(bufferImageCopy[ planeNdx * imageSparseInfo.mipLevels + mipmapNdx].bufferOffset);
426                                 bool                    is8bitSnormComponent    = false;
427
428                                 // Validate results
429                                 for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
430                                 {
431                                         if (!formatDescription.hasChannelNdx(channelNdx))
432                                                 continue;
433
434                                         if ((formatDescription.channels[channelNdx].type == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT) &&
435                                                 (formatDescription.channels[channelNdx].sizeBits == 8))
436                                         {
437                                                 is8bitSnormComponent = true;
438                                                 break;
439                                         }
440                                 }
441
442                                 for (size_t byteNdx = 0; byteNdx < mipLevelSizeInBytes; byteNdx++)
443                                 {
444                                         const deUint8   res     = *(outputData + bufferOffset + byteNdx);
445                                         const deUint8   ref     = referenceData[bufferOffset + byteNdx];
446
447                                         deUint8 mask = 0xFF;
448
449                                         if (!(byteNdx & 0x01) && (ignoreLsb6Bits))
450                                                 mask = 0xC0;
451                                         else if (!(byteNdx & 0x01) && (ignoreLsb4Bits))
452                                                 mask = 0xF0;
453
454                                         if (((!is8bitSnormComponent) || (ref != 0x80)) &&  ((res & mask) != (ref & mask)))
455                                         {
456                                                 return tcu::TestStatus::fail("Failed");
457                                         }
458                                 }
459                         }
460                 }
461         }
462
463         return tcu::TestStatus::pass("Passed");
464 }
465
466 TestInstance* ImageSparseBindingCase::createInstance (Context& context) const
467 {
468         return new ImageSparseBindingInstance(context, m_imageType, m_imageSize, m_format, m_useDeviceGroups);
469 }
470
471 } // anonymous ns
472
473 tcu::TestCaseGroup* createImageSparseBindingTestsCommon(tcu::TestContext& testCtx, de::MovePtr<tcu::TestCaseGroup> testGroup, const bool useDeviceGroup = false)
474 {
475         const std::vector<TestImageParameters> imageParameters =
476         {
477                 { IMAGE_TYPE_1D,                        { tcu::UVec3(512u, 1u,   1u ),  tcu::UVec3(1024u, 1u,   1u),    tcu::UVec3(11u,  1u,   1u) },   getTestFormats(IMAGE_TYPE_1D) },
478                 { IMAGE_TYPE_1D_ARRAY,          { tcu::UVec3(512u, 1u,   64u),  tcu::UVec3(1024u, 1u,   8u),    tcu::UVec3(11u,  1u,   3u) },   getTestFormats(IMAGE_TYPE_1D_ARRAY) },
479                 { IMAGE_TYPE_2D,                        { tcu::UVec3(512u, 256u, 1u ),  tcu::UVec3(1024u, 128u, 1u),    tcu::UVec3(11u,  137u, 1u) },   getTestFormats(IMAGE_TYPE_2D) },
480                 { IMAGE_TYPE_2D_ARRAY,          { tcu::UVec3(512u, 256u, 6u ),  tcu::UVec3(1024u, 128u, 8u),    tcu::UVec3(11u,  137u, 3u) },   getTestFormats(IMAGE_TYPE_2D_ARRAY) },
481                 { IMAGE_TYPE_3D,                        { tcu::UVec3(512u, 256u, 6u ),  tcu::UVec3(1024u, 128u, 8u),    tcu::UVec3(11u,  137u, 3u) },   getTestFormats(IMAGE_TYPE_3D) },
482                 { IMAGE_TYPE_CUBE,                      { tcu::UVec3(256u, 256u, 1u ),  tcu::UVec3(128u,  128u, 1u),    tcu::UVec3(137u, 137u, 1u) },   getTestFormats(IMAGE_TYPE_CUBE) },
483                 { IMAGE_TYPE_CUBE_ARRAY,        { tcu::UVec3(256u, 256u, 6u ),  tcu::UVec3(128u,  128u, 8u),    tcu::UVec3(137u, 137u, 3u) },   getTestFormats(IMAGE_TYPE_CUBE_ARRAY) }
484         };
485
486         for (size_t imageTypeNdx = 0; imageTypeNdx < imageParameters.size(); ++imageTypeNdx)
487         {
488                 const ImageType                                 imageType               = imageParameters[imageTypeNdx].imageType;
489                 de::MovePtr<tcu::TestCaseGroup> imageTypeGroup  (new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str(), ""));
490
491                 for (size_t formatNdx = 0; formatNdx < imageParameters[imageTypeNdx].formats.size(); ++formatNdx)
492                 {
493                         VkFormat                                                format                          = imageParameters[imageTypeNdx].formats[formatNdx].format;
494                         tcu::UVec3                                              imageSizeAlignment      = getImageSizeAlignment(format);
495                         de::MovePtr<tcu::TestCaseGroup> formatGroup                     (new tcu::TestCaseGroup(testCtx, getImageFormatID(format).c_str(), ""));
496
497                         for (size_t imageSizeNdx = 0; imageSizeNdx < imageParameters[imageTypeNdx].imageSizes.size(); ++imageSizeNdx)
498                         {
499                                 const tcu::UVec3 imageSize = imageParameters[imageTypeNdx].imageSizes[imageSizeNdx];
500
501                                 // skip test for images with odd sizes for some YCbCr formats
502                                 if ((imageSize.x() % imageSizeAlignment.x()) != 0)
503                                         continue;
504                                 if ((imageSize.y() % imageSizeAlignment.y()) != 0)
505                                         continue;
506
507                                 std::ostringstream      stream;
508                                 stream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
509
510                                 formatGroup->addChild(new ImageSparseBindingCase(testCtx, stream.str(), "", imageType, imageSize, format, useDeviceGroup));
511                         }
512                         imageTypeGroup->addChild(formatGroup.release());
513                 }
514                 testGroup->addChild(imageTypeGroup.release());
515         }
516
517         return testGroup.release();
518 }
519
520 tcu::TestCaseGroup* createImageSparseBindingTests(tcu::TestContext& testCtx)
521 {
522         de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_sparse_binding", "Image Sparse Binding"));
523         return createImageSparseBindingTestsCommon(testCtx, testGroup);
524 }
525
526 tcu::TestCaseGroup* createDeviceGroupImageSparseBindingTests(tcu::TestContext& testCtx)
527 {
528         de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "device_group_image_sparse_binding", "Device Group Image Sparse Binding"));
529         return createImageSparseBindingTestsCommon(testCtx, testGroup, true);
530 }
531
532 } // sparse
533 } // vkt