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