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