1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 The Khronos Group Inc.
6  * Copyright (c) 2017 Google Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file  vktSparseResourcesImageBlockShapes.cpp
22  * \brief Standard block shape tests.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktSparseResourcesBufferSparseBinding.hpp"
26 #include "vktSparseResourcesTestsUtil.hpp"
27 #include "vktSparseResourcesBase.hpp"
28 #include "vktTestCaseUtil.hpp"
29 
30 #include "vkDefs.hpp"
31 #include "vkRef.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkPlatform.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkTypeUtil.hpp"
40 
41 #include "deUniquePtr.hpp"
42 #include "deStringUtil.hpp"
43 
44 #include <string>
45 #include <vector>
46 
47 using namespace vk;
48 
49 namespace vkt
50 {
51 namespace sparse
52 {
53 namespace
54 {
55 
56 class ImageBlockShapesCase : public TestCase
57 {
58 public:
59     ImageBlockShapesCase(tcu::TestContext &testCtx, const std::string &name, const ImageType imageType,
60                          const tcu::UVec3 &imageSize, const VkFormat format, uint32_t numSamples);
61 
initPrograms(SourceCollections & sourceCollections) const62     void initPrograms(SourceCollections &sourceCollections) const
63     {
64         DE_UNREF(sourceCollections);
65     }
66     TestInstance *createInstance(Context &context) const;
67     virtual void checkSupport(Context &context) const;
68 
69 private:
70     const ImageType m_imageType;
71     const tcu::UVec3 m_imageSize;
72     const VkFormat m_format;
73     const uint32_t m_numSamples;
74 };
75 
ImageBlockShapesCase(tcu::TestContext & testCtx,const std::string & name,const ImageType imageType,const tcu::UVec3 & imageSize,const VkFormat format,uint32_t numSamples)76 ImageBlockShapesCase::ImageBlockShapesCase(tcu::TestContext &testCtx, const std::string &name,
77                                            const ImageType imageType, const tcu::UVec3 &imageSize,
78                                            const VkFormat format, uint32_t numSamples)
79     : TestCase(testCtx, name)
80     , m_imageType(imageType)
81     , m_imageSize(imageSize)
82     , m_format(format)
83     , m_numSamples(numSamples)
84 {
85 }
86 
checkSupport(Context & context) const87 void ImageBlockShapesCase::checkSupport(Context &context) const
88 {
89     const InstanceInterface &instance     = context.getInstanceInterface();
90     const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
91 
92     // Check the image size does not exceed device limits
93     if (!isImageSizeSupported(instance, physicalDevice, m_imageType, m_imageSize))
94         TCU_THROW(NotSupportedError, "Image size not supported for device");
95 
96     // Check if device supports sparse operations for image type
97     if (!checkSparseSupportForImageType(instance, physicalDevice, m_imageType))
98         TCU_THROW(NotSupportedError, "Sparse residency for image type is not supported");
99 
100     if (formatIsR64(m_format))
101     {
102         context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
103 
104         if (context.getShaderImageAtomicInt64FeaturesEXT().sparseImageInt64Atomics == VK_FALSE)
105         {
106             TCU_THROW(NotSupportedError, "sparseImageInt64Atomics is not supported for device");
107         }
108     }
109 }
110 
111 class ImageBlockShapesInstance : public SparseResourcesBaseInstance
112 {
113 public:
114     ImageBlockShapesInstance(Context &context, const ImageType imageType, const tcu::UVec3 &imageSize,
115                              const VkFormat format, uint32_t numSamples);
116 
117     tcu::TestStatus iterate(void);
118 
119 private:
120     const ImageType m_imageType;
121     const tcu::UVec3 m_imageSize;
122     const VkFormat m_format;
123     const uint32_t m_numSamples;
124 };
125 
ImageBlockShapesInstance(Context & context,const ImageType imageType,const tcu::UVec3 & imageSize,const VkFormat format,uint32_t numSamples)126 ImageBlockShapesInstance::ImageBlockShapesInstance(Context &context, const ImageType imageType,
127                                                    const tcu::UVec3 &imageSize, const VkFormat format,
128                                                    uint32_t numSamples)
129     : SparseResourcesBaseInstance(context)
130     , m_imageType(imageType)
131     , m_imageSize(imageSize)
132     , m_format(format)
133     , m_numSamples(numSamples)
134 {
135 }
136 
iterate(void)137 tcu::TestStatus ImageBlockShapesInstance::iterate(void)
138 {
139     const InstanceInterface &instance                         = m_context.getInstanceInterface();
140     const VkPhysicalDevice physicalDevice                     = m_context.getPhysicalDevice();
141     const VkPhysicalDeviceProperties physicalDeviceProperties = getPhysicalDeviceProperties(instance, physicalDevice);
142     VkImageCreateInfo imageCreateInfo;
143     std::vector<VkSparseImageMemoryRequirements> sparseMemoryRequirements;
144     const VkPhysicalDeviceSparseProperties sparseProperties = physicalDeviceProperties.sparseProperties;
145     const PlanarFormatDescription formatDescription         = getPlanarFormatDescription(m_format);
146 
147     imageCreateInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
148     imageCreateInfo.pNext                 = DE_NULL;
149     imageCreateInfo.flags                 = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
150     imageCreateInfo.imageType             = mapImageType(m_imageType);
151     imageCreateInfo.format                = m_format;
152     imageCreateInfo.extent                = makeExtent3D(getLayerSize(m_imageType, m_imageSize));
153     imageCreateInfo.mipLevels             = 1u;
154     imageCreateInfo.arrayLayers           = getNumLayers(m_imageType, m_imageSize);
155     imageCreateInfo.samples               = static_cast<VkSampleCountFlagBits>(m_numSamples);
156     imageCreateInfo.tiling                = VK_IMAGE_TILING_OPTIMAL;
157     imageCreateInfo.initialLayout         = VK_IMAGE_LAYOUT_UNDEFINED;
158     imageCreateInfo.usage                 = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
159     imageCreateInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
160     imageCreateInfo.queueFamilyIndexCount = 0u;
161     imageCreateInfo.pQueueFamilyIndices   = DE_NULL;
162 
163     if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
164     {
165         imageCreateInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
166     }
167 
168     // Check the format supports given number of samples
169     VkImageFormatProperties imageFormatProperties;
170 
171     if (instance.getPhysicalDeviceImageFormatProperties(
172             physicalDevice, imageCreateInfo.format, imageCreateInfo.imageType, imageCreateInfo.tiling,
173             imageCreateInfo.usage, imageCreateInfo.flags, &imageFormatProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
174     {
175         TCU_THROW(NotSupportedError, "Image format does not support sparse operations");
176     }
177 
178     if (!(imageFormatProperties.sampleCounts & imageCreateInfo.samples))
179         TCU_THROW(NotSupportedError, "The image format does not support the number of samples specified");
180 
181     // Check if device supports sparse operations for image format
182     if (!checkSparseSupportForImageFormat(instance, physicalDevice, imageCreateInfo))
183         TCU_THROW(NotSupportedError, "The image format does not support sparse operations");
184 
185     {
186         QueueRequirementsVec queueRequirements;
187         queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
188 
189         createDeviceSupportingQueues(queueRequirements);
190     }
191 
192     {
193         const DeviceInterface &deviceInterface = getDeviceInterface();
194 
195         // Create sparse image
196         const Unique<VkImage> imageSparse(createImage(deviceInterface, getDevice(), &imageCreateInfo));
197 
198         // Get sparse image sparse memory requirements
199         sparseMemoryRequirements = getImageSparseMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
200 
201         DE_ASSERT(sparseMemoryRequirements.size() != 0);
202     }
203 
204     for (uint32_t planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
205     {
206         const VkImageAspectFlags aspect =
207             (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
208         const uint32_t aspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, aspect);
209 
210         if (aspectIndex == NO_MATCH_FOUND)
211             TCU_THROW(NotSupportedError, "Not supported image aspect");
212 
213         VkSparseImageMemoryRequirements aspectRequirements = sparseMemoryRequirements[aspectIndex];
214         VkExtent3D imageGranularity                        = aspectRequirements.formatProperties.imageGranularity;
215         uint32_t pixelSize = static_cast<uint32_t>(formatDescription.planes[planeNdx].elementSizeBytes) * 8u;
216         VkExtent3D expectedGranularity;
217 
218         if (m_imageType == IMAGE_TYPE_3D)
219         {
220             if (!sparseProperties.residencyStandard3DBlockShape)
221                 return tcu::TestStatus::pass("Pass (residencyStandard3DBlockShape disabled)");
222 
223             switch (pixelSize)
224             {
225             case 8:
226                 expectedGranularity.width  = 64;
227                 expectedGranularity.height = 32;
228                 expectedGranularity.depth  = 32;
229                 break;
230             case 16:
231                 expectedGranularity.width  = 32;
232                 expectedGranularity.height = 32;
233                 expectedGranularity.depth  = 32;
234                 break;
235             case 32:
236                 expectedGranularity.width  = 32;
237                 expectedGranularity.height = 32;
238                 expectedGranularity.depth  = 16;
239                 break;
240             case 64:
241                 expectedGranularity.width  = 32;
242                 expectedGranularity.height = 16;
243                 expectedGranularity.depth  = 16;
244                 break;
245             default:
246                 DE_ASSERT(pixelSize == 128);
247                 expectedGranularity.width  = 16;
248                 expectedGranularity.height = 16;
249                 expectedGranularity.depth  = 16;
250                 break;
251             }
252         }
253         else if (m_numSamples == 2)
254         {
255             if (!sparseProperties.residencyStandard2DMultisampleBlockShape)
256                 return tcu::TestStatus::pass("Pass (residencyStandard2DMultisampleBlockShape disabled)");
257 
258             expectedGranularity.depth = 1;
259 
260             switch (pixelSize)
261             {
262             case 8:
263                 expectedGranularity.width  = 128;
264                 expectedGranularity.height = 256;
265                 break;
266             case 16:
267                 expectedGranularity.width  = 128;
268                 expectedGranularity.height = 128;
269                 break;
270             case 32:
271                 expectedGranularity.width  = 64;
272                 expectedGranularity.height = 128;
273                 break;
274             case 64:
275                 expectedGranularity.width  = 64;
276                 expectedGranularity.height = 64;
277                 break;
278             default:
279                 DE_ASSERT(pixelSize == 128);
280                 expectedGranularity.width  = 32;
281                 expectedGranularity.height = 64;
282                 break;
283             }
284         }
285         else if (m_numSamples == 4)
286         {
287             if (!sparseProperties.residencyStandard2DMultisampleBlockShape)
288                 return tcu::TestStatus::pass("Pass (residencyStandard2DMultisampleBlockShape disabled)");
289 
290             expectedGranularity.depth = 1;
291 
292             switch (pixelSize)
293             {
294             case 8:
295                 expectedGranularity.width  = 128;
296                 expectedGranularity.height = 128;
297                 break;
298             case 16:
299                 expectedGranularity.width  = 128;
300                 expectedGranularity.height = 64;
301                 break;
302             case 32:
303                 expectedGranularity.width  = 64;
304                 expectedGranularity.height = 64;
305                 break;
306             case 64:
307                 expectedGranularity.width  = 64;
308                 expectedGranularity.height = 32;
309                 break;
310             default:
311                 DE_ASSERT(pixelSize == 128);
312                 expectedGranularity.width  = 32;
313                 expectedGranularity.height = 32;
314                 break;
315             }
316         }
317         else if (m_numSamples == 8)
318         {
319             if (!sparseProperties.residencyStandard2DMultisampleBlockShape)
320                 return tcu::TestStatus::pass("Pass (residencyStandard2DMultisampleBlockShape disabled)");
321 
322             expectedGranularity.depth = 1;
323 
324             switch (pixelSize)
325             {
326             case 8:
327                 expectedGranularity.width  = 64;
328                 expectedGranularity.height = 128;
329                 break;
330             case 16:
331                 expectedGranularity.width  = 64;
332                 expectedGranularity.height = 64;
333                 break;
334             case 32:
335                 expectedGranularity.width  = 32;
336                 expectedGranularity.height = 64;
337                 break;
338             case 64:
339                 expectedGranularity.width  = 32;
340                 expectedGranularity.height = 32;
341                 break;
342             default:
343                 DE_ASSERT(pixelSize == 128);
344                 expectedGranularity.width  = 16;
345                 expectedGranularity.height = 32;
346                 break;
347             }
348         }
349         else if (m_numSamples == 16)
350         {
351             if (!sparseProperties.residencyStandard2DMultisampleBlockShape)
352                 return tcu::TestStatus::pass("Pass (residencyStandard2DMultisampleBlockShape disabled)");
353 
354             expectedGranularity.depth = 1;
355 
356             switch (pixelSize)
357             {
358             case 8:
359                 expectedGranularity.width  = 64;
360                 expectedGranularity.height = 64;
361                 break;
362             case 16:
363                 expectedGranularity.width  = 64;
364                 expectedGranularity.height = 32;
365                 break;
366             case 32:
367                 expectedGranularity.width  = 32;
368                 expectedGranularity.height = 32;
369                 break;
370             case 64:
371                 expectedGranularity.width  = 32;
372                 expectedGranularity.height = 16;
373                 break;
374             default:
375                 DE_ASSERT(pixelSize == 128);
376                 expectedGranularity.width  = 16;
377                 expectedGranularity.height = 16;
378                 break;
379             }
380         }
381         else
382         {
383             DE_ASSERT(m_numSamples == 1);
384 
385             if (!sparseProperties.residencyStandard2DBlockShape)
386                 return tcu::TestStatus::pass("Pass (residencyStandard2DBlockShape disabled)");
387 
388             expectedGranularity.depth = 1;
389 
390             switch (pixelSize)
391             {
392             case 8:
393                 expectedGranularity.width  = 256;
394                 expectedGranularity.height = 256;
395                 break;
396             case 16:
397                 expectedGranularity.width  = 256;
398                 expectedGranularity.height = 128;
399                 break;
400             case 32:
401                 expectedGranularity.width  = 128;
402                 expectedGranularity.height = 128;
403                 break;
404             case 64:
405                 expectedGranularity.width  = 128;
406                 expectedGranularity.height = 64;
407                 break;
408             default:
409                 DE_ASSERT(pixelSize == 128);
410                 expectedGranularity.width  = 64;
411                 expectedGranularity.height = 64;
412                 break;
413             }
414         }
415 
416         if (imageGranularity.width != expectedGranularity.width ||
417             imageGranularity.height != expectedGranularity.height ||
418             imageGranularity.depth != expectedGranularity.depth)
419         {
420             return tcu::TestStatus::fail("Non-standard block shape used");
421         }
422     }
423     return tcu::TestStatus::pass("Passed");
424 }
425 
createInstance(Context & context) const426 TestInstance *ImageBlockShapesCase::createInstance(Context &context) const
427 {
428     return new ImageBlockShapesInstance(context, m_imageType, m_imageSize, m_format, m_numSamples);
429 }
430 
431 } // namespace
432 
createImageBlockShapesTests(tcu::TestContext & testCtx)433 tcu::TestCaseGroup *createImageBlockShapesTests(tcu::TestContext &testCtx)
434 {
435     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_block_shapes"));
436 
437     const std::vector<TestImageParameters> imageParameters{
438         {IMAGE_TYPE_2D, {tcu::UVec3(512u, 256u, 1u)}, getTestFormats(IMAGE_TYPE_2D)},
439         {IMAGE_TYPE_2D_ARRAY, {tcu::UVec3(512u, 256u, 6u)}, getTestFormats(IMAGE_TYPE_2D_ARRAY)},
440         {IMAGE_TYPE_CUBE, {tcu::UVec3(256u, 256u, 1u)}, getTestFormats(IMAGE_TYPE_CUBE)},
441         {IMAGE_TYPE_CUBE_ARRAY, {tcu::UVec3(256u, 256u, 6u)}, getTestFormats(IMAGE_TYPE_CUBE_ARRAY)},
442         {IMAGE_TYPE_3D, {tcu::UVec3(512u, 256u, 16u)}, getTestFormats(IMAGE_TYPE_3D)}};
443 
444     static const uint32_t sampleCounts[] = {1u, 2u, 4u, 8u, 16u};
445 
446     for (size_t imageTypeNdx = 0; imageTypeNdx < imageParameters.size(); ++imageTypeNdx)
447     {
448         const ImageType imageType = imageParameters[imageTypeNdx].imageType;
449         de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(
450             new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str()));
451 
452         for (size_t formatNdx = 0; formatNdx < imageParameters[imageTypeNdx].formats.size(); ++formatNdx)
453         {
454             VkFormat format               = imageParameters[imageTypeNdx].formats[formatNdx].format;
455             tcu::UVec3 imageSizeAlignment = getImageSizeAlignment(format);
456             de::MovePtr<tcu::TestCaseGroup> formatGroup(
457                 new tcu::TestCaseGroup(testCtx, getImageFormatID(format).c_str()));
458 
459             for (int32_t sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleCountNdx)
460             {
461                 for (size_t imageSizeNdx = 0; imageSizeNdx < imageParameters[imageTypeNdx].imageSizes.size();
462                      ++imageSizeNdx)
463                 {
464                     const tcu::UVec3 imageSize = imageParameters[imageTypeNdx].imageSizes[imageSizeNdx];
465 
466                     // skip test for images with odd sizes for some YCbCr formats
467                     if ((imageSize.x() % imageSizeAlignment.x()) != 0)
468                         continue;
469                     if ((imageSize.y() % imageSizeAlignment.y()) != 0)
470                         continue;
471 
472                     const uint32_t sampleCount = sampleCounts[sampleCountNdx];
473                     const std::string name     = std::string("samples_") + de::toString(sampleCount);
474 
475                     formatGroup->addChild(
476                         new ImageBlockShapesCase(testCtx, name.c_str(), imageType, imageSize, format, sampleCount));
477                 }
478             }
479             imageTypeGroup->addChild(formatGroup.release());
480         }
481         testGroup->addChild(imageTypeGroup.release());
482     }
483 
484     return testGroup.release();
485 }
486 
487 } // namespace sparse
488 } // namespace vkt
489