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,
60 const std::string& name,
61 const std::string& description,
62 const ImageType imageType,
63 const tcu::UVec3& imageSize,
64 const VkFormat format,
65 deUint32 numSamples);
66
initPrograms(SourceCollections & sourceCollections) const67 void initPrograms (SourceCollections& sourceCollections) const {DE_UNREF(sourceCollections);}
68 TestInstance* createInstance (Context& context) const;
69 virtual void checkSupport (Context& context) const;
70
71 private:
72 const ImageType m_imageType;
73 const tcu::UVec3 m_imageSize;
74 const VkFormat m_format;
75 const deUint32 m_numSamples;
76 };
77
ImageBlockShapesCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const ImageType imageType,const tcu::UVec3 & imageSize,const VkFormat format,deUint32 numSamples)78 ImageBlockShapesCase::ImageBlockShapesCase (tcu::TestContext& testCtx,
79 const std::string& name,
80 const std::string& description,
81 const ImageType imageType,
82 const tcu::UVec3& imageSize,
83 const VkFormat format,
84 deUint32 numSamples)
85 : TestCase (testCtx, name, description)
86 , m_imageType (imageType)
87 , m_imageSize (imageSize)
88 , m_format (format)
89 , m_numSamples (numSamples)
90 {
91 }
92
checkSupport(Context & context) const93 void ImageBlockShapesCase::checkSupport (Context& context) const
94 {
95 const InstanceInterface& instance = context.getInstanceInterface();
96 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
97
98 // Check the image size does not exceed device limits
99 if (!isImageSizeSupported(instance, physicalDevice, m_imageType, m_imageSize))
100 TCU_THROW(NotSupportedError, "Image size not supported for device");
101
102 // Check if device supports sparse operations for image type
103 if (!checkSparseSupportForImageType(instance, physicalDevice, m_imageType))
104 TCU_THROW(NotSupportedError, "Sparse residency for image type is not supported");
105
106 if (formatIsR64(m_format))
107 {
108 context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
109
110 if (context.getShaderImageAtomicInt64FeaturesEXT().sparseImageInt64Atomics == VK_FALSE)
111 {
112 TCU_THROW(NotSupportedError, "sparseImageInt64Atomics is not supported for device");
113 }
114 }
115 }
116
117 class ImageBlockShapesInstance : public SparseResourcesBaseInstance
118 {
119 public:
120 ImageBlockShapesInstance (Context& context,
121 const ImageType imageType,
122 const tcu::UVec3& imageSize,
123 const VkFormat format,
124 deUint32 numSamples);
125
126 tcu::TestStatus iterate (void);
127
128 private:
129 const ImageType m_imageType;
130 const tcu::UVec3 m_imageSize;
131 const VkFormat m_format;
132 const deUint32 m_numSamples;
133 };
134
ImageBlockShapesInstance(Context & context,const ImageType imageType,const tcu::UVec3 & imageSize,const VkFormat format,deUint32 numSamples)135 ImageBlockShapesInstance::ImageBlockShapesInstance (Context& context,
136 const ImageType imageType,
137 const tcu::UVec3& imageSize,
138 const VkFormat format,
139 deUint32 numSamples)
140 : SparseResourcesBaseInstance (context)
141 , m_imageType (imageType)
142 , m_imageSize (imageSize)
143 , m_format (format)
144 , m_numSamples (numSamples)
145 {
146 }
147
iterate(void)148 tcu::TestStatus ImageBlockShapesInstance::iterate (void)
149 {
150 const InstanceInterface& instance = m_context.getInstanceInterface();
151 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
152 const VkPhysicalDeviceProperties physicalDeviceProperties = getPhysicalDeviceProperties(instance, physicalDevice);
153 VkImageCreateInfo imageCreateInfo;
154 std::vector<VkSparseImageMemoryRequirements> sparseMemoryRequirements;
155 const VkPhysicalDeviceSparseProperties sparseProperties = physicalDeviceProperties.sparseProperties;
156 const PlanarFormatDescription formatDescription = getPlanarFormatDescription(m_format);
157
158 imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
159 imageCreateInfo.pNext = DE_NULL;
160 imageCreateInfo.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
161 imageCreateInfo.imageType = mapImageType(m_imageType);
162 imageCreateInfo.format = m_format;
163 imageCreateInfo.extent = makeExtent3D(getLayerSize(m_imageType, m_imageSize));
164 imageCreateInfo.mipLevels = 1u;
165 imageCreateInfo.arrayLayers = getNumLayers(m_imageType, m_imageSize);
166 imageCreateInfo.samples = static_cast<VkSampleCountFlagBits>(m_numSamples);
167 imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
168 imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
169 imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
170 VK_IMAGE_USAGE_STORAGE_BIT;
171 imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
172 imageCreateInfo.queueFamilyIndexCount = 0u;
173 imageCreateInfo.pQueueFamilyIndices = DE_NULL;
174
175 if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
176 {
177 imageCreateInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
178 }
179
180 // Check the format supports given number of samples
181 VkImageFormatProperties imageFormatProperties;
182
183 if (instance.getPhysicalDeviceImageFormatProperties(physicalDevice,
184 imageCreateInfo.format,
185 imageCreateInfo.imageType,
186 imageCreateInfo.tiling,
187 imageCreateInfo.usage,
188 imageCreateInfo.flags,
189 &imageFormatProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
190 {
191 TCU_THROW(NotSupportedError, "Image format does not support sparse operations");
192 }
193
194 if (!(imageFormatProperties.sampleCounts & imageCreateInfo.samples))
195 TCU_THROW(NotSupportedError, "The image format does not support the number of samples specified");
196
197 // Check if device supports sparse operations for image format
198 if (!checkSparseSupportForImageFormat(instance, physicalDevice, imageCreateInfo))
199 TCU_THROW(NotSupportedError, "The image format does not support sparse operations");
200
201 {
202 QueueRequirementsVec queueRequirements;
203 queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
204
205 createDeviceSupportingQueues(queueRequirements);
206 }
207
208 {
209 const DeviceInterface& deviceInterface = getDeviceInterface();
210
211 // Create sparse image
212 const Unique<VkImage> imageSparse( createImage(deviceInterface, getDevice(), &imageCreateInfo) );
213
214 // Get sparse image sparse memory requirements
215 sparseMemoryRequirements = getImageSparseMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
216
217 DE_ASSERT(sparseMemoryRequirements.size() != 0);
218 }
219
220 for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
221 {
222 const VkImageAspectFlags aspect = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
223 const deUint32 aspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, aspect);
224
225 if (aspectIndex == NO_MATCH_FOUND)
226 TCU_THROW(NotSupportedError, "Not supported image aspect");
227
228 VkSparseImageMemoryRequirements aspectRequirements = sparseMemoryRequirements[aspectIndex];
229 VkExtent3D imageGranularity = aspectRequirements.formatProperties.imageGranularity;
230 deUint32 pixelSize = static_cast<deUint32>(formatDescription.planes[planeNdx].elementSizeBytes) * 8u;
231 VkExtent3D expectedGranularity;
232
233 if (m_imageType == IMAGE_TYPE_3D)
234 {
235 if (!sparseProperties.residencyStandard3DBlockShape)
236 return tcu::TestStatus::pass("Pass (residencyStandard3DBlockShape disabled)");
237
238 switch (pixelSize)
239 {
240 case 8:
241 expectedGranularity.width = 64;
242 expectedGranularity.height = 32;
243 expectedGranularity.depth = 32;
244 break;
245 case 16:
246 expectedGranularity.width = 32;
247 expectedGranularity.height = 32;
248 expectedGranularity.depth = 32;
249 break;
250 case 32:
251 expectedGranularity.width = 32;
252 expectedGranularity.height = 32;
253 expectedGranularity.depth = 16;
254 break;
255 case 64:
256 expectedGranularity.width = 32;
257 expectedGranularity.height = 16;
258 expectedGranularity.depth = 16;
259 break;
260 default:
261 DE_ASSERT(pixelSize == 128);
262 expectedGranularity.width = 16;
263 expectedGranularity.height = 16;
264 expectedGranularity.depth = 16;
265 break;
266 }
267 }
268 else if (m_numSamples == 2)
269 {
270 if (!sparseProperties.residencyStandard2DMultisampleBlockShape)
271 return tcu::TestStatus::pass("Pass (residencyStandard2DMultisampleBlockShape disabled)");
272
273 expectedGranularity.depth = 1;
274
275 switch (pixelSize)
276 {
277 case 8:
278 expectedGranularity.width = 128;
279 expectedGranularity.height = 256;
280 break;
281 case 16:
282 expectedGranularity.width = 128;
283 expectedGranularity.height = 128;
284 break;
285 case 32:
286 expectedGranularity.width = 64;
287 expectedGranularity.height = 128;
288 break;
289 case 64:
290 expectedGranularity.width = 64;
291 expectedGranularity.height = 64;
292 break;
293 default:
294 DE_ASSERT(pixelSize == 128);
295 expectedGranularity.width = 32;
296 expectedGranularity.height = 64;
297 break;
298 }
299 }
300 else if (m_numSamples == 4)
301 {
302 if (!sparseProperties.residencyStandard2DMultisampleBlockShape)
303 return tcu::TestStatus::pass("Pass (residencyStandard2DMultisampleBlockShape disabled)");
304
305 expectedGranularity.depth = 1;
306
307 switch (pixelSize)
308 {
309 case 8:
310 expectedGranularity.width = 128;
311 expectedGranularity.height = 128;
312 break;
313 case 16:
314 expectedGranularity.width = 128;
315 expectedGranularity.height = 64;
316 break;
317 case 32:
318 expectedGranularity.width = 64;
319 expectedGranularity.height = 64;
320 break;
321 case 64:
322 expectedGranularity.width = 64;
323 expectedGranularity.height = 32;
324 break;
325 default:
326 DE_ASSERT(pixelSize == 128);
327 expectedGranularity.width = 32;
328 expectedGranularity.height = 32;
329 break;
330 }
331 }
332 else if (m_numSamples == 8)
333 {
334 if (!sparseProperties.residencyStandard2DMultisampleBlockShape)
335 return tcu::TestStatus::pass("Pass (residencyStandard2DMultisampleBlockShape disabled)");
336
337 expectedGranularity.depth = 1;
338
339 switch (pixelSize)
340 {
341 case 8:
342 expectedGranularity.width = 64;
343 expectedGranularity.height = 128;
344 break;
345 case 16:
346 expectedGranularity.width = 64;
347 expectedGranularity.height = 64;
348 break;
349 case 32:
350 expectedGranularity.width = 32;
351 expectedGranularity.height = 64;
352 break;
353 case 64:
354 expectedGranularity.width = 32;
355 expectedGranularity.height = 32;
356 break;
357 default:
358 DE_ASSERT(pixelSize == 128);
359 expectedGranularity.width = 16;
360 expectedGranularity.height = 32;
361 break;
362 }
363 }
364 else if (m_numSamples == 16)
365 {
366 if (!sparseProperties.residencyStandard2DMultisampleBlockShape)
367 return tcu::TestStatus::pass("Pass (residencyStandard2DMultisampleBlockShape disabled)");
368
369 expectedGranularity.depth = 1;
370
371 switch (pixelSize)
372 {
373 case 8:
374 expectedGranularity.width = 64;
375 expectedGranularity.height = 64;
376 break;
377 case 16:
378 expectedGranularity.width = 64;
379 expectedGranularity.height = 32;
380 break;
381 case 32:
382 expectedGranularity.width = 32;
383 expectedGranularity.height = 32;
384 break;
385 case 64:
386 expectedGranularity.width = 32;
387 expectedGranularity.height = 16;
388 break;
389 default:
390 DE_ASSERT(pixelSize == 128);
391 expectedGranularity.width = 16;
392 expectedGranularity.height = 16;
393 break;
394 }
395 }
396 else
397 {
398 DE_ASSERT(m_numSamples == 1);
399
400 if (!sparseProperties.residencyStandard2DBlockShape)
401 return tcu::TestStatus::pass("Pass (residencyStandard2DBlockShape disabled)");
402
403 expectedGranularity.depth = 1;
404
405 switch (pixelSize)
406 {
407 case 8:
408 expectedGranularity.width = 256;
409 expectedGranularity.height = 256;
410 break;
411 case 16:
412 expectedGranularity.width = 256;
413 expectedGranularity.height = 128;
414 break;
415 case 32:
416 expectedGranularity.width = 128;
417 expectedGranularity.height = 128;
418 break;
419 case 64:
420 expectedGranularity.width = 128;
421 expectedGranularity.height = 64;
422 break;
423 default:
424 DE_ASSERT(pixelSize == 128);
425 expectedGranularity.width = 64;
426 expectedGranularity.height = 64;
427 break;
428 }
429 }
430
431 if ( imageGranularity.width != expectedGranularity.width
432 || imageGranularity.height != expectedGranularity.height
433 || imageGranularity.depth != expectedGranularity.depth)
434 {
435 return tcu::TestStatus::fail("Non-standard block shape used");
436 }
437 }
438 return tcu::TestStatus::pass("Passed");
439 }
440
createInstance(Context & context) const441 TestInstance* ImageBlockShapesCase::createInstance (Context& context) const
442 {
443 return new ImageBlockShapesInstance(context, m_imageType, m_imageSize, m_format, m_numSamples);
444 }
445
446 } // anonymous ns
447
createImageBlockShapesTests(tcu::TestContext & testCtx)448 tcu::TestCaseGroup* createImageBlockShapesTests (tcu::TestContext& testCtx)
449 {
450 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_block_shapes", "Standard block shape"));
451
452 const std::vector<TestImageParameters> imageParameters =
453 {
454 { IMAGE_TYPE_2D, { tcu::UVec3(512u, 256u, 1u) }, getTestFormats(IMAGE_TYPE_2D) },
455 { IMAGE_TYPE_2D_ARRAY, { tcu::UVec3(512u, 256u, 6u) }, getTestFormats(IMAGE_TYPE_2D_ARRAY) },
456 { IMAGE_TYPE_CUBE, { tcu::UVec3(256u, 256u, 1u) }, getTestFormats(IMAGE_TYPE_CUBE) },
457 { IMAGE_TYPE_CUBE_ARRAY, { tcu::UVec3(256u, 256u, 6u) }, getTestFormats(IMAGE_TYPE_CUBE_ARRAY) },
458 { IMAGE_TYPE_3D, { tcu::UVec3(512u, 256u, 16u) }, getTestFormats(IMAGE_TYPE_3D) }
459 };
460
461 static const deUint32 sampleCounts[] = { 1u, 2u, 4u, 8u, 16u };
462
463 for (size_t imageTypeNdx = 0; imageTypeNdx < imageParameters.size(); ++imageTypeNdx)
464 {
465 const ImageType imageType = imageParameters[imageTypeNdx].imageType;
466 de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str(), ""));
467
468 for (size_t formatNdx = 0; formatNdx < imageParameters[imageTypeNdx].formats.size(); ++formatNdx)
469 {
470 VkFormat format = imageParameters[imageTypeNdx].formats[formatNdx].format;
471 tcu::UVec3 imageSizeAlignment = getImageSizeAlignment(format);
472 de::MovePtr<tcu::TestCaseGroup> formatGroup (new tcu::TestCaseGroup(testCtx, getImageFormatID(format).c_str(), ""));
473
474 for (deInt32 sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleCountNdx)
475 {
476 for (size_t imageSizeNdx = 0; imageSizeNdx < imageParameters[imageTypeNdx].imageSizes.size(); ++imageSizeNdx)
477 {
478 const tcu::UVec3 imageSize = imageParameters[imageTypeNdx].imageSizes[imageSizeNdx];
479
480 // skip test for images with odd sizes for some YCbCr formats
481 if ((imageSize.x() % imageSizeAlignment.x()) != 0)
482 continue;
483 if ((imageSize.y() % imageSizeAlignment.y()) != 0)
484 continue;
485
486 const deUint32 sampleCount = sampleCounts[sampleCountNdx];
487 const std::string name = std::string("samples_") + de::toString(sampleCount);
488
489 formatGroup->addChild(new ImageBlockShapesCase(testCtx, name.c_str(), "", imageType, imageSize, format, sampleCount));
490 }
491 }
492 imageTypeGroup->addChild(formatGroup.release());
493 }
494 testGroup->addChild(imageTypeGroup.release());
495 }
496
497 return testGroup.release();
498 }
499
500 } // sparse
501 } // vkt
502