Test behaviour of color write enable with colorWriteMask
[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                 const VkSurfaceCapabilitiesKHR                  capabilities(getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface));
952
953                 if (maxCases < allCases.size())
954                         log << TestLog::Message << "Note: Will only test first " << maxCases << " cases out of total of " << allCases.size() << " parameter combinations" << TestLog::EndMessage;
955
956                 for (size_t caseNdx = 0; caseNdx < de::min(maxCases, allCases.size()); ++caseNdx)
957                 {
958                         log << TestLog::Message << "Testing parameter case " << caseNdx << ": " << allCases[caseNdx] << TestLog::EndMessage;
959
960                         for (deUint32 numPassingAllocs = 0; numPassingAllocs <= maxAllocs; ++numPassingAllocs)
961                         {
962                                 bool                                            gotOOM          = false;
963                                 VkSwapchainCreateInfoKHR        curParams       = allCases[caseNdx];
964                                 curParams.surface                               = *surface;
965                                 curParams.queueFamilyIndexCount = 1u;
966                                 curParams.pQueueFamilyIndices   = &devHelper.queueFamilyIndex;
967
968                                 failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
969
970                                 log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
971
972                                 try
973                                 {
974                                         // With concurrent sharing mode, at least two queues are needed.
975                                         if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
976                                                 continue;
977
978                                         const Unique<VkSwapchainKHR>    swapchain       (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
979                                 }
980                                 catch (const OutOfMemoryError& e)
981                                 {
982                                         log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
983                                         gotOOM = true;
984                                 }
985
986                                 if (!gotOOM)
987                                 {
988                                         log << TestLog::Message << "Creating swapchain succeeded!" << TestLog::EndMessage;
989
990                                         if (numPassingAllocs == 0)
991                                                 results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
992
993                                         break;
994                                 }
995                                 else if (numPassingAllocs == maxAllocs)
996                                 {
997                                         // The maxExtents case might not be able to create the requested surface due to insufficient
998                                         // memory, so in this case *only* we allow the OOM exception upto maxAllocs.
999                                         if (params.dimension == TEST_DIMENSION_IMAGE_EXTENT &&
1000                                                 capabilities.maxImageExtent.width == curParams.imageExtent.width &&
1001                                                 capabilities.maxImageExtent.height == curParams.imageExtent.height)
1002                                                 break;
1003
1004                                         results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
1005                                 }
1006                         }
1007
1008                         context.getTestContext().touchWatchdog();
1009                 }
1010         }
1011
1012         if (!validateAndLog(log, allocationRecorder, 0u))
1013                 results.fail("Detected invalid system allocation callback");
1014
1015         return tcu::TestStatus(results.getResult(), results.getMessage());
1016 }
1017
1018 tcu::TestStatus testImageSwapchainCreateInfo (Context& context, Type wsiType)
1019 {
1020         const tcu::UVec2                        desiredSize                     (256, 256);
1021         const InstanceHelper            instHelper                      (context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
1022         const NativeObjects                     native                          (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1023         const Unique<VkSurfaceKHR>      surface                         (createSurface(instHelper.vki,
1024                                                                                                                                    instHelper.instance,
1025                                                                                                                                    wsiType,
1026                                                                                                                                    native.getDisplay(),
1027                                                                                                                                    native.getWindow()));
1028         const DeviceHelper                      devHelper                       (context, instHelper.vki, instHelper.instance, *surface, vector<string>(1u, "VK_KHR_bind_memory2"));
1029         const Extensions&                       deviceExtensions        = enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL);
1030
1031         // structures this tests checks were added in revision 69
1032         if (!isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_swapchain", 69)))
1033                 TCU_THROW(NotSupportedError, "Required extension revision is not supported");
1034
1035         const VkSurfaceCapabilitiesKHR          capabilities            = getPhysicalDeviceSurfaceCapabilities(instHelper.vki,
1036                                                                                                                                                                                                    devHelper.physicalDevice,
1037                                                                                                                                                                                                    *surface);
1038         const vector<VkSurfaceFormatKHR>        formats                         = getPhysicalDeviceSurfaceFormats(instHelper.vki,
1039                                                                                                                                                                                           devHelper.physicalDevice,
1040                                                                                                                                                                                           *surface);
1041         const PlatformProperties&                       platformProperties      = getPlatformProperties(wsiType);
1042         const VkSurfaceTransformFlagBitsKHR transform                   = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
1043         const deUint32                                          desiredImageCount       = 2;
1044         const VkSwapchainCreateInfoKHR          swapchainInfo           =
1045         {
1046                 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
1047                 DE_NULL,
1048                 (VkSwapchainCreateFlagsKHR)0,
1049                 *surface,
1050                 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
1051                 formats[0].format,
1052                 formats[0].colorSpace,
1053                 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
1054                         ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
1055                 1u,
1056                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1057                 VK_SHARING_MODE_EXCLUSIVE,
1058                 0u,
1059                 (const deUint32*)DE_NULL,
1060                 transform,
1061                 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1062                 VK_PRESENT_MODE_FIFO_KHR,
1063                 VK_FALSE,                                                       // clipped
1064                 (VkSwapchainKHR)0                                       // oldSwapchain
1065         };
1066
1067         const Unique<VkSwapchainKHR>    swapchain       (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
1068         deUint32                                                numImages       = 0;
1069         VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
1070         if (numImages == 0)
1071                 return tcu::TestStatus::pass("Pass");
1072
1073         VkImageSwapchainCreateInfoKHR imageSwapchainCreateInfo =
1074         {
1075                 VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
1076                 DE_NULL,
1077                 *swapchain
1078         };
1079
1080         VkImageCreateInfo imageCreateInfo =
1081         {
1082                 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1083                 &imageSwapchainCreateInfo,
1084                 (VkImageCreateFlags)0u,                                 // flags
1085                 VK_IMAGE_TYPE_2D,                                               // imageType
1086                 formats[0].format,                                              // format
1087                 {                                                                               // extent
1088                         desiredSize.x(),                                        //   width
1089                         desiredSize.y(),                                        //   height
1090                         1u                                                                      //   depth
1091                 },
1092                 1u,                                                                             // mipLevels
1093                 1u,                                                                             // arrayLayers
1094                 VK_SAMPLE_COUNT_1_BIT,                                  // samples
1095                 VK_IMAGE_TILING_OPTIMAL,                                // tiling
1096                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,    // usage
1097                 VK_SHARING_MODE_EXCLUSIVE,                              // sharingMode
1098                 0u,                                                                             // queueFamilyIndexCount
1099                 DE_NULL,                                                                // pQueueFamilyIndices
1100                 VK_IMAGE_LAYOUT_UNDEFINED                               // initialLayout
1101         };
1102
1103         typedef vk::Unique<VkImage>                     UniqueImage;
1104         typedef de::SharedPtr<UniqueImage>      ImageSp;
1105
1106         std::vector<ImageSp>                                                    images                                          (numImages);
1107         std::vector<VkBindImageMemorySwapchainInfoKHR>  bindImageMemorySwapchainInfo(numImages);
1108         std::vector<VkBindImageMemoryInfo>                              bindImageMemoryInfos            (numImages);
1109
1110         for (deUint32 idx = 0; idx < numImages; ++idx)
1111         {
1112                 // Create image
1113                 images[idx] = ImageSp(new UniqueImage(createImage(devHelper.vkd, *devHelper.device, &imageCreateInfo)));
1114
1115                 VkBindImageMemorySwapchainInfoKHR bimsInfo =
1116                 {
1117                         VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR,
1118                         DE_NULL,
1119                         *swapchain,
1120                         idx
1121                 };
1122                 bindImageMemorySwapchainInfo[idx] = bimsInfo;
1123
1124                 VkBindImageMemoryInfo bimInfo =
1125                 {
1126                         VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
1127                         &bindImageMemorySwapchainInfo[idx],
1128                         **images[idx],
1129                         DE_NULL,                                // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
1130                         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.
1131                 };
1132
1133                 bindImageMemoryInfos[idx] = bimInfo;
1134         }
1135
1136         VK_CHECK(devHelper.vkd.bindImageMemory2(*devHelper.device, numImages, &bindImageMemoryInfos[0]));
1137
1138         return tcu::TestStatus::pass("Pass");
1139 }
1140
1141 struct GroupParameters
1142 {
1143         typedef FunctionInstance1<TestParameters>::Function     Function;
1144
1145         Type            wsiType;
1146         Function        function;
1147
1148         GroupParameters (Type wsiType_, Function function_)
1149                 : wsiType       (wsiType_)
1150                 , function      (function_)
1151         {}
1152
1153         GroupParameters (void)
1154                 : wsiType       (TYPE_LAST)
1155                 , function      ((Function)DE_NULL)
1156         {}
1157 };
1158
1159 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
1160 {
1161         for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
1162         {
1163                 const TestDimension             testDimension   = (TestDimension)dimensionNdx;
1164
1165                 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
1166         }
1167
1168         addFunctionCase(testGroup, "image_swapchain_create_info", "Test VkImageSwapchainCreateInfoKHR", testImageSwapchainCreateInfo, params.wsiType);
1169 }
1170
1171 void populateSwapchainPrivateDataGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
1172 {
1173         for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
1174         {
1175                 const TestDimension             testDimension   = (TestDimension)dimensionNdx;
1176                 if (testDimension == TEST_DIMENSION_IMAGE_EXTENT)
1177                         continue;
1178
1179                 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
1180         }
1181 }
1182
1183 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type                                              wsiType,
1184                                                                                                           const InstanceInterface&      vki,
1185                                                                                                           VkPhysicalDevice                      physicalDevice,
1186                                                                                                           VkSurfaceKHR                          surface,
1187                                                                                                           const tcu::UVec2&                     desiredSize,
1188                                                                                                           deUint32                                      desiredImageCount)
1189 {
1190         const VkSurfaceCapabilitiesKHR          capabilities            = getPhysicalDeviceSurfaceCapabilities(vki,
1191                                                                                                                                                                                                    physicalDevice,
1192                                                                                                                                                                                                    surface);
1193         const vector<VkSurfaceFormatKHR>        formats                         = getPhysicalDeviceSurfaceFormats(vki,
1194                                                                                                                                                                                           physicalDevice,
1195                                                                                                                                                                                           surface);
1196         const PlatformProperties&                       platformProperties      = getPlatformProperties(wsiType);
1197         const VkSurfaceTransformFlagBitsKHR transform                   = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
1198         const VkSwapchainCreateInfoKHR          parameters                      =
1199         {
1200                 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
1201                 DE_NULL,
1202                 (VkSwapchainCreateFlagsKHR)0,
1203                 surface,
1204                 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
1205                 formats[0].format,
1206                 formats[0].colorSpace,
1207                 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
1208                         ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
1209                 1u,                                                                     // imageArrayLayers
1210                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1211                 VK_SHARING_MODE_EXCLUSIVE,
1212                 0u,
1213                 (const deUint32*)DE_NULL,
1214                 transform,
1215                 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1216                 VK_PRESENT_MODE_FIFO_KHR,
1217                 VK_FALSE,                                                       // clipped
1218                 (VkSwapchainKHR)0                                       // oldSwapchain
1219         };
1220
1221         return parameters;
1222 }
1223
1224 typedef de::SharedPtr<Unique<VkCommandBuffer> > CommandBufferSp;
1225 typedef de::SharedPtr<Unique<VkFence> >                 FenceSp;
1226 typedef de::SharedPtr<Unique<VkSemaphore> >             SemaphoreSp;
1227
1228 vector<FenceSp> createFences (const DeviceInterface&    vkd,
1229                                                           const VkDevice                        device,
1230                                                           size_t                                        numFences,
1231                                                           bool                      isSignaled = true)
1232 {
1233         vector<FenceSp> fences(numFences);
1234
1235         for (size_t ndx = 0; ndx < numFences; ++ndx)
1236                 fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device, (isSignaled) ? vk::VK_FENCE_CREATE_SIGNALED_BIT : 0)));
1237
1238         return fences;
1239 }
1240
1241 vector<SemaphoreSp> createSemaphores (const DeviceInterface&    vkd,
1242                                                                           const VkDevice                        device,
1243                                                                           size_t                                        numSemaphores)
1244 {
1245         vector<SemaphoreSp> semaphores(numSemaphores);
1246
1247         for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1248                 semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
1249
1250         return semaphores;
1251 }
1252
1253 vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface&          vkd,
1254                                                                                                 const VkDevice                          device,
1255                                                                                                 const VkCommandPool                     commandPool,
1256                                                                                                 const VkCommandBufferLevel      level,
1257                                                                                                 const size_t                            numCommandBuffers)
1258 {
1259         vector<CommandBufferSp>                         buffers         (numCommandBuffers);
1260
1261         for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1262                 buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1263
1264         return buffers;
1265 }
1266
1267 class AcquireNextImageWrapper
1268 {
1269 public:
1270
1271         AcquireNextImageWrapper(const DeviceInterface&  vkd,
1272                                                         VkDevice                                device,
1273                                                         deUint32                                deviceMask,
1274                                                         VkSwapchainKHR                  swapchain,
1275                                                         deUint64                                timeout)
1276                 : m_vkd                 (vkd)
1277                 , m_device              (device)
1278                 , m_swapchain   (swapchain)
1279                 , m_timeout             (timeout)
1280         {
1281                 DE_UNREF(deviceMask);   // needed for compatibility with acquireNextImage2KHR
1282         }
1283
1284         bool featureAvailable(Context&)
1285         {
1286                 return true;                    // needed for compatibility with acquireNextImage2KHR
1287         }
1288
1289         VkResult call(VkSemaphore semaphore, VkFence fence, deUint32* imageIndex)
1290         {
1291                 return m_vkd.acquireNextImageKHR(m_device,
1292                                                                                  m_swapchain,
1293                                                                                  m_timeout,
1294                                                                                  semaphore,
1295                                                                                  fence,
1296                                                                                  imageIndex);
1297         }
1298
1299 protected:
1300
1301         const DeviceInterface&  m_vkd;
1302         VkDevice                                m_device;
1303         VkSwapchainKHR                  m_swapchain;
1304         deUint64                                m_timeout;
1305 };
1306
1307 class AcquireNextImage2Wrapper
1308 {
1309 public:
1310
1311         AcquireNextImage2Wrapper(const DeviceInterface& vkd,
1312                                                          VkDevice                               device,
1313                                                          deUint32                               deviceMask,
1314                                                          VkSwapchainKHR                 swapchain,
1315                                                          deUint64                               timeout)
1316                 : m_vkd         (vkd)
1317                 , m_device      (device)
1318         {
1319                 m_info.sType            = VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR;
1320                 m_info.pNext            = DE_NULL;
1321                 m_info.swapchain        = swapchain;
1322                 m_info.timeout          = timeout;
1323                 m_info.semaphore        = DE_NULL;
1324                 m_info.fence            = DE_NULL;
1325                 m_info.deviceMask       = deviceMask;
1326         }
1327
1328         bool featureAvailable(Context& context)
1329         {
1330                 return context.isDeviceFunctionalitySupported("VK_KHR_device_group");
1331         }
1332
1333         VkResult call(VkSemaphore semaphore, VkFence fence, deUint32* imageIndex)
1334         {
1335                 m_info.semaphore        = semaphore;
1336                 m_info.fence            = fence;
1337                 return m_vkd.acquireNextImage2KHR(m_device,
1338                                                                                   &m_info,
1339                                                                                   imageIndex);
1340         }
1341
1342 protected:
1343
1344         const DeviceInterface&          m_vkd;
1345         VkDevice                                        m_device;
1346         VkAcquireNextImageInfoKHR       m_info;
1347 };
1348
1349
1350 template <typename AcquireWrapperType>
1351 tcu::TestStatus basicRenderTest (Context& context, Type wsiType)
1352 {
1353         const tcu::UVec2                                desiredSize                                     (256, 256);
1354         const InstanceHelper                    instHelper                                      (context, wsiType);
1355         const NativeObjects                             native                                          (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1356         const Unique<VkSurfaceKHR>              surface                                         (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
1357         const DeviceHelper                              devHelper                                       (context, instHelper.vki, instHelper.instance, *surface);
1358         const DeviceInterface&                  vkd                                                     = devHelper.vkd;
1359         const VkDevice                                  device                                          = *devHelper.device;
1360         SimpleAllocator                                 allocator                                       (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1361         const VkSwapchainCreateInfoKHR  swapchainInfo                           = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1362         const Unique<VkSwapchainKHR>    swapchain                                       (createSwapchainKHR(vkd, device, &swapchainInfo));
1363         const vector<VkImage>                   swapchainImages                         = getSwapchainImages(vkd, device, *swapchain);
1364
1365         AcquireWrapperType acquireImageWrapper(vkd, device, 1u, *swapchain, std::numeric_limits<deUint64>::max());
1366         if (!acquireImageWrapper.featureAvailable(context))
1367                 TCU_THROW(NotSupportedError, "Required extension is not supported");
1368
1369         const WsiTriangleRenderer               renderer                                        (vkd,
1370                                                                                                                                  device,
1371                                                                                                                                  allocator,
1372                                                                                                                                  context.getBinaryCollection(),
1373                                                                                                                                  false,
1374                                                                                                                                  swapchainImages,
1375                                                                                                                                  swapchainImages,
1376                                                                                                                                  swapchainInfo.imageFormat,
1377                                                                                                                                  tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1378
1379         const Unique<VkCommandPool>             commandPool                                     (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1380
1381         const size_t                                    maxQueuedFrames                         = swapchainImages.size()*2;
1382
1383         // We need to keep hold of fences from vkAcquireNextImage(2)KHR to actually
1384         // limit number of frames we allow to be queued.
1385         const vector<FenceSp>                   imageReadyFences                        (createFences(vkd, device, maxQueuedFrames));
1386
1387         // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1388         // the semaphore in same time as the fence we use to meter rendering.
1389         const vector<SemaphoreSp>               imageReadySemaphores            (createSemaphores(vkd, device, maxQueuedFrames+1));
1390
1391         // For rest we simply need maxQueuedFrames as we will wait for image
1392         // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1393         // previous uses must have completed.
1394         const vector<SemaphoreSp>               renderingCompleteSemaphores     (createSemaphores(vkd, device, maxQueuedFrames));
1395         const vector<CommandBufferSp>   commandBuffers                          (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1396
1397         try
1398         {
1399                 const deUint32  numFramesToRender       = 60*10;
1400
1401                 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1402                 {
1403                         const VkFence           imageReadyFence         = **imageReadyFences[frameNdx%imageReadyFences.size()];
1404                         const VkSemaphore       imageReadySemaphore     = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1405                         deUint32                        imageNdx                        = ~0u;
1406
1407                         VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1408                         VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1409
1410                         {
1411                                 const VkResult  acquireResult   = acquireImageWrapper.call(imageReadySemaphore, (VkFence)0, &imageNdx);
1412
1413                                 if (acquireResult == VK_SUBOPTIMAL_KHR)
1414                                         context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1415                                 else
1416                                         VK_CHECK(acquireResult);
1417                         }
1418
1419                         TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1420
1421                         {
1422                                 const VkSemaphore                       renderingCompleteSemaphore      = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1423                                 const VkCommandBuffer           commandBuffer                           = **commandBuffers[frameNdx%commandBuffers.size()];
1424                                 const VkPipelineStageFlags      waitDstStage                            = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1425                                 const VkSubmitInfo                      submitInfo                                      =
1426                                 {
1427                                         VK_STRUCTURE_TYPE_SUBMIT_INFO,
1428                                         DE_NULL,
1429                                         1u,
1430                                         &imageReadySemaphore,
1431                                         &waitDstStage,
1432                                         1u,
1433                                         &commandBuffer,
1434                                         1u,
1435                                         &renderingCompleteSemaphore
1436                                 };
1437                                 const VkPresentInfoKHR          presentInfo                                     =
1438                                 {
1439                                         VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1440                                         DE_NULL,
1441                                         1u,
1442                                         &renderingCompleteSemaphore,
1443                                         1u,
1444                                         &*swapchain,
1445                                         &imageNdx,
1446                                         (VkResult*)DE_NULL
1447                                 };
1448
1449                                 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1450                                 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
1451                                 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1452                         }
1453                 }
1454
1455                 VK_CHECK(vkd.deviceWaitIdle(device));
1456         }
1457         catch (...)
1458         {
1459                 // Make sure device is idle before destroying resources
1460                 vkd.deviceWaitIdle(device);
1461                 throw;
1462         }
1463
1464         return tcu::TestStatus::pass("Rendering tests succeeded");
1465 }
1466
1467 class FrameStreamObjects
1468 {
1469 public:
1470         struct FrameObjects
1471         {
1472                 const vk::VkFence&                      renderCompleteFence;
1473                 const vk::VkSemaphore&          renderCompleteSemaphore;
1474                 const vk::VkSemaphore&          imageAvailableSemaphore;
1475                 const vk::VkCommandBuffer&      commandBuffer;
1476         };
1477
1478         FrameStreamObjects (const vk::DeviceInterface& vkd, vk::VkDevice device, vk::VkCommandPool cmdPool, size_t maxQueuedFrames)
1479                 : renderingCompleteFences(createFences(vkd, device, maxQueuedFrames))
1480                 , renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
1481                 , imageAvailableSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
1482                 , commandBuffers(allocateCommandBuffers(vkd, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames))
1483                 , m_maxQueuedFrames(maxQueuedFrames)
1484                 , m_nextFrame(0u)
1485         {}
1486
1487         size_t frameNumber (void) const { DE_ASSERT(m_nextFrame > 0u); return m_nextFrame - 1u; }
1488
1489         FrameObjects newFrame ()
1490         {
1491                 const size_t mod = m_nextFrame % m_maxQueuedFrames;
1492                 FrameObjects ret =
1493                 {
1494                         **renderingCompleteFences[mod],
1495                         **renderingCompleteSemaphores[mod],
1496                         **imageAvailableSemaphores[mod],
1497                         **commandBuffers[mod],
1498                 };
1499                 ++m_nextFrame;
1500                 return ret;
1501         }
1502
1503 private:
1504         const vector<FenceSp>                   renderingCompleteFences;
1505         const vector<SemaphoreSp>               renderingCompleteSemaphores;
1506         const vector<SemaphoreSp>               imageAvailableSemaphores;
1507         const vector<CommandBufferSp>   commandBuffers;
1508
1509         const size_t    m_maxQueuedFrames;
1510         size_t                  m_nextFrame;
1511 };
1512
1513 struct MultiSwapchainParams
1514 {
1515         Type    wsiType;
1516         size_t  swapchainCount;
1517 };
1518
1519 struct AccumulatedPresentInfo
1520 {
1521         vector<VkSemaphore>             semaphores;
1522         vector<VkSwapchainKHR>  swapchains;
1523         vector<deUint32>                imageIndices;
1524
1525         AccumulatedPresentInfo ()
1526                 : semaphores(), swapchains(), imageIndices()
1527         {
1528         }
1529
1530         void push_back (VkSemaphore sem, VkSwapchainKHR sc, deUint32 index)
1531         {
1532                 semaphores.push_back(sem);
1533                 swapchains.push_back(sc);
1534                 imageIndices.push_back(index);
1535         }
1536
1537         void reset ()
1538         {
1539                 semaphores.resize(0);
1540                 swapchains.resize(0);
1541                 imageIndices.resize(0);
1542         }
1543
1544         size_t size () const
1545         {
1546                 // Any of the vectors would do.
1547                 return semaphores.size();
1548         }
1549 };
1550
1551 template <typename AcquireWrapperType>
1552 tcu::TestStatus multiSwapchainRenderTest (Context& context, MultiSwapchainParams params)
1553 {
1554         DE_ASSERT(params.swapchainCount > 0);
1555
1556         const tcu::UVec2                desiredSize     (256, 256);
1557         const InstanceHelper    instHelper      (context, params.wsiType);
1558
1559         // Create native window system objects, surfaces and helper surface vector.
1560         std::unique_ptr<NativeObjects> native;
1561         try
1562         {
1563                 native.reset(new NativeObjects(context, instHelper.supportedExtensions, params.wsiType, params.swapchainCount, tcu::just(desiredSize)));
1564         }
1565         catch(tcu::ResourceError&)
1566         {
1567                 std::ostringstream msg;
1568                 msg << "Unable to create " << params.swapchainCount << " windows";
1569                 TCU_THROW(NotSupportedError, msg.str());
1570         }
1571
1572         vector<Move<VkSurfaceKHR>>      surface;
1573         vector<VkSurfaceKHR>            surfaceKHR;     // The plain Vulkan objects from the vector above.
1574
1575         for (size_t i = 0; i < params.swapchainCount; ++i)
1576         {
1577                 surface.emplace_back(createSurface(instHelper.vki, instHelper.instance, params.wsiType, native->getDisplay(), native->getWindow(i)));
1578                 surfaceKHR.push_back(surface.back().get());
1579         }
1580
1581         // Create a device compatible with all surfaces.
1582         const DeviceHelper              devHelper       (context, instHelper.vki, instHelper.instance, surfaceKHR);
1583         const DeviceInterface&  vkd                     = devHelper.vkd;
1584         const VkDevice                  device          = *devHelper.device;
1585         SimpleAllocator                 allocator       (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1586
1587         // Create several swapchains and images.
1588         vector<VkSwapchainCreateInfoKHR>        swapchainInfo;
1589         vector<Move<VkSwapchainKHR>>            swapchain;
1590         vector<vector<VkImage>>                         swapchainImages;
1591         vector<AcquireWrapperType>                      acquireImageWrapper;
1592         for (size_t i = 0; i < params.swapchainCount; ++i)
1593         {
1594                 swapchainInfo.emplace_back(getBasicSwapchainParameters(params.wsiType, instHelper.vki, devHelper.physicalDevice, *surface[i], desiredSize, 2));
1595                 swapchain.emplace_back(createSwapchainKHR(vkd, device, &swapchainInfo.back()));
1596                 swapchainImages.emplace_back(getSwapchainImages(vkd, device, swapchain.back().get()));
1597                 acquireImageWrapper.emplace_back(vkd, device, 1u, swapchain.back().get(), std::numeric_limits<deUint64>::max());
1598         }
1599
1600         // Every acquire wrapper requires the same features, so we only check the first one.
1601         if (!acquireImageWrapper.front().featureAvailable(context))
1602                 TCU_THROW(NotSupportedError, "Required extension is not supported");
1603
1604         // Renderer per swapchain.
1605         vector<WsiTriangleRenderer> renderer;
1606         for (size_t i = 0; i < params.swapchainCount; ++i)
1607         {
1608                 renderer.emplace_back(vkd,
1609                                                           device,
1610                                                           allocator,
1611                                                           context.getBinaryCollection(),
1612                                                           false,
1613                                                           swapchainImages[i],
1614                                                           swapchainImages[i],
1615                                                           swapchainInfo[i].imageFormat,
1616                                                           tcu::UVec2(swapchainInfo[i].imageExtent.width, swapchainInfo[i].imageExtent.height));
1617         }
1618
1619         const Unique<VkCommandPool>     commandPool                     (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1620         const size_t                            maxQueuedFrames         = swapchainImages.front().size()*2;     // Limit in-flight frames.
1621
1622         vector<FrameStreamObjects>      frameStreamObjects;
1623         for (size_t i = 0; i < params.swapchainCount; ++i)
1624                 frameStreamObjects.emplace_back(vkd, device, commandPool.get(), maxQueuedFrames);
1625
1626         try
1627         {
1628                 // 3 seconds for 60 Hz screens.
1629                 const deUint32                  kNumFramesToRender              = 60*3*static_cast<deUint32>(params.swapchainCount);
1630                 AccumulatedPresentInfo  accumulatedPresentInfo;
1631
1632                 for (size_t frameNdx = 0; frameNdx < kNumFramesToRender; ++frameNdx)
1633                 {
1634                         size_t          swapchainIndex  = frameNdx % params.swapchainCount;
1635                         auto&           fsObjects               = frameStreamObjects[swapchainIndex];
1636                         auto            frameObjects    = fsObjects.newFrame();
1637                         deUint32        imageNdx                = std::numeric_limits<deUint32>::max();
1638
1639                         VK_CHECK(vkd.waitForFences(device, 1u, &frameObjects.renderCompleteFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1640                         VK_CHECK(vkd.resetFences(device, 1u, &frameObjects.renderCompleteFence));
1641
1642                         {
1643                                 const VkResult acquireResult = acquireImageWrapper[swapchainIndex].call(frameObjects.imageAvailableSemaphore, (VkFence)DE_NULL, &imageNdx);
1644                                 if (acquireResult == VK_SUBOPTIMAL_KHR)
1645                                         context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1646                                 else
1647                                         VK_CHECK(acquireResult);
1648                         }
1649
1650                         TCU_CHECK(static_cast<size_t>(imageNdx) < swapchainImages[swapchainIndex].size());
1651
1652                         {
1653                                 const VkPipelineStageFlags      waitDstStage    = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1654                                 const VkSubmitInfo                      submitInfo              =
1655                                 {
1656                                         VK_STRUCTURE_TYPE_SUBMIT_INFO,
1657                                         DE_NULL,
1658                                         1u,
1659                                         &frameObjects.imageAvailableSemaphore,
1660                                         &waitDstStage,
1661                                         1u,
1662                                         &frameObjects.commandBuffer,
1663                                         1u,
1664                                         &frameObjects.renderCompleteSemaphore,
1665                                 };
1666
1667                                 renderer[swapchainIndex].recordFrame(frameObjects.commandBuffer, imageNdx, static_cast<deUint32>(frameNdx));
1668                                 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, frameObjects.renderCompleteFence));
1669
1670                                 // Save present information for the current frame.
1671                                 accumulatedPresentInfo.push_back(frameObjects.renderCompleteSemaphore, swapchain[swapchainIndex].get(), imageNdx);
1672
1673                                 // Present frames when we have accumulated one frame per swapchain.
1674                                 if (accumulatedPresentInfo.size() == params.swapchainCount)
1675                                 {
1676                                         DE_ASSERT(      accumulatedPresentInfo.semaphores.size() == accumulatedPresentInfo.swapchains.size()    &&
1677                                                                 accumulatedPresentInfo.semaphores.size() == accumulatedPresentInfo.imageIndices.size()  );
1678
1679                                         vector<VkResult> results(params.swapchainCount, VK_ERROR_DEVICE_LOST);
1680
1681                                         const VkPresentInfoKHR presentInfo =
1682                                         {
1683                                                 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1684                                                 DE_NULL,
1685                                                 static_cast<deUint32>(accumulatedPresentInfo.semaphores.size()),
1686                                                 accumulatedPresentInfo.semaphores.data(),
1687                                                 static_cast<deUint32>(accumulatedPresentInfo.swapchains.size()),
1688                                                 accumulatedPresentInfo.swapchains.data(),
1689                                                 accumulatedPresentInfo.imageIndices.data(),
1690                                                 results.data(),
1691                                         };
1692
1693                                         // Check both the global result and the individual results.
1694                                         VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1695                                         for (const auto& result : results)
1696                                                 VK_CHECK_WSI(result);
1697
1698                                         accumulatedPresentInfo.reset();
1699                                 }
1700                         }
1701                 }
1702
1703                 VK_CHECK(vkd.deviceWaitIdle(device));
1704         }
1705         catch (...)
1706         {
1707                 // Make sure device is idle before destroying resources
1708                 vkd.deviceWaitIdle(device);
1709                 throw;
1710         }
1711
1712         return tcu::TestStatus::pass("Rendering tests succeeded");
1713 }
1714
1715 tcu::TestStatus deviceGroupRenderTest (Context& context, Type wsiType)
1716 {
1717         const InstanceHelper            instHelper                      (context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
1718         const tcu::CommandLine&         cmdLine                         = context.getTestContext().getCommandLine();
1719         VkPhysicalDevice                        physicalDevice          = chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
1720         const Extensions&                       supportedExtensions     = enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
1721
1722         std::vector<const char*> deviceExtensions;
1723         deviceExtensions.push_back("VK_KHR_swapchain");
1724         if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
1725                 deviceExtensions.push_back("VK_KHR_device_group");
1726
1727         for (std::size_t ndx = 0; ndx < deviceExtensions.size(); ++ndx)
1728         {
1729                 if (!isExtensionSupported(supportedExtensions, RequiredExtension(deviceExtensions[ndx])))
1730                         TCU_THROW(NotSupportedError, (string(deviceExtensions[ndx]) + " is not supported").c_str());
1731         }
1732
1733         const tcu::UVec2                                                                desiredSize                                     (256, 256);
1734         const NativeObjects                                                             native                                          (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1735         const Unique<VkSurfaceKHR>                                              surface                                         (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
1736
1737         const deUint32                                                                  devGroupIdx                                     = cmdLine.getVKDeviceGroupId() - 1;
1738         const deUint32                                                                  deviceIdx                                       = context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
1739         const vector<VkPhysicalDeviceGroupProperties>   deviceGroupProps                        = enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
1740         deUint32                                                                                physicalDevicesInGroupCount     = deviceGroupProps[devGroupIdx].physicalDeviceCount;
1741         const VkPhysicalDevice*                                                 physicalDevicesInGroup          = deviceGroupProps[devGroupIdx].physicalDevices;
1742         deUint32                                                                                queueFamilyIndex                        = chooseQueueFamilyIndex(instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface);
1743         const std::vector<VkQueueFamilyProperties>              queueProps                                      = getPhysicalDeviceQueueFamilyProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]);
1744         const float                                                                             queuePriority                           = 1.0f;
1745         const deUint32                                                                  firstDeviceID                           = 0;
1746         const deUint32                                                                  secondDeviceID                          = 1;
1747
1748         // create a device group
1749         const VkDeviceGroupDeviceCreateInfo groupDeviceInfo =
1750         {
1751                 VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR,                  // stype
1752                 DE_NULL,                                                                                                                // pNext
1753                 physicalDevicesInGroupCount,                                                                    // physicalDeviceCount
1754                 physicalDevicesInGroup                                                                                  // physicalDevices
1755         };
1756         const VkDeviceQueueCreateInfo deviceQueueCreateInfo =
1757         {
1758                 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,                                             // type
1759                 DE_NULL,                                                                                                                // pNext
1760                 (VkDeviceQueueCreateFlags)0u,                                                                   // flags
1761                 queueFamilyIndex,                                                                                               // queueFamilyIndex
1762                 1u,                                                                                                                             // queueCount
1763                 &queuePriority,                                                                                                 // pQueuePriorities
1764         };
1765
1766         const VkDeviceCreateInfo        deviceCreateInfo =
1767         {
1768                 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,                                                   // sType
1769                 &groupDeviceInfo,                                                                                               // pNext
1770                 (VkDeviceCreateFlags)0u,                                                                                // flags
1771                 1,                                                                                                                              // queueRecordCount
1772                 &deviceQueueCreateInfo,                                                                                 // pRequestedQueues
1773                 0,                                                                                                                              // layerCount
1774                 DE_NULL,                                                                                                                // ppEnabledLayerNames
1775                 deUint32(deviceExtensions.size()),                                                              // enabledExtensionCount
1776                 &deviceExtensions[0],                                                                                   // ppEnabledExtensionNames
1777                 DE_NULL,                                                                                                                // pEnabledFeatures
1778         };
1779
1780         Move<VkDevice>                                  groupDevice                                     = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), instHelper.instance, instHelper.vki, physicalDevicesInGroup[deviceIdx], &deviceCreateInfo);
1781         const DeviceDriver                              vkd                                                     (context.getPlatformInterface(), instHelper.instance, *groupDevice);
1782         VkQueue                                                 queue                                           (getDeviceQueue(vkd, *groupDevice, queueFamilyIndex, 0));
1783         SimpleAllocator                                 allocator                                       (vkd, *groupDevice, getPhysicalDeviceMemoryProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]));
1784
1785         // create swapchain for device group
1786         VkDeviceGroupSwapchainCreateInfoKHR deviceGroupSwapchainInfo = initVulkanStructure();
1787         deviceGroupSwapchainInfo.modes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
1788
1789         VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType,
1790                                                                                                                                                  instHelper.vki,
1791                                                                                                                                                  physicalDevicesInGroup[deviceIdx],
1792                                                                                                                                                  *surface,
1793                                                                                                                                                  desiredSize,
1794                                                                                                                                                  2);
1795         swapchainInfo.pNext = &deviceGroupSwapchainInfo;
1796
1797         const Unique<VkSwapchainKHR>    swapchain                                       (createSwapchainKHR(vkd, *groupDevice, &swapchainInfo));
1798         const vector<VkImage>                   swapchainImages                         = getSwapchainImages(vkd, *groupDevice, *swapchain);
1799
1800         const WsiTriangleRenderer               renderer                                        (vkd,
1801                                                                                                                                  *groupDevice,
1802                                                                                                                                  allocator,
1803                                                                                                                                  context.getBinaryCollection(),
1804                                                                                                                                  false,
1805                                                                                                                                  swapchainImages,
1806                                                                                                                                  swapchainImages,
1807                                                                                                                                  swapchainInfo.imageFormat,
1808                                                                                                                                  tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1809
1810         const Unique<VkCommandPool>             commandPool                                     (createCommandPool(vkd, *groupDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1811
1812         const size_t                                    maxQueuedFrames                         = swapchainImages.size()*2;
1813
1814         // We need to keep hold of fences from vkAcquireNextImage2KHR
1815         // to actually limit number of frames we allow to be queued.
1816         const vector<FenceSp>                   imageReadyFences                        (createFences(vkd, *groupDevice, maxQueuedFrames));
1817
1818         // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to
1819         // pass the semaphore in same time as the fence we use to meter rendering.
1820         const vector<SemaphoreSp>               imageReadySemaphores            (createSemaphores(vkd, *groupDevice, maxQueuedFrames+1));
1821
1822         // For rest we simply need maxQueuedFrames as we will wait for image from frameNdx-maxQueuedFrames
1823         // to become available to us, guaranteeing that previous uses must have completed.
1824         const vector<SemaphoreSp>               renderingCompleteSemaphores     (createSemaphores(vkd, *groupDevice, maxQueuedFrames));
1825         const vector<CommandBufferSp>   commandBuffers                          (allocateCommandBuffers(vkd, *groupDevice, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1826
1827         try
1828         {
1829                 const deUint32  numFramesToRender = 60*10;
1830
1831                 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1832                 {
1833                         const VkFence           imageReadyFence         = **imageReadyFences[frameNdx%imageReadyFences.size()];
1834                         const VkSemaphore       imageReadySemaphore     = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1835                         deUint32                        imageNdx                        = ~0u;
1836
1837                         VK_CHECK(vkd.waitForFences(*groupDevice, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1838                         VK_CHECK(vkd.resetFences(*groupDevice, 1, &imageReadyFence));
1839
1840                         {
1841                                 VkAcquireNextImageInfoKHR acquireNextImageInfo =
1842                                 {
1843                                         VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR,
1844                                         DE_NULL,
1845                                         *swapchain,
1846                                         std::numeric_limits<deUint64>::max(),
1847                                         imageReadySemaphore,
1848                                         (VkFence)0,
1849                                         (1 << firstDeviceID)
1850                                 };
1851
1852                                 const VkResult acquireResult = vkd.acquireNextImage2KHR(*groupDevice, &acquireNextImageInfo, &imageNdx);
1853
1854                                 if (acquireResult == VK_SUBOPTIMAL_KHR)
1855                                         context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1856                                 else
1857                                         VK_CHECK(acquireResult);
1858                         }
1859
1860                         TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1861
1862                         {
1863                                 const VkSemaphore                       renderingCompleteSemaphore      = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1864                                 const VkCommandBuffer           commandBuffer                           = **commandBuffers[frameNdx%commandBuffers.size()];
1865                                 const VkPipelineStageFlags      waitDstStage                            = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1866
1867                                 // render triangle using one or two subdevices when available
1868                                 renderer.recordDeviceGroupFrame(commandBuffer, firstDeviceID, secondDeviceID, physicalDevicesInGroupCount, imageNdx, frameNdx);
1869
1870                                 // submit queue
1871                                 deUint32 deviceMask = (1 << firstDeviceID);
1872                                 std::vector<deUint32> deviceIndices(1, firstDeviceID);
1873                                 if (physicalDevicesInGroupCount > 1)
1874                                 {
1875                                         deviceMask |= (1 << secondDeviceID);
1876                                         deviceIndices.push_back(secondDeviceID);
1877                                 }
1878                                 const VkDeviceGroupSubmitInfo deviceGroupSubmitInfo =
1879                                 {
1880                                         VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR,         // sType
1881                                         DE_NULL,                                                                                        // pNext
1882                                         deUint32(deviceIndices.size()),                                         // waitSemaphoreCount
1883                                         &deviceIndices[0],                                                                      // pWaitSemaphoreDeviceIndices
1884                                         1u,                                                                                                     // commandBufferCount
1885                                         &deviceMask,                                                                            // pCommandBufferDeviceMasks
1886                                         deUint32(deviceIndices.size()),                                         // signalSemaphoreCount
1887                                         &deviceIndices[0],                                                                      // pSignalSemaphoreDeviceIndices
1888                                 };
1889                                 const VkSubmitInfo submitInfo =
1890                                 {
1891                                         VK_STRUCTURE_TYPE_SUBMIT_INFO,                                          // sType
1892                                         &deviceGroupSubmitInfo,                                                         // pNext
1893                                         1u,                                                                                                     // waitSemaphoreCount
1894                                         &imageReadySemaphore,                                                           // pWaitSemaphores
1895                                         &waitDstStage,                                                                          // pWaitDstStageMask
1896                                         1u,                                                                                                     // commandBufferCount
1897                                         &commandBuffer,                                                                         // pCommandBuffers
1898                                         1u,                                                                                                     // signalSemaphoreCount
1899                                         &renderingCompleteSemaphore,                                            // pSignalSemaphores
1900                                 };
1901                                 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, imageReadyFence));
1902
1903                                 // present swapchain image
1904                                 deviceMask = (1 << firstDeviceID);
1905                                 const VkDeviceGroupPresentInfoKHR deviceGroupPresentInfo =
1906                                 {
1907                                         VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR,
1908                                         DE_NULL,
1909                                         1u,
1910                                         &deviceMask,
1911                                         VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR,
1912                                 };
1913                                 const VkPresentInfoKHR presentInfo =
1914                                 {
1915                                         VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1916                                         &deviceGroupPresentInfo,
1917                                         1u,
1918                                         &renderingCompleteSemaphore,
1919                                         1u,
1920                                         &*swapchain,
1921                                         &imageNdx,
1922                                         (VkResult*)DE_NULL
1923                                 };
1924                                 VK_CHECK_WSI(vkd.queuePresentKHR(queue, &presentInfo));
1925                         }
1926                 }
1927
1928                 VK_CHECK(vkd.deviceWaitIdle(*groupDevice));
1929         }
1930         catch (...)
1931         {
1932                 // Make sure device is idle before destroying resources
1933                 vkd.deviceWaitIdle(*groupDevice);
1934                 throw;
1935         }
1936
1937         return tcu::TestStatus::pass("Rendering tests succeeded");
1938 }
1939
1940 tcu::TestStatus deviceGroupRenderTest2 (Context& context, Type wsiType)
1941 {
1942         const InstanceHelper            instHelper                      (context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
1943         const tcu::CommandLine&         cmdLine                         = context.getTestContext().getCommandLine();
1944         VkPhysicalDevice                        physicalDevice          = chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
1945         const Extensions&                       deviceExtensions        = enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
1946
1947         // structures this tests checks were added in revision 69
1948         if (!isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_swapchain", 69)))
1949                 TCU_THROW(NotSupportedError, "Required extension revision is not supported");
1950
1951         std::vector<const char*> requiredExtensions;
1952         requiredExtensions.push_back("VK_KHR_swapchain");
1953         if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
1954         {
1955                 requiredExtensions.push_back("VK_KHR_device_group");
1956                 if (!isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_device_group")))
1957                         TCU_THROW(NotSupportedError, "VK_KHR_device_group is not supported");
1958         }
1959
1960         const tcu::UVec2                                                                desiredSize                                     (256, 256);
1961         const NativeObjects                                                             native                                          (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1962         const Unique<VkSurfaceKHR>                                              surface                                         (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
1963
1964         const deUint32                                                                  devGroupIdx                                     = cmdLine.getVKDeviceGroupId() - 1;
1965         const deUint32                                                                  deviceIdx                                       = context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
1966         const vector<VkPhysicalDeviceGroupProperties>   deviceGroupProps                        = enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
1967         deUint32                                                                                physicalDevicesInGroupCount     = deviceGroupProps[devGroupIdx].physicalDeviceCount;
1968         const VkPhysicalDevice*                                                 physicalDevicesInGroup          = deviceGroupProps[devGroupIdx].physicalDevices;
1969         deUint32                                                                                queueFamilyIndex                        = chooseQueueFamilyIndex(instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface);
1970         const std::vector<VkQueueFamilyProperties>              queueProps                                      = getPhysicalDeviceQueueFamilyProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]);
1971         const float                                                                             queuePriority                           = 1.0f;
1972         const deUint32                                                                  firstDeviceID                           = 0;
1973         const deUint32                                                                  secondDeviceID                          = 1;
1974         const deUint32                                                                  deviceIndices[]                         = { firstDeviceID, secondDeviceID };
1975
1976         if (physicalDevicesInGroupCount < 2)
1977                 TCU_THROW(NotSupportedError, "Test requires more than 1 device in device group");
1978
1979         // create a device group
1980         const VkDeviceGroupDeviceCreateInfo groupDeviceInfo =
1981         {
1982                 VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR,                  // stype
1983                 DE_NULL,                                                                                                                // pNext
1984                 physicalDevicesInGroupCount,                                                                    // physicalDeviceCount
1985                 physicalDevicesInGroup                                                                                  // physicalDevices
1986         };
1987         const VkDeviceQueueCreateInfo deviceQueueCreateInfo =
1988         {
1989                 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,                                             // type
1990                 DE_NULL,                                                                                                                // pNext
1991                 (VkDeviceQueueCreateFlags)0u,                                                                   // flags
1992                 queueFamilyIndex,                                                                                               // queueFamilyIndex
1993                 1u,                                                                                                                             // queueCount
1994                 &queuePriority,                                                                                                 // pQueuePriorities
1995         };
1996
1997         const VkDeviceCreateInfo deviceCreateInfo =
1998         {
1999                 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,                                                   // sType
2000                 &groupDeviceInfo,                                                                                               // pNext
2001                 (VkDeviceCreateFlags)0u,                                                                                // flags
2002                 1,                                                                                                                              // queueRecordCount
2003                 &deviceQueueCreateInfo,                                                                                 // pRequestedQueues
2004                 0,                                                                                                                              // layerCount
2005                 DE_NULL,                                                                                                                // ppEnabledLayerNames
2006                 deUint32(requiredExtensions.size()),                                                    // enabledExtensionCount
2007                 &requiredExtensions[0],                                                                                 // ppEnabledExtensionNames
2008                 DE_NULL,                                                                                                                // pEnabledFeatures
2009         };
2010
2011         Move<VkDevice>                                          groupDevice                     = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), instHelper.instance, instHelper.vki, physicalDevicesInGroup[deviceIdx], &deviceCreateInfo);
2012         const DeviceDriver                                      vkd                                     (context.getPlatformInterface(), instHelper.instance, *groupDevice);
2013         VkQueue                                                         queue                           (getDeviceQueue(vkd, *groupDevice, queueFamilyIndex, 0));
2014         SimpleAllocator                                         allocator                       (vkd, *groupDevice, getPhysicalDeviceMemoryProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]));
2015
2016         // create swapchain for device group
2017         const VkSurfaceCapabilitiesKHR          capabilities            = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevice, *surface);
2018         const vector<VkSurfaceFormatKHR>        formats                         = getPhysicalDeviceSurfaceFormats(instHelper.vki, physicalDevice, *surface);
2019         const PlatformProperties&                       platformProperties      = getPlatformProperties(wsiType);
2020         const VkSurfaceTransformFlagBitsKHR transform                   = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
2021         const deUint32                                          desiredImageCount       = 2;
2022
2023         struct VkDeviceGroupSwapchainCreateInfoKHR deviceGroupSwapchainInfo =
2024         {
2025                 VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
2026                 DE_NULL,
2027                 VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR
2028         };
2029         const VkSwapchainCreateInfoKHR swapchainInfo =
2030         {
2031                 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
2032                 &deviceGroupSwapchainInfo,
2033                 VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR,
2034                 *surface,
2035                 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
2036                 formats[0].format,
2037                 formats[0].colorSpace,
2038                 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
2039                         ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
2040                 1u,
2041                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2042                 VK_SHARING_MODE_EXCLUSIVE,
2043                 0u,
2044                 (const deUint32*)DE_NULL,
2045                 transform,
2046                 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
2047                 VK_PRESENT_MODE_FIFO_KHR,
2048                 VK_FALSE,
2049                 (VkSwapchainKHR)0
2050         };
2051
2052         const Unique<VkSwapchainKHR>    swapchain       (createSwapchainKHR(vkd, *groupDevice, &swapchainInfo));
2053         deUint32                                                numImages       = 0;
2054         VK_CHECK(vkd.getSwapchainImagesKHR(*groupDevice, *swapchain, &numImages, DE_NULL));
2055         if (numImages == 0)
2056                 return tcu::TestStatus::pass("Pass");
2057
2058         VkImageSwapchainCreateInfoKHR imageSwapchainCreateInfo =
2059         {
2060                 VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
2061                 DE_NULL,
2062                 *swapchain
2063         };
2064
2065         VkImageCreateInfo imageCreateInfo =
2066         {
2067                 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2068                 &imageSwapchainCreateInfo,
2069                 VK_IMAGE_CREATE_ALIAS_BIT |
2070                 VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR,            // flags
2071                 VK_IMAGE_TYPE_2D,                                                                                       // imageType
2072                 formats[0].format,                                                                                      // format
2073                 {                                                                                                                       // extent
2074                         desiredSize.x(),                                                                                //   width
2075                         desiredSize.y(),                                                                                //   height
2076                         1u                                                                                                              //   depth
2077                 },
2078                 1u,                                                                                                                     // mipLevels
2079                 1u,                                                                                                                     // arrayLayers
2080                 VK_SAMPLE_COUNT_1_BIT,                                                                          // samples
2081                 VK_IMAGE_TILING_OPTIMAL,                                                                        // tiling
2082                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,                                            // usage
2083                 VK_SHARING_MODE_EXCLUSIVE,                                                                      // sharingMode
2084                 0u,                                                                                                                     // queueFamilyIndexCount
2085                 DE_NULL,                                                                                                        // pQueueFamilyIndices
2086                 VK_IMAGE_LAYOUT_UNDEFINED                                                                       // initialLayout
2087         };
2088
2089         typedef vk::Unique<VkImage>                     UniqueImage;
2090         typedef de::SharedPtr<UniqueImage>      ImageSp;
2091
2092         vector<ImageSp>                                                         images                                                  (numImages);
2093         vector<VkImage>                                                         rawImages                                               (numImages);
2094         vector<ImageSp>                                                         imagesSfr                                               (numImages);
2095         vector<VkImage>                                                         rawImagesSfr                                    (numImages);
2096         vector<VkBindImageMemorySwapchainInfoKHR>       bindImageMemorySwapchainInfo    (numImages);
2097
2098         // Create non-SFR image aliases for image layout transition
2099         {
2100                 vector<VkBindImageMemoryInfo>                           bindImageMemoryInfos                    (numImages);
2101
2102                 for (deUint32 idx = 0; idx < numImages; ++idx)
2103                 {
2104                         // Create image
2105                         images[idx] = ImageSp(new UniqueImage(createImage(vkd, *groupDevice, &imageCreateInfo)));
2106
2107                         VkBindImageMemorySwapchainInfoKHR bimsInfo =
2108                         {
2109                                 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR,
2110                                 DE_NULL,
2111                                 *swapchain,
2112                                 idx
2113                         };
2114                         bindImageMemorySwapchainInfo[idx] = bimsInfo;
2115
2116                         VkBindImageMemoryInfo bimInfo =
2117                         {
2118                                 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
2119                                 &bindImageMemorySwapchainInfo[idx],
2120                                 **images[idx],
2121                                 DE_NULL,                                // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
2122                                 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.
2123                         };
2124                         bindImageMemoryInfos[idx]       = bimInfo;
2125                         rawImages[idx]                          = **images[idx];
2126                 }
2127
2128                 VK_CHECK(vkd.bindImageMemory2(*groupDevice, numImages, &bindImageMemoryInfos[0]));
2129         }
2130
2131         // Create the SFR images
2132         {
2133                 vector<VkBindImageMemoryDeviceGroupInfo >       bindImageMemoryDeviceGroupInfo  (numImages);
2134                 vector<VkBindImageMemoryInfo>                           bindImageMemoryInfos                    (numImages);
2135                 for (deUint32 idx = 0; idx < numImages; ++idx)
2136                 {
2137                         // Create image
2138                         imagesSfr[idx] = ImageSp(new UniqueImage(createImage(vkd, *groupDevice, &imageCreateInfo)));
2139
2140                 // Split into 2 vertical halves
2141                 // NOTE: the same split has to be done also in WsiTriangleRenderer::recordDeviceGroupFrame
2142                 const deUint32  halfWidth                       = desiredSize.x() / 2;
2143                 const deUint32  height                          = desiredSize.y();
2144                 const VkRect2D  sfrRects[] =
2145                 {
2146                         {       { 0, 0 },                                       { halfWidth, height }   },              // offset, extent
2147                         {       { (deInt32)halfWidth, 0 },      { halfWidth, height }   },              // offset, extent
2148                         {       { 0, 0 },                                       { halfWidth, height }   },              // offset, extent
2149                         {       { (deInt32)halfWidth, 0 },      { halfWidth, height }   }               // offset, extent
2150                 };
2151
2152                 VkBindImageMemoryDeviceGroupInfo bimdgInfo =
2153                 {
2154                         VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO,
2155                         &bindImageMemorySwapchainInfo[idx],
2156                         DE_LENGTH_OF_ARRAY(deviceIndices),
2157                         deviceIndices,
2158                         DE_LENGTH_OF_ARRAY(sfrRects),
2159                         sfrRects
2160                 };
2161                 bindImageMemoryDeviceGroupInfo[idx] = bimdgInfo;
2162
2163                 VkBindImageMemoryInfo bimInfo =
2164                 {
2165                         VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
2166                         &bindImageMemoryDeviceGroupInfo[idx],
2167                                 **imagesSfr[idx],
2168                         DE_NULL,                                // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
2169                         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.
2170                 };
2171                 bindImageMemoryInfos[idx]       = bimInfo;
2172                         rawImagesSfr[idx]                       = **imagesSfr[idx];
2173         }
2174
2175         VK_CHECK(vkd.bindImageMemory2(*groupDevice, numImages, &bindImageMemoryInfos[0]));
2176         }
2177
2178         VkPeerMemoryFeatureFlags peerMemoryFeatures = 0u;
2179         vkd.getDeviceGroupPeerMemoryFeatures(*groupDevice, 0, firstDeviceID, secondDeviceID, &peerMemoryFeatures);
2180         bool explicitLayoutTransitions = !(peerMemoryFeatures & VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT) ||
2181                                                                          !(peerMemoryFeatures & VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT);
2182
2183         const WsiTriangleRenderer                       renderer                                        (vkd,
2184                                                                                                                                  *groupDevice,
2185                                                                                                                                  allocator,
2186                                                                                                                                  context.getBinaryCollection(),
2187                                                                                                                                  explicitLayoutTransitions,
2188                                                                                                                                  rawImagesSfr,
2189                                                                                                                                  rawImages,
2190                                                                                                                                  swapchainInfo.imageFormat,
2191                                                                                                                                  tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
2192
2193         const Unique<VkCommandPool>             commandPool                                     (createCommandPool(vkd, *groupDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2194
2195         const size_t                                    maxQueuedFrames                         = rawImagesSfr.size()*2;
2196
2197         // We need to keep hold of fences from vkAcquireNextImage2KHR
2198         // to actually limit number of frames we allow to be queued.
2199         const vector<FenceSp>                   imageReadyFences                        (createFences(vkd, *groupDevice, maxQueuedFrames));
2200
2201         // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to
2202         // pass the semaphore in same time as the fence we use to meter rendering.
2203         const vector<SemaphoreSp>               imageReadySemaphores            (createSemaphores(vkd, *groupDevice, maxQueuedFrames+1));
2204
2205         // For rest we simply need maxQueuedFrames as we will wait for image from frameNdx-maxQueuedFrames
2206         // to become available to us, guaranteeing that previous uses must have completed.
2207         const vector<SemaphoreSp>               renderingCompleteSemaphores     (createSemaphores(vkd, *groupDevice, maxQueuedFrames));
2208         const vector<CommandBufferSp>   commandBuffers                          (allocateCommandBuffers(vkd, *groupDevice, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
2209
2210         try
2211         {
2212                 const deUint32  numFramesToRender = 60*10;
2213
2214                 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
2215                 {
2216                         const VkFence           imageReadyFence         = **imageReadyFences[frameNdx%imageReadyFences.size()];
2217                         const VkSemaphore       imageReadySemaphore     = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
2218                         deUint32                        imageNdx                        = ~0u;
2219
2220                         VK_CHECK(vkd.waitForFences(*groupDevice, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
2221                         VK_CHECK(vkd.resetFences(*groupDevice, 1, &imageReadyFence));
2222
2223                         {
2224                                 VkAcquireNextImageInfoKHR acquireNextImageInfo =
2225                                 {
2226                                         VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR,
2227                                         DE_NULL,
2228                                         *swapchain,
2229                                         std::numeric_limits<deUint64>::max(),
2230                                         imageReadySemaphore,
2231                                         (VkFence)0,
2232                                         (1 << firstDeviceID)
2233                                 };
2234
2235                                 const VkResult acquireResult = vkd.acquireNextImage2KHR(*groupDevice, &acquireNextImageInfo, &imageNdx);
2236
2237                                 if (acquireResult == VK_SUBOPTIMAL_KHR)
2238                                         context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
2239                                 else
2240                                         VK_CHECK(acquireResult);
2241                         }
2242
2243                         TCU_CHECK((size_t)imageNdx < rawImagesSfr.size());
2244
2245                         {
2246                                 const VkSemaphore                       renderingCompleteSemaphore      = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
2247                                 const VkCommandBuffer           commandBuffer                           = **commandBuffers[frameNdx%commandBuffers.size()];
2248                                 const VkPipelineStageFlags      waitDstStage                            = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2249
2250                                 // render triangle using one or two subdevices when available
2251                                 renderer.recordDeviceGroupFrame(commandBuffer, firstDeviceID, secondDeviceID, physicalDevicesInGroupCount, imageNdx, frameNdx);
2252
2253                                 // submit queue
2254                                 deUint32 deviceMask = (1 << firstDeviceID) | (1 << secondDeviceID);
2255                                 const VkDeviceGroupSubmitInfo deviceGroupSubmitInfo =
2256                                 {
2257                                         VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR,         // sType
2258                                         DE_NULL,                                                                                        // pNext
2259                                         DE_LENGTH_OF_ARRAY(deviceIndices),                                      // waitSemaphoreCount
2260                                         deviceIndices,                                                                          // pWaitSemaphoreDeviceIndices
2261                                         1u,                                                                                                     // commandBufferCount
2262                                         &deviceMask,                                                                            // pCommandBufferDeviceMasks
2263                                         DE_LENGTH_OF_ARRAY(deviceIndices),                                      // signalSemaphoreCount
2264                                         deviceIndices,                                                                          // pSignalSemaphoreDeviceIndices
2265                                 };
2266                                 const VkSubmitInfo submitInfo =
2267                                 {
2268                                         VK_STRUCTURE_TYPE_SUBMIT_INFO,                                          // sType
2269                                         &deviceGroupSubmitInfo,                                                         // pNext
2270                                         1u,                                                                                                     // waitSemaphoreCount
2271                                         &imageReadySemaphore,                                                           // pWaitSemaphores
2272                                         &waitDstStage,                                                                          // pWaitDstStageMask
2273                                         1u,                                                                                                     // commandBufferCount
2274                                         &commandBuffer,                                                                         // pCommandBuffers
2275                                         1u,                                                                                                     // signalSemaphoreCount
2276                                         &renderingCompleteSemaphore,                                            // pSignalSemaphores
2277                                 };
2278                                 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, imageReadyFence));
2279
2280                                 // present swapchain image -  asume that first device has a presentation engine
2281                                 deviceMask = (1 << firstDeviceID);
2282                                 const VkDeviceGroupPresentInfoKHR deviceGroupPresentInfo =
2283                                 {
2284                                         VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR,
2285                                         DE_NULL,
2286                                         1u,
2287                                         &deviceMask,
2288                                         VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR,
2289                                 };
2290                                 const VkPresentInfoKHR presentInfo =
2291                                 {
2292                                         VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2293                                         &deviceGroupPresentInfo,
2294                                         1u,
2295                                         &renderingCompleteSemaphore,
2296                                         1u,
2297                                         &*swapchain,
2298                                         &imageNdx,
2299                                         (VkResult*)DE_NULL
2300                                 };
2301                                 VK_CHECK(vkd.queuePresentKHR(queue, &presentInfo));
2302                         }
2303                 }
2304
2305                 VK_CHECK(vkd.deviceWaitIdle(*groupDevice));
2306         }
2307         catch (...)
2308         {
2309                 // Make sure device is idle before destroying resources
2310                 vkd.deviceWaitIdle(*groupDevice);
2311                 throw;
2312         }
2313
2314         return tcu::TestStatus::pass("Rendering tests succeeded");
2315 }
2316
2317 vector<tcu::UVec2> getSwapchainSizeSequence (const VkSurfaceCapabilitiesKHR& capabilities, const tcu::UVec2& defaultSize)
2318 {
2319         vector<tcu::UVec2> sizes(3);
2320         sizes[0] = defaultSize / 2u;
2321         sizes[1] = defaultSize;
2322         sizes[2] = defaultSize * 2u;
2323
2324         for (deUint32 i = 0; i < sizes.size(); ++i)
2325         {
2326                 sizes[i].x() = de::clamp(sizes[i].x(), capabilities.minImageExtent.width,  capabilities.maxImageExtent.width);
2327                 sizes[i].y() = de::clamp(sizes[i].y(), capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
2328         }
2329
2330         return sizes;
2331 }
2332
2333 tcu::TestStatus resizeSwapchainTest (Context& context, Type wsiType)
2334 {
2335         const tcu::UVec2                                desiredSize                     (256, 256);
2336         const InstanceHelper                    instHelper                      (context, wsiType);
2337         const NativeObjects                             native                          (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2338         const Unique<VkSurfaceKHR>              surface                         (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2339         const DeviceHelper                              devHelper                       (context, instHelper.vki, instHelper.instance, *surface);
2340         const PlatformProperties&               platformProperties      = getPlatformProperties(wsiType);
2341         const VkSurfaceCapabilitiesKHR  capabilities            = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
2342         const DeviceInterface&                  vkd                                     = devHelper.vkd;
2343         const VkDevice                                  device                          = *devHelper.device;
2344         SimpleAllocator                                 allocator                       (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
2345         vector<tcu::UVec2>                              sizes                           = getSwapchainSizeSequence(capabilities, desiredSize);
2346         Move<VkSwapchainKHR>                    prevSwapchain;
2347
2348         DE_ASSERT(platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE);
2349         DE_UNREF(platformProperties);
2350
2351         for (deUint32 sizeNdx = 0; sizeNdx < sizes.size(); ++sizeNdx)
2352         {
2353                 // \todo [2016-05-30 jesse] This test currently waits for idle and
2354                 // recreates way more than necessary when recreating the swapchain. Make
2355                 // it match expected real app behavior better by smoothly switching from
2356                 // old to new swapchain. Once that is done, it will also be possible to
2357                 // test creating a new swapchain while images from the previous one are
2358                 // still acquired.
2359
2360                 VkSwapchainCreateInfoKHR                swapchainInfo                           = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, sizes[sizeNdx], 2);
2361                 swapchainInfo.oldSwapchain = *prevSwapchain;
2362
2363                 Move<VkSwapchainKHR>                    swapchain                                       (createSwapchainKHR(vkd, device, &swapchainInfo));
2364                 const vector<VkImage>                   swapchainImages                         = getSwapchainImages(vkd, device, *swapchain);
2365                 const WsiTriangleRenderer               renderer                                        (vkd,
2366                                                                                                                                         device,
2367                                                                                                                                         allocator,
2368                                                                                                                                         context.getBinaryCollection(),
2369                                                                                                                                         false,
2370                                                                                                                                         swapchainImages,
2371                                                                                                                                         swapchainImages,
2372                                                                                                                                         swapchainInfo.imageFormat,
2373                                                                                                                                         tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
2374                 const Unique<VkCommandPool>             commandPool                                     (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
2375                 const size_t                                    maxQueuedFrames                         = swapchainImages.size()*2;
2376
2377                 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
2378                 // limit number of frames we allow to be queued.
2379                 const vector<FenceSp>                   imageReadyFences                        (createFences(vkd, device, maxQueuedFrames));
2380
2381                 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
2382                 // the semaphore in same time as the fence we use to meter rendering.
2383                 const vector<SemaphoreSp>               imageReadySemaphores            (createSemaphores(vkd, device, maxQueuedFrames+1));
2384
2385                 // For rest we simply need maxQueuedFrames as we will wait for image
2386                 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
2387                 // previous uses must have completed.
2388                 const vector<SemaphoreSp>               renderingCompleteSemaphores     (createSemaphores(vkd, device, maxQueuedFrames));
2389                 const vector<CommandBufferSp>   commandBuffers                          (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
2390
2391                 try
2392                 {
2393                         const deUint32  numFramesToRender       = 60;
2394
2395                         for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
2396                         {
2397                                 const VkFence           imageReadyFence         = **imageReadyFences[frameNdx%imageReadyFences.size()];
2398                                 const VkSemaphore       imageReadySemaphore     = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
2399                                 deUint32                        imageNdx                        = ~0u;
2400
2401                                 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
2402                                 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
2403
2404                                 {
2405                                         const VkResult  acquireResult   = vkd.acquireNextImageKHR(device,
2406                                                                                                                                                           *swapchain,
2407                                                                                                                                                           std::numeric_limits<deUint64>::max(),
2408                                                                                                                                                           imageReadySemaphore,
2409                                                                                                                                                           DE_NULL,
2410                                                                                                                                                           &imageNdx);
2411
2412                                         if (acquireResult == VK_SUBOPTIMAL_KHR)
2413                                                 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
2414                                         else
2415                                                 VK_CHECK(acquireResult);
2416                                 }
2417
2418                                 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
2419
2420                                 {
2421                                         const VkSemaphore                       renderingCompleteSemaphore      = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
2422                                         const VkCommandBuffer           commandBuffer                           = **commandBuffers[frameNdx%commandBuffers.size()];
2423                                         const VkPipelineStageFlags      waitDstStage                            = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2424                                         const VkSubmitInfo                      submitInfo                                      =
2425                                         {
2426                                                 VK_STRUCTURE_TYPE_SUBMIT_INFO,
2427                                                 DE_NULL,
2428                                                 1u,
2429                                                 &imageReadySemaphore,
2430                                                 &waitDstStage,
2431                                                 1u,
2432                                                 &commandBuffer,
2433                                                 1u,
2434                                                 &renderingCompleteSemaphore
2435                                         };
2436                                         const VkPresentInfoKHR          presentInfo                                     =
2437                                         {
2438                                                 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2439                                                 DE_NULL,
2440                                                 1u,
2441                                                 &renderingCompleteSemaphore,
2442                                                 1u,
2443                                                 &*swapchain,
2444                                                 &imageNdx,
2445                                                 (VkResult*)DE_NULL
2446                                         };
2447
2448                                         renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
2449                                         VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
2450                                         VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
2451                                 }
2452                         }
2453
2454                         VK_CHECK(vkd.deviceWaitIdle(device));
2455
2456                         prevSwapchain = swapchain;
2457                 }
2458                 catch (...)
2459                 {
2460                         // Make sure device is idle before destroying resources
2461                         vkd.deviceWaitIdle(device);
2462                         throw;
2463                 }
2464         }
2465
2466         return tcu::TestStatus::pass("Resizing tests succeeded");
2467 }
2468
2469 tcu::TestStatus getImagesIncompleteResultTest (Context& context, Type wsiType)
2470 {
2471         const tcu::UVec2                                desiredSize             (256, 256);
2472         const InstanceHelper                    instHelper              (context, wsiType);
2473         const NativeObjects                             native                  (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2474         const Unique<VkSurfaceKHR>              surface                 (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2475         const DeviceHelper                              devHelper               (context, instHelper.vki, instHelper.instance, *surface);
2476         const VkSwapchainCreateInfoKHR  swapchainInfo   = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2477         const Unique<VkSwapchainKHR>    swapchain               (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2478
2479         vector<VkImage>         swapchainImages = getSwapchainImages(devHelper.vkd, *devHelper.device, *swapchain);
2480
2481         ValidateQueryBits::fillBits(swapchainImages.begin(), swapchainImages.end());
2482
2483         const deUint32          usedCount               = static_cast<deUint32>(swapchainImages.size() / 2);
2484         deUint32                        count                   = usedCount;
2485         const VkResult          result                  = devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &count, &swapchainImages[0]);
2486
2487         if (count != usedCount || result != VK_INCOMPLETE || !ValidateQueryBits::checkBits(swapchainImages.begin() + count, swapchainImages.end()))
2488                 return tcu::TestStatus::fail("Get swapchain images didn't return VK_INCOMPLETE");
2489         else
2490                 return tcu::TestStatus::pass("Get swapchain images tests succeeded");
2491 }
2492
2493 tcu::TestStatus getImagesResultsCountTest (Context& context, Type wsiType)
2494 {
2495         const tcu::UVec2                                desiredSize(256, 256);
2496         const InstanceHelper                    instHelper(context, wsiType);
2497         const NativeObjects                             native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2498         const Unique<VkSurfaceKHR>              surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2499         const DeviceHelper                              devHelper(context, instHelper.vki, instHelper.instance, *surface);
2500         const VkSwapchainCreateInfoKHR  swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2501         const Unique<VkSwapchainKHR>    swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2502
2503         deUint32        numImages = 0;
2504
2505         VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2506
2507         if (numImages > 0)
2508         {
2509                 std::vector<VkImage>    images                  (numImages + 1);
2510                 const deUint32                  numImagesOrig   = numImages;
2511
2512                 // check if below call properly overwrites formats count
2513                 numImages++;
2514
2515                 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, &images[0]));
2516
2517                 if ((size_t)numImages != numImagesOrig)
2518                         TCU_FAIL("Image count changed between calls");
2519         }
2520         return tcu::TestStatus::pass("Get swapchain images tests succeeded");
2521 }
2522
2523 tcu::TestStatus destroyNullHandleSwapchainTest (Context& context, Type wsiType)
2524 {
2525         const InstanceHelper            instHelper      (context, wsiType);
2526         const NativeObjects                     native          (context, instHelper.supportedExtensions, wsiType);
2527         const Unique<VkSurfaceKHR>      surface         (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2528         const DeviceHelper                      devHelper       (context, instHelper.vki, instHelper.instance, *surface);
2529         const VkSwapchainKHR            nullHandle      = DE_NULL;
2530
2531         // Default allocator
2532         devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, DE_NULL);
2533
2534         // Custom allocator
2535         {
2536                 AllocationCallbackRecorder      recordingAllocator      (getSystemAllocator(), 1u);
2537
2538                 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, recordingAllocator.getCallbacks());
2539
2540                 if (recordingAllocator.getNumRecords() != 0u)
2541                         return tcu::TestStatus::fail("Implementation allocated/freed the memory");
2542         }
2543
2544         return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
2545 }
2546
2547 tcu::TestStatus acquireTooManyTest (Context& context, Type wsiType)
2548 {
2549         const tcu::UVec2               desiredSize     (256, 256);
2550         const InstanceHelper           instHelper      (context, wsiType);
2551         const NativeObjects            native          (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
2552         const Unique<VkSurfaceKHR>     surface         (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2553         const DeviceHelper             devHelper       (context, instHelper.vki, instHelper.instance, *surface);
2554         const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2555         const Unique<VkSwapchainKHR>   swapchain       (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2556
2557         deUint32 numImages;
2558         VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2559         const deUint32 minImageCount = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface).minImageCount;
2560         if (numImages < minImageCount) return tcu::TestStatus::fail("Get swapchain images returned less than minImageCount images");
2561         const deUint32 numAcquirableImages = numImages - minImageCount + 1;
2562
2563         const auto fences = createFences(devHelper.vkd, *devHelper.device, numAcquirableImages + 1, false);
2564         deUint32 dummy;
2565         for (deUint32 i = 0; i < numAcquirableImages; ++i) {
2566                 VK_CHECK_WSI(devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, std::numeric_limits<deUint64>::max(), (VkSemaphore)0, **fences[i], &dummy));
2567         }
2568
2569         const auto result = devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, 0, (VkSemaphore)0, **fences[numAcquirableImages], &dummy);
2570
2571         if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR && result != VK_NOT_READY ){
2572                 return tcu::TestStatus::fail("Implementation failed to respond well acquiring too many images with 0 timeout");
2573         }
2574
2575         // cleanup
2576         const deUint32 numFences = (result == VK_NOT_READY) ? static_cast<deUint32>(fences.size() - 1) : static_cast<deUint32>(fences.size());
2577         vector<vk::VkFence> fencesRaw(numFences);
2578         std::transform(fences.begin(), fences.begin() + numFences, fencesRaw.begin(), [](const FenceSp& f) -> vk::VkFence{ return **f; });
2579         VK_CHECK(devHelper.vkd.waitForFences(*devHelper.device, numFences, fencesRaw.data(), VK_TRUE, std::numeric_limits<deUint64>::max()));
2580
2581         return tcu::TestStatus::pass("Acquire too many swapchain images test succeeded");
2582 }
2583
2584 tcu::TestStatus acquireTooManyTimeoutTest (Context& context, Type wsiType)
2585 {
2586         const tcu::UVec2               desiredSize     (256, 256);
2587         const InstanceHelper           instHelper      (context, wsiType);
2588         const NativeObjects            native          (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
2589         const Unique<VkSurfaceKHR>     surface         (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2590         const DeviceHelper             devHelper       (context, instHelper.vki, instHelper.instance, *surface);
2591         const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2592         const Unique<VkSwapchainKHR>   swapchain       (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2593
2594         deUint32 numImages;
2595         VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2596         const deUint32 minImageCount = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface).minImageCount;
2597         if (numImages < minImageCount) return tcu::TestStatus::fail("Get swapchain images returned less than minImageCount images");
2598         const deUint32 numAcquirableImages = numImages - minImageCount + 1;
2599
2600         const auto fences = createFences(devHelper.vkd, *devHelper.device, numAcquirableImages + 1, false);
2601         deUint32 dummy;
2602         for (deUint32 i = 0; i < numAcquirableImages; ++i) {
2603                 VK_CHECK_WSI(devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, std::numeric_limits<deUint64>::max(), (VkSemaphore)0, **fences[i], &dummy));
2604         }
2605
2606         const deUint64 millisecond = 1000000;
2607         const deUint64 timeout = 50 * millisecond; // arbitrary realistic non-0 non-infinite timeout
2608         const auto result = devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, timeout, (VkSemaphore)0, **fences[numAcquirableImages], &dummy);
2609
2610         if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR && result != VK_TIMEOUT ){
2611                 return tcu::TestStatus::fail("Implementation failed to respond well acquiring too many images with timeout");
2612         }
2613
2614         // cleanup
2615         const deUint32 numFences = (result == VK_TIMEOUT) ? static_cast<deUint32>(fences.size() - 1) : static_cast<deUint32>(fences.size());
2616         vector<vk::VkFence> fencesRaw(numFences);
2617         std::transform(fences.begin(), fences.begin() + numFences, fencesRaw.begin(), [](const FenceSp& f) -> vk::VkFence{ return **f; });
2618         VK_CHECK(devHelper.vkd.waitForFences(*devHelper.device, numFences, fencesRaw.data(), VK_TRUE, std::numeric_limits<deUint64>::max()));
2619
2620         return tcu::TestStatus::pass("Acquire too many swapchain images test succeeded");
2621 }
2622
2623 void getBasicRenderPrograms (SourceCollections& dst, Type)
2624 {
2625         WsiTriangleRenderer::getPrograms(dst);
2626 }
2627
2628 void getBasicRenderPrograms (SourceCollections& dst, MultiSwapchainParams)
2629 {
2630         WsiTriangleRenderer::getPrograms(dst);
2631 }
2632
2633 void populateRenderGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2634 {
2635         addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest<AcquireNextImageWrapper>, wsiType);
2636         addFunctionCaseWithPrograms(testGroup, "basic2", "Basic Rendering Test using AcquireNextImage2", getBasicRenderPrograms, basicRenderTest<AcquireNextImage2Wrapper>, wsiType);
2637         addFunctionCaseWithPrograms(testGroup, "device_group", "Basic Rendering Test using device_group", getBasicRenderPrograms, deviceGroupRenderTest, wsiType);
2638         addFunctionCaseWithPrograms(testGroup, "device_group2", "Rendering Test using device_group and VkImageSwapchainCreateInfo", getBasicRenderPrograms, deviceGroupRenderTest2, wsiType);
2639
2640         const MultiSwapchainParams kTwoSwapchains       { wsiType, 2u   };
2641         const MultiSwapchainParams kTenSwapchains       { wsiType, 10u  };
2642
2643         addFunctionCaseWithPrograms(testGroup, "2swapchains", "2 Swapchains Rendering Test", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImageWrapper>, kTwoSwapchains);
2644         addFunctionCaseWithPrograms(testGroup, "2swapchains2", "2 Swapchains Rendering Test using AcquireNextImage2", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImage2Wrapper>, kTwoSwapchains);
2645         addFunctionCaseWithPrograms(testGroup, "10swapchains", "10 Swapchains Rendering Test", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImageWrapper>, kTenSwapchains);
2646         addFunctionCaseWithPrograms(testGroup, "10swapchains2", "10 Swapchains Rendering Test using AcquireNextImage2", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImage2Wrapper>, kTenSwapchains);
2647 }
2648
2649 void populateGetImagesGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2650 {
2651         addFunctionCase(testGroup, "incomplete", "Test VK_INCOMPLETE return code", getImagesIncompleteResultTest, wsiType);
2652         addFunctionCase(testGroup, "count",     "Test proper count of images", getImagesResultsCountTest, wsiType);
2653 }
2654
2655 void populateModifyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2656 {
2657         const PlatformProperties&       platformProperties      = getPlatformProperties(wsiType);
2658
2659         if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
2660         {
2661                 addFunctionCaseWithPrograms(testGroup, "resize", "Resize Swapchain Test", getBasicRenderPrograms, resizeSwapchainTest, wsiType);
2662         }
2663
2664         // \todo [2016-05-30 jesse] Add tests for modifying preTransform, compositeAlpha, presentMode
2665 }
2666
2667 void populateDestroyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2668 {
2669         addFunctionCase(testGroup, "null_handle", "Destroying a VK_NULL_HANDLE swapchain", destroyNullHandleSwapchainTest, wsiType);
2670 }
2671
2672 void populateAcquireGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2673 {
2674         addFunctionCase(testGroup, "too_many", "Test acquiring too many images with 0 timeout", acquireTooManyTest, wsiType);
2675         addFunctionCase(testGroup, "too_many_timeout", "Test acquiring too many images with timeout", acquireTooManyTimeoutTest, wsiType);
2676 }
2677
2678 } // anonymous
2679
2680 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
2681 {
2682         addTestGroup(testGroup, "create",                       "Create VkSwapchain with various parameters",                                   populateSwapchainGroup,                                 GroupParameters(wsiType, createSwapchainTest));
2683         addTestGroup(testGroup, "simulate_oom",         "Simulate OOM using callbacks during swapchain construction",   populateSwapchainGroup,                                 GroupParameters(wsiType, createSwapchainSimulateOOMTest));
2684         addTestGroup(testGroup, "render",                       "Rendering Tests",                                                                                              populateRenderGroup,                                    wsiType);
2685         addTestGroup(testGroup, "modify",                       "Modify VkSwapchain",                                                                                   populateModifyGroup,                                    wsiType);
2686         addTestGroup(testGroup, "destroy",                      "Destroy VkSwapchain",                                                                                  populateDestroyGroup,                                   wsiType);
2687         addTestGroup(testGroup, "get_images",           "Get swapchain images",                                                                                 populateGetImagesGroup,                                 wsiType);
2688         addTestGroup(testGroup, "acquire",                      "Ancquire next swapchain image",                                                                populateAcquireGroup,                                   wsiType);
2689         addTestGroup(testGroup, "private_data",         "Create VkSwapchain and use VK_EXT_private_data",                               populateSwapchainPrivateDataGroup,              GroupParameters(wsiType, createSwapchainPrivateDataTest));
2690 }
2691
2692 } // wsi
2693 } // vkt