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