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