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