• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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