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