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