1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief VkSwapchain Tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktWsiSwapchainTests.hpp"
25
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vktCustomInstancesDevices.hpp"
29 #include "vktNativeObjectsUtil.hpp"
30
31 #include "vkDefs.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkStrUtil.hpp"
34 #include "vkRef.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkMemUtil.hpp"
38 #include "vkDeviceUtil.hpp"
39 #include "vkPrograms.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkWsiPlatform.hpp"
42 #include "vkWsiUtil.hpp"
43 #include "vkAllocationCallbackUtil.hpp"
44 #include "vkCmdUtil.hpp"
45 #include "vkObjTypeImpl.inl"
46 #include "vkObjUtil.hpp"
47
48 #include "tcuCommandLine.hpp"
49 #include "tcuTestLog.hpp"
50 #include "tcuFormatUtil.hpp"
51 #include "tcuPlatform.hpp"
52 #include "tcuResultCollector.hpp"
53
54 #include "deUniquePtr.hpp"
55 #include "deStringUtil.hpp"
56 #include "deArrayUtil.hpp"
57 #include "deSharedPtr.hpp"
58
59 #include <limits>
60 #include <algorithm>
61 #include <iterator>
62
63 #if (DE_OS == DE_OS_ANDROID)
64 #include <thread>
65 #include <chrono>
66 #endif
67
68 namespace vkt
69 {
70 namespace wsi
71 {
72
73 namespace
74 {
75
76 using namespace vk;
77 using namespace vk::wsi;
78
79 using tcu::Maybe;
80 using tcu::TestLog;
81 using tcu::UVec2;
82
83 using de::MovePtr;
84 using de::SharedPtr;
85 using de::UniquePtr;
86
87 using std::string;
88 using std::vector;
89
90 typedef vector<VkExtensionProperties> Extensions;
91
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)92 void checkAllSupported(const Extensions &supportedExtensions, const vector<string> &requiredExtensions)
93 {
94 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
95 requiredExtName != requiredExtensions.end(); ++requiredExtName)
96 {
97 if (!isExtensionStructSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
98 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
99 }
100 }
101
createInstanceWithWsi(Context & context,const Extensions & supportedExtensions,Type wsiType,const vector<string> extraExtensions,const VkAllocationCallbacks * pAllocator=DE_NULL)102 CustomInstance createInstanceWithWsi(Context &context, const Extensions &supportedExtensions, Type wsiType,
103 const vector<string> extraExtensions,
104 const VkAllocationCallbacks *pAllocator = DE_NULL)
105 {
106 vector<string> extensions = extraExtensions;
107
108 extensions.push_back("VK_KHR_surface");
109 extensions.push_back(getExtensionName(wsiType));
110 if (isDisplaySurface(wsiType))
111 extensions.push_back("VK_KHR_display");
112
113 // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
114 // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
115 // but using them without enabling the extension is not allowed. Thus we have
116 // two options:
117 //
118 // 1) Filter out non-core formats to stay within valid usage.
119 //
120 // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
121 //
122 // We opt for (2) as it provides basic coverage for the extension as a bonus.
123 if (isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
124 extensions.push_back("VK_EXT_swapchain_colorspace");
125
126 checkAllSupported(supportedExtensions, extensions);
127
128 return vkt::createCustomInstanceWithExtensions(context, extensions, pAllocator);
129 }
130
getDeviceFeaturesForWsi(void)131 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi(void)
132 {
133 VkPhysicalDeviceFeatures features;
134 deMemset(&features, 0, sizeof(features));
135 return features;
136 }
137
createDeviceWithWsi(const PlatformInterface & vkp,uint32_t apiVersion,VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const vector<string> & additionalExtensions,const vector<uint32_t> & queueFamilyIndices,bool validationEnabled,const VkAllocationCallbacks * pAllocator=DE_NULL)138 Move<VkDevice> createDeviceWithWsi(const PlatformInterface &vkp, uint32_t apiVersion, VkInstance instance,
139 const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
140 const Extensions &supportedExtensions, const vector<string> &additionalExtensions,
141 const vector<uint32_t> &queueFamilyIndices, bool validationEnabled,
142 const VkAllocationCallbacks *pAllocator = DE_NULL)
143 {
144 const float queuePriorities[] = {1.0f};
145 vector<VkDeviceQueueCreateInfo> queueInfos;
146
147 for (const auto familyIndex : queueFamilyIndices)
148 {
149 const VkDeviceQueueCreateInfo info = {
150 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
151 nullptr,
152 (VkDeviceQueueCreateFlags)0,
153 familyIndex,
154 DE_LENGTH_OF_ARRAY(queuePriorities),
155 &queuePriorities[0],
156 };
157
158 queueInfos.push_back(info);
159 }
160
161 vector<string> extensions;
162 extensions.push_back("VK_KHR_swapchain");
163 extensions.insert(end(extensions), begin(additionalExtensions), end(additionalExtensions));
164
165 for (const auto &extName : extensions)
166 {
167 if (!isCoreDeviceExtension(apiVersion, extName) &&
168 !isExtensionStructSupported(supportedExtensions, RequiredExtension(extName)))
169 TCU_THROW(NotSupportedError, extName + " is not supported");
170 }
171
172 const void *pNext = nullptr;
173 const VkPhysicalDeviceFeatures features = getDeviceFeaturesForWsi();
174
175 VkDevicePrivateDataCreateInfoEXT pdci = initVulkanStructure();
176 pdci.privateDataSlotRequestCount = 4u;
177
178 VkPhysicalDevicePrivateDataFeaturesEXT privateDataFeatures = initVulkanStructure(&pdci);
179 privateDataFeatures.privateData = VK_TRUE;
180
181 if (de::contains(begin(extensions), end(extensions), "VK_EXT_private_data"))
182 {
183 pNext = &privateDataFeatures;
184 }
185
186 // Convert from std::vector<std::string> to std::vector<const char*>.
187 std::vector<const char *> extensionsChar;
188 extensionsChar.reserve(extensions.size());
189 std::transform(begin(extensions), end(extensions), std::back_inserter(extensionsChar),
190 [](const std::string &s) { return s.c_str(); });
191
192 const VkDeviceCreateInfo deviceParams = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
193 pNext,
194 (VkDeviceCreateFlags)0,
195 static_cast<uint32_t>(queueInfos.size()),
196 queueInfos.data(),
197 0u, // enabledLayerCount
198 nullptr, // ppEnabledLayerNames
199 static_cast<uint32_t>(extensionsChar.size()), // enabledExtensionCount
200 extensionsChar.data(), // ppEnabledExtensionNames
201 &features};
202
203 return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
204 }
205
createDeviceWithWsi(const PlatformInterface & vkp,uint32_t apiVersion,VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const vector<string> & additionalExtensions,const uint32_t queueFamilyIndex,bool validationEnabled,const VkAllocationCallbacks * pAllocator=DE_NULL)206 Move<VkDevice> createDeviceWithWsi(const PlatformInterface &vkp, uint32_t apiVersion, VkInstance instance,
207 const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
208 const Extensions &supportedExtensions, const vector<string> &additionalExtensions,
209 const uint32_t queueFamilyIndex, bool validationEnabled,
210 const VkAllocationCallbacks *pAllocator = DE_NULL)
211 {
212 return createDeviceWithWsi(vkp, apiVersion, instance, vki, physicalDevice, supportedExtensions,
213 additionalExtensions, vector<uint32_t>(1u, queueFamilyIndex), validationEnabled,
214 pAllocator);
215 }
216
217 struct InstanceHelper
218 {
219 const vector<VkExtensionProperties> supportedExtensions;
220 const CustomInstance instance;
221 const InstanceDriver &vki;
222
InstanceHelpervkt::wsi::__anon59f5a5ee0111::InstanceHelper223 InstanceHelper(Context &context, Type wsiType, const VkAllocationCallbacks *pAllocator = DE_NULL)
224 : supportedExtensions(enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL))
225 , instance(createInstanceWithWsi(context, supportedExtensions, wsiType, vector<string>(), pAllocator))
226 , vki(instance.getDriver())
227 {
228 }
229
InstanceHelpervkt::wsi::__anon59f5a5ee0111::InstanceHelper230 InstanceHelper(Context &context, Type wsiType, const vector<string> &extensions,
231 const VkAllocationCallbacks *pAllocator = DE_NULL)
232 : supportedExtensions(enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL))
233 , instance(createInstanceWithWsi(context, supportedExtensions, wsiType, extensions, pAllocator))
234 , vki(instance.getDriver())
235 {
236 }
237 };
238
239 struct DeviceHelper
240 {
241 const VkPhysicalDevice physicalDevice;
242 const uint32_t queueFamilyIndex;
243 const Unique<VkDevice> device;
244 const DeviceDriver vkd;
245 const VkQueue queue;
246
DeviceHelpervkt::wsi::__anon59f5a5ee0111::DeviceHelper247 DeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance,
248 const vector<VkSurfaceKHR> &surface, const vector<string> &additionalExtensions = vector<string>(),
249 const VkAllocationCallbacks *pAllocator = DE_NULL)
250 : physicalDevice(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
251 , queueFamilyIndex(chooseQueueFamilyIndex(vki, physicalDevice, surface))
252 , device(createDeviceWithWsi(context.getPlatformInterface(), context.getUsedApiVersion(), instance, vki,
253 physicalDevice, enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
254 additionalExtensions, queueFamilyIndex,
255 context.getTestContext().getCommandLine().isValidationEnabled(), pAllocator))
256 , vkd(context.getPlatformInterface(), instance, *device, context.getUsedApiVersion(),
257 context.getTestContext().getCommandLine())
258 , queue(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
259 {
260 }
261
262 // Single-surface shortcut.
DeviceHelpervkt::wsi::__anon59f5a5ee0111::DeviceHelper263 DeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance, VkSurfaceKHR surface,
264 const vector<string> &additionalExtensions = vector<string>(),
265 const VkAllocationCallbacks *pAllocator = DE_NULL)
266 : DeviceHelper(context, vki, instance, vector<VkSurfaceKHR>(1u, surface), additionalExtensions, pAllocator)
267 {
268 }
269 };
270
271 // Similar to the one above with no queues and multiple queue families.
272 struct MultiQueueDeviceHelper
273 {
274 const VkPhysicalDevice physicalDevice;
275 const vector<uint32_t> queueFamilyIndices;
276 const Unique<VkDevice> device;
277 const DeviceDriver vkd;
278
MultiQueueDeviceHelpervkt::wsi::__anon59f5a5ee0111::MultiQueueDeviceHelper279 MultiQueueDeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance,
280 const vector<VkSurfaceKHR> &surface,
281 const vector<string> &additionalExtensions = vector<string>(),
282 const VkAllocationCallbacks *pAllocator = DE_NULL)
283 : physicalDevice(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
284 , queueFamilyIndices(getCompatibleQueueFamilyIndices(vki, physicalDevice, surface))
285 , device(createDeviceWithWsi(context.getPlatformInterface(), context.getUsedApiVersion(), instance, vki,
286 physicalDevice, enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
287 additionalExtensions, queueFamilyIndices,
288 context.getTestContext().getCommandLine().isValidationEnabled(), pAllocator))
289 , vkd(context.getPlatformInterface(), instance, *device, context.getUsedApiVersion(),
290 context.getTestContext().getCommandLine())
291 {
292 }
293
294 // Single-surface shortcut.
MultiQueueDeviceHelpervkt::wsi::__anon59f5a5ee0111::MultiQueueDeviceHelper295 MultiQueueDeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance, VkSurfaceKHR surface,
296 const vector<string> additionalExtensions = vector<string>(),
297 const VkAllocationCallbacks *pAllocator = DE_NULL)
298 : MultiQueueDeviceHelper(context, vki, instance, vector<VkSurfaceKHR>(1u, surface), additionalExtensions,
299 pAllocator)
300 {
301 }
302 };
303
304 enum TestDimension
305 {
306 TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
307 TEST_DIMENSION_IMAGE_FORMAT, //!< Test all supported formats
308 TEST_DIMENSION_IMAGE_EXTENT, //!< Test various (supported) extents
309 TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
310 TEST_DIMENSION_IMAGE_USAGE,
311 TEST_DIMENSION_IMAGE_SHARING_MODE,
312 TEST_DIMENSION_PRE_TRANSFORM,
313 TEST_DIMENSION_COMPOSITE_ALPHA,
314 TEST_DIMENSION_PRESENT_MODE,
315 TEST_DIMENSION_CLIPPED,
316 TEST_DIMENSION_EXCLUSIVE_NONZERO, //!< Test VK_SHARING_MODE_EXCLUSIVE and a nonzero queue count.
317
318 TEST_DIMENSION_LAST
319 };
320
getTestDimensionName(TestDimension dimension)321 const char *getTestDimensionName(TestDimension dimension)
322 {
323 static const char *const s_names[] = {
324 "min_image_count", "image_format", "image_extent", "image_array_layers", "image_usage",
325 "image_sharing_mode", "pre_transform", "composite_alpha", "present_mode", "clipped",
326 "exclusive_nonzero_queues",
327 };
328 static_assert(static_cast<int>(de::arrayLength(s_names)) == TEST_DIMENSION_LAST,
329 "Array of names does not provide a 1:1 mapping to TestDimension");
330 return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
331 }
332
333 struct TestParameters
334 {
335 Type wsiType;
336 TestDimension dimension;
337
TestParametersvkt::wsi::__anon59f5a5ee0111::TestParameters338 TestParameters(Type wsiType_, TestDimension dimension_) : wsiType(wsiType_), dimension(dimension_)
339 {
340 }
341
TestParametersvkt::wsi::__anon59f5a5ee0111::TestParameters342 TestParameters(void) : wsiType(TYPE_LAST), dimension(TEST_DIMENSION_LAST)
343 {
344 }
345 };
346
generateSwapchainParameterCases(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,Type wsiType,TestDimension dimension,const VkSurfaceCapabilitiesKHR & capabilities,const vector<VkSurfaceFormatKHR> & formats,const vector<VkPresentModeKHR> & presentModes)347 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases(const InstanceInterface &vki,
348 VkPhysicalDevice physicalDevice, Type wsiType,
349 TestDimension dimension,
350 const VkSurfaceCapabilitiesKHR &capabilities,
351 const vector<VkSurfaceFormatKHR> &formats,
352 const vector<VkPresentModeKHR> &presentModes)
353 {
354 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
355 vector<VkSwapchainCreateInfoKHR> cases;
356 const VkSurfaceTransformFlagBitsKHR defaultTransform =
357 (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
358 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
359 capabilities.currentTransform;
360 const VkSwapchainCreateInfoKHR baseParameters = {
361 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
362 DE_NULL,
363 (VkSwapchainCreateFlagsKHR)0,
364 (VkSurfaceKHR)0,
365 capabilities.minImageCount,
366 formats[0].format,
367 formats[0].colorSpace,
368 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ?
369 capabilities.minImageExtent :
370 capabilities.currentExtent),
371 1u, // imageArrayLayers
372 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
373 VK_SHARING_MODE_EXCLUSIVE,
374 0u,
375 nullptr,
376 defaultTransform,
377 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
378 VK_PRESENT_MODE_FIFO_KHR,
379 VK_FALSE, // clipped
380 (VkSwapchainKHR)0 // oldSwapchain
381 };
382
383 switch (dimension)
384 {
385 case TEST_DIMENSION_MIN_IMAGE_COUNT:
386 {
387 const uint32_t maxImageCountToTest =
388 de::clamp(16u, capabilities.minImageCount,
389 (capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u);
390
391 for (uint32_t imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
392 {
393 cases.push_back(baseParameters);
394 cases.back().minImageCount = imageCount;
395 }
396
397 break;
398 }
399
400 case TEST_DIMENSION_IMAGE_FORMAT:
401 {
402 for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
403 {
404 cases.push_back(baseParameters);
405 cases.back().imageFormat = curFmt->format;
406 cases.back().imageColorSpace = curFmt->colorSpace;
407 }
408
409 break;
410 }
411
412 case TEST_DIMENSION_IMAGE_EXTENT:
413 {
414 static const VkExtent2D s_testSizes[] = {
415 {1, 1}, {16, 32}, {32, 16}, {632, 231}, {117, 998},
416 };
417
418 if (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
419 platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
420 {
421 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
422 {
423 cases.push_back(baseParameters);
424 cases.back().imageExtent.width = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width,
425 capabilities.maxImageExtent.width);
426 cases.back().imageExtent.height = de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height,
427 capabilities.maxImageExtent.height);
428 }
429 }
430
431 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
432 {
433 cases.push_back(baseParameters);
434 cases.back().imageExtent = capabilities.currentExtent;
435 }
436
437 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
438 {
439 cases.push_back(baseParameters);
440 cases.back().imageExtent = capabilities.minImageExtent;
441
442 cases.push_back(baseParameters);
443 cases.back().imageExtent = capabilities.maxImageExtent;
444 }
445
446 break;
447 }
448
449 case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
450 {
451 const uint32_t maxLayers = de::min(capabilities.maxImageArrayLayers, 16u);
452
453 for (uint32_t numLayers = 1; numLayers <= maxLayers; ++numLayers)
454 {
455 cases.push_back(baseParameters);
456 cases.back().imageArrayLayers = numLayers;
457 }
458
459 break;
460 }
461
462 case TEST_DIMENSION_IMAGE_USAGE:
463 {
464 for (uint32_t flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
465 {
466 VkImageFormatProperties imageProps;
467
468 if ((flags & ~capabilities.supportedUsageFlags) == 0)
469 {
470 if (vki.getPhysicalDeviceImageFormatProperties(physicalDevice, baseParameters.imageFormat,
471 VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, flags,
472 (VkImageCreateFlags)0u, &imageProps) != VK_SUCCESS)
473 continue;
474
475 cases.push_back(baseParameters);
476 cases.back().imageUsage = flags;
477 }
478 }
479
480 break;
481 }
482
483 case TEST_DIMENSION_IMAGE_SHARING_MODE:
484 {
485 #if 0
486 // Skipping since this matches the base parameters.
487 cases.push_back(baseParameters);
488 cases.back().imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
489 #endif
490
491 cases.push_back(baseParameters);
492 cases.back().imageSharingMode = VK_SHARING_MODE_CONCURRENT;
493
494 break;
495 }
496
497 case TEST_DIMENSION_PRE_TRANSFORM:
498 {
499 for (uint32_t transform = 1u; transform <= capabilities.supportedTransforms; transform = transform << 1u)
500 {
501 if ((transform & capabilities.supportedTransforms) != 0)
502 {
503 cases.push_back(baseParameters);
504 cases.back().preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
505 }
506 }
507
508 break;
509 }
510
511 case TEST_DIMENSION_COMPOSITE_ALPHA:
512 {
513 for (uint32_t alphaMode = 1u; alphaMode <= capabilities.supportedCompositeAlpha; alphaMode = alphaMode << 1u)
514 {
515 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
516 {
517 cases.push_back(baseParameters);
518 cases.back().compositeAlpha = (VkCompositeAlphaFlagBitsKHR)alphaMode;
519 }
520 }
521
522 break;
523 }
524
525 case TEST_DIMENSION_PRESENT_MODE:
526 {
527 for (vector<VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end();
528 ++curMode)
529 {
530 cases.push_back(baseParameters);
531 cases.back().presentMode = *curMode;
532 }
533
534 break;
535 }
536
537 case TEST_DIMENSION_CLIPPED:
538 {
539 cases.push_back(baseParameters);
540 cases.back().clipped = VK_FALSE;
541
542 cases.push_back(baseParameters);
543 cases.back().clipped = VK_TRUE;
544
545 break;
546 }
547
548 case TEST_DIMENSION_EXCLUSIVE_NONZERO:
549 {
550 // Test the implementation doesn't attempt to do anything with the queue index array in exclusive sharing mode.
551 cases.push_back(baseParameters);
552 cases.back().queueFamilyIndexCount = 2u;
553
554 break;
555 }
556
557 default:
558 DE_FATAL("Impossible");
559 }
560
561 DE_ASSERT(!cases.empty());
562 return cases;
563 }
564
generateSwapchainParameterCases(Type wsiType,TestDimension dimension,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)565 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases(Type wsiType, TestDimension dimension,
566 const InstanceInterface &vki,
567 VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
568 {
569 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki, physicalDevice, surface);
570 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(vki, physicalDevice, surface);
571 const vector<VkPresentModeKHR> presentModes = getPhysicalDeviceSurfacePresentModes(vki, physicalDevice, surface);
572
573 return generateSwapchainParameterCases(vki, physicalDevice, wsiType, dimension, capabilities, formats,
574 presentModes);
575 }
576
createSwapchainTest(Context & context,TestParameters params)577 tcu::TestStatus createSwapchainTest(Context &context, TestParameters params)
578 {
579 tcu::TestLog &log = context.getTestContext().getLog();
580 const InstanceHelper instHelper(context, params.wsiType);
581 const NativeObjects native(context, instHelper.supportedExtensions, params.wsiType);
582 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, params.wsiType,
583 native.getDisplay(), native.getWindow(),
584 context.getTestContext().getCommandLine()));
585 const MultiQueueDeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
586 const vector<VkSwapchainCreateInfoKHR> cases(generateSwapchainParameterCases(
587 params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
588 const VkSurfaceCapabilitiesKHR capabilities(
589 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface));
590
591 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
592 {
593 std::ostringstream subcase;
594 subcase << "Sub-case " << (caseNdx + 1) << " / " << cases.size() << ": ";
595
596 VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
597
598 if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
599 {
600 const auto numFamilies = static_cast<uint32_t>(devHelper.queueFamilyIndices.size());
601 if (numFamilies < 2u)
602 TCU_THROW(NotSupportedError, "Only " + de::toString(numFamilies) +
603 " queue families available for VK_SHARING_MODE_CONCURRENT");
604
605 curParams.queueFamilyIndexCount = numFamilies;
606 curParams.pQueueFamilyIndices = devHelper.queueFamilyIndices.data();
607 }
608
609 // Overwrite surface.
610 curParams.surface = *surface;
611
612 log << TestLog::Message << subcase.str() << curParams << TestLog::EndMessage;
613
614 // The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
615 //
616 // * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
617 // VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
618 VkImageFormatProperties properties;
619 const VkResult propertiesResult = instHelper.vki.getPhysicalDeviceImageFormatProperties(
620 devHelper.physicalDevice, curParams.imageFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
621 curParams.imageUsage,
622 0, // flags
623 &properties);
624
625 log << TestLog::Message << subcase.str() << "vkGetPhysicalDeviceImageFormatProperties => "
626 << getResultStr(propertiesResult) << TestLog::EndMessage;
627
628 switch (propertiesResult)
629 {
630 case VK_SUCCESS:
631 {
632 // The maxExtents case might not be able to create the requested surface due to insufficient
633 // memory, so in this case *only* we handle the OOM exception.
634 if (params.dimension == TEST_DIMENSION_IMAGE_EXTENT &&
635 capabilities.maxImageExtent.width == curParams.imageExtent.width &&
636 capabilities.maxImageExtent.height == curParams.imageExtent.height)
637 {
638 try
639 {
640 const Unique<VkSwapchainKHR> swapchain(
641 createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
642
643 log << TestLog::Message << subcase.str() << "Creating swapchain succeeded" << TestLog::EndMessage;
644 }
645 catch (const OutOfMemoryError &e)
646 {
647 log << TestLog::Message << subcase.str() << "vkCreateSwapchainKHR with maxImageExtent encountered "
648 << e.getError() << TestLog::EndMessage;
649 }
650 }
651 else
652 {
653 const Unique<VkSwapchainKHR> swapchain(
654 createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
655
656 log << TestLog::Message << subcase.str() << "Creating swapchain succeeded" << TestLog::EndMessage;
657 }
658 }
659 break;
660 case VK_ERROR_FORMAT_NOT_SUPPORTED:
661 log << TestLog::Message << subcase.str()
662 << "Skip because vkGetPhysicalDeviceImageFormatProperties returned VK_ERROR_FORMAT_NOT_SUPPORTED"
663 << TestLog::EndMessage;
664 break;
665 default:
666 log << TestLog::Message << subcase.str()
667 << "Fail because vkGetPhysicalDeviceImageFormatProperties returned " << getResultStr(propertiesResult)
668 << TestLog::EndMessage;
669 return tcu::TestStatus::fail("Unexpected result from vkGetPhysicalDeviceImageFormatProperties");
670 }
671 }
672
673 return tcu::TestStatus::pass("No sub-case failed");
674 }
675
676 template <typename T>
HandleToInt(T t)677 static uint64_t HandleToInt(T t)
678 {
679 return t.getInternal();
680 }
681
createSwapchainPrivateDataTest(Context & context,TestParameters params)682 tcu::TestStatus createSwapchainPrivateDataTest(Context &context, TestParameters params)
683 {
684 if (!context.getPrivateDataFeatures().privateData)
685 TCU_THROW(NotSupportedError, "privateData not supported");
686
687 tcu::TestLog &log = context.getTestContext().getLog();
688 const InstanceHelper instHelper(context, params.wsiType);
689 const NativeObjects native(context, instHelper.supportedExtensions, params.wsiType);
690 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, params.wsiType,
691 native.getDisplay(), native.getWindow(),
692 context.getTestContext().getCommandLine()));
693 const vector<string> extraExts(1u, "VK_EXT_private_data");
694 const MultiQueueDeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface, extraExts);
695 const vector<VkSwapchainCreateInfoKHR> cases(generateSwapchainParameterCases(
696 params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
697
698 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
699 {
700 std::ostringstream subcase;
701 subcase << "Sub-case " << (caseNdx + 1) << " / " << cases.size() << ": ";
702
703 VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
704
705 if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
706 {
707 const uint32_t numFamilies = static_cast<uint32_t>(devHelper.queueFamilyIndices.size());
708 if (numFamilies < 2u)
709 TCU_THROW(NotSupportedError, "Only " + de::toString(numFamilies) +
710 " queue families available for VK_SHARING_MODE_CONCURRENT");
711 curParams.queueFamilyIndexCount = numFamilies;
712 }
713 else
714 {
715 // Take only the first queue.
716 if (devHelper.queueFamilyIndices.empty())
717 TCU_THROW(NotSupportedError, "No queue families compatible with the given surface");
718 curParams.queueFamilyIndexCount = 1u;
719 }
720 curParams.pQueueFamilyIndices = devHelper.queueFamilyIndices.data();
721 curParams.surface = *surface;
722
723 log << TestLog::Message << subcase.str() << curParams << TestLog::EndMessage;
724
725 // The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
726 //
727 // * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
728 // VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
729 VkImageFormatProperties properties;
730 const VkResult propertiesResult = instHelper.vki.getPhysicalDeviceImageFormatProperties(
731 devHelper.physicalDevice, curParams.imageFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
732 curParams.imageUsage,
733 0, // flags
734 &properties);
735
736 log << TestLog::Message << subcase.str() << "vkGetPhysicalDeviceImageFormatProperties => "
737 << getResultStr(propertiesResult) << TestLog::EndMessage;
738
739 switch (propertiesResult)
740 {
741 case VK_SUCCESS:
742 {
743 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
744
745 const int numSlots = 100;
746 typedef Unique<VkPrivateDataSlotEXT> PrivateDataSlotUp;
747 typedef SharedPtr<PrivateDataSlotUp> PrivateDataSlotSp;
748 vector<PrivateDataSlotSp> slots;
749
750 const VkPrivateDataSlotCreateInfoEXT createInfo = {
751 VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT, // VkStructureType sType;
752 DE_NULL, // const void* pNext;
753 0u, // VkPrivateDataSlotCreateFlagsEXT flags;
754 };
755
756 for (int i = 0; i < numSlots; ++i)
757 {
758 Move<VkPrivateDataSlotEXT> s =
759 createPrivateDataSlot(devHelper.vkd, *devHelper.device, &createInfo, DE_NULL);
760 slots.push_back(PrivateDataSlotSp(new PrivateDataSlotUp(s)));
761 }
762
763 // Based on code in vktApiObjectManagementTests.cpp
764 for (int r = 0; r < 3; ++r)
765 {
766 uint64_t data;
767
768 for (int i = 0; i < numSlots; ++i)
769 {
770 data = 1234;
771 devHelper.vkd.getPrivateData(*devHelper.device, getObjectType<VkSwapchainKHR>(),
772 HandleToInt(swapchain.get()), **slots[i], &data);
773 // Don't test default value of zero on Android, due to spec erratum
774 if (params.wsiType != TYPE_ANDROID)
775 {
776 if (data != 0)
777 return tcu::TestStatus::fail("Expected initial value of zero");
778 }
779 }
780
781 for (int i = 0; i < numSlots; ++i)
782 VK_CHECK(devHelper.vkd.setPrivateData(*devHelper.device, getObjectType<VkSwapchainKHR>(),
783 HandleToInt(swapchain.get()), **slots[i], i * i * i + 1));
784
785 for (int i = 0; i < numSlots; ++i)
786 {
787 data = 1234;
788 devHelper.vkd.getPrivateData(*devHelper.device, getObjectType<VkSwapchainKHR>(),
789 HandleToInt(swapchain.get()), **slots[i], &data);
790 if (data != (uint64_t)(i * i * i + 1))
791 return tcu::TestStatus::fail("Didn't read back set value");
792 }
793
794 // Destroy and realloc slots for the next iteration
795 slots.clear();
796 for (int i = 0; i < numSlots; ++i)
797 {
798 Move<VkPrivateDataSlotEXT> s =
799 createPrivateDataSlot(devHelper.vkd, *devHelper.device, &createInfo, DE_NULL);
800 slots.push_back(PrivateDataSlotSp(new PrivateDataSlotUp(s)));
801 }
802 }
803 }
804 break;
805 case VK_ERROR_FORMAT_NOT_SUPPORTED:
806 log << TestLog::Message << subcase.str()
807 << "Skip because vkGetPhysicalDeviceImageFormatProperties returned VK_ERROR_FORMAT_NOT_SUPPORTED"
808 << TestLog::EndMessage;
809 break;
810 default:
811 log << TestLog::Message << subcase.str()
812 << "Fail because vkGetPhysicalDeviceImageFormatProperties returned " << getResultStr(propertiesResult)
813 << TestLog::EndMessage;
814 return tcu::TestStatus::fail("Unexpected result from vkGetPhysicalDeviceImageFormatProperties");
815 }
816 }
817
818 return tcu::TestStatus::pass("No sub-case failed");
819 }
820
createSwapchainSimulateOOMTest(Context & context,TestParameters params)821 tcu::TestStatus createSwapchainSimulateOOMTest(Context &context, TestParameters params)
822 {
823 const size_t maxCases = 300u;
824 const uint32_t maxAllocs = 1024u;
825
826 tcu::TestLog &log = context.getTestContext().getLog();
827 tcu::ResultCollector results(log);
828
829 AllocationCallbackRecorder allocationRecorder(getSystemAllocator());
830 DeterministicFailAllocator failingAllocator(allocationRecorder.getCallbacks(),
831 DeterministicFailAllocator::MODE_DO_NOT_COUNT, 0);
832 {
833 const InstanceHelper instHelper(context, params.wsiType, failingAllocator.getCallbacks());
834 const NativeObjects native(context, instHelper.supportedExtensions, params.wsiType);
835 const Unique<VkSurfaceKHR> surface(
836 createSurface(instHelper.vki, instHelper.instance, params.wsiType, native.getDisplay(), native.getWindow(),
837 context.getTestContext().getCommandLine(), failingAllocator.getCallbacks()));
838 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface, vector<string>(),
839 failingAllocator.getCallbacks());
840 const vector<VkSwapchainCreateInfoKHR> allCases(generateSwapchainParameterCases(
841 params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
842 const VkSurfaceCapabilitiesKHR capabilities(
843 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface));
844
845 if (maxCases < allCases.size())
846 log << TestLog::Message << "Note: Will only test first " << maxCases << " cases out of total of "
847 << allCases.size() << " parameter combinations" << TestLog::EndMessage;
848
849 for (size_t caseNdx = 0; caseNdx < de::min(maxCases, allCases.size()); ++caseNdx)
850 {
851 log << TestLog::Message << "Testing parameter case " << caseNdx << ": " << allCases[caseNdx]
852 << TestLog::EndMessage;
853
854 for (uint32_t numPassingAllocs = 0; numPassingAllocs <= maxAllocs; ++numPassingAllocs)
855 {
856 bool gotOOM = false;
857 VkSwapchainCreateInfoKHR curParams = allCases[caseNdx];
858 curParams.surface = *surface;
859 curParams.queueFamilyIndexCount = 1u;
860 curParams.pQueueFamilyIndices = &devHelper.queueFamilyIndex;
861
862 failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
863
864 log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding"
865 << TestLog::EndMessage;
866
867 try
868 {
869 // With concurrent sharing mode, at least two queues are needed.
870 if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
871 continue;
872
873 #if (DE_OS == DE_OS_ANDROID)
874 // Give some extra time to deallocate memory from previous createSwapchainKHR calls with large dimensions on Android.
875 // 15ms was decided to be the safest amount of time, otherwise test may crash with an OOM issue.
876 constexpr uint32_t sleepInMs = 15;
877
878 if (params.dimension == TEST_DIMENSION_MIN_IMAGE_COUNT)
879 {
880 std::this_thread::sleep_for(std::chrono::milliseconds(sleepInMs));
881 }
882 #endif
883
884 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(
885 devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
886 }
887 catch (const OutOfMemoryError &e)
888 {
889 log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
890 gotOOM = true;
891 }
892
893 if (!gotOOM)
894 {
895 log << TestLog::Message << "Creating swapchain succeeded!" << TestLog::EndMessage;
896
897 if (numPassingAllocs == 0)
898 results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
899
900 break;
901 }
902 else if (numPassingAllocs == maxAllocs)
903 {
904 // The maxExtents case might not be able to create the requested surface due to insufficient
905 // memory, so in this case *only* we allow the OOM exception upto maxAllocs.
906 if (params.dimension == TEST_DIMENSION_IMAGE_EXTENT &&
907 capabilities.maxImageExtent.width == curParams.imageExtent.width &&
908 capabilities.maxImageExtent.height == curParams.imageExtent.height)
909 break;
910
911 results.addResult(QP_TEST_RESULT_QUALITY_WARNING,
912 "Creating swapchain did not succeed, callback limit exceeded");
913 }
914 }
915
916 context.getTestContext().touchWatchdog();
917 }
918 }
919
920 if (!validateAndLog(log, allocationRecorder, 0u))
921 results.fail("Detected invalid system allocation callback");
922
923 return tcu::TestStatus(results.getResult(), results.getMessage());
924 }
925
testImageSwapchainCreateInfo(Context & context,Type wsiType)926 tcu::TestStatus testImageSwapchainCreateInfo(Context &context, Type wsiType)
927 {
928 const tcu::UVec2 desiredSize(256, 256);
929 const InstanceHelper instHelper(context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
930 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
931 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
932 native.getWindow(), context.getTestContext().getCommandLine()));
933 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface,
934 vector<string>(1u, "VK_KHR_bind_memory2"));
935 const Extensions &deviceExtensions =
936 enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL);
937
938 // structures this tests checks were added in revision 69
939 if (!isExtensionStructSupported(deviceExtensions, RequiredExtension("VK_KHR_swapchain", 69)))
940 TCU_THROW(NotSupportedError, "Required extension revision is not supported");
941
942 const VkSurfaceCapabilitiesKHR capabilities =
943 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
944 const vector<VkSurfaceFormatKHR> formats =
945 getPhysicalDeviceSurfaceFormats(instHelper.vki, devHelper.physicalDevice, *surface);
946 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
947 const VkSurfaceTransformFlagBitsKHR transform =
948 (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
949 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
950 capabilities.currentTransform;
951 const uint32_t desiredImageCount = 2;
952 const VkSwapchainCreateInfoKHR swapchainInfo = {
953 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
954 DE_NULL,
955 (VkSwapchainCreateFlagsKHR)0,
956 *surface,
957 de::clamp(desiredImageCount, capabilities.minImageCount,
958 capabilities.maxImageCount > 0 ? capabilities.maxImageCount :
959 capabilities.minImageCount + desiredImageCount),
960 formats[0].format,
961 formats[0].colorSpace,
962 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ?
963 capabilities.currentExtent :
964 vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
965 1u,
966 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
967 VK_SHARING_MODE_EXCLUSIVE,
968 0u,
969 (const uint32_t *)DE_NULL,
970 transform,
971 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
972 VK_PRESENT_MODE_FIFO_KHR,
973 VK_FALSE, // clipped
974 (VkSwapchainKHR)0 // oldSwapchain
975 };
976
977 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
978 uint32_t numImages = 0;
979 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
980 if (numImages == 0)
981 return tcu::TestStatus::pass("Pass");
982
983 VkImageSwapchainCreateInfoKHR imageSwapchainCreateInfo = {VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
984 DE_NULL, *swapchain};
985
986 VkImageCreateInfo imageCreateInfo = {
987 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
988 &imageSwapchainCreateInfo,
989 (VkImageCreateFlags)0u, // flags
990 VK_IMAGE_TYPE_2D, // imageType
991 formats[0].format, // format
992 {
993 // extent
994 desiredSize.x(), // width
995 desiredSize.y(), // height
996 1u // depth
997 },
998 1u, // mipLevels
999 1u, // arrayLayers
1000 VK_SAMPLE_COUNT_1_BIT, // samples
1001 VK_IMAGE_TILING_OPTIMAL, // tiling
1002 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // usage
1003 VK_SHARING_MODE_EXCLUSIVE, // sharingMode
1004 0u, // queueFamilyIndexCount
1005 DE_NULL, // pQueueFamilyIndices
1006 VK_IMAGE_LAYOUT_UNDEFINED // initialLayout
1007 };
1008
1009 typedef vk::Unique<VkImage> UniqueImage;
1010 typedef de::SharedPtr<UniqueImage> ImageSp;
1011
1012 std::vector<ImageSp> images(numImages);
1013 std::vector<VkBindImageMemorySwapchainInfoKHR> bindImageMemorySwapchainInfo(numImages);
1014 std::vector<VkBindImageMemoryInfo> bindImageMemoryInfos(numImages);
1015
1016 for (uint32_t idx = 0; idx < numImages; ++idx)
1017 {
1018 // Create image
1019 images[idx] = ImageSp(new UniqueImage(createImage(devHelper.vkd, *devHelper.device, &imageCreateInfo)));
1020
1021 VkBindImageMemorySwapchainInfoKHR bimsInfo = {VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR, DE_NULL,
1022 *swapchain, idx};
1023 bindImageMemorySwapchainInfo[idx] = bimsInfo;
1024
1025 VkBindImageMemoryInfo bimInfo = {
1026 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, &bindImageMemorySwapchainInfo[idx], **images[idx],
1027 DE_NULL, // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
1028 0u // If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
1029 };
1030
1031 bindImageMemoryInfos[idx] = bimInfo;
1032 }
1033
1034 VK_CHECK(devHelper.vkd.bindImageMemory2(*devHelper.device, numImages, &bindImageMemoryInfos[0]));
1035
1036 return tcu::TestStatus::pass("Pass");
1037 }
1038
1039 struct GroupParameters
1040 {
1041 typedef FunctionInstance1<TestParameters>::Function Function;
1042
1043 Type wsiType;
1044 Function function;
1045
GroupParametersvkt::wsi::__anon59f5a5ee0111::GroupParameters1046 GroupParameters(Type wsiType_, Function function_) : wsiType(wsiType_), function(function_)
1047 {
1048 }
1049
GroupParametersvkt::wsi::__anon59f5a5ee0111::GroupParameters1050 GroupParameters(void) : wsiType(TYPE_LAST), function((Function)DE_NULL)
1051 {
1052 }
1053 };
1054
populateSwapchainGroup(tcu::TestCaseGroup * testGroup,GroupParameters params)1055 void populateSwapchainGroup(tcu::TestCaseGroup *testGroup, GroupParameters params)
1056 {
1057 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
1058 {
1059 const TestDimension testDimension = (TestDimension)dimensionNdx;
1060
1061 addFunctionCase(testGroup, getTestDimensionName(testDimension), params.function,
1062 TestParameters(params.wsiType, testDimension));
1063 }
1064
1065 addFunctionCase(testGroup, "image_swapchain_create_info", testImageSwapchainCreateInfo, params.wsiType);
1066 }
1067
populateSwapchainPrivateDataGroup(tcu::TestCaseGroup * testGroup,GroupParameters params)1068 void populateSwapchainPrivateDataGroup(tcu::TestCaseGroup *testGroup, GroupParameters params)
1069 {
1070 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
1071 {
1072 const TestDimension testDimension = (TestDimension)dimensionNdx;
1073 if (testDimension == TEST_DIMENSION_IMAGE_EXTENT)
1074 continue;
1075
1076 addFunctionCase(testGroup, getTestDimensionName(testDimension), params.function,
1077 TestParameters(params.wsiType, testDimension));
1078 }
1079 }
1080
getBasicSwapchainParameters(Type wsiType,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,const tcu::UVec2 & desiredSize,uint32_t desiredImageCount)1081 VkSwapchainCreateInfoKHR getBasicSwapchainParameters(Type wsiType, const InstanceInterface &vki,
1082 VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
1083 const tcu::UVec2 &desiredSize, uint32_t desiredImageCount)
1084 {
1085 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki, physicalDevice, surface);
1086 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(vki, physicalDevice, surface);
1087 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
1088 const VkSurfaceTransformFlagBitsKHR transform =
1089 (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
1090 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
1091 capabilities.currentTransform;
1092 const VkSwapchainCreateInfoKHR parameters = {
1093 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
1094 DE_NULL,
1095 (VkSwapchainCreateFlagsKHR)0,
1096 surface,
1097 de::clamp(desiredImageCount, capabilities.minImageCount,
1098 capabilities.maxImageCount > 0 ? capabilities.maxImageCount :
1099 capabilities.minImageCount + desiredImageCount),
1100 formats[0].format,
1101 formats[0].colorSpace,
1102 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ?
1103 capabilities.currentExtent :
1104 vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
1105 1u, // imageArrayLayers
1106 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1107 VK_SHARING_MODE_EXCLUSIVE,
1108 0u,
1109 (const uint32_t *)DE_NULL,
1110 transform,
1111 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1112 VK_PRESENT_MODE_FIFO_KHR,
1113 VK_FALSE, // clipped
1114 (VkSwapchainKHR)0 // oldSwapchain
1115 };
1116
1117 return parameters;
1118 }
1119
1120 typedef de::SharedPtr<Unique<VkCommandBuffer>> CommandBufferSp;
1121 typedef de::SharedPtr<Unique<VkFence>> FenceSp;
1122 typedef de::SharedPtr<Unique<VkSemaphore>> SemaphoreSp;
1123
createFences(const DeviceInterface & vkd,const VkDevice device,size_t numFences,bool isSignaled=true)1124 vector<FenceSp> createFences(const DeviceInterface &vkd, const VkDevice device, size_t numFences,
1125 bool isSignaled = true)
1126 {
1127 vector<FenceSp> fences(numFences);
1128
1129 for (size_t ndx = 0; ndx < numFences; ++ndx)
1130 fences[ndx] =
1131 FenceSp(new Unique<VkFence>(createFence(vkd, device, (isSignaled) ? vk::VK_FENCE_CREATE_SIGNALED_BIT : 0)));
1132
1133 return fences;
1134 }
1135
createSemaphores(const DeviceInterface & vkd,const VkDevice device,size_t numSemaphores)1136 vector<SemaphoreSp> createSemaphores(const DeviceInterface &vkd, const VkDevice device, size_t numSemaphores)
1137 {
1138 vector<SemaphoreSp> semaphores(numSemaphores);
1139
1140 for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1141 semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
1142
1143 return semaphores;
1144 }
1145
allocateCommandBuffers(const DeviceInterface & vkd,const VkDevice device,const VkCommandPool commandPool,const VkCommandBufferLevel level,const size_t numCommandBuffers)1146 vector<CommandBufferSp> allocateCommandBuffers(const DeviceInterface &vkd, const VkDevice device,
1147 const VkCommandPool commandPool, const VkCommandBufferLevel level,
1148 const size_t numCommandBuffers)
1149 {
1150 vector<CommandBufferSp> buffers(numCommandBuffers);
1151
1152 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1153 buffers[ndx] =
1154 CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1155
1156 return buffers;
1157 }
1158
1159 class AcquireNextImageWrapper
1160 {
1161 public:
AcquireNextImageWrapper(const DeviceInterface & vkd,VkDevice device,uint32_t deviceMask,VkSwapchainKHR swapchain,uint64_t timeout)1162 AcquireNextImageWrapper(const DeviceInterface &vkd, VkDevice device, uint32_t deviceMask, VkSwapchainKHR swapchain,
1163 uint64_t timeout)
1164 : m_vkd(vkd)
1165 , m_device(device)
1166 , m_swapchain(swapchain)
1167 , m_timeout(timeout)
1168 {
1169 DE_UNREF(deviceMask); // needed for compatibility with acquireNextImage2KHR
1170 }
1171
featureAvailable(Context &)1172 bool featureAvailable(Context &)
1173 {
1174 return true; // needed for compatibility with acquireNextImage2KHR
1175 }
1176
call(VkSemaphore semaphore,VkFence fence,uint32_t * imageIndex)1177 VkResult call(VkSemaphore semaphore, VkFence fence, uint32_t *imageIndex)
1178 {
1179 return m_vkd.acquireNextImageKHR(m_device, m_swapchain, m_timeout, semaphore, fence, imageIndex);
1180 }
1181
1182 protected:
1183 const DeviceInterface &m_vkd;
1184 VkDevice m_device;
1185 VkSwapchainKHR m_swapchain;
1186 uint64_t m_timeout;
1187 };
1188
1189 class AcquireNextImage2Wrapper
1190 {
1191 public:
AcquireNextImage2Wrapper(const DeviceInterface & vkd,VkDevice device,uint32_t deviceMask,VkSwapchainKHR swapchain,uint64_t timeout)1192 AcquireNextImage2Wrapper(const DeviceInterface &vkd, VkDevice device, uint32_t deviceMask, VkSwapchainKHR swapchain,
1193 uint64_t timeout)
1194 : m_vkd(vkd)
1195 , m_device(device)
1196 {
1197 m_info.sType = VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR;
1198 m_info.pNext = DE_NULL;
1199 m_info.swapchain = swapchain;
1200 m_info.timeout = timeout;
1201 m_info.semaphore = DE_NULL;
1202 m_info.fence = DE_NULL;
1203 m_info.deviceMask = deviceMask;
1204 }
1205
featureAvailable(Context & context)1206 bool featureAvailable(Context &context)
1207 {
1208 return context.isDeviceFunctionalitySupported("VK_KHR_device_group");
1209 }
1210
call(VkSemaphore semaphore,VkFence fence,uint32_t * imageIndex)1211 VkResult call(VkSemaphore semaphore, VkFence fence, uint32_t *imageIndex)
1212 {
1213 m_info.semaphore = semaphore;
1214 m_info.fence = fence;
1215 return m_vkd.acquireNextImage2KHR(m_device, &m_info, imageIndex);
1216 }
1217
1218 protected:
1219 const DeviceInterface &m_vkd;
1220 VkDevice m_device;
1221 VkAcquireNextImageInfoKHR m_info;
1222 };
1223
1224 template <typename AcquireWrapperType>
basicRenderTest(Context & context,Type wsiType)1225 tcu::TestStatus basicRenderTest(Context &context, Type wsiType)
1226 {
1227 const tcu::UVec2 desiredSize(256, 256);
1228 const InstanceHelper instHelper(context, wsiType);
1229 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1230 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
1231 native.getWindow(), context.getTestContext().getCommandLine()));
1232 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
1233 const DeviceInterface &vkd = devHelper.vkd;
1234 const VkDevice device = *devHelper.device;
1235 SimpleAllocator allocator(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1236 const VkSwapchainCreateInfoKHR swapchainInfo =
1237 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1238 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(vkd, device, &swapchainInfo));
1239 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
1240
1241 AcquireWrapperType acquireImageWrapper(vkd, device, 1u, *swapchain, std::numeric_limits<uint64_t>::max());
1242 if (!acquireImageWrapper.featureAvailable(context))
1243 TCU_THROW(NotSupportedError, "Required extension is not supported");
1244
1245 const WsiTriangleRenderer renderer(vkd, device, allocator, context.getBinaryCollection(), false, swapchainImages,
1246 swapchainImages, swapchainInfo.imageFormat,
1247 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1248
1249 const Unique<VkCommandPool> commandPool(
1250 createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1251
1252 const size_t maxQueuedFrames = swapchainImages.size() * 2;
1253
1254 // We need to keep hold of fences from vkAcquireNextImage(2)KHR to actually
1255 // limit number of frames we allow to be queued.
1256 const vector<FenceSp> imageReadyFences(createFences(vkd, device, maxQueuedFrames));
1257
1258 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1259 // the semaphore in same time as the fence we use to meter rendering.
1260 const vector<SemaphoreSp> imageReadySemaphores(createSemaphores(vkd, device, maxQueuedFrames + 1));
1261
1262 // For rest we simply need maxQueuedFrames as we will wait for image
1263 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1264 // previous uses must have completed.
1265 const vector<SemaphoreSp> renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames));
1266 const vector<CommandBufferSp> commandBuffers(
1267 allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1268
1269 try
1270 {
1271 const uint32_t numFramesToRender = 60 * 10;
1272
1273 for (uint32_t frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1274 {
1275 const VkFence imageReadyFence = **imageReadyFences[frameNdx % imageReadyFences.size()];
1276 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx % imageReadySemaphores.size()];
1277 uint32_t imageNdx = ~0u;
1278
1279 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<uint64_t>::max()));
1280 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1281
1282 {
1283 const VkResult acquireResult = acquireImageWrapper.call(imageReadySemaphore, (VkFence)0, &imageNdx);
1284
1285 if (acquireResult == VK_SUBOPTIMAL_KHR)
1286 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame "
1287 << frameNdx << TestLog::EndMessage;
1288 else
1289 VK_CHECK(acquireResult);
1290 }
1291
1292 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1293
1294 {
1295 const VkSemaphore renderingCompleteSemaphore =
1296 **renderingCompleteSemaphores[frameNdx % renderingCompleteSemaphores.size()];
1297 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx % commandBuffers.size()];
1298 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1299 const VkSubmitInfo submitInfo = {VK_STRUCTURE_TYPE_SUBMIT_INFO,
1300 DE_NULL,
1301 1u,
1302 &imageReadySemaphore,
1303 &waitDstStage,
1304 1u,
1305 &commandBuffer,
1306 1u,
1307 &renderingCompleteSemaphore};
1308 const VkPresentInfoKHR presentInfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1309 DE_NULL,
1310 1u,
1311 &renderingCompleteSemaphore,
1312 1u,
1313 &*swapchain,
1314 &imageNdx,
1315 (VkResult *)DE_NULL};
1316
1317 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1318 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
1319 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1320 }
1321 }
1322
1323 VK_CHECK(vkd.deviceWaitIdle(device));
1324 }
1325 catch (...)
1326 {
1327 // Make sure device is idle before destroying resources
1328 vkd.deviceWaitIdle(device);
1329 throw;
1330 }
1331
1332 return tcu::TestStatus::pass("Rendering tests succeeded");
1333 }
1334
1335 class FrameStreamObjects
1336 {
1337 public:
1338 struct FrameObjects
1339 {
1340 const vk::VkFence &renderCompleteFence;
1341 const vk::VkSemaphore &renderCompleteSemaphore;
1342 const vk::VkSemaphore &imageAvailableSemaphore;
1343 const vk::VkCommandBuffer &commandBuffer;
1344 };
1345
FrameStreamObjects(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool cmdPool,size_t maxQueuedFrames)1346 FrameStreamObjects(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkCommandPool cmdPool,
1347 size_t maxQueuedFrames)
1348 : renderingCompleteFences(createFences(vkd, device, maxQueuedFrames))
1349 , renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
1350 , imageAvailableSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
1351 , commandBuffers(
1352 allocateCommandBuffers(vkd, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames))
1353 , m_maxQueuedFrames(maxQueuedFrames)
1354 , m_nextFrame(0u)
1355 {
1356 }
1357
frameNumber(void) const1358 size_t frameNumber(void) const
1359 {
1360 DE_ASSERT(m_nextFrame > 0u);
1361 return m_nextFrame - 1u;
1362 }
1363
newFrame()1364 FrameObjects newFrame()
1365 {
1366 const size_t mod = m_nextFrame % m_maxQueuedFrames;
1367 FrameObjects ret = {
1368 **renderingCompleteFences[mod],
1369 **renderingCompleteSemaphores[mod],
1370 **imageAvailableSemaphores[mod],
1371 **commandBuffers[mod],
1372 };
1373 ++m_nextFrame;
1374 return ret;
1375 }
1376
1377 private:
1378 const vector<FenceSp> renderingCompleteFences;
1379 const vector<SemaphoreSp> renderingCompleteSemaphores;
1380 const vector<SemaphoreSp> imageAvailableSemaphores;
1381 const vector<CommandBufferSp> commandBuffers;
1382
1383 const size_t m_maxQueuedFrames;
1384 size_t m_nextFrame;
1385 };
1386
1387 struct MultiSwapchainParams
1388 {
1389 Type wsiType;
1390 size_t swapchainCount;
1391 };
1392
1393 struct AccumulatedPresentInfo
1394 {
1395 vector<VkSemaphore> semaphores;
1396 vector<VkSwapchainKHR> swapchains;
1397 vector<uint32_t> imageIndices;
1398
AccumulatedPresentInfovkt::wsi::__anon59f5a5ee0111::AccumulatedPresentInfo1399 AccumulatedPresentInfo() : semaphores(), swapchains(), imageIndices()
1400 {
1401 }
1402
push_backvkt::wsi::__anon59f5a5ee0111::AccumulatedPresentInfo1403 void push_back(VkSemaphore sem, VkSwapchainKHR sc, uint32_t index)
1404 {
1405 semaphores.push_back(sem);
1406 swapchains.push_back(sc);
1407 imageIndices.push_back(index);
1408 }
1409
resetvkt::wsi::__anon59f5a5ee0111::AccumulatedPresentInfo1410 void reset()
1411 {
1412 semaphores.resize(0);
1413 swapchains.resize(0);
1414 imageIndices.resize(0);
1415 }
1416
sizevkt::wsi::__anon59f5a5ee0111::AccumulatedPresentInfo1417 size_t size() const
1418 {
1419 // Any of the vectors would do.
1420 return semaphores.size();
1421 }
1422 };
1423
1424 template <typename AcquireWrapperType>
multiSwapchainRenderTest(Context & context,MultiSwapchainParams params)1425 tcu::TestStatus multiSwapchainRenderTest(Context &context, MultiSwapchainParams params)
1426 {
1427 DE_ASSERT(params.swapchainCount > 0);
1428 const PlatformProperties &platformProperties = getPlatformProperties(params.wsiType);
1429 if (params.swapchainCount > platformProperties.maxWindowsPerDisplay)
1430 {
1431 std::ostringstream msg;
1432 msg << "Creating " << params.swapchainCount << " windows not supported";
1433 TCU_THROW(NotSupportedError, msg.str());
1434 }
1435
1436 const tcu::UVec2 desiredSize(256, 256);
1437 const InstanceHelper instHelper(context, params.wsiType);
1438
1439 // Create native window system objects, surfaces and helper surface vector.
1440 std::unique_ptr<NativeObjects> native;
1441 try
1442 {
1443 native.reset(new NativeObjects(context, instHelper.supportedExtensions, params.wsiType, params.swapchainCount,
1444 tcu::just(desiredSize)));
1445 }
1446 catch (tcu::ResourceError &)
1447 {
1448 std::ostringstream msg;
1449 msg << "Unable to create " << params.swapchainCount << " windows";
1450 TCU_THROW(NotSupportedError, msg.str());
1451 }
1452
1453 vector<Move<VkSurfaceKHR>> surface;
1454 vector<VkSurfaceKHR> surfaceKHR; // The plain Vulkan objects from the vector above.
1455
1456 for (size_t i = 0; i < params.swapchainCount; ++i)
1457 {
1458 surface.emplace_back(createSurface(instHelper.vki, instHelper.instance, params.wsiType, native->getDisplay(),
1459 native->getWindow(i), context.getTestContext().getCommandLine()));
1460 surfaceKHR.push_back(surface.back().get());
1461 }
1462
1463 // Create a device compatible with all surfaces.
1464 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, surfaceKHR);
1465 const DeviceInterface &vkd = devHelper.vkd;
1466 const VkDevice device = *devHelper.device;
1467 SimpleAllocator allocator(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1468
1469 // Create several swapchains and images.
1470 vector<VkSwapchainCreateInfoKHR> swapchainInfo;
1471 vector<Move<VkSwapchainKHR>> swapchain;
1472 vector<vector<VkImage>> swapchainImages;
1473 vector<AcquireWrapperType> acquireImageWrapper;
1474 for (size_t i = 0; i < params.swapchainCount; ++i)
1475 {
1476 swapchainInfo.emplace_back(getBasicSwapchainParameters(params.wsiType, instHelper.vki, devHelper.physicalDevice,
1477 *surface[i], desiredSize, 2));
1478 swapchain.emplace_back(createSwapchainKHR(vkd, device, &swapchainInfo.back()));
1479 swapchainImages.emplace_back(getSwapchainImages(vkd, device, swapchain.back().get()));
1480 acquireImageWrapper.emplace_back(vkd, device, 1u, swapchain.back().get(), std::numeric_limits<uint64_t>::max());
1481 }
1482
1483 // Every acquire wrapper requires the same features, so we only check the first one.
1484 if (!acquireImageWrapper.front().featureAvailable(context))
1485 TCU_THROW(NotSupportedError, "Required extension is not supported");
1486
1487 // Renderer per swapchain.
1488 vector<WsiTriangleRenderer> renderer;
1489 for (size_t i = 0; i < params.swapchainCount; ++i)
1490 {
1491 renderer.emplace_back(vkd, device, allocator, context.getBinaryCollection(), false, swapchainImages[i],
1492 swapchainImages[i], swapchainInfo[i].imageFormat,
1493 tcu::UVec2(swapchainInfo[i].imageExtent.width, swapchainInfo[i].imageExtent.height));
1494 }
1495
1496 const Unique<VkCommandPool> commandPool(
1497 createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1498 const size_t maxQueuedFrames = swapchainImages.front().size() * 2; // Limit in-flight frames.
1499
1500 vector<FrameStreamObjects> frameStreamObjects;
1501 for (size_t i = 0; i < params.swapchainCount; ++i)
1502 frameStreamObjects.emplace_back(vkd, device, commandPool.get(), maxQueuedFrames);
1503
1504 try
1505 {
1506 // 3 seconds for 60 Hz screens.
1507 const uint32_t kNumFramesToRender = 60 * 3 * static_cast<uint32_t>(params.swapchainCount);
1508 AccumulatedPresentInfo accumulatedPresentInfo;
1509
1510 for (size_t frameNdx = 0; frameNdx < kNumFramesToRender; ++frameNdx)
1511 {
1512 size_t swapchainIndex = frameNdx % params.swapchainCount;
1513 auto &fsObjects = frameStreamObjects[swapchainIndex];
1514 auto frameObjects = fsObjects.newFrame();
1515 uint32_t imageNdx = std::numeric_limits<uint32_t>::max();
1516
1517 VK_CHECK(vkd.waitForFences(device, 1u, &frameObjects.renderCompleteFence, VK_TRUE,
1518 std::numeric_limits<uint64_t>::max()));
1519 VK_CHECK(vkd.resetFences(device, 1u, &frameObjects.renderCompleteFence));
1520
1521 {
1522 const VkResult acquireResult = acquireImageWrapper[swapchainIndex].call(
1523 frameObjects.imageAvailableSemaphore, (VkFence)DE_NULL, &imageNdx);
1524 if (acquireResult == VK_SUBOPTIMAL_KHR)
1525 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame "
1526 << frameNdx << TestLog::EndMessage;
1527 else
1528 VK_CHECK(acquireResult);
1529 }
1530
1531 TCU_CHECK(static_cast<size_t>(imageNdx) < swapchainImages[swapchainIndex].size());
1532
1533 {
1534 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1535 const VkSubmitInfo submitInfo = {
1536 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1537 DE_NULL,
1538 1u,
1539 &frameObjects.imageAvailableSemaphore,
1540 &waitDstStage,
1541 1u,
1542 &frameObjects.commandBuffer,
1543 1u,
1544 &frameObjects.renderCompleteSemaphore,
1545 };
1546
1547 renderer[swapchainIndex].recordFrame(frameObjects.commandBuffer, imageNdx,
1548 static_cast<uint32_t>(frameNdx));
1549 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, frameObjects.renderCompleteFence));
1550
1551 // Save present information for the current frame.
1552 accumulatedPresentInfo.push_back(frameObjects.renderCompleteSemaphore, swapchain[swapchainIndex].get(),
1553 imageNdx);
1554
1555 // Present frames when we have accumulated one frame per swapchain.
1556 if (accumulatedPresentInfo.size() == params.swapchainCount)
1557 {
1558 DE_ASSERT(accumulatedPresentInfo.semaphores.size() == accumulatedPresentInfo.swapchains.size() &&
1559 accumulatedPresentInfo.semaphores.size() == accumulatedPresentInfo.imageIndices.size());
1560
1561 vector<VkResult> results(params.swapchainCount, VK_ERROR_DEVICE_LOST);
1562
1563 const VkPresentInfoKHR presentInfo = {
1564 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1565 DE_NULL,
1566 static_cast<uint32_t>(accumulatedPresentInfo.semaphores.size()),
1567 accumulatedPresentInfo.semaphores.data(),
1568 static_cast<uint32_t>(accumulatedPresentInfo.swapchains.size()),
1569 accumulatedPresentInfo.swapchains.data(),
1570 accumulatedPresentInfo.imageIndices.data(),
1571 results.data(),
1572 };
1573
1574 // Check both the global result and the individual results.
1575 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1576 for (const auto &result : results)
1577 VK_CHECK_WSI(result);
1578
1579 accumulatedPresentInfo.reset();
1580 }
1581 }
1582 }
1583
1584 VK_CHECK(vkd.deviceWaitIdle(device));
1585 }
1586 catch (...)
1587 {
1588 // Make sure device is idle before destroying resources
1589 vkd.deviceWaitIdle(device);
1590 throw;
1591 }
1592
1593 return tcu::TestStatus::pass("Rendering tests succeeded");
1594 }
1595
deviceGroupRenderTest(Context & context,Type wsiType)1596 tcu::TestStatus deviceGroupRenderTest(Context &context, Type wsiType)
1597 {
1598 const InstanceHelper instHelper(context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
1599 const tcu::CommandLine &cmdLine = context.getTestContext().getCommandLine();
1600 VkPhysicalDevice physicalDevice = chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
1601 const Extensions &supportedExtensions = enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
1602
1603 std::vector<const char *> deviceExtensions;
1604 deviceExtensions.push_back("VK_KHR_swapchain");
1605 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
1606 deviceExtensions.push_back("VK_KHR_device_group");
1607
1608 for (std::size_t ndx = 0; ndx < deviceExtensions.size(); ++ndx)
1609 {
1610 if (!isExtensionStructSupported(supportedExtensions, RequiredExtension(deviceExtensions[ndx])))
1611 TCU_THROW(NotSupportedError, (string(deviceExtensions[ndx]) + " is not supported").c_str());
1612 }
1613
1614 const tcu::UVec2 desiredSize(256, 256);
1615 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1616 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
1617 native.getWindow(), context.getTestContext().getCommandLine()));
1618
1619 const uint32_t devGroupIdx = cmdLine.getVKDeviceGroupId() - 1;
1620 const uint32_t deviceIdx = context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
1621 const vector<VkPhysicalDeviceGroupProperties> deviceGroupProps =
1622 enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
1623 uint32_t physicalDevicesInGroupCount = deviceGroupProps[devGroupIdx].physicalDeviceCount;
1624 const VkPhysicalDevice *physicalDevicesInGroup = deviceGroupProps[devGroupIdx].physicalDevices;
1625 uint32_t queueFamilyIndex = chooseQueueFamilyIndex(instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface);
1626 const std::vector<VkQueueFamilyProperties> queueProps =
1627 getPhysicalDeviceQueueFamilyProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]);
1628 const float queuePriority = 1.0f;
1629 const uint32_t firstDeviceID = 0;
1630 const uint32_t secondDeviceID = 1;
1631
1632 // create a device group
1633 const VkDeviceGroupDeviceCreateInfo groupDeviceInfo = {
1634 VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR, // stype
1635 DE_NULL, // pNext
1636 physicalDevicesInGroupCount, // physicalDeviceCount
1637 physicalDevicesInGroup // physicalDevices
1638 };
1639 const VkDeviceQueueCreateInfo deviceQueueCreateInfo = {
1640 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // type
1641 DE_NULL, // pNext
1642 (VkDeviceQueueCreateFlags)0u, // flags
1643 queueFamilyIndex, // queueFamilyIndex
1644 1u, // queueCount
1645 &queuePriority, // pQueuePriorities
1646 };
1647
1648 const VkDeviceCreateInfo deviceCreateInfo = {
1649 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
1650 &groupDeviceInfo, // pNext
1651 (VkDeviceCreateFlags)0u, // flags
1652 1, // queueRecordCount
1653 &deviceQueueCreateInfo, // pRequestedQueues
1654 0, // layerCount
1655 DE_NULL, // ppEnabledLayerNames
1656 uint32_t(deviceExtensions.size()), // enabledExtensionCount
1657 &deviceExtensions[0], // ppEnabledExtensionNames
1658 DE_NULL, // pEnabledFeatures
1659 };
1660
1661 Move<VkDevice> groupDevice = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(),
1662 context.getPlatformInterface(), instHelper.instance, instHelper.vki,
1663 physicalDevicesInGroup[deviceIdx], &deviceCreateInfo);
1664 const DeviceDriver vkd(context.getPlatformInterface(), instHelper.instance, *groupDevice,
1665 context.getUsedApiVersion(), context.getTestContext().getCommandLine());
1666 VkQueue queue(getDeviceQueue(vkd, *groupDevice, queueFamilyIndex, 0));
1667 SimpleAllocator allocator(vkd, *groupDevice,
1668 getPhysicalDeviceMemoryProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]));
1669
1670 // create swapchain for device group
1671 VkDeviceGroupSwapchainCreateInfoKHR deviceGroupSwapchainInfo = initVulkanStructure();
1672 deviceGroupSwapchainInfo.modes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
1673
1674 VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(
1675 wsiType, instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface, desiredSize, 2);
1676 swapchainInfo.pNext = &deviceGroupSwapchainInfo;
1677
1678 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(vkd, *groupDevice, &swapchainInfo));
1679 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, *groupDevice, *swapchain);
1680
1681 const WsiTriangleRenderer renderer(vkd, *groupDevice, allocator, context.getBinaryCollection(), false,
1682 swapchainImages, swapchainImages, swapchainInfo.imageFormat,
1683 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1684
1685 const Unique<VkCommandPool> commandPool(
1686 createCommandPool(vkd, *groupDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1687
1688 const size_t maxQueuedFrames = swapchainImages.size() * 2;
1689
1690 // We need to keep hold of fences from vkAcquireNextImage2KHR
1691 // to actually limit number of frames we allow to be queued.
1692 const vector<FenceSp> imageReadyFences(createFences(vkd, *groupDevice, maxQueuedFrames));
1693
1694 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to
1695 // pass the semaphore in same time as the fence we use to meter rendering.
1696 const vector<SemaphoreSp> imageReadySemaphores(createSemaphores(vkd, *groupDevice, maxQueuedFrames + 1));
1697
1698 // For rest we simply need maxQueuedFrames as we will wait for image from frameNdx-maxQueuedFrames
1699 // to become available to us, guaranteeing that previous uses must have completed.
1700 const vector<SemaphoreSp> renderingCompleteSemaphores(createSemaphores(vkd, *groupDevice, maxQueuedFrames));
1701 const vector<CommandBufferSp> commandBuffers(
1702 allocateCommandBuffers(vkd, *groupDevice, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1703
1704 try
1705 {
1706 const uint32_t numFramesToRender = 60 * 10;
1707
1708 for (uint32_t frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1709 {
1710 const VkFence imageReadyFence = **imageReadyFences[frameNdx % imageReadyFences.size()];
1711 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx % imageReadySemaphores.size()];
1712 uint32_t imageNdx = ~0u;
1713
1714 VK_CHECK(
1715 vkd.waitForFences(*groupDevice, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<uint64_t>::max()));
1716 VK_CHECK(vkd.resetFences(*groupDevice, 1, &imageReadyFence));
1717
1718 {
1719 VkAcquireNextImageInfoKHR acquireNextImageInfo = {VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR,
1720 DE_NULL,
1721 *swapchain,
1722 std::numeric_limits<uint64_t>::max(),
1723 imageReadySemaphore,
1724 (VkFence)0,
1725 (1 << firstDeviceID)};
1726
1727 const VkResult acquireResult = vkd.acquireNextImage2KHR(*groupDevice, &acquireNextImageInfo, &imageNdx);
1728
1729 if (acquireResult == VK_SUBOPTIMAL_KHR)
1730 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame "
1731 << frameNdx << TestLog::EndMessage;
1732 else
1733 VK_CHECK(acquireResult);
1734 }
1735
1736 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1737
1738 {
1739 const VkSemaphore renderingCompleteSemaphore =
1740 **renderingCompleteSemaphores[frameNdx % renderingCompleteSemaphores.size()];
1741 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx % commandBuffers.size()];
1742 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1743
1744 // render triangle using one or two subdevices when available
1745 renderer.recordDeviceGroupFrame(commandBuffer, firstDeviceID, secondDeviceID,
1746 physicalDevicesInGroupCount, imageNdx, frameNdx);
1747
1748 // submit queue
1749 uint32_t deviceMask = (1 << firstDeviceID);
1750 std::vector<uint32_t> deviceIndices(1, firstDeviceID);
1751 if (physicalDevicesInGroupCount > 1)
1752 {
1753 deviceMask |= (1 << secondDeviceID);
1754 deviceIndices.push_back(secondDeviceID);
1755 }
1756 const VkDeviceGroupSubmitInfo deviceGroupSubmitInfo = {
1757 VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR, // sType
1758 DE_NULL, // pNext
1759 uint32_t(deviceIndices.size()), // waitSemaphoreCount
1760 &deviceIndices[0], // pWaitSemaphoreDeviceIndices
1761 1u, // commandBufferCount
1762 &deviceMask, // pCommandBufferDeviceMasks
1763 uint32_t(deviceIndices.size()), // signalSemaphoreCount
1764 &deviceIndices[0], // pSignalSemaphoreDeviceIndices
1765 };
1766 const VkSubmitInfo submitInfo = {
1767 VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
1768 &deviceGroupSubmitInfo, // pNext
1769 1u, // waitSemaphoreCount
1770 &imageReadySemaphore, // pWaitSemaphores
1771 &waitDstStage, // pWaitDstStageMask
1772 1u, // commandBufferCount
1773 &commandBuffer, // pCommandBuffers
1774 1u, // signalSemaphoreCount
1775 &renderingCompleteSemaphore, // pSignalSemaphores
1776 };
1777 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, imageReadyFence));
1778
1779 // present swapchain image
1780 deviceMask = (1 << firstDeviceID);
1781 const VkDeviceGroupPresentInfoKHR deviceGroupPresentInfo = {
1782 VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR, DE_NULL, 1u, &deviceMask,
1783 VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR,
1784 };
1785 const VkPresentInfoKHR presentInfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1786 &deviceGroupPresentInfo,
1787 1u,
1788 &renderingCompleteSemaphore,
1789 1u,
1790 &*swapchain,
1791 &imageNdx,
1792 (VkResult *)DE_NULL};
1793 VK_CHECK_WSI(vkd.queuePresentKHR(queue, &presentInfo));
1794 }
1795 }
1796
1797 VK_CHECK(vkd.deviceWaitIdle(*groupDevice));
1798 }
1799 catch (...)
1800 {
1801 // Make sure device is idle before destroying resources
1802 vkd.deviceWaitIdle(*groupDevice);
1803 throw;
1804 }
1805
1806 return tcu::TestStatus::pass("Rendering tests succeeded");
1807 }
1808
deviceGroupRenderTest2(Context & context,Type wsiType)1809 tcu::TestStatus deviceGroupRenderTest2(Context &context, Type wsiType)
1810 {
1811 const InstanceHelper instHelper(context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
1812 const tcu::CommandLine &cmdLine = context.getTestContext().getCommandLine();
1813 VkPhysicalDevice physicalDevice = chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
1814 const Extensions &deviceExtensions = enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
1815
1816 // structures this tests checks were added in revision 69
1817 if (!isExtensionStructSupported(deviceExtensions, RequiredExtension("VK_KHR_swapchain", 69)))
1818 TCU_THROW(NotSupportedError, "Required extension revision is not supported");
1819
1820 std::vector<const char *> requiredExtensions;
1821 requiredExtensions.push_back("VK_KHR_swapchain");
1822 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
1823 {
1824 requiredExtensions.push_back("VK_KHR_device_group");
1825 if (!isExtensionStructSupported(deviceExtensions, RequiredExtension("VK_KHR_device_group")))
1826 TCU_THROW(NotSupportedError, "VK_KHR_device_group is not supported");
1827 }
1828
1829 const tcu::UVec2 desiredSize(256, 256);
1830 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1831 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
1832 native.getWindow(), context.getTestContext().getCommandLine()));
1833
1834 const uint32_t devGroupIdx = cmdLine.getVKDeviceGroupId() - 1;
1835 const uint32_t deviceIdx = context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
1836 const vector<VkPhysicalDeviceGroupProperties> deviceGroupProps =
1837 enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
1838 uint32_t physicalDevicesInGroupCount = deviceGroupProps[devGroupIdx].physicalDeviceCount;
1839 const VkPhysicalDevice *physicalDevicesInGroup = deviceGroupProps[devGroupIdx].physicalDevices;
1840 uint32_t queueFamilyIndex = chooseQueueFamilyIndex(instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface);
1841 const std::vector<VkQueueFamilyProperties> queueProps =
1842 getPhysicalDeviceQueueFamilyProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]);
1843 const float queuePriority = 1.0f;
1844 const uint32_t firstDeviceID = 0;
1845 const uint32_t secondDeviceID = 1;
1846 const uint32_t deviceIndices[] = {firstDeviceID, secondDeviceID};
1847
1848 if (physicalDevicesInGroupCount < 2)
1849 TCU_THROW(NotSupportedError, "Test requires more than 1 device in device group");
1850
1851 // create a device group
1852 const VkDeviceGroupDeviceCreateInfo groupDeviceInfo = {
1853 VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR, // stype
1854 DE_NULL, // pNext
1855 physicalDevicesInGroupCount, // physicalDeviceCount
1856 physicalDevicesInGroup // physicalDevices
1857 };
1858 const VkDeviceQueueCreateInfo deviceQueueCreateInfo = {
1859 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // type
1860 DE_NULL, // pNext
1861 (VkDeviceQueueCreateFlags)0u, // flags
1862 queueFamilyIndex, // queueFamilyIndex
1863 1u, // queueCount
1864 &queuePriority, // pQueuePriorities
1865 };
1866
1867 const VkDeviceCreateInfo deviceCreateInfo = {
1868 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
1869 &groupDeviceInfo, // pNext
1870 (VkDeviceCreateFlags)0u, // flags
1871 1, // queueRecordCount
1872 &deviceQueueCreateInfo, // pRequestedQueues
1873 0, // layerCount
1874 DE_NULL, // ppEnabledLayerNames
1875 uint32_t(requiredExtensions.size()), // enabledExtensionCount
1876 &requiredExtensions[0], // ppEnabledExtensionNames
1877 DE_NULL, // pEnabledFeatures
1878 };
1879
1880 Move<VkDevice> groupDevice = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(),
1881 context.getPlatformInterface(), instHelper.instance, instHelper.vki,
1882 physicalDevicesInGroup[deviceIdx], &deviceCreateInfo);
1883 const DeviceDriver vkd(context.getPlatformInterface(), instHelper.instance, *groupDevice,
1884 context.getUsedApiVersion(), context.getTestContext().getCommandLine());
1885 VkQueue queue(getDeviceQueue(vkd, *groupDevice, queueFamilyIndex, 0));
1886 SimpleAllocator allocator(vkd, *groupDevice,
1887 getPhysicalDeviceMemoryProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]));
1888
1889 // create swapchain for device group
1890 const VkSurfaceCapabilitiesKHR capabilities =
1891 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevice, *surface);
1892 const vector<VkSurfaceFormatKHR> formats =
1893 getPhysicalDeviceSurfaceFormats(instHelper.vki, physicalDevice, *surface);
1894 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
1895 const VkSurfaceTransformFlagBitsKHR transform =
1896 (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
1897 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
1898 capabilities.currentTransform;
1899 const uint32_t desiredImageCount = 2;
1900
1901 struct VkDeviceGroupSwapchainCreateInfoKHR deviceGroupSwapchainInfo = {
1902 VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR, DE_NULL, VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR};
1903 const VkSwapchainCreateInfoKHR swapchainInfo = {
1904 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
1905 &deviceGroupSwapchainInfo,
1906 VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR,
1907 *surface,
1908 de::clamp(desiredImageCount, capabilities.minImageCount,
1909 capabilities.maxImageCount > 0 ? capabilities.maxImageCount :
1910 capabilities.minImageCount + desiredImageCount),
1911 formats[0].format,
1912 formats[0].colorSpace,
1913 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ?
1914 capabilities.currentExtent :
1915 vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
1916 1u,
1917 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1918 VK_SHARING_MODE_EXCLUSIVE,
1919 0u,
1920 (const uint32_t *)DE_NULL,
1921 transform,
1922 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1923 VK_PRESENT_MODE_FIFO_KHR,
1924 VK_FALSE,
1925 (VkSwapchainKHR)0};
1926
1927 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(vkd, *groupDevice, &swapchainInfo));
1928 uint32_t numImages = 0;
1929 VK_CHECK(vkd.getSwapchainImagesKHR(*groupDevice, *swapchain, &numImages, DE_NULL));
1930 if (numImages == 0)
1931 return tcu::TestStatus::pass("Pass");
1932
1933 VkImageSwapchainCreateInfoKHR imageSwapchainCreateInfo = {VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
1934 DE_NULL, *swapchain};
1935
1936 VkImageCreateInfo imageCreateInfo = {
1937 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1938 &imageSwapchainCreateInfo,
1939 VK_IMAGE_CREATE_ALIAS_BIT | VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR, // flags
1940 VK_IMAGE_TYPE_2D, // imageType
1941 formats[0].format, // format
1942 {
1943 // extent
1944 desiredSize.x(), // width
1945 desiredSize.y(), // height
1946 1u // depth
1947 },
1948 1u, // mipLevels
1949 1u, // arrayLayers
1950 VK_SAMPLE_COUNT_1_BIT, // samples
1951 VK_IMAGE_TILING_OPTIMAL, // tiling
1952 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // usage
1953 VK_SHARING_MODE_EXCLUSIVE, // sharingMode
1954 0u, // queueFamilyIndexCount
1955 DE_NULL, // pQueueFamilyIndices
1956 VK_IMAGE_LAYOUT_UNDEFINED // initialLayout
1957 };
1958
1959 typedef vk::Unique<VkImage> UniqueImage;
1960 typedef de::SharedPtr<UniqueImage> ImageSp;
1961
1962 vector<ImageSp> images(numImages);
1963 vector<VkImage> rawImages(numImages);
1964 vector<ImageSp> imagesSfr(numImages);
1965 vector<VkImage> rawImagesSfr(numImages);
1966 vector<VkBindImageMemorySwapchainInfoKHR> bindImageMemorySwapchainInfo(numImages);
1967
1968 // Create non-SFR image aliases for image layout transition
1969 {
1970 vector<VkBindImageMemoryInfo> bindImageMemoryInfos(numImages);
1971
1972 for (uint32_t idx = 0; idx < numImages; ++idx)
1973 {
1974 // Create image
1975 images[idx] = ImageSp(new UniqueImage(createImage(vkd, *groupDevice, &imageCreateInfo)));
1976
1977 VkBindImageMemorySwapchainInfoKHR bimsInfo = {VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR,
1978 DE_NULL, *swapchain, idx};
1979 bindImageMemorySwapchainInfo[idx] = bimsInfo;
1980
1981 VkBindImageMemoryInfo bimInfo = {
1982 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, &bindImageMemorySwapchainInfo[idx], **images[idx],
1983 DE_NULL, // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
1984 0u // If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
1985 };
1986 bindImageMemoryInfos[idx] = bimInfo;
1987 rawImages[idx] = **images[idx];
1988 }
1989
1990 VK_CHECK(vkd.bindImageMemory2(*groupDevice, numImages, &bindImageMemoryInfos[0]));
1991 }
1992
1993 // Create the SFR images
1994 {
1995 vector<VkBindImageMemoryDeviceGroupInfo> bindImageMemoryDeviceGroupInfo(numImages);
1996 vector<VkBindImageMemoryInfo> bindImageMemoryInfos(numImages);
1997 for (uint32_t idx = 0; idx < numImages; ++idx)
1998 {
1999 // Create image
2000 imagesSfr[idx] = ImageSp(new UniqueImage(createImage(vkd, *groupDevice, &imageCreateInfo)));
2001
2002 // Split into 2 vertical halves
2003 // NOTE: the same split has to be done also in WsiTriangleRenderer::recordDeviceGroupFrame
2004 const uint32_t halfWidth = desiredSize.x() / 2;
2005 const uint32_t height = desiredSize.y();
2006 const VkRect2D sfrRects[] = {
2007 {{0, 0}, {halfWidth, height}}, // offset, extent
2008 {{(int32_t)halfWidth, 0}, {halfWidth, height}}, // offset, extent
2009 {{0, 0}, {halfWidth, height}}, // offset, extent
2010 {{(int32_t)halfWidth, 0}, {halfWidth, height}} // offset, extent
2011 };
2012
2013 VkBindImageMemoryDeviceGroupInfo bimdgInfo = {VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO,
2014 &bindImageMemorySwapchainInfo[idx],
2015 DE_LENGTH_OF_ARRAY(deviceIndices),
2016 deviceIndices,
2017 DE_LENGTH_OF_ARRAY(sfrRects),
2018 sfrRects};
2019 bindImageMemoryDeviceGroupInfo[idx] = bimdgInfo;
2020
2021 VkBindImageMemoryInfo bimInfo = {
2022 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, &bindImageMemoryDeviceGroupInfo[idx], **imagesSfr[idx],
2023 DE_NULL, // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
2024 0u // If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
2025 };
2026 bindImageMemoryInfos[idx] = bimInfo;
2027 rawImagesSfr[idx] = **imagesSfr[idx];
2028 }
2029
2030 VK_CHECK(vkd.bindImageMemory2(*groupDevice, numImages, &bindImageMemoryInfos[0]));
2031 }
2032
2033 VkPeerMemoryFeatureFlags peerMemoryFeatures = 0u;
2034 vkd.getDeviceGroupPeerMemoryFeatures(*groupDevice, 0, firstDeviceID, secondDeviceID, &peerMemoryFeatures);
2035 bool explicitLayoutTransitions = !(peerMemoryFeatures & VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT) ||
2036 !(peerMemoryFeatures & VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT);
2037
2038 const WsiTriangleRenderer renderer(vkd, *groupDevice, allocator, context.getBinaryCollection(),
2039 explicitLayoutTransitions, rawImagesSfr, rawImages, swapchainInfo.imageFormat,
2040 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
2041
2042 const Unique<VkCommandPool> commandPool(
2043 createCommandPool(vkd, *groupDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2044
2045 const size_t maxQueuedFrames = rawImagesSfr.size() * 2;
2046
2047 // We need to keep hold of fences from vkAcquireNextImage2KHR
2048 // to actually limit number of frames we allow to be queued.
2049 const vector<FenceSp> imageReadyFences(createFences(vkd, *groupDevice, maxQueuedFrames));
2050
2051 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to
2052 // pass the semaphore in same time as the fence we use to meter rendering.
2053 const vector<SemaphoreSp> imageReadySemaphores(createSemaphores(vkd, *groupDevice, maxQueuedFrames + 1));
2054
2055 // For rest we simply need maxQueuedFrames as we will wait for image from frameNdx-maxQueuedFrames
2056 // to become available to us, guaranteeing that previous uses must have completed.
2057 const vector<SemaphoreSp> renderingCompleteSemaphores(createSemaphores(vkd, *groupDevice, maxQueuedFrames));
2058 const vector<CommandBufferSp> commandBuffers(
2059 allocateCommandBuffers(vkd, *groupDevice, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
2060
2061 try
2062 {
2063 const uint32_t numFramesToRender = 60 * 10;
2064
2065 for (uint32_t frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
2066 {
2067 const VkFence imageReadyFence = **imageReadyFences[frameNdx % imageReadyFences.size()];
2068 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx % imageReadySemaphores.size()];
2069 uint32_t imageNdx = ~0u;
2070
2071 VK_CHECK(
2072 vkd.waitForFences(*groupDevice, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<uint64_t>::max()));
2073 VK_CHECK(vkd.resetFences(*groupDevice, 1, &imageReadyFence));
2074
2075 {
2076 VkAcquireNextImageInfoKHR acquireNextImageInfo = {VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR,
2077 DE_NULL,
2078 *swapchain,
2079 std::numeric_limits<uint64_t>::max(),
2080 imageReadySemaphore,
2081 (VkFence)0,
2082 (1 << firstDeviceID)};
2083
2084 const VkResult acquireResult = vkd.acquireNextImage2KHR(*groupDevice, &acquireNextImageInfo, &imageNdx);
2085
2086 if (acquireResult == VK_SUBOPTIMAL_KHR)
2087 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame "
2088 << frameNdx << TestLog::EndMessage;
2089 else
2090 VK_CHECK(acquireResult);
2091 }
2092
2093 TCU_CHECK((size_t)imageNdx < rawImagesSfr.size());
2094
2095 {
2096 const VkSemaphore renderingCompleteSemaphore =
2097 **renderingCompleteSemaphores[frameNdx % renderingCompleteSemaphores.size()];
2098 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx % commandBuffers.size()];
2099 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2100
2101 // render triangle using one or two subdevices when available
2102 renderer.recordDeviceGroupFrame(commandBuffer, firstDeviceID, secondDeviceID,
2103 physicalDevicesInGroupCount, imageNdx, frameNdx);
2104
2105 // submit queue
2106 uint32_t deviceMask = (1 << firstDeviceID) | (1 << secondDeviceID);
2107 const VkDeviceGroupSubmitInfo deviceGroupSubmitInfo = {
2108 VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR, // sType
2109 DE_NULL, // pNext
2110 DE_LENGTH_OF_ARRAY(deviceIndices), // waitSemaphoreCount
2111 deviceIndices, // pWaitSemaphoreDeviceIndices
2112 1u, // commandBufferCount
2113 &deviceMask, // pCommandBufferDeviceMasks
2114 DE_LENGTH_OF_ARRAY(deviceIndices), // signalSemaphoreCount
2115 deviceIndices, // pSignalSemaphoreDeviceIndices
2116 };
2117 const VkSubmitInfo submitInfo = {
2118 VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
2119 &deviceGroupSubmitInfo, // pNext
2120 1u, // waitSemaphoreCount
2121 &imageReadySemaphore, // pWaitSemaphores
2122 &waitDstStage, // pWaitDstStageMask
2123 1u, // commandBufferCount
2124 &commandBuffer, // pCommandBuffers
2125 1u, // signalSemaphoreCount
2126 &renderingCompleteSemaphore, // pSignalSemaphores
2127 };
2128 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, imageReadyFence));
2129
2130 // present swapchain image - asume that first device has a presentation engine
2131 deviceMask = (1 << firstDeviceID);
2132 const VkDeviceGroupPresentInfoKHR deviceGroupPresentInfo = {
2133 VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR, DE_NULL, 1u, &deviceMask,
2134 VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR,
2135 };
2136 const VkPresentInfoKHR presentInfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2137 &deviceGroupPresentInfo,
2138 1u,
2139 &renderingCompleteSemaphore,
2140 1u,
2141 &*swapchain,
2142 &imageNdx,
2143 (VkResult *)DE_NULL};
2144 VK_CHECK(vkd.queuePresentKHR(queue, &presentInfo));
2145 }
2146 }
2147
2148 VK_CHECK(vkd.deviceWaitIdle(*groupDevice));
2149 }
2150 catch (...)
2151 {
2152 // Make sure device is idle before destroying resources
2153 vkd.deviceWaitIdle(*groupDevice);
2154 throw;
2155 }
2156
2157 return tcu::TestStatus::pass("Rendering tests succeeded");
2158 }
2159
getSwapchainSizeSequence(const VkSurfaceCapabilitiesKHR & capabilities,const tcu::UVec2 & defaultSize)2160 vector<tcu::UVec2> getSwapchainSizeSequence(const VkSurfaceCapabilitiesKHR &capabilities, const tcu::UVec2 &defaultSize)
2161 {
2162 vector<tcu::UVec2> sizes(3);
2163 sizes[0] = defaultSize / 2u;
2164 sizes[1] = defaultSize;
2165 sizes[2] = defaultSize * 2u;
2166
2167 for (uint32_t i = 0; i < sizes.size(); ++i)
2168 {
2169 sizes[i].x() = de::clamp(sizes[i].x(), capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
2170 sizes[i].y() = de::clamp(sizes[i].y(), capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
2171 }
2172
2173 return sizes;
2174 }
2175
resizeSwapchainTest(Context & context,Type wsiType)2176 tcu::TestStatus resizeSwapchainTest(Context &context, Type wsiType)
2177 {
2178 const tcu::UVec2 desiredSize(256, 256);
2179 const InstanceHelper instHelper(context, wsiType);
2180 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2181 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2182 native.getWindow(), context.getTestContext().getCommandLine()));
2183 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2184 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
2185 const VkSurfaceCapabilitiesKHR capabilities =
2186 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
2187 const DeviceInterface &vkd = devHelper.vkd;
2188 const VkDevice device = *devHelper.device;
2189 SimpleAllocator allocator(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
2190 vector<tcu::UVec2> sizes = getSwapchainSizeSequence(capabilities, desiredSize);
2191 Move<VkSwapchainKHR> prevSwapchain;
2192
2193 DE_ASSERT(platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE);
2194 DE_UNREF(platformProperties);
2195
2196 for (uint32_t sizeNdx = 0; sizeNdx < sizes.size(); ++sizeNdx)
2197 {
2198 // \todo [2016-05-30 jesse] This test currently waits for idle and
2199 // recreates way more than necessary when recreating the swapchain. Make
2200 // it match expected real app behavior better by smoothly switching from
2201 // old to new swapchain. Once that is done, it will also be possible to
2202 // test creating a new swapchain while images from the previous one are
2203 // still acquired.
2204
2205 VkSwapchainCreateInfoKHR swapchainInfo =
2206 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, sizes[sizeNdx], 2);
2207 swapchainInfo.oldSwapchain = *prevSwapchain;
2208
2209 Move<VkSwapchainKHR> swapchain(createSwapchainKHR(vkd, device, &swapchainInfo));
2210 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
2211 const WsiTriangleRenderer renderer(
2212 vkd, device, allocator, context.getBinaryCollection(), false, swapchainImages, swapchainImages,
2213 swapchainInfo.imageFormat, tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
2214 const Unique<VkCommandPool> commandPool(createCommandPool(
2215 vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
2216 const size_t maxQueuedFrames = swapchainImages.size() * 2;
2217
2218 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
2219 // limit number of frames we allow to be queued.
2220 const vector<FenceSp> imageReadyFences(createFences(vkd, device, maxQueuedFrames));
2221
2222 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
2223 // the semaphore in same time as the fence we use to meter rendering.
2224 const vector<SemaphoreSp> imageReadySemaphores(createSemaphores(vkd, device, maxQueuedFrames + 1));
2225
2226 // For rest we simply need maxQueuedFrames as we will wait for image
2227 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
2228 // previous uses must have completed.
2229 const vector<SemaphoreSp> renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames));
2230 const vector<CommandBufferSp> commandBuffers(
2231 allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
2232
2233 try
2234 {
2235 const uint32_t numFramesToRender = 60;
2236
2237 for (uint32_t frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
2238 {
2239 const VkFence imageReadyFence = **imageReadyFences[frameNdx % imageReadyFences.size()];
2240 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx % imageReadySemaphores.size()];
2241 uint32_t imageNdx = ~0u;
2242
2243 VK_CHECK(
2244 vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<uint64_t>::max()));
2245 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
2246
2247 {
2248 const VkResult acquireResult =
2249 vkd.acquireNextImageKHR(device, *swapchain, std::numeric_limits<uint64_t>::max(),
2250 imageReadySemaphore, DE_NULL, &imageNdx);
2251
2252 if (acquireResult == VK_SUBOPTIMAL_KHR)
2253 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame "
2254 << frameNdx << TestLog::EndMessage;
2255 else
2256 VK_CHECK(acquireResult);
2257 }
2258
2259 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
2260
2261 {
2262 const VkSemaphore renderingCompleteSemaphore =
2263 **renderingCompleteSemaphores[frameNdx % renderingCompleteSemaphores.size()];
2264 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx % commandBuffers.size()];
2265 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2266 const VkSubmitInfo submitInfo = {VK_STRUCTURE_TYPE_SUBMIT_INFO,
2267 DE_NULL,
2268 1u,
2269 &imageReadySemaphore,
2270 &waitDstStage,
2271 1u,
2272 &commandBuffer,
2273 1u,
2274 &renderingCompleteSemaphore};
2275 const VkPresentInfoKHR presentInfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2276 DE_NULL,
2277 1u,
2278 &renderingCompleteSemaphore,
2279 1u,
2280 &*swapchain,
2281 &imageNdx,
2282 (VkResult *)DE_NULL};
2283
2284 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
2285 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
2286 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
2287 }
2288 }
2289
2290 VK_CHECK(vkd.deviceWaitIdle(device));
2291
2292 prevSwapchain = swapchain;
2293 }
2294 catch (...)
2295 {
2296 // Make sure device is idle before destroying resources
2297 vkd.deviceWaitIdle(device);
2298 throw;
2299 }
2300 }
2301
2302 return tcu::TestStatus::pass("Resizing tests succeeded");
2303 }
2304
getImagesIncompleteResultTest(Context & context,Type wsiType)2305 tcu::TestStatus getImagesIncompleteResultTest(Context &context, Type wsiType)
2306 {
2307 const tcu::UVec2 desiredSize(256, 256);
2308 const InstanceHelper instHelper(context, wsiType);
2309 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2310 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2311 native.getWindow(), context.getTestContext().getCommandLine()));
2312 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2313 const VkSwapchainCreateInfoKHR swapchainInfo =
2314 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2315 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2316
2317 vector<VkImage> swapchainImages = getSwapchainImages(devHelper.vkd, *devHelper.device, *swapchain);
2318
2319 ValidateQueryBits::fillBits(swapchainImages.begin(), swapchainImages.end());
2320
2321 const uint32_t usedCount = static_cast<uint32_t>(swapchainImages.size() / 2);
2322 uint32_t count = usedCount;
2323 const VkResult result =
2324 devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &count, &swapchainImages[0]);
2325
2326 if (count != usedCount || result != VK_INCOMPLETE ||
2327 !ValidateQueryBits::checkBits(swapchainImages.begin() + count, swapchainImages.end()))
2328 return tcu::TestStatus::fail("Get swapchain images didn't return VK_INCOMPLETE");
2329 else
2330 return tcu::TestStatus::pass("Get swapchain images tests succeeded");
2331 }
2332
getImagesResultsCountTest(Context & context,Type wsiType)2333 tcu::TestStatus getImagesResultsCountTest(Context &context, Type wsiType)
2334 {
2335 const tcu::UVec2 desiredSize(256, 256);
2336 const InstanceHelper instHelper(context, wsiType);
2337 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2338 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2339 native.getWindow(), context.getTestContext().getCommandLine()));
2340 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2341 const VkSwapchainCreateInfoKHR swapchainInfo =
2342 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2343 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2344
2345 uint32_t numImages = 0;
2346
2347 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2348
2349 if (numImages > 0)
2350 {
2351 std::vector<VkImage> images(numImages + 1);
2352 const uint32_t numImagesOrig = numImages;
2353
2354 // check if below call properly overwrites formats count
2355 numImages++;
2356
2357 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, &images[0]));
2358
2359 if ((size_t)numImages != numImagesOrig)
2360 TCU_FAIL("Image count changed between calls");
2361 }
2362 return tcu::TestStatus::pass("Get swapchain images tests succeeded");
2363 }
2364
destroyNullHandleSwapchainTest(Context & context,Type wsiType)2365 tcu::TestStatus destroyNullHandleSwapchainTest(Context &context, Type wsiType)
2366 {
2367 const InstanceHelper instHelper(context, wsiType);
2368 const NativeObjects native(context, instHelper.supportedExtensions, wsiType);
2369 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2370 native.getWindow(), context.getTestContext().getCommandLine()));
2371 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2372 const VkSwapchainKHR nullHandle = DE_NULL;
2373
2374 // Default allocator
2375 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, DE_NULL);
2376
2377 // Custom allocator
2378 {
2379 AllocationCallbackRecorder recordingAllocator(getSystemAllocator(), 1u);
2380
2381 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, recordingAllocator.getCallbacks());
2382
2383 if (recordingAllocator.getNumRecords() != 0u)
2384 return tcu::TestStatus::fail("Implementation allocated/freed the memory");
2385 }
2386
2387 return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
2388 }
2389
destroyOldSwapchainTest(Context & context,Type wsiType)2390 tcu::TestStatus destroyOldSwapchainTest(Context &context, Type wsiType)
2391 {
2392 const tcu::UVec2 desiredSize(256, 256);
2393 const InstanceHelper instHelper(context, wsiType);
2394 const NativeObjects native(context, instHelper.supportedExtensions, wsiType);
2395 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2396 native.getWindow(), context.getTestContext().getCommandLine()));
2397 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2398
2399 // Create the first swapchain.
2400 VkSwapchainCreateInfoKHR swapchainInfo =
2401 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2402 VkSwapchainKHR swapchain = 0;
2403 VK_CHECK(devHelper.vkd.createSwapchainKHR(*devHelper.device, &swapchainInfo, DE_NULL, &swapchain));
2404
2405 // Create a new swapchain replacing the old one.
2406 swapchainInfo.oldSwapchain = swapchain;
2407 VkSwapchainKHR recreatedSwapchain = 0;
2408 VK_CHECK(devHelper.vkd.createSwapchainKHR(*devHelper.device, &swapchainInfo, DE_NULL, &recreatedSwapchain));
2409
2410 // Destroying the old swapchain should have no effect.
2411 devHelper.vkd.destroySwapchainKHR(*devHelper.device, swapchain, DE_NULL);
2412
2413 // Destroy the new swapchain for cleanup.
2414 devHelper.vkd.destroySwapchainKHR(*devHelper.device, recreatedSwapchain, DE_NULL);
2415
2416 return tcu::TestStatus::pass("Destroying an old swapchain has no effect.");
2417 }
2418
acquireTooManyTest(Context & context,Type wsiType)2419 tcu::TestStatus acquireTooManyTest(Context &context, Type wsiType)
2420 {
2421 const tcu::UVec2 desiredSize(256, 256);
2422 const InstanceHelper instHelper(context, wsiType);
2423 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
2424 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2425 native.getWindow(), context.getTestContext().getCommandLine()));
2426 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2427 const VkSwapchainCreateInfoKHR swapchainInfo =
2428 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2429 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2430
2431 uint32_t numImages;
2432 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2433 const uint32_t minImageCount =
2434 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface).minImageCount;
2435 if (numImages < minImageCount)
2436 return tcu::TestStatus::fail("Get swapchain images returned less than minImageCount images");
2437 const uint32_t numAcquirableImages = numImages - minImageCount + 1;
2438
2439 const auto fences = createFences(devHelper.vkd, *devHelper.device, numAcquirableImages + 1, false);
2440 uint32_t unused;
2441
2442 for (uint32_t i = 0; i < numAcquirableImages; ++i)
2443 {
2444 VK_CHECK_WSI(devHelper.vkd.acquireNextImageKHR(
2445 *devHelper.device, *swapchain, std::numeric_limits<uint64_t>::max(), (VkSemaphore)0, **fences[i], &unused));
2446 }
2447
2448 const auto result = devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, 0, (VkSemaphore)0,
2449 **fences[numAcquirableImages], &unused);
2450
2451 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR && result != VK_NOT_READY)
2452 {
2453 return tcu::TestStatus::fail("Implementation failed to respond well acquiring too many images with 0 timeout");
2454 }
2455
2456 // cleanup
2457 const uint32_t numFences =
2458 (result == VK_NOT_READY) ? static_cast<uint32_t>(fences.size() - 1) : static_cast<uint32_t>(fences.size());
2459 vector<vk::VkFence> fencesRaw(numFences);
2460 std::transform(fences.begin(), fences.begin() + numFences, fencesRaw.begin(),
2461 [](const FenceSp &f) -> vk::VkFence { return **f; });
2462 VK_CHECK(devHelper.vkd.waitForFences(*devHelper.device, numFences, fencesRaw.data(), VK_TRUE,
2463 std::numeric_limits<uint64_t>::max()));
2464
2465 return tcu::TestStatus::pass("Acquire too many swapchain images test succeeded");
2466 }
2467
acquireTooManyTimeoutTest(Context & context,Type wsiType)2468 tcu::TestStatus acquireTooManyTimeoutTest(Context &context, Type wsiType)
2469 {
2470 const tcu::UVec2 desiredSize(256, 256);
2471 const InstanceHelper instHelper(context, wsiType);
2472 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
2473 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2474 native.getWindow(), context.getTestContext().getCommandLine()));
2475 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2476 const VkSwapchainCreateInfoKHR swapchainInfo =
2477 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2478 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2479
2480 uint32_t numImages;
2481 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2482 const uint32_t minImageCount =
2483 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface).minImageCount;
2484 if (numImages < minImageCount)
2485 return tcu::TestStatus::fail("Get swapchain images returned less than minImageCount images");
2486 const uint32_t numAcquirableImages = numImages - minImageCount + 1;
2487
2488 const auto fences = createFences(devHelper.vkd, *devHelper.device, numAcquirableImages + 1, false);
2489 uint32_t unused;
2490
2491 for (uint32_t i = 0; i < numAcquirableImages; ++i)
2492 {
2493 VK_CHECK_WSI(devHelper.vkd.acquireNextImageKHR(
2494 *devHelper.device, *swapchain, std::numeric_limits<uint64_t>::max(), (VkSemaphore)0, **fences[i], &unused));
2495 }
2496
2497 const uint64_t millisecond = 1000000;
2498 const uint64_t timeout = 50 * millisecond; // arbitrary realistic non-0 non-infinite timeout
2499 const auto result = devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, timeout, (VkSemaphore)0,
2500 **fences[numAcquirableImages], &unused);
2501
2502 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR && result != VK_TIMEOUT)
2503 {
2504 return tcu::TestStatus::fail("Implementation failed to respond well acquiring too many images with timeout");
2505 }
2506
2507 // cleanup
2508 const uint32_t numFences =
2509 (result == VK_TIMEOUT) ? static_cast<uint32_t>(fences.size() - 1) : static_cast<uint32_t>(fences.size());
2510 vector<vk::VkFence> fencesRaw(numFences);
2511 std::transform(fences.begin(), fences.begin() + numFences, fencesRaw.begin(),
2512 [](const FenceSp &f) -> vk::VkFence { return **f; });
2513 VK_CHECK(devHelper.vkd.waitForFences(*devHelper.device, numFences, fencesRaw.data(), VK_TRUE,
2514 std::numeric_limits<uint64_t>::max()));
2515
2516 return tcu::TestStatus::pass("Acquire too many swapchain images test succeeded");
2517 }
2518
getBasicRenderPrograms(SourceCollections & dst,Type)2519 void getBasicRenderPrograms(SourceCollections &dst, Type)
2520 {
2521 WsiTriangleRenderer::getPrograms(dst);
2522 }
2523
getBasicRenderPrograms(SourceCollections & dst,MultiSwapchainParams)2524 void getBasicRenderPrograms(SourceCollections &dst, MultiSwapchainParams)
2525 {
2526 WsiTriangleRenderer::getPrograms(dst);
2527 }
2528
populateRenderGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2529 void populateRenderGroup(tcu::TestCaseGroup *testGroup, Type wsiType)
2530 {
2531 // Basic Rendering Test
2532 addFunctionCaseWithPrograms(testGroup, "basic", getBasicRenderPrograms, basicRenderTest<AcquireNextImageWrapper>,
2533 wsiType);
2534 // Basic Rendering Test using AcquireNextImage2
2535 addFunctionCaseWithPrograms(testGroup, "basic2", getBasicRenderPrograms, basicRenderTest<AcquireNextImage2Wrapper>,
2536 wsiType);
2537 // Basic Rendering Test using device_group
2538 addFunctionCaseWithPrograms(testGroup, "device_group", getBasicRenderPrograms, deviceGroupRenderTest, wsiType);
2539 // Rendering Test using device_group and VkImageSwapchainCreateInfo
2540 addFunctionCaseWithPrograms(testGroup, "device_group2", getBasicRenderPrograms, deviceGroupRenderTest2, wsiType);
2541
2542 const MultiSwapchainParams kTwoSwapchains{wsiType, 2u};
2543 const MultiSwapchainParams kTenSwapchains{wsiType, 10u};
2544
2545 // 2 Swapchains Rendering Test
2546 addFunctionCaseWithPrograms(testGroup, "2swapchains", getBasicRenderPrograms,
2547 multiSwapchainRenderTest<AcquireNextImageWrapper>, kTwoSwapchains);
2548 // 2 Swapchains Rendering Test using AcquireNextImage2
2549 addFunctionCaseWithPrograms(testGroup, "2swapchains2", getBasicRenderPrograms,
2550 multiSwapchainRenderTest<AcquireNextImage2Wrapper>, kTwoSwapchains);
2551 // 10 Swapchains Rendering Test
2552 addFunctionCaseWithPrograms(testGroup, "10swapchains", getBasicRenderPrograms,
2553 multiSwapchainRenderTest<AcquireNextImageWrapper>, kTenSwapchains);
2554 // 10 Swapchains Rendering Test using AcquireNextImage2
2555 addFunctionCaseWithPrograms(testGroup, "10swapchains2", getBasicRenderPrograms,
2556 multiSwapchainRenderTest<AcquireNextImage2Wrapper>, kTenSwapchains);
2557 }
2558
populateGetImagesGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2559 void populateGetImagesGroup(tcu::TestCaseGroup *testGroup, Type wsiType)
2560 {
2561 // Test VK_INCOMPLETE return code
2562 addFunctionCase(testGroup, "incomplete", getImagesIncompleteResultTest, wsiType);
2563 // Test proper count of images
2564 addFunctionCase(testGroup, "count", getImagesResultsCountTest, wsiType);
2565 }
2566
populateModifyGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2567 void populateModifyGroup(tcu::TestCaseGroup *testGroup, Type wsiType)
2568 {
2569 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
2570
2571 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
2572 {
2573 // Resize Swapchain Test
2574 addFunctionCaseWithPrograms(testGroup, "resize", getBasicRenderPrograms, resizeSwapchainTest, wsiType);
2575 }
2576
2577 // \todo [2016-05-30 jesse] Add tests for modifying preTransform, compositeAlpha, presentMode
2578 }
2579
populateDestroyGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2580 void populateDestroyGroup(tcu::TestCaseGroup *testGroup, Type wsiType)
2581 {
2582 // Destroying a VK_NULL_HANDLE swapchain
2583 addFunctionCase(testGroup, "null_handle", destroyNullHandleSwapchainTest, wsiType);
2584 // Destroying an old swapchain
2585 addFunctionCase(testGroup, "old_swapchain", destroyOldSwapchainTest, wsiType);
2586 }
2587
populateAcquireGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2588 void populateAcquireGroup(tcu::TestCaseGroup *testGroup, Type wsiType)
2589 {
2590 // Test acquiring too many images with 0 timeout
2591 addFunctionCase(testGroup, "too_many", acquireTooManyTest, wsiType);
2592 // Test acquiring too many images with timeout
2593 addFunctionCase(testGroup, "too_many_timeout", acquireTooManyTimeoutTest, wsiType);
2594 }
2595
2596 } // namespace
2597
createSwapchainTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)2598 void createSwapchainTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
2599 {
2600 // Create VkSwapchain with various parameters
2601 addTestGroup(testGroup, "create", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
2602 // Simulate OOM using callbacks during swapchain construction
2603 addTestGroup(testGroup, "simulate_oom", populateSwapchainGroup,
2604 GroupParameters(wsiType, createSwapchainSimulateOOMTest));
2605 // Rendering Tests
2606 addTestGroup(testGroup, "render", populateRenderGroup, wsiType);
2607 // Modify VkSwapchain
2608 addTestGroup(testGroup, "modify", populateModifyGroup, wsiType);
2609 // Destroy VkSwapchain
2610 addTestGroup(testGroup, "destroy", populateDestroyGroup, wsiType);
2611 // Get swapchain images
2612 addTestGroup(testGroup, "get_images", populateGetImagesGroup, wsiType);
2613 // Ancquire next swapchain image
2614 addTestGroup(testGroup, "acquire", populateAcquireGroup, wsiType);
2615 // Create VkSwapchain and use VK_EXT_private_data
2616 addTestGroup(testGroup, "private_data", populateSwapchainPrivateDataGroup,
2617 GroupParameters(wsiType, createSwapchainPrivateDataTest));
2618 }
2619
2620 } // namespace wsi
2621 } // namespace vkt
2622