Fix image_extent test to handle OOM errors
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / wsi / vktWsiSwapchainTests.cpp
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief VkSwapchain Tests
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktWsiSwapchainTests.hpp"
25
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkPlatform.hpp"
31 #include "vkStrUtil.hpp"
32 #include "vkRef.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkDeviceUtil.hpp"
37 #include "vkPrograms.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkWsiPlatform.hpp"
40 #include "vkWsiUtil.hpp"
41 #include "vkAllocationCallbackUtil.hpp"
42 #include "vkCmdUtil.hpp"
43 #include "vkObjUtil.hpp"
44
45 #include "tcuTestLog.hpp"
46 #include "tcuFormatUtil.hpp"
47 #include "tcuPlatform.hpp"
48 #include "tcuResultCollector.hpp"
49
50 #include "deUniquePtr.hpp"
51 #include "deStringUtil.hpp"
52 #include "deArrayUtil.hpp"
53 #include "deSharedPtr.hpp"
54
55 #include <limits>
56
57 namespace vkt
58 {
59 namespace wsi
60 {
61
62 namespace
63 {
64
65 using namespace vk;
66 using namespace vk::wsi;
67
68 using tcu::TestLog;
69 using tcu::Maybe;
70 using tcu::UVec2;
71
72 using de::MovePtr;
73 using de::UniquePtr;
74
75 using std::string;
76 using std::vector;
77
78 typedef vector<VkExtensionProperties> Extensions;
79
80 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
81 {
82         for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
83                  requiredExtName != requiredExtensions.end();
84                  ++requiredExtName)
85         {
86                 if (!isExtensionSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
87                         TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
88         }
89 }
90
91 Move<VkInstance> createInstanceWithWsi (const PlatformInterface&                vkp,
92                                                                                 deUint32                                                version,
93                                                                                 const Extensions&                               supportedExtensions,
94                                                                                 Type                                                    wsiType,
95                                                                                 const VkAllocationCallbacks*    pAllocator      = DE_NULL)
96 {
97         vector<string>  extensions;
98
99         extensions.push_back("VK_KHR_surface");
100         extensions.push_back(getExtensionName(wsiType));
101
102         // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
103         // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
104         // but using them without enabling the extension is not allowed. Thus we have
105         // two options:
106         //
107         // 1) Filter out non-core formats to stay within valid usage.
108         //
109         // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
110         //
111         // We opt for (2) as it provides basic coverage for the extension as a bonus.
112         if (isExtensionSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
113                 extensions.push_back("VK_EXT_swapchain_colorspace");
114
115         checkAllSupported(supportedExtensions, extensions);
116
117         return vk::createDefaultInstance(vkp, version, vector<string>(), extensions, pAllocator);
118 }
119
120 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
121 {
122         VkPhysicalDeviceFeatures features;
123         deMemset(&features, 0, sizeof(features));
124         return features;
125 }
126
127 Move<VkDevice> createDeviceWithWsi (const PlatformInterface&            vkp,
128                                                                         VkInstance                                              instance,
129                                                                         const InstanceInterface&                vki,
130                                                                         VkPhysicalDevice                                physicalDevice,
131                                                                         const Extensions&                               supportedExtensions,
132                                                                         const deUint32                                  queueFamilyIndex,
133                                                                         const VkAllocationCallbacks*    pAllocator = DE_NULL)
134 {
135         const float                                             queuePriorities[]       = { 1.0f };
136         const VkDeviceQueueCreateInfo   queueInfos[]            =
137         {
138                 {
139                         VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
140                         DE_NULL,
141                         (VkDeviceQueueCreateFlags)0,
142                         queueFamilyIndex,
143                         DE_LENGTH_OF_ARRAY(queuePriorities),
144                         &queuePriorities[0]
145                 }
146         };
147         const VkPhysicalDeviceFeatures  features                = getDeviceFeaturesForWsi();
148         const char* const                               extensions[]    = { "VK_KHR_swapchain" };
149         const VkDeviceCreateInfo                deviceParams    =
150         {
151                 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
152                 DE_NULL,
153                 (VkDeviceCreateFlags)0,
154                 DE_LENGTH_OF_ARRAY(queueInfos),
155                 &queueInfos[0],
156                 0u,                                                                     // enabledLayerCount
157                 DE_NULL,                                                        // ppEnabledLayerNames
158                 DE_LENGTH_OF_ARRAY(extensions),         // enabledExtensionCount
159                 DE_ARRAY_BEGIN(extensions),                     // ppEnabledExtensionNames
160                 &features
161         };
162
163         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
164         {
165                 if (!isExtensionSupported(supportedExtensions, RequiredExtension(extensions[ndx])))
166                         TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
167         }
168
169         return createDevice(vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
170 }
171
172 deUint32 getNumQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
173 {
174         deUint32        numFamilies             = 0;
175
176         vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
177
178         return numFamilies;
179 }
180
181 vector<deUint32> getSupportedQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
182 {
183         const deUint32          numTotalFamilyIndices   = getNumQueueFamilyIndices(vki, physicalDevice);
184         vector<deUint32>        supportedFamilyIndices;
185
186         for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
187         {
188                 if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
189                         supportedFamilyIndices.push_back(queueFamilyNdx);
190         }
191
192         return supportedFamilyIndices;
193 }
194
195 deUint32 chooseQueueFamilyIndex (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
196 {
197         const vector<deUint32>  supportedFamilyIndices  = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
198
199         if (supportedFamilyIndices.empty())
200                 TCU_THROW(NotSupportedError, "Device doesn't support presentation");
201
202         return supportedFamilyIndices[0];
203 }
204
205 struct InstanceHelper
206 {
207         const vector<VkExtensionProperties>     supportedExtensions;
208         const Unique<VkInstance>                        instance;
209         const InstanceDriver                            vki;
210
211         InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
212                 : supportedExtensions   (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
213                                                                                                                                           DE_NULL))
214                 , instance                              (createInstanceWithWsi(context.getPlatformInterface(),
215                                                                                                            context.getUsedApiVersion(),
216                                                                                                            supportedExtensions,
217                                                                                                            wsiType,
218                                                                                                            pAllocator))
219                 , vki                                   (context.getPlatformInterface(), *instance)
220         {}
221 };
222
223 struct DeviceHelper
224 {
225         const VkPhysicalDevice  physicalDevice;
226         const deUint32                  queueFamilyIndex;
227         const Unique<VkDevice>  device;
228         const DeviceDriver              vkd;
229         const VkQueue                   queue;
230
231         DeviceHelper (Context&                                          context,
232                                   const InstanceInterface&              vki,
233                                   VkInstance                                    instance,
234                                   VkSurfaceKHR                                  surface,
235                                   const VkAllocationCallbacks*  pAllocator = DE_NULL)
236                 : physicalDevice        (chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
237                 , queueFamilyIndex      (chooseQueueFamilyIndex(vki, physicalDevice, surface))
238                 , device                        (createDeviceWithWsi(context.getPlatformInterface(),
239                                                                                                  context.getInstance(),
240                                                                                                  vki,
241                                                                                                  physicalDevice,
242                                                                                                  enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
243                                                                                                  queueFamilyIndex,
244                                                                                                  pAllocator))
245                 , vkd                           (context.getPlatformInterface(), context.getInstance(), *device)
246                 , queue                         (getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
247         {
248         }
249 };
250
251 MovePtr<Display> createDisplay (const vk::Platform&     platform,
252                                                                 const Extensions&       supportedExtensions,
253                                                                 Type                            wsiType)
254 {
255         try
256         {
257                 return MovePtr<Display>(platform.createWsiDisplay(wsiType));
258         }
259         catch (const tcu::NotSupportedError& e)
260         {
261                 if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))) &&
262                     platform.hasDisplay(wsiType))
263                 {
264                         // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
265                         // must support creating native display & window for that WSI type.
266                         throw tcu::TestError(e.getMessage());
267                 }
268                 else
269                         throw;
270         }
271 }
272
273 MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
274 {
275         try
276         {
277                 return MovePtr<Window>(display.createWindow(initialSize));
278         }
279         catch (const tcu::NotSupportedError& e)
280         {
281                 // See createDisplay - assuming that wsi::Display was supported platform port
282                 // should also support creating a window.
283                 throw tcu::TestError(e.getMessage());
284         }
285 }
286
287 struct NativeObjects
288 {
289         const UniquePtr<Display>        display;
290         const UniquePtr<Window>         window;
291
292         NativeObjects (Context&                         context,
293                                    const Extensions&    supportedExtensions,
294                                    Type                                 wsiType,
295                                    const Maybe<UVec2>&  initialWindowSize = tcu::nothing<UVec2>())
296                 : display       (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
297                 , window        (createWindow(*display, initialWindowSize))
298         {}
299 };
300
301 enum TestDimension
302 {
303         TEST_DIMENSION_MIN_IMAGE_COUNT = 0,     //!< Test all supported image counts
304         TEST_DIMENSION_IMAGE_FORMAT,            //!< Test all supported formats
305         TEST_DIMENSION_IMAGE_EXTENT,            //!< Test various (supported) extents
306         TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
307         TEST_DIMENSION_IMAGE_USAGE,
308         TEST_DIMENSION_IMAGE_SHARING_MODE,
309         TEST_DIMENSION_PRE_TRANSFORM,
310         TEST_DIMENSION_COMPOSITE_ALPHA,
311         TEST_DIMENSION_PRESENT_MODE,
312         TEST_DIMENSION_CLIPPED,
313
314         TEST_DIMENSION_LAST
315 };
316
317 const char* getTestDimensionName (TestDimension dimension)
318 {
319         static const char* const s_names[] =
320         {
321                 "min_image_count",
322                 "image_format",
323                 "image_extent",
324                 "image_array_layers",
325                 "image_usage",
326                 "image_sharing_mode",
327                 "pre_transform",
328                 "composite_alpha",
329                 "present_mode",
330                 "clipped"
331         };
332         return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
333 }
334
335 struct TestParameters
336 {
337         Type                    wsiType;
338         TestDimension   dimension;
339
340         TestParameters (Type wsiType_, TestDimension dimension_)
341                 : wsiType       (wsiType_)
342                 , dimension     (dimension_)
343         {}
344
345         TestParameters (void)
346                 : wsiType       (TYPE_LAST)
347                 , dimension     (TEST_DIMENSION_LAST)
348         {}
349 };
350
351 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type                                                          wsiType,
352                                                                                                                                   TestDimension                                         dimension,
353                                                                                                                                   const VkSurfaceCapabilitiesKHR&       capabilities,
354                                                                                                                                   const vector<VkSurfaceFormatKHR>&     formats,
355                                                                                                                                   const vector<VkPresentModeKHR>&       presentModes)
356 {
357         const PlatformProperties&                       platformProperties      = getPlatformProperties(wsiType);
358         vector<VkSwapchainCreateInfoKHR>        cases;
359         const VkSurfaceTransformFlagBitsKHR defaultTransform    = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
360         const VkSwapchainCreateInfoKHR          baseParameters          =
361         {
362                 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
363                 DE_NULL,
364                 (VkSwapchainCreateFlagsKHR)0,
365                 (VkSurfaceKHR)0,
366                 capabilities.minImageCount,
367                 formats[0].format,
368                 formats[0].colorSpace,
369                 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
370                         ? capabilities.minImageExtent : capabilities.currentExtent),
371                 1u,                                                                     // imageArrayLayers
372                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
373                 VK_SHARING_MODE_EXCLUSIVE,
374                 0u,
375                 (const deUint32*)DE_NULL,
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 deUint32  maxImageCountToTest     = de::clamp(16u, capabilities.minImageCount, (capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u);
388
389                         for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
390                         {
391                                 cases.push_back(baseParameters);
392                                 cases.back().minImageCount = imageCount;
393                         }
394
395                         break;
396                 }
397
398                 case TEST_DIMENSION_IMAGE_FORMAT:
399                 {
400                         for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
401                         {
402                                 cases.push_back(baseParameters);
403                                 cases.back().imageFormat                = curFmt->format;
404                                 cases.back().imageColorSpace    = curFmt->colorSpace;
405                         }
406
407                         break;
408                 }
409
410                 case TEST_DIMENSION_IMAGE_EXTENT:
411                 {
412                         static const VkExtent2D s_testSizes[]   =
413                         {
414                                 { 1, 1 },
415                                 { 16, 32 },
416                                 { 32, 16 },
417                                 { 632, 231 },
418                                 { 117, 998 },
419                         };
420
421                         if (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
422                                 platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
423                         {
424                                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
425                                 {
426                                         cases.push_back(baseParameters);
427                                         cases.back().imageExtent.width  = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
428                                         cases.back().imageExtent.height = de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
429                                 }
430                         }
431
432                         if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
433                         {
434                                 cases.push_back(baseParameters);
435                                 cases.back().imageExtent = capabilities.currentExtent;
436                         }
437
438                         if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
439                         {
440                                 cases.push_back(baseParameters);
441                                 cases.back().imageExtent = capabilities.minImageExtent;
442
443                                 cases.push_back(baseParameters);
444                                 cases.back().imageExtent = capabilities.maxImageExtent;
445                         }
446
447                         break;
448                 }
449
450                 case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
451                 {
452                         const deUint32  maxLayers       = de::min(capabilities.maxImageArrayLayers, 16u);
453
454                         for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
455                         {
456                                 cases.push_back(baseParameters);
457                                 cases.back().imageArrayLayers = numLayers;
458                         }
459
460                         break;
461                 }
462
463                 case TEST_DIMENSION_IMAGE_USAGE:
464                 {
465                         for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
466                         {
467                                 if ((flags & ~capabilities.supportedUsageFlags) == 0)
468                                 {
469                                         cases.push_back(baseParameters);
470                                         cases.back().imageUsage = flags;
471                                 }
472                         }
473
474                         break;
475                 }
476
477                 case TEST_DIMENSION_IMAGE_SHARING_MODE:
478                 {
479                         cases.push_back(baseParameters);
480                         cases.back().imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
481
482                         cases.push_back(baseParameters);
483                         cases.back().imageSharingMode = VK_SHARING_MODE_CONCURRENT;
484
485                         break;
486                 }
487
488                 case TEST_DIMENSION_PRE_TRANSFORM:
489                 {
490                         for (deUint32 transform = 1u;
491                                  transform <= capabilities.supportedTransforms;
492                                  transform = transform<<1u)
493                         {
494                                 if ((transform & capabilities.supportedTransforms) != 0)
495                                 {
496                                         cases.push_back(baseParameters);
497                                         cases.back().preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
498                                 }
499                         }
500
501                         break;
502                 }
503
504                 case TEST_DIMENSION_COMPOSITE_ALPHA:
505                 {
506                         for (deUint32 alphaMode = 1u;
507                                  alphaMode <= capabilities.supportedCompositeAlpha;
508                                  alphaMode = alphaMode<<1u)
509                         {
510                                 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
511                                 {
512                                         cases.push_back(baseParameters);
513                                         cases.back().compositeAlpha = (VkCompositeAlphaFlagBitsKHR)alphaMode;
514                                 }
515                         }
516
517                         break;
518                 }
519
520                 case TEST_DIMENSION_PRESENT_MODE:
521                 {
522                         for (vector<VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
523                         {
524                                 cases.push_back(baseParameters);
525                                 cases.back().presentMode = *curMode;
526                         }
527
528                         break;
529                 }
530
531                 case TEST_DIMENSION_CLIPPED:
532                 {
533                         cases.push_back(baseParameters);
534                         cases.back().clipped = VK_FALSE;
535
536                         cases.push_back(baseParameters);
537                         cases.back().clipped = VK_TRUE;
538
539                         break;
540                 }
541
542                 default:
543                         DE_FATAL("Impossible");
544         }
545
546         DE_ASSERT(!cases.empty());
547         return cases;
548 }
549
550 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type                                                          wsiType,
551                                                                                                                                   TestDimension                                         dimension,
552                                                                                                                                   const InstanceInterface&                      vki,
553                                                                                                                                   VkPhysicalDevice                                      physicalDevice,
554                                                                                                                                   VkSurfaceKHR                                          surface)
555 {
556         const VkSurfaceCapabilitiesKHR          capabilities    = getPhysicalDeviceSurfaceCapabilities(vki,
557                                                                                                                                                                                            physicalDevice,
558                                                                                                                                                                                            surface);
559         const vector<VkSurfaceFormatKHR>        formats                 = getPhysicalDeviceSurfaceFormats(vki,
560                                                                                                                                                                                   physicalDevice,
561                                                                                                                                                                                   surface);
562         const vector<VkPresentModeKHR>          presentModes    = getPhysicalDeviceSurfacePresentModes(vki,
563                                                                                                                                                                                            physicalDevice,
564                                                                                                                                                                                            surface);
565
566         return generateSwapchainParameterCases(wsiType, dimension, capabilities, formats, presentModes);
567 }
568
569 tcu::TestStatus createSwapchainTest (Context& context, TestParameters params)
570 {
571         tcu::TestLog&                                                   log                     = context.getTestContext().getLog();
572         const InstanceHelper                                    instHelper      (context, params.wsiType);
573         const NativeObjects                                             native          (context, instHelper.supportedExtensions, params.wsiType);
574         const Unique<VkSurfaceKHR>                              surface         (createSurface(instHelper.vki, *instHelper.instance, params.wsiType, *native.display, *native.window));
575         const DeviceHelper                                              devHelper       (context, instHelper.vki, *instHelper.instance, *surface);
576         const vector<VkSwapchainCreateInfoKHR>  cases           (generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
577         const VkSurfaceCapabilitiesKHR                  capabilities(getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface));
578
579         for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
580         {
581                 std::ostringstream subcase;
582                 subcase << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": ";
583
584                 VkSwapchainCreateInfoKHR        curParams       = cases[caseNdx];
585
586                 curParams.surface                               = *surface;
587                 curParams.queueFamilyIndexCount = 1u;
588                 curParams.pQueueFamilyIndices   = &devHelper.queueFamilyIndex;
589
590                 log << TestLog::Message << subcase.str() << curParams << TestLog::EndMessage;
591
592                 // The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
593                 //
594                 //     * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
595                 //     VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
596                 VkImageFormatProperties properties;
597                 const VkResult propertiesResult = instHelper.vki.getPhysicalDeviceImageFormatProperties(devHelper.physicalDevice,
598                                                                                                                                                                                                 curParams.imageFormat,
599                                                                                                                                                                                                 VK_IMAGE_TYPE_2D,
600                                                                                                                                                                                                 VK_IMAGE_TILING_OPTIMAL,
601                                                                                                                                                                                                 curParams.imageUsage,
602                                                                                                                                                                                                 0, // flags
603                                                                                                                                                                                                 &properties);
604
605                 log << TestLog::Message << subcase.str()
606                         << "vkGetPhysicalDeviceImageFormatProperties => "
607                         << getResultStr(propertiesResult) << TestLog::EndMessage;
608
609                 switch (propertiesResult) {
610                 case VK_SUCCESS:
611                         {
612                                 // The maxExtents case might not be able to create the requested surface due to insufficient
613                                 // memory, so in this case *only* we handle the OOM exception.
614                                 if (params.dimension == TEST_DIMENSION_IMAGE_EXTENT &&
615                                         capabilities.maxImageExtent.width == curParams.imageExtent.width &&
616                                         capabilities.maxImageExtent.height == curParams.imageExtent.height)
617                                 {
618                                         try
619                                         {
620                                                 const Unique<VkSwapchainKHR>    swapchain       (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
621
622                                                 log << TestLog::Message << subcase.str()
623                                                         << "Creating swapchain succeeded" << TestLog::EndMessage;
624                                         }
625                                         catch (const OutOfMemoryError& e)
626                                         {
627                                                 log << TestLog::Message << subcase.str() << "vkCreateSwapchainKHR with maxImageExtent encountered " << e.getError() << TestLog::EndMessage;
628                                         }
629                                 }
630                                 else
631                                 {
632                                         const Unique<VkSwapchainKHR>    swapchain       (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
633
634                                         log << TestLog::Message << subcase.str()
635                                                 << "Creating swapchain succeeded" << TestLog::EndMessage;
636                                 }
637                         }
638                         break;
639                 case VK_ERROR_FORMAT_NOT_SUPPORTED:
640                         log << TestLog::Message << subcase.str()
641                                 << "Skip because vkGetPhysicalDeviceImageFormatProperties returned VK_ERROR_FORMAT_NOT_SUPPORTED" << TestLog::EndMessage;
642                         break;
643                 default:
644                         log << TestLog::Message << subcase.str()
645                                 << "Fail because vkGetPhysicalDeviceImageFormatProperties returned "
646                                 << getResultStr(propertiesResult) << TestLog::EndMessage;
647                         return tcu::TestStatus::fail("Unexpected result from vkGetPhysicalDeviceImageFormatProperties");
648                 }
649         }
650
651         return tcu::TestStatus::pass("No sub-case failed");
652 }
653
654 tcu::TestStatus createSwapchainSimulateOOMTest (Context& context, TestParameters params)
655 {
656         const size_t                            maxCases                        = 300u;
657         const deUint32                          maxAllocs                       = 1024u;
658
659         tcu::TestLog&                           log                                     = context.getTestContext().getLog();
660         tcu::ResultCollector            results                         (log);
661
662         AllocationCallbackRecorder      allocationRecorder      (getSystemAllocator());
663         DeterministicFailAllocator      failingAllocator        (allocationRecorder.getCallbacks(),
664                                                                                                          DeterministicFailAllocator::MODE_DO_NOT_COUNT,
665                                                                                                          0);
666         {
667                 const InstanceHelper                                    instHelper      (context, params.wsiType, failingAllocator.getCallbacks());
668                 const NativeObjects                                             native          (context, instHelper.supportedExtensions, params.wsiType);
669                 const Unique<VkSurfaceKHR>                              surface         (createSurface(instHelper.vki,
670                                                                                                                                                         *instHelper.instance,
671                                                                                                                                                         params.wsiType,
672                                                                                                                                                         *native.display,
673                                                                                                                                                         *native.window,
674                                                                                                                                                         failingAllocator.getCallbacks()));
675                 const DeviceHelper                                              devHelper       (context, instHelper.vki, *instHelper.instance, *surface, failingAllocator.getCallbacks());
676                 const vector<VkSwapchainCreateInfoKHR>  allCases        (generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
677
678                 if (maxCases < allCases.size())
679                         log << TestLog::Message << "Note: Will only test first " << maxCases << " cases out of total of " << allCases.size() << " parameter combinations" << TestLog::EndMessage;
680
681                 for (size_t caseNdx = 0; caseNdx < de::min(maxCases, allCases.size()); ++caseNdx)
682                 {
683                         log << TestLog::Message << "Testing parameter case " << caseNdx << ": " << allCases[caseNdx] << TestLog::EndMessage;
684
685                         for (deUint32 numPassingAllocs = 0; numPassingAllocs <= maxAllocs; ++numPassingAllocs)
686                         {
687                                 bool    gotOOM  = false;
688
689                                 failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
690
691                                 log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
692
693                                 try
694                                 {
695                                         VkSwapchainCreateInfoKHR        curParams       = allCases[caseNdx];
696
697                                         curParams.surface                               = *surface;
698                                         curParams.queueFamilyIndexCount = 1u;
699                                         curParams.pQueueFamilyIndices   = &devHelper.queueFamilyIndex;
700
701                                         {
702                                                 const Unique<VkSwapchainKHR>    swapchain       (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
703                                         }
704                                 }
705                                 catch (const OutOfMemoryError& e)
706                                 {
707                                         log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
708                                         gotOOM = true;
709                                 }
710
711                                 if (!gotOOM)
712                                 {
713                                         log << TestLog::Message << "Creating swapchain succeeded!" << TestLog::EndMessage;
714
715                                         if (numPassingAllocs == 0)
716                                                 results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
717
718                                         break;
719                                 }
720                                 else if (numPassingAllocs == maxAllocs)
721                                         results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
722                         }
723
724                         context.getTestContext().touchWatchdog();
725                 }
726         }
727
728         if (!validateAndLog(log, allocationRecorder, 0u))
729                 results.fail("Detected invalid system allocation callback");
730
731         return tcu::TestStatus(results.getResult(), results.getMessage());
732 }
733
734 struct GroupParameters
735 {
736         typedef FunctionInstance1<TestParameters>::Function     Function;
737
738         Type            wsiType;
739         Function        function;
740
741         GroupParameters (Type wsiType_, Function function_)
742                 : wsiType       (wsiType_)
743                 , function      (function_)
744         {}
745
746         GroupParameters (void)
747                 : wsiType       (TYPE_LAST)
748                 , function      ((Function)DE_NULL)
749         {}
750 };
751
752 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
753 {
754         for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
755         {
756                 const TestDimension             testDimension   = (TestDimension)dimensionNdx;
757
758                 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
759         }
760 }
761
762 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type                                              wsiType,
763                                                                                                           const InstanceInterface&      vki,
764                                                                                                           VkPhysicalDevice                      physicalDevice,
765                                                                                                           VkSurfaceKHR                          surface,
766                                                                                                           const tcu::UVec2&                     desiredSize,
767                                                                                                           deUint32                                      desiredImageCount)
768 {
769         const VkSurfaceCapabilitiesKHR          capabilities            = getPhysicalDeviceSurfaceCapabilities(vki,
770                                                                                                                                                                                                    physicalDevice,
771                                                                                                                                                                                                    surface);
772         const vector<VkSurfaceFormatKHR>        formats                         = getPhysicalDeviceSurfaceFormats(vki,
773                                                                                                                                                                                           physicalDevice,
774                                                                                                                                                                                           surface);
775         const PlatformProperties&                       platformProperties      = getPlatformProperties(wsiType);
776         const VkSurfaceTransformFlagBitsKHR transform                   = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
777         const VkSwapchainCreateInfoKHR          parameters                      =
778         {
779                 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
780                 DE_NULL,
781                 (VkSwapchainCreateFlagsKHR)0,
782                 surface,
783                 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
784                 formats[0].format,
785                 formats[0].colorSpace,
786                 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
787                         ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
788                 1u,                                                                     // imageArrayLayers
789                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
790                 VK_SHARING_MODE_EXCLUSIVE,
791                 0u,
792                 (const deUint32*)DE_NULL,
793                 transform,
794                 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
795                 VK_PRESENT_MODE_FIFO_KHR,
796                 VK_FALSE,                                                       // clipped
797                 (VkSwapchainKHR)0                                       // oldSwapchain
798         };
799
800         return parameters;
801 }
802
803 typedef de::SharedPtr<Unique<VkImageView> >             ImageViewSp;
804 typedef de::SharedPtr<Unique<VkFramebuffer> >   FramebufferSp;
805
806 class TriangleRenderer
807 {
808 public:
809                                                                         TriangleRenderer        (const DeviceInterface&         vkd,
810                                                                                                                  const VkDevice                         device,
811                                                                                                                  Allocator&                                     allocator,
812                                                                                                                  const BinaryCollection&        binaryRegistry,
813                                                                                                                  const vector<VkImage>          swapchainImages,
814                                                                                                                  const VkFormat                         framebufferFormat,
815                                                                                                                  const UVec2&                           renderSize);
816                                                                         ~TriangleRenderer       (void);
817
818         void                                                    recordFrame                     (VkCommandBuffer                        cmdBuffer,
819                                                                                                                  deUint32                                       imageNdx,
820                                                                                                                  deUint32                                       frameNdx) const;
821
822         static void                                             getPrograms                     (SourceCollections& dst);
823
824 private:
825         static Move<VkRenderPass>               createRenderPass        (const DeviceInterface&         vkd,
826                                                                                                                  const VkDevice                         device,
827                                                                                                                  const VkFormat                         colorAttachmentFormat);
828         static Move<VkPipelineLayout>   createPipelineLayout(const DeviceInterface&             vkd,
829                                                                                                                  VkDevice                                       device);
830         static Move<VkPipeline>                 createPipeline          (const DeviceInterface&         vkd,
831                                                                                                                  const VkDevice                         device,
832                                                                                                                  const VkRenderPass                     renderPass,
833                                                                                                                  const VkPipelineLayout         pipelineLayout,
834                                                                                                                  const BinaryCollection&        binaryCollection,
835                                                                                                                  const UVec2&                           renderSize);
836
837         static Move<VkImageView>                createAttachmentView(const DeviceInterface&             vkd,
838                                                                                                                  const VkDevice                         device,
839                                                                                                                  const VkImage                          image,
840                                                                                                                  const VkFormat                         format);
841         static Move<VkFramebuffer>              createFramebuffer       (const DeviceInterface&         vkd,
842                                                                                                                  const VkDevice                         device,
843                                                                                                                  const VkRenderPass                     renderPass,
844                                                                                                                  const VkImageView                      colorAttachment,
845                                                                                                                  const UVec2&                           renderSize);
846
847         static Move<VkBuffer>                   createBuffer            (const DeviceInterface&         vkd,
848                                                                                                                  VkDevice                                       device,
849                                                                                                                  VkDeviceSize                           size,
850                                                                                                                  VkBufferUsageFlags                     usage);
851
852         const DeviceInterface&                  m_vkd;
853
854         const vector<VkImage>                   m_swapchainImages;
855         const tcu::UVec2                                m_renderSize;
856
857         const Unique<VkRenderPass>              m_renderPass;
858         const Unique<VkPipelineLayout>  m_pipelineLayout;
859         const Unique<VkPipeline>                m_pipeline;
860
861         const Unique<VkBuffer>                  m_vertexBuffer;
862         const UniquePtr<Allocation>             m_vertexBufferMemory;
863
864         vector<ImageViewSp>                             m_attachmentViews;
865         vector<FramebufferSp>                   m_framebuffers;
866 };
867
868 Move<VkRenderPass> TriangleRenderer::createRenderPass (const DeviceInterface&   vkd,
869                                                                                                            const VkDevice                       device,
870                                                                                                            const VkFormat                       colorAttachmentFormat)
871 {
872         const VkAttachmentDescription   colorAttDesc            =
873         {
874                 (VkAttachmentDescriptionFlags)0,
875                 colorAttachmentFormat,
876                 VK_SAMPLE_COUNT_1_BIT,
877                 VK_ATTACHMENT_LOAD_OP_CLEAR,
878                 VK_ATTACHMENT_STORE_OP_STORE,
879                 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
880                 VK_ATTACHMENT_STORE_OP_DONT_CARE,
881                 VK_IMAGE_LAYOUT_UNDEFINED,
882                 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
883         };
884         const VkAttachmentReference             colorAttRef                     =
885         {
886                 0u,
887                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
888         };
889         const VkSubpassDescription              subpassDesc                     =
890         {
891                 (VkSubpassDescriptionFlags)0u,
892                 VK_PIPELINE_BIND_POINT_GRAPHICS,
893                 0u,                                                     // inputAttachmentCount
894                 DE_NULL,                                        // pInputAttachments
895                 1u,                                                     // colorAttachmentCount
896                 &colorAttRef,                           // pColorAttachments
897                 DE_NULL,                                        // pResolveAttachments
898                 DE_NULL,                                        // depthStencilAttachment
899                 0u,                                                     // preserveAttachmentCount
900                 DE_NULL,                                        // pPreserveAttachments
901         };
902         const VkSubpassDependency               dependencies[]          =
903         {
904                 {
905                         VK_SUBPASS_EXTERNAL,    // srcSubpass
906                         0u,                                             // dstSubpass
907                         VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
908                         VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
909                         VK_ACCESS_MEMORY_READ_BIT,
910                         (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
911                          VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
912                         VK_DEPENDENCY_BY_REGION_BIT
913                 },
914                 {
915                         0u,                                             // srcSubpass
916                         VK_SUBPASS_EXTERNAL,    // dstSubpass
917                         VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
918                         VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
919                         (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
920                          VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
921                         VK_ACCESS_MEMORY_READ_BIT,
922                         VK_DEPENDENCY_BY_REGION_BIT
923                 },
924         };
925         const VkRenderPassCreateInfo    renderPassParams        =
926         {
927                 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
928                 DE_NULL,
929                 (VkRenderPassCreateFlags)0,
930                 1u,
931                 &colorAttDesc,
932                 1u,
933                 &subpassDesc,
934                 DE_LENGTH_OF_ARRAY(dependencies),
935                 dependencies,
936         };
937
938         return vk::createRenderPass(vkd, device, &renderPassParams);
939 }
940
941 Move<VkPipelineLayout> TriangleRenderer::createPipelineLayout (const DeviceInterface&   vkd,
942                                                                                                                            const VkDevice                       device)
943 {
944         const VkPushConstantRange                                               pushConstantRange               =
945         {
946                 VK_SHADER_STAGE_VERTEX_BIT,
947                 0u,                                                                                     // offset
948                 (deUint32)sizeof(deUint32),                                     // size
949         };
950         const VkPipelineLayoutCreateInfo                                pipelineLayoutParams    =
951         {
952                 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
953                 DE_NULL,
954                 (vk::VkPipelineLayoutCreateFlags)0,
955                 0u,                                                                                     // setLayoutCount
956                 DE_NULL,                                                                        // pSetLayouts
957                 1u,
958                 &pushConstantRange,
959         };
960
961         return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
962 }
963
964 Move<VkPipeline> TriangleRenderer::createPipeline (const DeviceInterface&       vkd,
965                                                                                                    const VkDevice                       device,
966                                                                                                    const VkRenderPass           renderPass,
967                                                                                                    const VkPipelineLayout       pipelineLayout,
968                                                                                                    const BinaryCollection&      binaryCollection,
969                                                                                                    const UVec2&                         renderSize)
970 {
971         // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
972         //               and can be deleted immediately following that call.
973         const Unique<VkShaderModule>                                    vertShaderModule                (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
974         const Unique<VkShaderModule>                                    fragShaderModule                (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
975         const std::vector<VkViewport>                                   viewports                               (1, makeViewport(renderSize));
976         const std::vector<VkRect2D>                                             scissors                                (1, makeRect2D(renderSize));
977
978         return vk::makeGraphicsPipeline(vkd,                            // const DeviceInterface&            vk
979                                                                         device,                         // const VkDevice                    device
980                                                                         pipelineLayout,         // const VkPipelineLayout            pipelineLayout
981                                                                         *vertShaderModule,      // const VkShaderModule              vertexShaderModule
982                                                                         DE_NULL,                        // const VkShaderModule              tessellationControlShaderModule
983                                                                         DE_NULL,                        // const VkShaderModule              tessellationEvalShaderModule
984                                                                         DE_NULL,                        // const VkShaderModule              geometryShaderModule
985                                                                         *fragShaderModule,      // const VkShaderModule              fragmentShaderModule
986                                                                         renderPass,                     // const VkRenderPass                renderPass
987                                                                         viewports,                      // const std::vector<VkViewport>&    viewports
988                                                                         scissors);                      // const std::vector<VkRect2D>&      scissors
989 }
990
991 Move<VkImageView> TriangleRenderer::createAttachmentView (const DeviceInterface&        vkd,
992                                                                                                                   const VkDevice                        device,
993                                                                                                                   const VkImage                         image,
994                                                                                                                   const VkFormat                        format)
995 {
996         const VkImageViewCreateInfo             viewParams      =
997         {
998                 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
999                 DE_NULL,
1000                 (VkImageViewCreateFlags)0,
1001                 image,
1002                 VK_IMAGE_VIEW_TYPE_2D,
1003                 format,
1004                 vk::makeComponentMappingRGBA(),
1005                 {
1006                         VK_IMAGE_ASPECT_COLOR_BIT,
1007                         0u,                                             // baseMipLevel
1008                         1u,                                             // levelCount
1009                         0u,                                             // baseArrayLayer
1010                         1u,                                             // layerCount
1011                 },
1012         };
1013
1014         return vk::createImageView(vkd, device, &viewParams);
1015 }
1016
1017 Move<VkFramebuffer> TriangleRenderer::createFramebuffer (const DeviceInterface&         vkd,
1018                                                                                                                  const VkDevice                         device,
1019                                                                                                                  const VkRenderPass                     renderPass,
1020                                                                                                                  const VkImageView                      colorAttachment,
1021                                                                                                                  const UVec2&                           renderSize)
1022 {
1023         const VkFramebufferCreateInfo   framebufferParams       =
1024         {
1025                 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1026                 DE_NULL,
1027                 (VkFramebufferCreateFlags)0,
1028                 renderPass,
1029                 1u,
1030                 &colorAttachment,
1031                 renderSize.x(),
1032                 renderSize.y(),
1033                 1u,                                                     // layers
1034         };
1035
1036         return vk::createFramebuffer(vkd, device, &framebufferParams);
1037 }
1038
1039 Move<VkBuffer> TriangleRenderer::createBuffer (const DeviceInterface&   vkd,
1040                                                                                            VkDevice                                     device,
1041                                                                                            VkDeviceSize                         size,
1042                                                                                            VkBufferUsageFlags           usage)
1043 {
1044         const VkBufferCreateInfo        bufferParams    =
1045         {
1046                 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1047                 DE_NULL,
1048                 (VkBufferCreateFlags)0,
1049                 size,
1050                 usage,
1051                 VK_SHARING_MODE_EXCLUSIVE,
1052                 0,
1053                 DE_NULL
1054         };
1055
1056         return vk::createBuffer(vkd, device, &bufferParams);
1057 }
1058
1059 TriangleRenderer::TriangleRenderer (const DeviceInterface&      vkd,
1060                                                                         const VkDevice                  device,
1061                                                                         Allocator&                              allocator,
1062                                                                         const BinaryCollection& binaryRegistry,
1063                                                                         const vector<VkImage>   swapchainImages,
1064                                                                         const VkFormat                  framebufferFormat,
1065                                                                         const UVec2&                    renderSize)
1066         : m_vkd                                 (vkd)
1067         , m_swapchainImages             (swapchainImages)
1068         , m_renderSize                  (renderSize)
1069         , m_renderPass                  (createRenderPass(vkd, device, framebufferFormat))
1070         , m_pipelineLayout              (createPipelineLayout(vkd, device))
1071         , m_pipeline                    (createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
1072         , m_vertexBuffer                (createBuffer(vkd, device, (VkDeviceSize)(sizeof(float)*4*3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
1073         , m_vertexBufferMemory  (allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer),
1074                                                          MemoryRequirement::HostVisible))
1075 {
1076         m_attachmentViews.resize(swapchainImages.size());
1077         m_framebuffers.resize(swapchainImages.size());
1078
1079         for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
1080         {
1081                 m_attachmentViews[imageNdx]     = ImageViewSp(new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
1082                 m_framebuffers[imageNdx]        = FramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
1083         }
1084
1085         VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset()));
1086
1087         {
1088                 const VkMappedMemoryRange       memRange        =
1089                 {
1090                         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
1091                         DE_NULL,
1092                         m_vertexBufferMemory->getMemory(),
1093                         m_vertexBufferMemory->getOffset(),
1094                         VK_WHOLE_SIZE
1095                 };
1096                 const tcu::Vec4                         vertices[]      =
1097                 {
1098                         tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
1099                         tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
1100                         tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
1101                 };
1102                 DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
1103
1104                 deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
1105                 VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
1106         }
1107 }
1108
1109 TriangleRenderer::~TriangleRenderer (void)
1110 {
1111 }
1112
1113 void TriangleRenderer::recordFrame (VkCommandBuffer     cmdBuffer,
1114                                                                         deUint32                imageNdx,
1115                                                                         deUint32                frameNdx) const
1116 {
1117         const VkFramebuffer     curFramebuffer  = **m_framebuffers[imageNdx];
1118
1119         beginCommandBuffer(m_vkd, cmdBuffer, 0u);
1120
1121         beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
1122
1123         m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1124
1125         {
1126                 const VkDeviceSize bindingOffset = 0;
1127                 m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
1128         }
1129
1130         m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
1131         m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1132         endRenderPass(m_vkd, cmdBuffer);
1133
1134         endCommandBuffer(m_vkd, cmdBuffer);
1135 }
1136
1137 void TriangleRenderer::getPrograms (SourceCollections& dst)
1138 {
1139         dst.glslSources.add("tri-vert") << glu::VertexSource(
1140                 "#version 310 es\n"
1141                 "layout(location = 0) in highp vec4 a_position;\n"
1142                 "layout(push_constant) uniform FrameData\n"
1143                 "{\n"
1144                 "    highp uint frameNdx;\n"
1145                 "} frameData;\n"
1146                 "void main (void)\n"
1147                 "{\n"
1148                 "    highp float angle = float(frameData.frameNdx) / 100.0;\n"
1149                 "    highp float c     = cos(angle);\n"
1150                 "    highp float s     = sin(angle);\n"
1151                 "    highp mat4  t     = mat4( c, -s,  0,  0,\n"
1152                 "                              s,  c,  0,  0,\n"
1153                 "                              0,  0,  1,  0,\n"
1154                 "                              0,  0,  0,  1);\n"
1155                 "    gl_Position = t * a_position;\n"
1156                 "}\n");
1157         dst.glslSources.add("tri-frag") << glu::FragmentSource(
1158                 "#version 310 es\n"
1159                 "layout(location = 0) out lowp vec4 o_color;\n"
1160                 "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1161 }
1162
1163 typedef de::SharedPtr<Unique<VkCommandBuffer> > CommandBufferSp;
1164 typedef de::SharedPtr<Unique<VkFence> >                 FenceSp;
1165 typedef de::SharedPtr<Unique<VkSemaphore> >             SemaphoreSp;
1166
1167 vector<FenceSp> createFences (const DeviceInterface&    vkd,
1168                                                           const VkDevice                        device,
1169                                                           size_t                                        numFences)
1170 {
1171         vector<FenceSp> fences(numFences);
1172
1173         for (size_t ndx = 0; ndx < numFences; ++ndx)
1174                 fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
1175
1176         return fences;
1177 }
1178
1179 vector<SemaphoreSp> createSemaphores (const DeviceInterface&    vkd,
1180                                                                           const VkDevice                        device,
1181                                                                           size_t                                        numSemaphores)
1182 {
1183         vector<SemaphoreSp> semaphores(numSemaphores);
1184
1185         for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1186                 semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
1187
1188         return semaphores;
1189 }
1190
1191 vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface&          vkd,
1192                                                                                                 const VkDevice                          device,
1193                                                                                                 const VkCommandPool                     commandPool,
1194                                                                                                 const VkCommandBufferLevel      level,
1195                                                                                                 const size_t                            numCommandBuffers)
1196 {
1197         vector<CommandBufferSp>                         buffers         (numCommandBuffers);
1198
1199         for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1200                 buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1201
1202         return buffers;
1203 }
1204
1205 tcu::TestStatus basicRenderTest (Context& context, Type wsiType)
1206 {
1207         const tcu::UVec2                                desiredSize                                     (256, 256);
1208         const InstanceHelper                    instHelper                                      (context, wsiType);
1209         const NativeObjects                             native                                          (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1210         const Unique<VkSurfaceKHR>              surface                                         (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1211         const DeviceHelper                              devHelper                                       (context, instHelper.vki, *instHelper.instance, *surface);
1212         const DeviceInterface&                  vkd                                                     = devHelper.vkd;
1213         const VkDevice                                  device                                          = *devHelper.device;
1214         SimpleAllocator                                 allocator                                       (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1215         const VkSwapchainCreateInfoKHR  swapchainInfo                           = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1216         const Unique<VkSwapchainKHR>    swapchain                                       (createSwapchainKHR(vkd, device, &swapchainInfo));
1217         const vector<VkImage>                   swapchainImages                         = getSwapchainImages(vkd, device, *swapchain);
1218
1219         const TriangleRenderer                  renderer                                        (vkd,
1220                                                                                                                                  device,
1221                                                                                                                                  allocator,
1222                                                                                                                                  context.getBinaryCollection(),
1223                                                                                                                                  swapchainImages,
1224                                                                                                                                  swapchainInfo.imageFormat,
1225                                                                                                                                  tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1226
1227         const Unique<VkCommandPool>             commandPool                                     (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1228
1229         const size_t                                    maxQueuedFrames                         = swapchainImages.size()*2;
1230
1231         // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1232         // limit number of frames we allow to be queued.
1233         const vector<FenceSp>                   imageReadyFences                        (createFences(vkd, device, maxQueuedFrames));
1234
1235         // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1236         // the semaphore in same time as the fence we use to meter rendering.
1237         const vector<SemaphoreSp>               imageReadySemaphores            (createSemaphores(vkd, device, maxQueuedFrames+1));
1238
1239         // For rest we simply need maxQueuedFrames as we will wait for image
1240         // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1241         // previous uses must have completed.
1242         const vector<SemaphoreSp>               renderingCompleteSemaphores     (createSemaphores(vkd, device, maxQueuedFrames));
1243         const vector<CommandBufferSp>   commandBuffers                          (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1244
1245         try
1246         {
1247                 const deUint32  numFramesToRender       = 60*10;
1248
1249                 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1250                 {
1251                         const VkFence           imageReadyFence         = **imageReadyFences[frameNdx%imageReadyFences.size()];
1252                         const VkSemaphore       imageReadySemaphore     = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1253                         deUint32                        imageNdx                        = ~0u;
1254
1255                         if (frameNdx >= maxQueuedFrames)
1256                                 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1257
1258                         VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1259
1260                         {
1261                                 const VkResult  acquireResult   = vkd.acquireNextImageKHR(device,
1262                                                                                                                                                   *swapchain,
1263                                                                                                                                                   std::numeric_limits<deUint64>::max(),
1264                                                                                                                                                   imageReadySemaphore,
1265                                                                                                                                                   (VkFence)0,
1266                                                                                                                                                   &imageNdx);
1267
1268                                 if (acquireResult == VK_SUBOPTIMAL_KHR)
1269                                         context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1270                                 else
1271                                         VK_CHECK(acquireResult);
1272                         }
1273
1274                         TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1275
1276                         {
1277                                 const VkSemaphore                       renderingCompleteSemaphore      = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1278                                 const VkCommandBuffer           commandBuffer                           = **commandBuffers[frameNdx%commandBuffers.size()];
1279                                 const VkPipelineStageFlags      waitDstStage                            = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1280                                 const VkSubmitInfo                      submitInfo                                      =
1281                                 {
1282                                         VK_STRUCTURE_TYPE_SUBMIT_INFO,
1283                                         DE_NULL,
1284                                         1u,
1285                                         &imageReadySemaphore,
1286                                         &waitDstStage,
1287                                         1u,
1288                                         &commandBuffer,
1289                                         1u,
1290                                         &renderingCompleteSemaphore
1291                                 };
1292                                 const VkPresentInfoKHR          presentInfo                                     =
1293                                 {
1294                                         VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1295                                         DE_NULL,
1296                                         1u,
1297                                         &renderingCompleteSemaphore,
1298                                         1u,
1299                                         &*swapchain,
1300                                         &imageNdx,
1301                                         (VkResult*)DE_NULL
1302                                 };
1303
1304                                 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1305                                 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
1306                                 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1307                         }
1308                 }
1309
1310                 VK_CHECK(vkd.deviceWaitIdle(device));
1311         }
1312         catch (...)
1313         {
1314                 // Make sure device is idle before destroying resources
1315                 vkd.deviceWaitIdle(device);
1316                 throw;
1317         }
1318
1319         return tcu::TestStatus::pass("Rendering tests succeeded");
1320 }
1321
1322 vector<tcu::UVec2> getSwapchainSizeSequence (const VkSurfaceCapabilitiesKHR& capabilities, const tcu::UVec2& defaultSize)
1323 {
1324         vector<tcu::UVec2> sizes(3);
1325         sizes[0] = defaultSize / 2u;
1326         sizes[1] = defaultSize;
1327         sizes[2] = defaultSize * 2u;
1328
1329         for (deUint32 i = 0; i < sizes.size(); ++i)
1330         {
1331                 sizes[i].x() = de::clamp(sizes[i].x(), capabilities.minImageExtent.width,  capabilities.maxImageExtent.width);
1332                 sizes[i].y() = de::clamp(sizes[i].y(), capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
1333         }
1334
1335         return sizes;
1336 }
1337
1338 tcu::TestStatus resizeSwapchainTest (Context& context, Type wsiType)
1339 {
1340         const tcu::UVec2                                desiredSize                     (256, 256);
1341         const InstanceHelper                    instHelper                      (context, wsiType);
1342         const NativeObjects                             native                          (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1343         const Unique<VkSurfaceKHR>              surface                         (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1344         const DeviceHelper                              devHelper                       (context, instHelper.vki, *instHelper.instance, *surface);
1345         const PlatformProperties&               platformProperties      = getPlatformProperties(wsiType);
1346         const VkSurfaceCapabilitiesKHR  capabilities            = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
1347         const DeviceInterface&                  vkd                                     = devHelper.vkd;
1348         const VkDevice                                  device                          = *devHelper.device;
1349         SimpleAllocator                                 allocator                       (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1350         vector<tcu::UVec2>                              sizes                           = getSwapchainSizeSequence(capabilities, desiredSize);
1351         Move<VkSwapchainKHR>                    prevSwapchain;
1352
1353         DE_ASSERT(platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE);
1354         DE_UNREF(platformProperties);
1355
1356         for (deUint32 sizeNdx = 0; sizeNdx < sizes.size(); ++sizeNdx)
1357         {
1358                 // \todo [2016-05-30 jesse] This test currently waits for idle and
1359                 // recreates way more than necessary when recreating the swapchain. Make
1360                 // it match expected real app behavior better by smoothly switching from
1361                 // old to new swapchain. Once that is done, it will also be possible to
1362                 // test creating a new swapchain while images from the previous one are
1363                 // still acquired.
1364
1365                 VkSwapchainCreateInfoKHR                swapchainInfo                           = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, sizes[sizeNdx], 2);
1366                 swapchainInfo.oldSwapchain = *prevSwapchain;
1367
1368                 Move<VkSwapchainKHR>                    swapchain                                       (createSwapchainKHR(vkd, device, &swapchainInfo));
1369                 const vector<VkImage>                   swapchainImages                         = getSwapchainImages(vkd, device, *swapchain);
1370                 const TriangleRenderer                  renderer                                        (vkd,
1371                                                                                                                                         device,
1372                                                                                                                                         allocator,
1373                                                                                                                                         context.getBinaryCollection(),
1374                                                                                                                                         swapchainImages,
1375                                                                                                                                         swapchainInfo.imageFormat,
1376                                                                                                                                         tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1377                 const Unique<VkCommandPool>             commandPool                                     (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1378                 const size_t                                    maxQueuedFrames                         = swapchainImages.size()*2;
1379
1380                 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1381                 // limit number of frames we allow to be queued.
1382                 const vector<FenceSp>                   imageReadyFences                        (createFences(vkd, device, maxQueuedFrames));
1383
1384                 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1385                 // the semaphore in same time as the fence we use to meter rendering.
1386                 const vector<SemaphoreSp>               imageReadySemaphores            (createSemaphores(vkd, device, maxQueuedFrames+1));
1387
1388                 // For rest we simply need maxQueuedFrames as we will wait for image
1389                 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1390                 // previous uses must have completed.
1391                 const vector<SemaphoreSp>               renderingCompleteSemaphores     (createSemaphores(vkd, device, maxQueuedFrames));
1392                 const vector<CommandBufferSp>   commandBuffers                          (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1393
1394                 try
1395                 {
1396                         const deUint32  numFramesToRender       = 60;
1397
1398                         for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1399                         {
1400                                 const VkFence           imageReadyFence         = **imageReadyFences[frameNdx%imageReadyFences.size()];
1401                                 const VkSemaphore       imageReadySemaphore     = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1402                                 deUint32                        imageNdx                        = ~0u;
1403
1404                                 if (frameNdx >= maxQueuedFrames)
1405                                         VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1406
1407                                 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1408
1409                                 {
1410                                         const VkResult  acquireResult   = vkd.acquireNextImageKHR(device,
1411                                                                                                                                                           *swapchain,
1412                                                                                                                                                           std::numeric_limits<deUint64>::max(),
1413                                                                                                                                                           imageReadySemaphore,
1414                                                                                                                                                           imageReadyFence,
1415                                                                                                                                                           &imageNdx);
1416
1417                                         if (acquireResult == VK_SUBOPTIMAL_KHR)
1418                                                 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1419                                         else
1420                                                 VK_CHECK(acquireResult);
1421                                 }
1422
1423                                 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1424
1425                                 {
1426                                         const VkSemaphore                       renderingCompleteSemaphore      = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1427                                         const VkCommandBuffer           commandBuffer                           = **commandBuffers[frameNdx%commandBuffers.size()];
1428                                         const VkPipelineStageFlags      waitDstStage                            = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1429                                         const VkSubmitInfo                      submitInfo                                      =
1430                                         {
1431                                                 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1432                                                 DE_NULL,
1433                                                 1u,
1434                                                 &imageReadySemaphore,
1435                                                 &waitDstStage,
1436                                                 1u,
1437                                                 &commandBuffer,
1438                                                 1u,
1439                                                 &renderingCompleteSemaphore
1440                                         };
1441                                         const VkPresentInfoKHR          presentInfo                                     =
1442                                         {
1443                                                 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1444                                                 DE_NULL,
1445                                                 1u,
1446                                                 &renderingCompleteSemaphore,
1447                                                 1u,
1448                                                 &*swapchain,
1449                                                 &imageNdx,
1450                                                 (VkResult*)DE_NULL
1451                                         };
1452
1453                                         renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1454                                         VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, (VkFence)0));
1455                                         VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1456                                 }
1457                         }
1458
1459                         VK_CHECK(vkd.deviceWaitIdle(device));
1460
1461                         prevSwapchain = swapchain;
1462                 }
1463                 catch (...)
1464                 {
1465                         // Make sure device is idle before destroying resources
1466                         vkd.deviceWaitIdle(device);
1467                         throw;
1468                 }
1469         }
1470
1471         return tcu::TestStatus::pass("Resizing tests succeeded");
1472 }
1473
1474 tcu::TestStatus getImagesIncompleteResultTest (Context& context, Type wsiType)
1475 {
1476         const tcu::UVec2                                desiredSize             (256, 256);
1477         const InstanceHelper                    instHelper              (context, wsiType);
1478         const NativeObjects                             native                  (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1479         const Unique<VkSurfaceKHR>              surface                 (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1480         const DeviceHelper                              devHelper               (context, instHelper.vki, *instHelper.instance, *surface);
1481         const VkSwapchainCreateInfoKHR  swapchainInfo   = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1482         const Unique<VkSwapchainKHR>    swapchain               (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
1483
1484         vector<VkImage>         swapchainImages = getSwapchainImages(devHelper.vkd, *devHelper.device, *swapchain);
1485
1486         ValidateQueryBits::fillBits(swapchainImages.begin(), swapchainImages.end());
1487
1488         const deUint32          usedCount               = static_cast<deUint32>(swapchainImages.size() / 2);
1489         deUint32                        count                   = usedCount;
1490         const VkResult          result                  = devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &count, &swapchainImages[0]);
1491
1492         if (count != usedCount || result != VK_INCOMPLETE || !ValidateQueryBits::checkBits(swapchainImages.begin() + count, swapchainImages.end()))
1493                 return tcu::TestStatus::fail("Get swapchain images didn't return VK_INCOMPLETE");
1494         else
1495                 return tcu::TestStatus::pass("Get swapchain images tests succeeded");
1496 }
1497
1498 tcu::TestStatus getImagesResultsCountTest (Context& context, Type wsiType)
1499 {
1500         const tcu::UVec2                                desiredSize(256, 256);
1501         const InstanceHelper                    instHelper(context, wsiType);
1502         const NativeObjects                             native(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1503         const Unique<VkSurfaceKHR>              surface(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1504         const DeviceHelper                              devHelper(context, instHelper.vki, *instHelper.instance, *surface);
1505         const VkSwapchainCreateInfoKHR  swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1506         const Unique<VkSwapchainKHR>    swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
1507
1508         deUint32        numImages = 0;
1509
1510         VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
1511
1512         if (numImages > 0)
1513         {
1514                 std::vector<VkImage>    images                  (numImages + 1);
1515                 const deUint32                  numImagesOrig   = numImages;
1516
1517                 // check if below call properly overwrites formats count
1518                 numImages++;
1519
1520                 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, &images[0]));
1521
1522                 if ((size_t)numImages != numImagesOrig)
1523                         TCU_FAIL("Image count changed between calls");
1524         }
1525         return tcu::TestStatus::pass("Get swapchain images tests succeeded");
1526 }
1527
1528 tcu::TestStatus destroyNullHandleSwapchainTest (Context& context, Type wsiType)
1529 {
1530         const InstanceHelper            instHelper      (context, wsiType);
1531         const NativeObjects                     native          (context, instHelper.supportedExtensions, wsiType);
1532         const Unique<VkSurfaceKHR>      surface         (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1533         const DeviceHelper                      devHelper       (context, instHelper.vki, *instHelper.instance, *surface);
1534         const VkSwapchainKHR            nullHandle      = DE_NULL;
1535
1536         // Default allocator
1537         devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, DE_NULL);
1538
1539         // Custom allocator
1540         {
1541                 AllocationCallbackRecorder      recordingAllocator      (getSystemAllocator(), 1u);
1542
1543                 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, recordingAllocator.getCallbacks());
1544
1545                 if (recordingAllocator.getNumRecords() != 0u)
1546                         return tcu::TestStatus::fail("Implementation allocated/freed the memory");
1547         }
1548
1549         return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
1550 }
1551
1552 void getBasicRenderPrograms (SourceCollections& dst, Type)
1553 {
1554         TriangleRenderer::getPrograms(dst);
1555 }
1556
1557 void populateRenderGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1558 {
1559         addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
1560 }
1561
1562 void populateGetImagesGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1563 {
1564         addFunctionCase(testGroup, "incomplete", "Test VK_INCOMPLETE return code", getImagesIncompleteResultTest, wsiType);
1565         addFunctionCase(testGroup, "count",     "Test proper count of images", getImagesResultsCountTest, wsiType);
1566 }
1567
1568 void populateModifyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1569 {
1570         const PlatformProperties&       platformProperties      = getPlatformProperties(wsiType);
1571
1572         if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
1573         {
1574                 addFunctionCaseWithPrograms(testGroup, "resize", "Resize Swapchain Test", getBasicRenderPrograms, resizeSwapchainTest, wsiType);
1575         }
1576
1577         // \todo [2016-05-30 jesse] Add tests for modifying preTransform, compositeAlpha, presentMode
1578 }
1579
1580 void populateDestroyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1581 {
1582         addFunctionCase(testGroup, "null_handle", "Destroying a VK_NULL_HANDLE swapchain", destroyNullHandleSwapchainTest, wsiType);
1583 }
1584
1585 } // anonymous
1586
1587 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1588 {
1589         addTestGroup(testGroup, "create",                       "Create VkSwapchain with various parameters",                                   populateSwapchainGroup,         GroupParameters(wsiType, createSwapchainTest));
1590         addTestGroup(testGroup, "simulate_oom",         "Simulate OOM using callbacks during swapchain construction",   populateSwapchainGroup,         GroupParameters(wsiType, createSwapchainSimulateOOMTest));
1591         addTestGroup(testGroup, "render",                       "Rendering Tests",                                                                                              populateRenderGroup,            wsiType);
1592         addTestGroup(testGroup, "modify",                       "Modify VkSwapchain",                                                                                   populateModifyGroup,            wsiType);
1593         addTestGroup(testGroup, "destroy",                      "Destroy VkSwapchain",                                                                                  populateDestroyGroup,           wsiType);
1594         addTestGroup(testGroup, "get_images",           "Get swapchain images",                                                                                 populateGetImagesGroup,         wsiType);
1595 }
1596
1597 } // wsi
1598 } // vkt