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