Update Vulkan CTS to version 1.0.2.3 am: 148890e79f
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / sparse_resources / vktSparseResourcesImageSparseResidency.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  vktSparseResourcesImageSparseResidency.cpp
21  * \brief Sparse partially resident images 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 "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
55 const std::string getCoordStr  (const ImageType         imageType,
56                                                                 const std::string&      x,
57                                                                 const std::string&      y,
58                                                                 const std::string&      z)
59 {
60         switch (imageType)
61         {
62                 case IMAGE_TYPE_1D:
63                 case IMAGE_TYPE_BUFFER:
64                         return x;
65
66                 case IMAGE_TYPE_1D_ARRAY:
67                 case IMAGE_TYPE_2D:
68                         return "ivec2(" + x + "," + y + ")";
69
70                 case IMAGE_TYPE_2D_ARRAY:
71                 case IMAGE_TYPE_3D:
72                 case IMAGE_TYPE_CUBE:
73                 case IMAGE_TYPE_CUBE_ARRAY:
74                         return "ivec3(" + x + "," + y + "," + z + ")";
75
76                 default:
77                         DE_ASSERT(false);
78                         return "";
79         }
80 }
81
82 tcu::UVec3 alignedDivide (const VkExtent3D& extent, const VkExtent3D& divisor)
83 {
84         tcu::UVec3 result;
85
86         result.x() = extent.width  / divisor.width  + ((extent.width  % divisor.width)  ? 1u : 0u);
87         result.y() = extent.height / divisor.height + ((extent.height % divisor.height) ? 1u : 0u);
88         result.z() = extent.depth  / divisor.depth  + ((extent.depth  % divisor.depth)  ? 1u : 0u);
89
90         return result;
91 }
92
93 tcu::UVec3 computeWorkGroupSize (const tcu::UVec3& gridSize)
94 {
95         const deUint32          maxComputeWorkGroupInvocations  = 128u;
96         const tcu::UVec3        maxComputeWorkGroupSize                 = tcu::UVec3(128u, 128u, 64u);
97
98         const deUint32 xWorkGroupSize = std::min(std::min(gridSize.x(), maxComputeWorkGroupSize.x()), maxComputeWorkGroupInvocations);
99         const deUint32 yWorkGroupSize = std::min(std::min(gridSize.y(), maxComputeWorkGroupSize.y()), maxComputeWorkGroupInvocations /  xWorkGroupSize);
100         const deUint32 zWorkGroupSize = std::min(std::min(gridSize.z(), maxComputeWorkGroupSize.z()), maxComputeWorkGroupInvocations / (xWorkGroupSize*yWorkGroupSize));
101
102         return tcu::UVec3(xWorkGroupSize, yWorkGroupSize, zWorkGroupSize);
103 }
104
105 class ImageSparseResidencyCase : public TestCase
106 {
107 public:
108                                         ImageSparseResidencyCase        (tcu::TestContext&                      testCtx,
109                                                                                                  const std::string&                     name,
110                                                                                                  const std::string&                     description,
111                                                                                                  const ImageType                        imageType,
112                                                                                                  const tcu::UVec3&                      imageSize,
113                                                                                                  const tcu::TextureFormat&      format,
114                                                                                                  const glu::GLSLVersion         glslVersion);
115
116         void                    initPrograms                            (SourceCollections&                     sourceCollections) const;
117         TestInstance*   createInstance                          (Context&                                       context) const;
118
119 private:
120         const ImageType                         m_imageType;
121         const tcu::UVec3                        m_imageSize;
122         const tcu::TextureFormat        m_format;
123         const glu::GLSLVersion          m_glslVersion;
124 };
125
126 ImageSparseResidencyCase::ImageSparseResidencyCase (tcu::TestContext&                   testCtx,
127                                                                                                         const std::string&                      name,
128                                                                                                         const std::string&                      description,
129                                                                                                         const ImageType                         imageType,
130                                                                                                         const tcu::UVec3&                       imageSize,
131                                                                                                         const tcu::TextureFormat&       format,
132                                                                                                         const glu::GLSLVersion          glslVersion)
133         : TestCase                              (testCtx, name, description)
134         , m_imageType                   (imageType)
135         , m_imageSize                   (imageSize)
136         , m_format                              (format)
137         , m_glslVersion                 (glslVersion)
138 {
139 }
140
141 void ImageSparseResidencyCase::initPrograms (SourceCollections& sourceCollections) const
142 {
143         // Create compute program
144         const char* const versionDecl                   = glu::getGLSLVersionDeclaration(m_glslVersion);
145         const std::string imageTypeStr                  = getShaderImageType(m_format, m_imageType);
146         const std::string formatQualifierStr    = getShaderImageFormatQualifier(m_format);
147         const std::string formatDataStr                 = getShaderImageDataType(m_format);
148         const tcu::UVec3  gridSize                              = getShaderGridSize(m_imageType, m_imageSize);
149         const tcu::UVec3  workGroupSize                 = computeWorkGroupSize(gridSize);
150
151         std::ostringstream src;
152         src << versionDecl << "\n"
153                 << "layout (local_size_x = " << workGroupSize.x() << ", local_size_y = " << workGroupSize.y() << ", local_size_z = " << workGroupSize.z() << ") in; \n"
154                 << "layout (binding = 0, " << formatQualifierStr << ") writeonly uniform highp " << imageTypeStr << " u_image;\n"
155                 << "void main (void)\n"
156                 << "{\n"
157                 << "    if( gl_GlobalInvocationID.x < " << gridSize.x() << " ) \n"
158                 << "    if( gl_GlobalInvocationID.y < " << gridSize.y() << " ) \n"
159                 << "    if( gl_GlobalInvocationID.z < " << gridSize.z() << " ) \n"
160                 << "    {\n"
161                 << "            imageStore(u_image, " << getCoordStr(m_imageType, "gl_GlobalInvocationID.x", "gl_GlobalInvocationID.y", "gl_GlobalInvocationID.z") << ","
162                 << formatDataStr << "( int(gl_GlobalInvocationID.x) % 127, int(gl_GlobalInvocationID.y) % 127, int(gl_GlobalInvocationID.z) % 127, 1));\n"
163                 << "    }\n"
164                 << "}\n";
165
166         sourceCollections.glslSources.add("comp") << glu::ComputeSource(src.str());
167 }
168
169 class ImageSparseResidencyInstance : public SparseResourcesBaseInstance
170 {
171 public:
172                                         ImageSparseResidencyInstance(Context&                                                                    context,
173                                                                                                  const ImageType                                                         imageType,
174                                                                                                  const tcu::UVec3&                                                       imageSize,
175                                                                                                  const tcu::TextureFormat&                                       format);
176
177         tcu::TestStatus iterate                                         (void);
178
179 private:
180         const ImageType                         m_imageType;
181         const tcu::UVec3                        m_imageSize;
182         const tcu::TextureFormat        m_format;
183 };
184
185 ImageSparseResidencyInstance::ImageSparseResidencyInstance (Context&                                    context,
186                                                                                                                         const ImageType                         imageType,
187                                                                                                                         const tcu::UVec3&                       imageSize,
188                                                                                                                         const tcu::TextureFormat&       format)
189         : SparseResourcesBaseInstance   (context)
190         , m_imageType                                   (imageType)
191         , m_imageSize                                   (imageSize)
192         , m_format                                              (format)
193 {
194 }
195
196 tcu::TestStatus ImageSparseResidencyInstance::iterate (void)
197 {
198         const InstanceInterface&                        instance = m_context.getInstanceInterface();
199         const VkPhysicalDevice                          physicalDevice = m_context.getPhysicalDevice();
200         const VkPhysicalDeviceProperties        physicalDeviceProperties = getPhysicalDeviceProperties(instance, physicalDevice);
201         VkImageCreateInfo                                       imageCreateInfo;
202         VkSparseImageMemoryRequirements         aspectRequirements;
203         VkExtent3D                                                      imageGranularity;
204         std::vector<DeviceMemorySp>                     deviceMemUniquePtrVec;
205
206         // Check if image size does not exceed device limits
207         if (!isImageSizeSupported(instance, physicalDevice, m_imageType, m_imageSize))
208                 TCU_THROW(NotSupportedError, "Image size not supported for device");
209
210         // Check if device supports sparse operations for image type
211         if (!checkSparseSupportForImageType(instance, physicalDevice, m_imageType))
212                 TCU_THROW(NotSupportedError, "Sparse residency for image type is not supported");
213
214         imageCreateInfo.sType                                   = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
215         imageCreateInfo.pNext                                   = DE_NULL;
216         imageCreateInfo.flags                                   = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
217         imageCreateInfo.imageType                               = mapImageType(m_imageType);
218         imageCreateInfo.format                                  = mapTextureFormat(m_format);
219         imageCreateInfo.extent                                  = makeExtent3D(getLayerSize(m_imageType, m_imageSize));
220         imageCreateInfo.mipLevels                               = 1u;
221         imageCreateInfo.arrayLayers                             = getNumLayers(m_imageType, m_imageSize);
222         imageCreateInfo.samples                                 = VK_SAMPLE_COUNT_1_BIT;
223         imageCreateInfo.tiling                                  = VK_IMAGE_TILING_OPTIMAL;
224         imageCreateInfo.initialLayout                   = VK_IMAGE_LAYOUT_UNDEFINED;
225         imageCreateInfo.usage                                   = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
226                                                                                           VK_IMAGE_USAGE_STORAGE_BIT;
227         imageCreateInfo.sharingMode                             = VK_SHARING_MODE_EXCLUSIVE;
228         imageCreateInfo.queueFamilyIndexCount   = 0u;
229         imageCreateInfo.pQueueFamilyIndices             = DE_NULL;
230
231         if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
232         {
233                 imageCreateInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
234         }
235
236         // Check if device supports sparse operations for image format
237         if (!checkSparseSupportForImageFormat(instance, physicalDevice, imageCreateInfo))
238                 TCU_THROW(NotSupportedError, "The image format does not support sparse operations");
239
240         {
241                 // Create logical device supporting both sparse and compute queues
242                 QueueRequirementsVec queueRequirements;
243                 queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
244                 queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u));
245
246                 createDeviceSupportingQueues(queueRequirements);
247         }
248
249         const DeviceInterface&  deviceInterface = getDeviceInterface();
250         const Queue&                    sparseQueue             = getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0);
251         const Queue&                    computeQueue    = getQueue(VK_QUEUE_COMPUTE_BIT, 0);
252
253         // Create sparse image
254         const Unique<VkImage> sparseImage(createImage(deviceInterface, getDevice(), &imageCreateInfo));
255
256         // Create sparse image memory bind semaphore
257         const Unique<VkSemaphore> imageMemoryBindSemaphore(createSemaphore(deviceInterface, getDevice()));
258
259         {
260                 // Get image general memory requirements
261                 const VkMemoryRequirements imageMemoryRequirements = getImageMemoryRequirements(deviceInterface, getDevice(), *sparseImage);
262
263                 if (imageMemoryRequirements.size > physicalDeviceProperties.limits.sparseAddressSpaceSize)
264                         TCU_THROW(NotSupportedError, "Required memory size for sparse resource exceeds device limits");
265
266                 DE_ASSERT((imageMemoryRequirements.size % imageMemoryRequirements.alignment) == 0);
267
268                 // Get sparse image sparse memory requirements
269                 const std::vector<VkSparseImageMemoryRequirements> sparseMemoryRequirements = getImageSparseMemoryRequirements(deviceInterface, getDevice(), *sparseImage);
270
271                 DE_ASSERT(sparseMemoryRequirements.size() != 0);
272
273                 const deUint32 colorAspectIndex         = getSparseAspectRequirementsIndex(sparseMemoryRequirements, VK_IMAGE_ASPECT_COLOR_BIT);
274                 const deUint32 metadataAspectIndex      = getSparseAspectRequirementsIndex(sparseMemoryRequirements, VK_IMAGE_ASPECT_METADATA_BIT);
275
276                 if (colorAspectIndex == NO_MATCH_FOUND)
277                         TCU_THROW(NotSupportedError, "Not supported image aspect - the test supports currently only VK_IMAGE_ASPECT_COLOR_BIT");
278
279                 aspectRequirements      = sparseMemoryRequirements[colorAspectIndex];
280                 imageGranularity        = aspectRequirements.formatProperties.imageGranularity;
281
282                 const VkImageAspectFlags aspectMask = aspectRequirements.formatProperties.aspectMask;
283
284                 DE_ASSERT((aspectRequirements.imageMipTailSize % imageMemoryRequirements.alignment) == 0);
285
286                 std::vector<VkSparseImageMemoryBind> imageResidencyMemoryBinds;
287                 std::vector<VkSparseMemoryBind>          imageMipTailMemoryBinds;
288
289                 const deUint32                                           memoryType = findMatchingMemoryType(instance, physicalDevice, imageMemoryRequirements, MemoryRequirement::Any);
290
291                 if (memoryType == NO_MATCH_FOUND)
292                         return tcu::TestStatus::fail("No matching memory type found");
293
294                 // Bind device memory for each aspect
295                 for (deUint32 layerNdx = 0; layerNdx < imageCreateInfo.arrayLayers; ++layerNdx)
296                 {
297                         for (deUint32 mipLevelNdx = 0; mipLevelNdx < aspectRequirements.imageMipTailFirstLod; ++mipLevelNdx)
298                         {
299                                 const VkImageSubresource subresource            = { aspectMask, mipLevelNdx, layerNdx };
300                                 const VkExtent3D                 mipExtent                      = mipLevelExtents(imageCreateInfo.extent, mipLevelNdx);
301                                 const tcu::UVec3                 numSparseBinds         = alignedDivide(mipExtent, imageGranularity);
302                                 const tcu::UVec3                 lastBlockExtent        = tcu::UVec3(mipExtent.width  % imageGranularity.width  ? mipExtent.width   % imageGranularity.width  : imageGranularity.width,
303                                                                                                                                                  mipExtent.height % imageGranularity.height ? mipExtent.height  % imageGranularity.height : imageGranularity.height,
304                                                                                                                                                  mipExtent.depth  % imageGranularity.depth  ? mipExtent.depth   % imageGranularity.depth  : imageGranularity.depth);
305                                 for (deUint32 z = 0; z < numSparseBinds.z(); ++z)
306                                 for (deUint32 y = 0; y < numSparseBinds.y(); ++y)
307                                 for (deUint32 x = 0; x < numSparseBinds.x(); ++x)
308                                 {
309                                         const deUint32 linearIndex = x + y*numSparseBinds.x() + z*numSparseBinds.x()*numSparseBinds.y() + layerNdx*numSparseBinds.x()*numSparseBinds.y()*numSparseBinds.z();
310
311                                         if (linearIndex % 2u == 1u)
312                                         {
313                                                 continue;
314                                         }
315
316                                         VkOffset3D offset;
317                                         offset.x = x*imageGranularity.width;
318                                         offset.y = y*imageGranularity.height;
319                                         offset.z = z*imageGranularity.depth;
320
321                                         VkExtent3D extent;
322                                         extent.width  = (x == numSparseBinds.x() - 1) ? lastBlockExtent.x() : imageGranularity.width;
323                                         extent.height = (y == numSparseBinds.y() - 1) ? lastBlockExtent.y() : imageGranularity.height;
324                                         extent.depth  = (z == numSparseBinds.z() - 1) ? lastBlockExtent.z() : imageGranularity.depth;
325
326                                         const VkSparseImageMemoryBind imageMemoryBind = makeSparseImageMemoryBind(deviceInterface, getDevice(),
327                                                 imageMemoryRequirements.alignment, memoryType, subresource, offset, extent);
328
329                                         deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
330
331                                         imageResidencyMemoryBinds.push_back(imageMemoryBind);
332                                 }
333                         }
334
335                         if (!(aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) && aspectRequirements.imageMipTailFirstLod < imageCreateInfo.mipLevels)
336                         {
337                                 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
338                                         aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset + layerNdx * aspectRequirements.imageMipTailStride);
339
340                                 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
341
342                                 imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
343                         }
344
345                         // Metadata
346                         if (metadataAspectIndex != NO_MATCH_FOUND)
347                         {
348                                 const VkSparseImageMemoryRequirements metadataAspectRequirements = sparseMemoryRequirements[metadataAspectIndex];
349
350                                 if (!(metadataAspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT))
351                                 {
352                                         const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
353                                                 metadataAspectRequirements.imageMipTailSize, memoryType,
354                                                 metadataAspectRequirements.imageMipTailOffset + layerNdx * metadataAspectRequirements.imageMipTailStride,
355                                                 VK_SPARSE_MEMORY_BIND_METADATA_BIT);
356
357                                         deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
358
359                                         imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
360                                 }
361                         }
362                 }
363
364                 if ((aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) && aspectRequirements.imageMipTailFirstLod < imageCreateInfo.mipLevels)
365                 {
366                         const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
367                                 aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset);
368
369                         deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
370
371                         imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
372                 }
373
374                 // Metadata
375                 if (metadataAspectIndex != NO_MATCH_FOUND)
376                 {
377                         const VkSparseImageMemoryRequirements metadataAspectRequirements = sparseMemoryRequirements[metadataAspectIndex];
378
379                         if ((metadataAspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT))
380                         {
381                                 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
382                                         metadataAspectRequirements.imageMipTailSize, memoryType, metadataAspectRequirements.imageMipTailOffset,
383                                         VK_SPARSE_MEMORY_BIND_METADATA_BIT);
384
385                                 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
386
387                                 imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
388                         }
389                 }
390
391                 VkBindSparseInfo bindSparseInfo =
392                 {
393                         VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,                     //VkStructureType                                                       sType;
394                         DE_NULL,                                                                        //const void*                                                           pNext;
395                         0u,                                                                                     //deUint32                                                                      waitSemaphoreCount;
396                         DE_NULL,                                                                        //const VkSemaphore*                                            pWaitSemaphores;
397                         0u,                                                                                     //deUint32                                                                      bufferBindCount;
398                         DE_NULL,                                                                        //const VkSparseBufferMemoryBindInfo*           pBufferBinds;
399                         0u,                                                                                     //deUint32                                                                      imageOpaqueBindCount;
400                         DE_NULL,                                                                        //const VkSparseImageOpaqueMemoryBindInfo*      pImageOpaqueBinds;
401                         0u,                                                                                     //deUint32                                                                      imageBindCount;
402                         DE_NULL,                                                                        //const VkSparseImageMemoryBindInfo*            pImageBinds;
403                         1u,                                                                                     //deUint32                                                                      signalSemaphoreCount;
404                         &imageMemoryBindSemaphore.get()                         //const VkSemaphore*                                            pSignalSemaphores;
405                 };
406
407                 VkSparseImageMemoryBindInfo               imageResidencyBindInfo;
408                 VkSparseImageOpaqueMemoryBindInfo imageMipTailBindInfo;
409
410                 if (imageResidencyMemoryBinds.size() > 0)
411                 {
412                         imageResidencyBindInfo.image            = *sparseImage;
413                         imageResidencyBindInfo.bindCount        = static_cast<deUint32>(imageResidencyMemoryBinds.size());
414                         imageResidencyBindInfo.pBinds           = &imageResidencyMemoryBinds[0];
415
416                         bindSparseInfo.imageBindCount           = 1u;
417                         bindSparseInfo.pImageBinds                      = &imageResidencyBindInfo;
418                 }
419
420                 if (imageMipTailMemoryBinds.size() > 0)
421                 {
422                         imageMipTailBindInfo.image                      = *sparseImage;
423                         imageMipTailBindInfo.bindCount          = static_cast<deUint32>(imageMipTailMemoryBinds.size());
424                         imageMipTailBindInfo.pBinds                     = &imageMipTailMemoryBinds[0];
425
426                         bindSparseInfo.imageOpaqueBindCount = 1u;
427                         bindSparseInfo.pImageOpaqueBinds        = &imageMipTailBindInfo;
428                 }
429
430                 // Submit sparse bind commands for execution
431                 VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
432         }
433
434         // Create command buffer for compute and transfer oparations
435         const Unique<VkCommandPool>       commandPool(makeCommandPool(deviceInterface, getDevice(), computeQueue.queueFamilyIndex));
436         const Unique<VkCommandBuffer> commandBuffer(allocateCommandBuffer(deviceInterface, getDevice(), *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
437
438         // Start recording commands
439         beginCommandBuffer(deviceInterface, *commandBuffer);
440
441         // Create descriptor set layout
442         const Unique<VkDescriptorSetLayout> descriptorSetLayout(
443                 DescriptorSetLayoutBuilder()
444                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
445                 .build(deviceInterface, getDevice()));
446
447         // Create and bind compute pipeline
448         const Unique<VkShaderModule>    shaderModule(createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get("comp"), DE_NULL));
449         const Unique<VkPipelineLayout>  pipelineLayout(makePipelineLayout(deviceInterface, getDevice(), *descriptorSetLayout));
450         const Unique<VkPipeline>                computePipeline(makeComputePipeline(deviceInterface, getDevice(), *pipelineLayout, *shaderModule));
451
452         deviceInterface.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
453
454         // Create and bind descriptor set
455         const Unique<VkDescriptorPool> descriptorPool(
456                 DescriptorPoolBuilder()
457                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1u)
458                 .build(deviceInterface, getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
459
460         const Unique<VkDescriptorSet>   descriptorSet(makeDescriptorSet(deviceInterface, getDevice(), *descriptorPool, *descriptorSetLayout));
461
462         const VkImageSubresourceRange   subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize));
463         const Unique<VkImageView>               imageView(makeImageView(deviceInterface, getDevice(), *sparseImage, mapImageViewType(m_imageType), mapTextureFormat(m_format), subresourceRange));
464         const VkDescriptorImageInfo             sparseImageInfo  = makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
465
466         DescriptorSetUpdateBuilder()
467                 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &sparseImageInfo)
468                 .update(deviceInterface, getDevice());
469
470         deviceInterface.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
471
472         {
473                 const VkImageMemoryBarrier sparseImageLayoutChangeBarrier = makeImageMemoryBarrier
474                 (
475                         0u,
476                         VK_ACCESS_SHADER_WRITE_BIT,
477                         VK_IMAGE_LAYOUT_UNDEFINED,
478                         VK_IMAGE_LAYOUT_GENERAL,
479                         sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? sparseQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED,
480                         sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? computeQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED,
481                         *sparseImage,
482                         subresourceRange
483                 );
484
485                 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &sparseImageLayoutChangeBarrier);
486         }
487
488         const tcu::UVec3  gridSize = getShaderGridSize(m_imageType, m_imageSize);
489
490         {
491                 const tcu::UVec3  workGroupSize = computeWorkGroupSize(gridSize);
492
493                 const deUint32 xWorkGroupCount = gridSize.x() / workGroupSize.x() + (gridSize.x() % workGroupSize.x() ? 1u : 0u);
494                 const deUint32 yWorkGroupCount = gridSize.y() / workGroupSize.y() + (gridSize.y() % workGroupSize.y() ? 1u : 0u);
495                 const deUint32 zWorkGroupCount = gridSize.z() / workGroupSize.z() + (gridSize.z() % workGroupSize.z() ? 1u : 0u);
496
497                 const tcu::UVec3 maxComputeWorkGroupCount = tcu::UVec3(65535u, 65535u, 65535u);
498
499                 if (maxComputeWorkGroupCount.x() < xWorkGroupCount ||
500                         maxComputeWorkGroupCount.y() < yWorkGroupCount ||
501                         maxComputeWorkGroupCount.z() < zWorkGroupCount)
502                 {
503                         TCU_THROW(NotSupportedError, "Image size is not supported");
504                 }
505
506                 deviceInterface.cmdDispatch(*commandBuffer, xWorkGroupCount, yWorkGroupCount, zWorkGroupCount);
507         }
508
509         {
510                 const VkImageMemoryBarrier sparseImageTrasferBarrier = makeImageMemoryBarrier
511                 (
512                         VK_ACCESS_SHADER_WRITE_BIT,
513                         VK_ACCESS_TRANSFER_READ_BIT,
514                         VK_IMAGE_LAYOUT_GENERAL,
515                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
516                         *sparseImage,
517                         subresourceRange
518                 );
519
520                 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &sparseImageTrasferBarrier);
521         }
522
523         const deUint32                                  imageSizeInBytes                = getNumPixels(m_imageType, m_imageSize) * tcu::getPixelSize(m_format);
524         const VkBufferCreateInfo                outputBufferCreateInfo  = makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
525         const Unique<VkBuffer>                  outputBuffer                    (createBuffer(deviceInterface, getDevice(), &outputBufferCreateInfo));
526         const de::UniquePtr<Allocation> outputBufferAlloc               (bindBuffer(deviceInterface, getDevice(), getAllocator(), *outputBuffer, MemoryRequirement::HostVisible));
527
528         {
529                 const VkBufferImageCopy bufferImageCopy = makeBufferImageCopy(imageCreateInfo.extent, imageCreateInfo.arrayLayers);
530
531                 deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *sparseImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *outputBuffer, 1u, &bufferImageCopy);
532         }
533
534         {
535                 const VkBufferMemoryBarrier outputBufferHostReadBarrier = makeBufferMemoryBarrier
536                 (
537                         VK_ACCESS_TRANSFER_WRITE_BIT,
538                         VK_ACCESS_HOST_READ_BIT,
539                         *outputBuffer,
540                         0u,
541                         imageSizeInBytes
542                 );
543
544                 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferHostReadBarrier, 0u, DE_NULL);
545         }
546
547         // End recording commands
548         endCommandBuffer(deviceInterface, *commandBuffer);
549
550         // The stage at which execution is going to wait for finish of sparse binding operations
551         const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT };
552
553         // Submit commands for execution and wait for completion
554         submitCommandsAndWait(deviceInterface, getDevice(), computeQueue.queueHandle, *commandBuffer, 1u, &imageMemoryBindSemaphore.get(), stageBits);
555
556         // Retrieve data from buffer to host memory
557         invalidateMappedMemoryRange(deviceInterface, getDevice(), outputBufferAlloc->getMemory(), outputBufferAlloc->getOffset(), imageSizeInBytes);
558
559         const deUint8* outputData = static_cast<const deUint8*>(outputBufferAlloc->getHostPtr());
560         const tcu::ConstPixelBufferAccess pixelBuffer = tcu::ConstPixelBufferAccess(m_format, gridSize.x(), gridSize.y(), gridSize.z(), outputData);
561
562         // Wait for sparse queue to become idle
563         deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
564
565         // Validate results
566         if( aspectRequirements.imageMipTailFirstLod > 0u )
567         {
568                 const VkExtent3D                 mipExtent               = mipLevelExtents(imageCreateInfo.extent, 0u);
569                 const tcu::UVec3                 numSparseBinds  = alignedDivide(mipExtent, imageGranularity);
570                 const tcu::UVec3                 lastBlockExtent = tcu::UVec3(  mipExtent.width  % imageGranularity.width  ? mipExtent.width  % imageGranularity.width  : imageGranularity.width,
571                                                                                                                                 mipExtent.height % imageGranularity.height ? mipExtent.height % imageGranularity.height : imageGranularity.height,
572                                                                                                                                 mipExtent.depth  % imageGranularity.depth  ? mipExtent.depth  % imageGranularity.depth  : imageGranularity.depth);
573
574                 for (deUint32 layerNdx = 0; layerNdx < imageCreateInfo.arrayLayers; ++layerNdx)
575                 {
576                         for (deUint32 z = 0; z < numSparseBinds.z(); ++z)
577                         for (deUint32 y = 0; y < numSparseBinds.y(); ++y)
578                         for (deUint32 x = 0; x < numSparseBinds.x(); ++x)
579                         {
580                                 VkExtent3D offset;
581                                 offset.width  = x*imageGranularity.width;
582                                 offset.height = y*imageGranularity.height;
583                                 offset.depth  = z*imageGranularity.depth + layerNdx*numSparseBinds.z()*imageGranularity.depth;
584
585                                 VkExtent3D extent;
586                                 extent.width  = (x == numSparseBinds.x() - 1) ? lastBlockExtent.x() : imageGranularity.width;
587                                 extent.height = (y == numSparseBinds.y() - 1) ? lastBlockExtent.y() : imageGranularity.height;
588                                 extent.depth  = (z == numSparseBinds.z() - 1) ? lastBlockExtent.z() : imageGranularity.depth;
589
590                                 const deUint32 linearIndex = x + y*numSparseBinds.x() + z*numSparseBinds.x()*numSparseBinds.y() + layerNdx*numSparseBinds.x()*numSparseBinds.y()*numSparseBinds.z();
591
592                                 if (linearIndex % 2u == 0u)
593                                 {
594                                         for (deUint32 offsetZ = offset.depth;  offsetZ < offset.depth  + extent.depth;  ++offsetZ)
595                                         for (deUint32 offsetY = offset.height; offsetY < offset.height + extent.height; ++offsetY)
596                                         for (deUint32 offsetX = offset.width;  offsetX < offset.width  + extent.width;  ++offsetX)
597                                         {
598                                                 const tcu::UVec4 referenceValue = tcu::UVec4(offsetX % 127u, offsetY % 127u, offsetZ % 127u, 1u);
599                                                 const tcu::UVec4 outputValue    = pixelBuffer.getPixelUint(offsetX, offsetY, offsetZ);
600
601                                                 if (deMemCmp(&outputValue, &referenceValue, sizeof(deUint32) * getNumUsedChannels(m_format.order)) != 0)
602                                                         return tcu::TestStatus::fail("Failed");
603                                         }
604                                 }
605                                 else if (physicalDeviceProperties.sparseProperties.residencyNonResidentStrict)
606                                 {
607                                         for (deUint32 offsetZ = offset.depth;  offsetZ < offset.depth  + extent.depth;  ++offsetZ)
608                                         for (deUint32 offsetY = offset.height; offsetY < offset.height + extent.height; ++offsetY)
609                                         for (deUint32 offsetX = offset.width;  offsetX < offset.width  + extent.width;  ++offsetX)
610                                         {
611                                                 const tcu::UVec4 referenceValue = tcu::UVec4(0u, 0u, 0u, 0u);
612                                                 const tcu::UVec4 outputValue = pixelBuffer.getPixelUint(offsetX, offsetY, offsetZ);
613
614                                                 if (deMemCmp(&outputValue, &referenceValue, sizeof(deUint32) * getNumUsedChannels(m_format.order)) != 0)
615                                                         return tcu::TestStatus::fail("Failed");
616                                         }
617                                 }
618                         }
619                 }
620         }
621         else
622         {
623                 const VkExtent3D mipExtent = mipLevelExtents(imageCreateInfo.extent, 0u);
624
625                 for (deUint32 offsetZ = 0u; offsetZ < mipExtent.depth * imageCreateInfo.arrayLayers; ++offsetZ)
626                 for (deUint32 offsetY = 0u; offsetY < mipExtent.height; ++offsetY)
627                 for (deUint32 offsetX = 0u; offsetX < mipExtent.width;  ++offsetX)
628                 {
629                         const tcu::UVec4 referenceValue = tcu::UVec4(offsetX % 127u, offsetY % 127u, offsetZ % 127u, 1u);
630                         const tcu::UVec4 outputValue    = pixelBuffer.getPixelUint(offsetX, offsetY, offsetZ);
631
632                         if (deMemCmp(&outputValue, &referenceValue, sizeof(deUint32) * getNumUsedChannels(m_format.order)) != 0)
633                                 return tcu::TestStatus::fail("Failed");
634                 }
635         }
636
637         return tcu::TestStatus::pass("Passed");
638 }
639
640 TestInstance* ImageSparseResidencyCase::createInstance (Context& context) const
641 {
642         return new ImageSparseResidencyInstance(context, m_imageType, m_imageSize, m_format);
643 }
644
645 } // anonymous ns
646
647 tcu::TestCaseGroup* createImageSparseResidencyTests (tcu::TestContext& testCtx)
648 {
649         de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_sparse_residency", "Buffer Sparse Residency"));
650
651         static const deUint32 sizeCountPerImageType = 3u;
652
653         struct ImageParameters
654         {
655                 ImageType       imageType;
656                 tcu::UVec3      imageSizes[sizeCountPerImageType];
657         };
658
659         static const ImageParameters imageParametersArray[] =
660         {
661                 { IMAGE_TYPE_2D,                 { tcu::UVec3(512u, 256u, 1u),  tcu::UVec3(1024u, 128u, 1u), tcu::UVec3(11u,  137u, 1u) } },
662                 { IMAGE_TYPE_2D_ARRAY,   { tcu::UVec3(512u, 256u, 6u),  tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u,  137u, 3u) } },
663                 { IMAGE_TYPE_CUBE,               { tcu::UVec3(256u, 256u, 1u),  tcu::UVec3(128u,  128u, 1u), tcu::UVec3(137u, 137u, 1u) } },
664                 { IMAGE_TYPE_CUBE_ARRAY, { tcu::UVec3(256u, 256u, 6u),  tcu::UVec3(128u,  128u, 8u), tcu::UVec3(137u, 137u, 3u) } },
665                 { IMAGE_TYPE_3D,                 { tcu::UVec3(512u, 256u, 16u), tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u,  137u, 3u) } }
666         };
667
668         static const tcu::TextureFormat formats[] =
669         {
670                 tcu::TextureFormat(tcu::TextureFormat::R,        tcu::TextureFormat::SIGNED_INT32),
671                 tcu::TextureFormat(tcu::TextureFormat::R,        tcu::TextureFormat::SIGNED_INT16),
672                 tcu::TextureFormat(tcu::TextureFormat::R,        tcu::TextureFormat::SIGNED_INT8),
673                 tcu::TextureFormat(tcu::TextureFormat::RG,       tcu::TextureFormat::SIGNED_INT32),
674                 tcu::TextureFormat(tcu::TextureFormat::RG,   tcu::TextureFormat::SIGNED_INT16),
675                 tcu::TextureFormat(tcu::TextureFormat::RG,   tcu::TextureFormat::SIGNED_INT8),
676                 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32),
677                 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT16),
678                 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8)
679         };
680
681         for (deInt32 imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageParametersArray); ++imageTypeNdx)
682         {
683                 const ImageType                                 imageType = imageParametersArray[imageTypeNdx].imageType;
684                 de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str(), ""));
685
686                 for (deInt32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
687                 {
688                         const tcu::TextureFormat&               format = formats[formatNdx];
689                         de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, getShaderImageFormatQualifier(format).c_str(), ""));
690
691                         for (deInt32 imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(imageParametersArray[imageTypeNdx].imageSizes); ++imageSizeNdx)
692                         {
693                                 const tcu::UVec3 imageSize = imageParametersArray[imageTypeNdx].imageSizes[imageSizeNdx];
694
695                                 std::ostringstream stream;
696                                 stream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
697
698                                 formatGroup->addChild(new ImageSparseResidencyCase(testCtx, stream.str(), "", imageType, imageSize, format, glu::GLSL_VERSION_440));
699                         }
700                         imageTypeGroup->addChild(formatGroup.release());
701                 }
702                 testGroup->addChild(imageTypeGroup.release());
703         }
704
705         return testGroup.release();
706 }
707
708 } // sparse
709 } // vkt