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  vktSparseResourcesImageAlignedMipSize.cpp
22  * \brief Aligned mip size 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 ImageAlignedMipSizeCase : public TestCase
57 {
58 public:
59     ImageAlignedMipSizeCase(tcu::TestContext &testCtx, const std::string &name, const ImageType imageType,
60                             const tcu::UVec3 &imageSize, const VkFormat format);
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 };
74 
ImageAlignedMipSizeCase(tcu::TestContext & testCtx,const std::string & name,const ImageType imageType,const tcu::UVec3 & imageSize,const VkFormat format)75 ImageAlignedMipSizeCase::ImageAlignedMipSizeCase(tcu::TestContext &testCtx, const std::string &name,
76                                                  const ImageType imageType, const tcu::UVec3 &imageSize,
77                                                  const VkFormat format)
78     : TestCase(testCtx, name)
79     , m_imageType(imageType)
80     , m_imageSize(imageSize)
81     , m_format(format)
82 {
83 }
84 
checkSupport(Context & context) const85 void ImageAlignedMipSizeCase::checkSupport(Context &context) const
86 {
87     const InstanceInterface &instance     = context.getInstanceInterface();
88     const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
89 
90     // Check the image size does not exceed device limits
91     if (!isImageSizeSupported(instance, physicalDevice, m_imageType, m_imageSize))
92         TCU_THROW(NotSupportedError, "Image size not supported for device");
93 
94     // Check if device supports sparse operations for image type
95     if (!checkSparseSupportForImageType(instance, physicalDevice, m_imageType))
96         TCU_THROW(NotSupportedError, "Sparse residency for image type is not supported");
97 
98     if (formatIsR64(m_format))
99     {
100         context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
101 
102         if (context.getShaderImageAtomicInt64FeaturesEXT().sparseImageInt64Atomics == VK_FALSE)
103         {
104             TCU_THROW(NotSupportedError, "sparseImageInt64Atomics is not supported for device");
105         }
106     }
107 }
108 
109 class ImageAlignedMipSizeInstance : public SparseResourcesBaseInstance
110 {
111 public:
112     ImageAlignedMipSizeInstance(Context &context, const ImageType imageType, const tcu::UVec3 &imageSize,
113                                 const VkFormat format);
114 
115     tcu::TestStatus iterate(void);
116 
117 private:
118     const ImageType m_imageType;
119     const tcu::UVec3 m_imageSize;
120     const VkFormat m_format;
121 };
122 
ImageAlignedMipSizeInstance(Context & context,const ImageType imageType,const tcu::UVec3 & imageSize,const VkFormat format)123 ImageAlignedMipSizeInstance::ImageAlignedMipSizeInstance(Context &context, const ImageType imageType,
124                                                          const tcu::UVec3 &imageSize, const VkFormat format)
125     : SparseResourcesBaseInstance(context)
126     , m_imageType(imageType)
127     , m_imageSize(imageSize)
128     , m_format(format)
129 {
130 }
131 
iterate(void)132 tcu::TestStatus ImageAlignedMipSizeInstance::iterate(void)
133 {
134     const InstanceInterface &instance                         = m_context.getInstanceInterface();
135     const VkPhysicalDevice physicalDevice                     = m_context.getPhysicalDevice();
136     const VkPhysicalDeviceProperties physicalDeviceProperties = getPhysicalDeviceProperties(instance, physicalDevice);
137     VkImageCreateInfo imageCreateInfo;
138     VkSparseImageMemoryRequirements aspectRequirements;
139     VkExtent3D imageGranularity;
140     const VkPhysicalDeviceSparseProperties sparseProperties = physicalDeviceProperties.sparseProperties;
141     const PlanarFormatDescription formatDescription         = getPlanarFormatDescription(m_format);
142 
143     imageCreateInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
144     imageCreateInfo.pNext                 = DE_NULL;
145     imageCreateInfo.flags                 = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
146     imageCreateInfo.imageType             = mapImageType(m_imageType);
147     imageCreateInfo.format                = m_format;
148     imageCreateInfo.extent                = makeExtent3D(getLayerSize(m_imageType, m_imageSize));
149     imageCreateInfo.arrayLayers           = getNumLayers(m_imageType, m_imageSize);
150     imageCreateInfo.samples               = VK_SAMPLE_COUNT_1_BIT;
151     imageCreateInfo.tiling                = VK_IMAGE_TILING_OPTIMAL;
152     imageCreateInfo.initialLayout         = VK_IMAGE_LAYOUT_UNDEFINED;
153     imageCreateInfo.usage                 = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
154     imageCreateInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
155     imageCreateInfo.queueFamilyIndexCount = 0u;
156     imageCreateInfo.pQueueFamilyIndices   = DE_NULL;
157 
158     if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
159     {
160         imageCreateInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
161     }
162 
163     // Check if device supports sparse operations for image format
164     if (!checkSparseSupportForImageFormat(instance, physicalDevice, imageCreateInfo))
165         TCU_THROW(NotSupportedError, "The image format does not support sparse operations");
166 
167     {
168         VkImageFormatProperties imageFormatProperties;
169 
170         if (instance.getPhysicalDeviceImageFormatProperties(
171                 physicalDevice, imageCreateInfo.format, imageCreateInfo.imageType, imageCreateInfo.tiling,
172                 imageCreateInfo.usage, imageCreateInfo.flags, &imageFormatProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
173         {
174             TCU_THROW(NotSupportedError, "Image format does not support sparse operations");
175         }
176 
177         imageCreateInfo.mipLevels =
178             getMipmapCount(m_format, formatDescription, imageFormatProperties, imageCreateInfo.extent);
179     }
180 
181     {
182         QueueRequirementsVec queueRequirements;
183         queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
184 
185         createDeviceSupportingQueues(queueRequirements);
186     }
187 
188     {
189         const DeviceInterface &deviceInterface = getDeviceInterface();
190 
191         // Create sparse image
192         const Unique<VkImage> imageSparse(createImage(deviceInterface, getDevice(), &imageCreateInfo));
193 
194         // Get sparse image sparse memory requirements
195         const std::vector<VkSparseImageMemoryRequirements> sparseMemoryRequirements =
196             getImageSparseMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
197 
198         DE_ASSERT(sparseMemoryRequirements.size() != 0);
199 
200         const uint32_t colorAspectIndex =
201             getSparseAspectRequirementsIndex(sparseMemoryRequirements, VK_IMAGE_ASPECT_COLOR_BIT);
202 
203         if (colorAspectIndex == NO_MATCH_FOUND)
204             TCU_THROW(NotSupportedError,
205                       "Not supported image aspect - the test supports currently only VK_IMAGE_ASPECT_COLOR_BIT");
206 
207         aspectRequirements = sparseMemoryRequirements[colorAspectIndex];
208         imageGranularity   = aspectRequirements.formatProperties.imageGranularity;
209     }
210 
211     if (sparseProperties.residencyAlignedMipSize)
212     {
213         uint32_t lod = 0;
214         VkExtent3D extent;
215 
216         do
217         {
218             extent = mipLevelExtents(imageCreateInfo.extent, lod);
219             if (extent.width % imageGranularity.width != 0 || extent.height % imageGranularity.height != 0 ||
220                 extent.depth % imageGranularity.depth != 0)
221             {
222                 break;
223             }
224 
225             lod++;
226         } while (extent.width != 1 || extent.height != 1 || extent.depth != 1);
227 
228         if (lod != aspectRequirements.imageMipTailFirstLod)
229             return tcu::TestStatus::fail("Unexpected first LOD for mip tail.");
230         else
231             return tcu::TestStatus::pass("pass");
232     }
233     else if (aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT)
234     {
235         return tcu::TestStatus::fail("Aligned mip size flag doesn't match in device and image properties.");
236     }
237     else
238     {
239         return tcu::TestStatus::pass("Aligned mip size not enabled.");
240     }
241 }
242 
createInstance(Context & context) const243 TestInstance *ImageAlignedMipSizeCase::createInstance(Context &context) const
244 {
245     return new ImageAlignedMipSizeInstance(context, m_imageType, m_imageSize, m_format);
246 }
247 
248 } // namespace
249 
createImageAlignedMipSizeTests(tcu::TestContext & testCtx)250 tcu::TestCaseGroup *createImageAlignedMipSizeTests(tcu::TestContext &testCtx)
251 {
252     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "aligned_mip_size"));
253 
254     const std::vector<TestImageParameters> imageParameters{
255         {IMAGE_TYPE_2D, {tcu::UVec3(512u, 256u, 1u)}, getTestFormats(IMAGE_TYPE_2D)},
256         {IMAGE_TYPE_2D_ARRAY, {tcu::UVec3(512u, 256u, 6u)}, getTestFormats(IMAGE_TYPE_2D_ARRAY)},
257         {IMAGE_TYPE_CUBE, {tcu::UVec3(256u, 256u, 1u)}, getTestFormats(IMAGE_TYPE_CUBE)},
258         {IMAGE_TYPE_CUBE_ARRAY, {tcu::UVec3(256u, 256u, 6u)}, getTestFormats(IMAGE_TYPE_CUBE_ARRAY)},
259         {IMAGE_TYPE_3D, {tcu::UVec3(512u, 256u, 16u)}, getTestFormats(IMAGE_TYPE_3D)}};
260 
261     for (size_t imageTypeNdx = 0; imageTypeNdx < imageParameters.size(); ++imageTypeNdx)
262     {
263         const ImageType imageType = imageParameters[imageTypeNdx].imageType;
264         de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(
265             new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str()));
266 
267         for (size_t formatNdx = 0; formatNdx < imageParameters[imageTypeNdx].formats.size(); ++formatNdx)
268         {
269             VkFormat format               = imageParameters[imageTypeNdx].formats[formatNdx].format;
270             tcu::UVec3 imageSizeAlignment = getImageSizeAlignment(format);
271             const std::string name        = getImageFormatID(format);
272             const tcu::UVec3 imageSize    = imageParameters[imageTypeNdx].imageSizes[0];
273 
274             // skip test for images with odd sizes for some YCbCr formats
275             if ((imageSize.x() % imageSizeAlignment.x()) != 0)
276                 continue;
277             if ((imageSize.y() % imageSizeAlignment.y()) != 0)
278                 continue;
279 
280             imageTypeGroup->addChild(new ImageAlignedMipSizeCase(testCtx, name.c_str(), imageType, imageSize, format));
281         }
282         testGroup->addChild(imageTypeGroup.release());
283     }
284 
285     return testGroup.release();
286 }
287 
288 } // namespace sparse
289 } // namespace vkt
290