Merge remote-tracking branch 'aosp/master' into HEAD
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / protected_memory / vktProtectedMemWsiSwapchainTests.cpp
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 The Khronos Group Inc.
6  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Protected memory interaction with VkSwapchain Tests
23  *//*--------------------------------------------------------------------*/
24
25 #include "vktProtectedMemWsiSwapchainTests.hpp"
26
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29
30 #include "vkDefs.hpp"
31 #include "vkPlatform.hpp"
32 #include "vkStrUtil.hpp"
33 #include "vkRef.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkMemUtil.hpp"
37 #include "vkDeviceUtil.hpp"
38 #include "vkPrograms.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkWsiPlatform.hpp"
42 #include "vkWsiUtil.hpp"
43 #include "vkAllocationCallbackUtil.hpp"
44 #include "vkCmdUtil.hpp"
45
46 #include "tcuTestLog.hpp"
47 #include "tcuFormatUtil.hpp"
48 #include "tcuPlatform.hpp"
49 #include "tcuResultCollector.hpp"
50
51 #include "deUniquePtr.hpp"
52 #include "deStringUtil.hpp"
53 #include "deArrayUtil.hpp"
54 #include "deSharedPtr.hpp"
55
56 #include <limits>
57
58 #include "vktProtectedMemContext.hpp"
59 #include "vktProtectedMemUtils.hpp"
60
61 namespace vkt
62 {
63 namespace ProtectedMem
64 {
65
66 namespace
67 {
68
69 typedef std::vector<vk::VkExtensionProperties> Extensions;
70
71 void checkAllSupported (const Extensions& supportedExtensions, const std::vector<std::string>& requiredExtensions)
72 {
73         for (std::vector<std::string>::const_iterator requiredExtName = requiredExtensions.begin();
74                  requiredExtName != requiredExtensions.end();
75                  ++requiredExtName)
76         {
77                 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
78                         TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
79         }
80 }
81
82 std::vector<std::string> getRequiredWsiExtensions (const Extensions&    supportedExtensions,
83                                                                                                    vk::wsi::Type                wsiType)
84 {
85         std::vector<std::string>        extensions;
86
87         extensions.push_back("VK_KHR_surface");
88         extensions.push_back(getExtensionName(wsiType));
89
90         // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
91         // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
92         // but using them without enabling the extension is not allowed. Thus we have
93         // two options:
94         //
95         // 1) Filter out non-core formats to stay within valid usage.
96         //
97         // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
98         //
99         // We opt for (2) as it provides basic coverage for the extension as a bonus.
100         if (isExtensionSupported(supportedExtensions, vk::RequiredExtension("VK_EXT_swapchain_colorspace")))
101                 extensions.push_back("VK_EXT_swapchain_colorspace");
102
103         checkAllSupported(supportedExtensions, extensions);
104
105         return extensions;
106 }
107
108 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform&        platform,
109                                                                                          const Extensions&              supportedExtensions,
110                                                                                          vk::wsi::Type                  wsiType)
111 {
112         try
113         {
114                 return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
115         }
116         catch (const tcu::NotSupportedError& e)
117         {
118                 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))))
119                 {
120                         // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
121                         // must support creating native display & window for that WSI type.
122                         throw tcu::TestError(e.getMessage());
123                 }
124                 else
125                         throw;
126         }
127 }
128
129 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const tcu::Maybe<tcu::UVec2>& initialSize)
130 {
131         try
132         {
133                 return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
134         }
135         catch (const tcu::NotSupportedError& e)
136         {
137                 // See createDisplay - assuming that wsi::Display was supported platform port
138                 // should also support creating a window.
139                 throw tcu::TestError(e.getMessage());
140         }
141 }
142
143 struct NativeObjects
144 {
145         const de::UniquePtr<vk::wsi::Display>   display;
146         const de::UniquePtr<vk::wsi::Window>    window;
147
148         NativeObjects (Context&                                                 context,
149                                    const Extensions&                            supportedExtensions,
150                                    vk::wsi::Type                                        wsiType,
151                                    const tcu::Maybe<tcu::UVec2>&        initialWindowSize = tcu::nothing<tcu::UVec2>())
152                 : display                               (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
153                 , window                                (createWindow(*display, initialWindowSize))
154         {}
155 };
156
157 enum TestDimension
158 {
159         TEST_DIMENSION_MIN_IMAGE_COUNT = 0,     //!< Test all supported image counts
160         TEST_DIMENSION_IMAGE_FORMAT,            //!< Test all supported formats
161         TEST_DIMENSION_IMAGE_EXTENT,            //!< Test various (supported) extents
162         TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
163         TEST_DIMENSION_IMAGE_USAGE,
164         TEST_DIMENSION_IMAGE_SHARING_MODE,
165         TEST_DIMENSION_PRE_TRANSFORM,
166         TEST_DIMENSION_COMPOSITE_ALPHA,
167         TEST_DIMENSION_PRESENT_MODE,
168         TEST_DIMENSION_CLIPPED,
169
170         TEST_DIMENSION_LAST
171 };
172
173 const char* getTestDimensionName (TestDimension dimension)
174 {
175         static const char* const s_names[] =
176         {
177                 "min_image_count",
178                 "image_format",
179                 "image_extent",
180                 "image_array_layers",
181                 "image_usage",
182                 "image_sharing_mode",
183                 "pre_transform",
184                 "composite_alpha",
185                 "present_mode",
186                 "clipped"
187         };
188         return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
189 }
190
191 struct TestParameters
192 {
193         vk::wsi::Type   wsiType;
194         TestDimension   dimension;
195
196         TestParameters (vk::wsi::Type wsiType_, TestDimension dimension_)
197                 : wsiType       (wsiType_)
198                 , dimension     (dimension_)
199         {}
200
201         TestParameters (void)
202                 : wsiType       (vk::wsi::TYPE_LAST)
203                 , dimension     (TEST_DIMENSION_LAST)
204         {}
205 };
206
207 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type                                                                wsiType,
208                                                                                                                                                    TestDimension                                                                dimension,
209                                                                                                                                                    const ProtectedContext&                                              context,
210                                                                                                                                                    const vk::VkSurfaceCapabilitiesKHR&                  capabilities,
211                                                                                                                                                    const std::vector<vk::VkSurfaceFormatKHR>&   formats,
212                                                                                                                                                    const std::vector<vk::VkPresentModeKHR>&             presentModes)
213 {
214         std::vector<vk::VkSwapchainCreateInfoKHR>       cases;
215         const vk::wsi::PlatformProperties&                      platformProperties      = getPlatformProperties(wsiType);
216         const vk::VkSurfaceTransformFlagBitsKHR         defaultTransform        = (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
217                                                                                                                                                 ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
218         const vk::VkSwapchainCreateInfoKHR                      baseParameters          =
219         {
220                 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
221                 DE_NULL,
222                 vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
223                 (vk::VkSurfaceKHR)0,
224                 capabilities.minImageCount,
225                 formats[0].format,
226                 formats[0].colorSpace,
227                 (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
228                         ? capabilities.minImageExtent : capabilities.currentExtent),
229                 1u,                                                                     // imageArrayLayers
230                 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
231                 vk::VK_SHARING_MODE_EXCLUSIVE,
232                 0u,
233                 (const deUint32*)DE_NULL,
234                 defaultTransform,
235                 vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
236                 vk::VK_PRESENT_MODE_FIFO_KHR,
237                 VK_FALSE,                                                       // clipped
238                 (vk::VkSwapchainKHR)0                           // oldSwapchain
239         };
240
241         switch (dimension)
242         {
243                 case TEST_DIMENSION_MIN_IMAGE_COUNT:
244                 {
245                         // Estimate how much memory each swapchain image consumes. This isn't perfect, since
246                         // swapchain images may have additional constraints that equivalent non-swapchain
247                         // images don't have. But it's the best we can do.
248                         const vk::DeviceInterface&                              vkd                                     = context.getDeviceInterface();
249                         vk::VkDevice                                                    device                          = context.getDevice();
250                         vk::VkMemoryRequirements                                memoryRequirements;
251                         {
252                                 const vk::VkImageCreateInfo                     imageInfo                       =
253                                 {
254                                         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
255                                         DE_NULL,
256                                         vk::VK_IMAGE_CREATE_PROTECTED_BIT,
257                                         vk::VK_IMAGE_TYPE_2D,
258                                         baseParameters.imageFormat,
259                                         {
260                                                 baseParameters.imageExtent.width,
261                                                 baseParameters.imageExtent.height,
262                                                 1,
263                                         },
264                                         1,      // mipLevels
265                                         baseParameters.imageArrayLayers,
266                                         vk::VK_SAMPLE_COUNT_1_BIT,
267                                         vk::VK_IMAGE_TILING_OPTIMAL,
268                                         baseParameters.imageUsage,
269                                         baseParameters.imageSharingMode,
270                                         baseParameters.queueFamilyIndexCount,
271                                         baseParameters.pQueueFamilyIndices,
272                                         vk::VK_IMAGE_LAYOUT_UNDEFINED
273                                 };
274                                 vk::Move<vk::VkImage>                           image                           = vk::createImage(vkd, device, &imageInfo);
275
276                                 memoryRequirements      = vk::getImageMemoryRequirements(vkd, device, *image);
277                         }
278
279                         // Determine the maximum memory heap space available for protected images
280                         vk::VkPhysicalDeviceMemoryProperties    memoryProperties        = vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
281                         vk::VkDeviceSize                                                protectedHeapSize       = 0;
282                         vk::VkDeviceSize                                                maxMemoryUsage          = 0;
283                         deUint32                                                                protectedHeapMask       = 0;
284
285                         for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
286                         {
287                                 deUint32 heapIndex      = memoryProperties.memoryTypes[memType].heapIndex;
288                                 if ((memoryRequirements.memoryTypeBits & (1u << memType)) != 0 &&
289                                         (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0 &&
290                                         (protectedHeapMask & (1u << heapIndex)) == 0)
291                                 {
292                                         protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
293                                         maxMemoryUsage    = protectedHeapSize / 4 ; /* Use at maximum 25% of heap */
294                                         protectedHeapMask |= 1u << heapIndex;
295                                 }
296                         }
297
298                         // If the implementation doesn't have a max image count, min+16 means we won't clamp.
299                         // Limit it to how many protected images we estimate can be allocated - 25% of heap size
300                         const deUint32  maxImageCount           = de::min((capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u,
301                                                                                                                   deUint32(maxMemoryUsage / memoryRequirements.size));
302                         if (maxImageCount < capabilities.minImageCount)
303                                 TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory!.");
304
305                         const deUint32  maxImageCountToTest     = de::clamp(16u, capabilities.minImageCount, maxImageCount);
306                         for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
307                         {
308                                 cases.push_back(baseParameters);
309                                 cases.back().minImageCount = imageCount;
310                         }
311
312                         break;
313                 }
314
315                 case TEST_DIMENSION_IMAGE_FORMAT:
316                 {
317                         for (std::vector<vk::VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
318                         {
319                                 cases.push_back(baseParameters);
320                                 cases.back().imageFormat                = curFmt->format;
321                                 cases.back().imageColorSpace    = curFmt->colorSpace;
322                         }
323
324                         break;
325                 }
326
327                 case TEST_DIMENSION_IMAGE_EXTENT:
328                 {
329                         static const vk::VkExtent2D     s_testSizes[]   =
330                         {
331                                 { 1, 1 },
332                                 { 16, 32 },
333                                 { 32, 16 },
334                                 { 632, 231 },
335                                 { 117, 998 },
336                         };
337
338                         const vk::DeviceInterface&                              vkd                                     = context.getDeviceInterface();
339                         vk::VkDevice                                                    device                          = context.getDevice();
340                         vk::VkPhysicalDeviceMemoryProperties    memoryProperties        = vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
341                         vk::VkDeviceSize                                                protectedHeapSize       = 0;
342                         vk::VkDeviceSize                                                maxMemoryUsage          = 0;
343
344                         for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
345                         {
346                                 deUint32 heapIndex      = memoryProperties.memoryTypes[memType].heapIndex;
347                                 if (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT)
348                                 {
349                                         protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
350                                         maxMemoryUsage    = protectedHeapSize / 4 ; /* Use at maximum 25% of heap */
351                                 }
352                         }
353
354                         if (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
355                                 platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
356                         {
357                                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
358                                 {
359                                         vk::VkMemoryRequirements memoryRequirements;
360                                         {
361                                                 const vk::VkImageCreateInfo imageInfo =
362                                                 {
363                                                         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
364                                                         DE_NULL,
365                                                         vk::VK_IMAGE_CREATE_PROTECTED_BIT,
366                                                         vk::VK_IMAGE_TYPE_2D,
367                                                         baseParameters.imageFormat,
368                                                         {
369                                                                 s_testSizes[ndx].width,
370                                                                 s_testSizes[ndx].height,
371                                                                 1,
372                                                         },
373                                                         1,      // mipLevels
374                                                         baseParameters.imageArrayLayers,
375                                                         vk::VK_SAMPLE_COUNT_1_BIT,
376                                                         vk::VK_IMAGE_TILING_OPTIMAL,
377                                                         baseParameters.imageUsage,
378                                                         baseParameters.imageSharingMode,
379                                                         baseParameters.queueFamilyIndexCount,
380                                                         baseParameters.pQueueFamilyIndices,
381                                                         vk::VK_IMAGE_LAYOUT_UNDEFINED
382                                                 };
383
384                                                 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
385
386                                                 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
387                                         }
388
389                                         // Check for the image size requirement based on double/triple buffering
390                                         if (memoryRequirements.size  * capabilities.minImageCount < maxMemoryUsage)
391                                         {
392                                                 cases.push_back(baseParameters);
393                                                 cases.back().imageExtent.width  = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
394                                                 cases.back().imageExtent.height = de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
395                                         }
396                                 }
397                         }
398
399                         if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
400                         {
401                                 vk::VkMemoryRequirements memoryRequirements;
402                                 {
403                                         const vk::VkImageCreateInfo imageInfo =
404                                         {
405                                                 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
406                                                 DE_NULL,
407                                                 vk::VK_IMAGE_CREATE_PROTECTED_BIT,
408                                                 vk::VK_IMAGE_TYPE_2D,
409                                                 baseParameters.imageFormat,
410                                                 {
411                                                         capabilities.currentExtent.width,
412                                                         capabilities.currentExtent.height,
413                                                         1,
414                                                 },
415                                                 1,      // mipLevels
416                                                 baseParameters.imageArrayLayers,
417                                                 vk::VK_SAMPLE_COUNT_1_BIT,
418                                                 vk::VK_IMAGE_TILING_OPTIMAL,
419                                                 baseParameters.imageUsage,
420                                                 baseParameters.imageSharingMode,
421                                                 baseParameters.queueFamilyIndexCount,
422                                                 baseParameters.pQueueFamilyIndices,
423                                                 vk::VK_IMAGE_LAYOUT_UNDEFINED
424                                         };
425
426                                         vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
427
428                                         memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
429                                 }
430
431                                 // Check for the image size requirement based on double/triple buffering
432                                 if (memoryRequirements.size  * capabilities.minImageCount < maxMemoryUsage)
433                                 {
434                                         cases.push_back(baseParameters);
435                                         cases.back().imageExtent = capabilities.currentExtent;
436                                 }
437                         }
438
439                         if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
440                         {
441                                 static const vk::VkExtent2D     s_testExtentSizes[]     =
442                                 {
443                                         { capabilities.minImageExtent.width, capabilities.minImageExtent.height },
444                                         { capabilities.maxImageExtent.width, capabilities.maxImageExtent.height },
445                                 };
446
447                                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testExtentSizes); ++ndx)
448                                 {
449                                         vk::VkMemoryRequirements memoryRequirements;
450                                         {
451                                                 const vk::VkImageCreateInfo     imageInfo =
452                                                 {
453                                                         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
454                                                         DE_NULL,
455                                                         vk::VK_IMAGE_CREATE_PROTECTED_BIT,
456                                                         vk::VK_IMAGE_TYPE_2D,
457                                                         baseParameters.imageFormat,
458                                                         {
459                                                                 s_testExtentSizes[ndx].width,
460                                                                 s_testExtentSizes[ndx].height,
461                                                                 1,
462                                                         },
463                                                         1,      // mipLevels
464                                                         baseParameters.imageArrayLayers,
465                                                         vk::VK_SAMPLE_COUNT_1_BIT,
466                                                         vk::VK_IMAGE_TILING_OPTIMAL,
467                                                         baseParameters.imageUsage,
468                                                         baseParameters.imageSharingMode,
469                                                         baseParameters.queueFamilyIndexCount,
470                                                         baseParameters.pQueueFamilyIndices,
471                                                         vk::VK_IMAGE_LAYOUT_UNDEFINED
472                                                 };
473
474                                                 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
475
476                                                 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
477                                         }
478
479                                         // Check for the image size requirement based on double/triple buffering
480                                         if (memoryRequirements.size  * capabilities.minImageCount < maxMemoryUsage)
481                                         {
482                                                 cases.push_back(baseParameters);
483                                                 cases.back().imageExtent =s_testExtentSizes[ndx];
484                                         }
485                                 }
486                         }
487
488                         break;
489                 }
490
491                 case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
492                 {
493                         const deUint32  maxLayers       = de::min(capabilities.maxImageArrayLayers, 16u);
494
495                         for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
496                         {
497                                 cases.push_back(baseParameters);
498                                 cases.back().imageArrayLayers = numLayers;
499                         }
500
501                         break;
502                 }
503
504                 case TEST_DIMENSION_IMAGE_USAGE:
505                 {
506                         for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
507                         {
508                                 if ((flags & ~capabilities.supportedUsageFlags) == 0)
509                                 {
510                                         cases.push_back(baseParameters);
511                                         cases.back().imageUsage = flags;
512                                 }
513                         }
514
515                         break;
516                 }
517
518                 case TEST_DIMENSION_IMAGE_SHARING_MODE:
519                 {
520                         cases.push_back(baseParameters);
521                         cases.back().imageSharingMode = vk::VK_SHARING_MODE_EXCLUSIVE;
522
523                         cases.push_back(baseParameters);
524                         cases.back().imageSharingMode = vk::VK_SHARING_MODE_CONCURRENT;
525
526                         break;
527                 }
528
529                 case TEST_DIMENSION_PRE_TRANSFORM:
530                 {
531                         for (deUint32 transform = 1u;
532                                  transform <= capabilities.supportedTransforms;
533                                  transform = transform<<1u)
534                         {
535                                 if ((transform & capabilities.supportedTransforms) != 0)
536                                 {
537                                         cases.push_back(baseParameters);
538                                         cases.back().preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
539                                 }
540                         }
541
542                         break;
543                 }
544
545                 case TEST_DIMENSION_COMPOSITE_ALPHA:
546                 {
547                         for (deUint32 alphaMode = 1u;
548                                  alphaMode <= capabilities.supportedCompositeAlpha;
549                                  alphaMode = alphaMode<<1u)
550                         {
551                                 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
552                                 {
553                                         cases.push_back(baseParameters);
554                                         cases.back().compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
555                                 }
556                         }
557
558                         break;
559                 }
560
561                 case TEST_DIMENSION_PRESENT_MODE:
562                 {
563                         for (std::vector<vk::VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
564                         {
565                                 cases.push_back(baseParameters);
566                                 cases.back().presentMode = *curMode;
567                         }
568
569                         break;
570                 }
571
572                 case TEST_DIMENSION_CLIPPED:
573                 {
574                         cases.push_back(baseParameters);
575                         cases.back().clipped = VK_FALSE;
576
577                         cases.push_back(baseParameters);
578                         cases.back().clipped = VK_TRUE;
579
580                         break;
581                 }
582
583                 default:
584                         DE_FATAL("Impossible");
585         }
586
587         DE_ASSERT(!cases.empty());
588         return cases;
589 }
590
591 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type                                        wsiType,
592                                                                                                                                                    TestDimension                                        dimension,
593                                                                                                                                                    const ProtectedContext&                      context,
594                                                                                                                                                    vk::VkSurfaceKHR                                     surface)
595 {
596         const vk::InstanceInterface&                            vki                             = context.getInstanceDriver();
597         vk::VkPhysicalDevice                                            physicalDevice  = context.getPhysicalDevice();
598         const vk::VkSurfaceCapabilitiesKHR                      capabilities    = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
599                                                                                                                                                                                                                            physicalDevice,
600                                                                                                                                                                                                                            surface);
601         const std::vector<vk::VkSurfaceFormatKHR>       formats                 = vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
602                                                                                                                                                                                                                    physicalDevice,
603                                                                                                                                                                                                                    surface);
604         const std::vector<vk::VkPresentModeKHR>         presentModes    = vk::wsi::getPhysicalDeviceSurfacePresentModes(vki,
605                                                                                                                                                                                                                             physicalDevice,
606                                                                                                                                                                                                                             surface);
607
608         return generateSwapchainParameterCases(wsiType, dimension, context, capabilities, formats, presentModes);
609 }
610
611 tcu::TestStatus createSwapchainTest (Context& baseCtx, TestParameters params)
612 {
613         std::vector<vk::VkExtensionProperties>                  supportedExtensions (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
614         std::vector<std::string>                                                instExts        = getRequiredWsiExtensions(supportedExtensions, params.wsiType);
615         std::vector<std::string>                                                devExts;
616         devExts.push_back("VK_KHR_swapchain");
617
618         const NativeObjects                                                             native          (baseCtx, supportedExtensions, params.wsiType);
619         ProtectedContext                                                                context         (baseCtx, params.wsiType, *native.display, *native.window, instExts, devExts);
620         vk::VkSurfaceKHR                                                                surface         = context.getSurface();
621         const std::vector<vk::VkSwapchainCreateInfoKHR> cases           (generateSwapchainParameterCases(params.wsiType,
622                                                                                                                                                                                                  params.dimension,
623                                                                                                                                                                                                  context,
624                                                                                                                                                                                                  surface));
625         deUint32                                                                                queueIdx        = context.getQueueFamilyIndex();
626         for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
627         {
628                 vk::VkSwapchainCreateInfoKHR    curParams       = cases[caseNdx];
629
630                 curParams.surface                               = surface;
631                 curParams.queueFamilyIndexCount = 1u;
632                 curParams.pQueueFamilyIndices   = &queueIdx;
633
634                 context.getTestContext().getLog()
635                         << tcu::TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": " << curParams << tcu::TestLog::EndMessage;
636
637                 {
638                         const vk::Unique<vk::VkSwapchainKHR>    swapchain       (createSwapchainKHR(context.getDeviceDriver(), context.getDevice(), &curParams));
639                 }
640         }
641
642         return tcu::TestStatus::pass("Creating swapchain succeeded");
643 }
644
645 struct GroupParameters
646 {
647         typedef FunctionInstance1<TestParameters>::Function     Function;
648
649         vk::wsi::Type   wsiType;
650         Function                function;
651
652         GroupParameters (vk::wsi::Type wsiType_, Function function_)
653                 : wsiType       (wsiType_)
654                 , function      (function_)
655         {}
656
657         GroupParameters (void)
658                 : wsiType       (vk::wsi::TYPE_LAST)
659                 , function      ((Function)DE_NULL)
660         {}
661 };
662
663 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
664 {
665         for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
666         {
667                 const TestDimension             testDimension   = (TestDimension)dimensionNdx;
668
669                 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
670         }
671 }
672
673 vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters (vk::wsi::Type                                 wsiType,
674                                                                                                                   const vk::InstanceInterface&  vki,
675                                                                                                                   vk::VkPhysicalDevice                  physicalDevice,
676                                                                                                                   vk::VkSurfaceKHR                              surface,
677                                                                                                                   const tcu::UVec2&                             desiredSize,
678                                                                                                                   deUint32                                              desiredImageCount)
679 {
680         const vk::VkSurfaceCapabilitiesKHR                      capabilities            = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
681                                                                                                                                                                                                                                     physicalDevice,
682                                                                                                                                                                                                                                     surface);
683         const std::vector<vk::VkSurfaceFormatKHR>       formats                         = vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
684                                                                                                                                                                                                                            physicalDevice,
685                                                                                                                                                                                                                            surface);
686         const vk::wsi::PlatformProperties&                      platformProperties      = vk::wsi::getPlatformProperties(wsiType);
687         const vk::VkSurfaceTransformFlagBitsKHR         transform                       = (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
688                                                                                                                                                 ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
689         const vk::VkSwapchainCreateInfoKHR                      parameters                      =
690         {
691                 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
692                 DE_NULL,
693                 vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
694                 surface,
695                 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
696                 formats[0].format,
697                 formats[0].colorSpace,
698                 (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
699                         ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
700                 1u,                                                                     // imageArrayLayers
701                 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
702                 vk::VK_SHARING_MODE_EXCLUSIVE,
703                 0u,
704                 (const deUint32*)DE_NULL,
705                 transform,
706                 vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
707                 vk::VK_PRESENT_MODE_FIFO_KHR,
708                 VK_FALSE,                                                       // clipped
709                 (vk::VkSwapchainKHR)0                           // oldSwapchain
710         };
711
712         return parameters;
713 }
714
715 typedef de::SharedPtr<vk::Unique<vk::VkImageView> >             ImageViewSp;
716 typedef de::SharedPtr<vk::Unique<vk::VkFramebuffer> >   FramebufferSp;
717
718 class TriangleRenderer
719 {
720 public:
721                                                                                                 TriangleRenderer        (ProtectedContext&                              context,
722                                                                                                                                          const vk::BinaryCollection&    binaryRegistry,
723                                                                                                                                          const std::vector<vk::VkImage> swapchainImages,
724                                                                                                                                          const vk::VkFormat                             framebufferFormat,
725                                                                                                                                          const tcu::UVec2&                              renderSize);
726                                                                                                 ~TriangleRenderer       (void);
727
728         void                                                                            recordFrame                     (vk::VkCommandBuffer                    cmdBuffer,
729                                                                                                                                          deUint32                                               imageNdx,
730                                                                                                                                          deUint32                                               frameNdx) const;
731
732         static void                                                                     getPrograms                     (vk::SourceCollections&                 dst);
733
734 private:
735         static vk::Move<vk::VkRenderPass>                       createRenderPass        (const vk::DeviceInterface&             vkd,
736                                                                                                                                          const vk::VkDevice                             device,
737                                                                                                                                          const vk::VkFormat                             colorAttachmentFormat);
738         static vk::Move<vk::VkPipelineLayout>           createPipelineLayout(const vk::DeviceInterface&         vkd,
739                                                                                                                                          vk::VkDevice                                   device);
740         static vk::Move<vk::VkPipeline>                         createPipeline          (const vk::DeviceInterface&             vkd,
741                                                                                                                                          const vk::VkDevice                             device,
742                                                                                                                                          const vk::VkRenderPass                 renderPass,
743                                                                                                                                          const vk::VkPipelineLayout             pipelineLayout,
744                                                                                                                                          const vk::BinaryCollection&    binaryCollection,
745                                                                                                                                          const tcu::UVec2&                              renderSize);
746
747         const vk::DeviceInterface&                                      m_vkd;
748
749         const std::vector<vk::VkImage>                          m_swapchainImages;
750         const tcu::UVec2                                                        m_renderSize;
751
752         const vk::Unique<vk::VkRenderPass>                      m_renderPass;
753         const vk::Unique<vk::VkPipelineLayout>          m_pipelineLayout;
754         const vk::Unique<vk::VkPipeline>                        m_pipeline;
755
756         const de::UniquePtr<vk::BufferWithMemory>       m_vertexBuffer;
757
758         std::vector<ImageViewSp>                                        m_attachmentViews;
759         std::vector<FramebufferSp>                                      m_framebuffers;
760 };
761
762 vk::Move<vk::VkRenderPass> TriangleRenderer::createRenderPass (const vk::DeviceInterface&       vkd,
763                                                                                                                            const vk::VkDevice                   device,
764                                                                                                                            const vk::VkFormat                   colorAttachmentFormat)
765 {
766         const vk::VkAttachmentDescription       colorAttDesc            =
767         {
768                 (vk::VkAttachmentDescriptionFlags)0,
769                 colorAttachmentFormat,
770                 vk::VK_SAMPLE_COUNT_1_BIT,
771                 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
772                 vk::VK_ATTACHMENT_STORE_OP_STORE,
773                 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
774                 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
775                 vk::VK_IMAGE_LAYOUT_UNDEFINED,
776                 vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
777         };
778         const vk::VkAttachmentReference         colorAttRef                     =
779         {
780                 0u,
781                 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
782         };
783         const vk::VkSubpassDescription          subpassDesc                     =
784         {
785                 (vk::VkSubpassDescriptionFlags)0u,
786                 vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
787                 0u,                                                     // inputAttachmentCount
788                 DE_NULL,                                        // pInputAttachments
789                 1u,                                                     // colorAttachmentCount
790                 &colorAttRef,                           // pColorAttachments
791                 DE_NULL,                                        // pResolveAttachments
792                 DE_NULL,                                        // depthStencilAttachment
793                 0u,                                                     // preserveAttachmentCount
794                 DE_NULL,                                        // pPreserveAttachments
795         };
796         const vk::VkSubpassDependency           dependencies[]          =
797         {
798                 {
799                         VK_SUBPASS_EXTERNAL,    // srcSubpass
800                         0u,                                             // dstSubpass
801                         vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
802                         vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
803                         vk::VK_ACCESS_MEMORY_READ_BIT,
804                         (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
805                          vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
806                         vk::VK_DEPENDENCY_BY_REGION_BIT
807                 },
808                 {
809                         0u,                                             // srcSubpass
810                         VK_SUBPASS_EXTERNAL,    // dstSubpass
811                         vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
812                         vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
813                         (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
814                          vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
815                         vk::VK_ACCESS_MEMORY_READ_BIT,
816                         vk::VK_DEPENDENCY_BY_REGION_BIT
817                 },
818         };
819         const vk::VkRenderPassCreateInfo        renderPassParams        =
820         {
821                 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
822                 DE_NULL,
823                 (vk::VkRenderPassCreateFlags)0,
824                 1u,
825                 &colorAttDesc,
826                 1u,
827                 &subpassDesc,
828                 DE_LENGTH_OF_ARRAY(dependencies),
829                 dependencies,
830         };
831
832         return vk::createRenderPass(vkd, device, &renderPassParams);
833 }
834
835 vk::Move<vk::VkPipelineLayout> TriangleRenderer::createPipelineLayout (const vk::DeviceInterface&       vkd,
836                                                                                                                                            const vk::VkDevice                   device)
837 {
838         const vk::VkPushConstantRange                                   pushConstantRange               =
839         {
840                 vk::VK_SHADER_STAGE_VERTEX_BIT,
841                 0u,                                                                                     // offset
842                 (deUint32)sizeof(deUint32),                                     // size
843         };
844         const vk::VkPipelineLayoutCreateInfo                    pipelineLayoutParams    =
845         {
846                 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
847                 DE_NULL,
848                 (vk::VkPipelineLayoutCreateFlags)0,
849                 0u,                                                                                     // setLayoutCount
850                 DE_NULL,                                                                        // pSetLayouts
851                 1u,
852                 &pushConstantRange,
853         };
854
855         return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
856 }
857
858 vk::Move<vk::VkPipeline> TriangleRenderer::createPipeline (const vk::DeviceInterface&   vkd,
859                                                                                                                    const vk::VkDevice                   device,
860                                                                                                                    const vk::VkRenderPass               renderPass,
861                                                                                                                    const vk::VkPipelineLayout   pipelineLayout,
862                                                                                                                    const vk::BinaryCollection&  binaryCollection,
863                                                                                                                    const tcu::UVec2&                    renderSize)
864 {
865         // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
866         //               and can be deleted immediately following that call.
867         const vk::Unique<vk::VkShaderModule>                            vertShaderModule                (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
868         const vk::Unique<vk::VkShaderModule>                            fragShaderModule                (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
869         const std::vector<vk::VkViewport>                                       viewports                               (1, vk::makeViewport(renderSize));
870         const std::vector<vk::VkRect2D>                                         scissors                                (1, vk::makeRect2D(renderSize));
871
872         return vk::makeGraphicsPipeline(vkd,                            // const DeviceInterface&            vk
873                                                                         device,                         // const VkDevice                    device
874                                                                         pipelineLayout,         // const VkPipelineLayout            pipelineLayout
875                                                                         *vertShaderModule,      // const VkShaderModule              vertexShaderModule
876                                                                         DE_NULL,                        // const VkShaderModule              tessellationControlShaderModule
877                                                                         DE_NULL,                        // const VkShaderModule              tessellationEvalShaderModule
878                                                                         DE_NULL,                        // const VkShaderModule              geometryShaderModule
879                                                                         *fragShaderModule,      // const VkShaderModule              fragmentShaderModule
880                                                                         renderPass,                     // const VkRenderPass                renderPass
881                                                                         viewports,                      // const std::vector<VkViewport>&    viewports
882                                                                         scissors);                      // const std::vector<VkRect2D>&      scissors
883 }
884
885 TriangleRenderer::TriangleRenderer (ProtectedContext&                           context,
886                                                                         const vk::BinaryCollection&             binaryRegistry,
887                                                                         const std::vector<vk::VkImage>  swapchainImages,
888                                                                         const vk::VkFormat                              framebufferFormat,
889                                                                         const tcu::UVec2&                               renderSize)
890         : m_vkd                                 (context.getDeviceInterface())
891         , m_swapchainImages             (swapchainImages)
892         , m_renderSize                  (renderSize)
893         , m_renderPass                  (createRenderPass(m_vkd, context.getDevice(), framebufferFormat))
894         , m_pipelineLayout              (createPipelineLayout(m_vkd, context.getDevice()))
895         , m_pipeline                    (createPipeline(m_vkd, context.getDevice(), *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
896         , m_vertexBuffer                (makeBuffer(context,
897                                                                         PROTECTION_DISABLED,
898                                                                         context.getQueueFamilyIndex(),
899                                                                         (deUint32)(sizeof(float)*4*3),
900                                                                         vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
901                                                                         vk::MemoryRequirement::HostVisible))
902 {
903         m_attachmentViews.resize(swapchainImages.size());
904         m_framebuffers.resize(swapchainImages.size());
905
906         for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
907         {
908                 m_attachmentViews[imageNdx]     = ImageViewSp(new vk::Unique<vk::VkImageView>(createImageView(context, swapchainImages[imageNdx], framebufferFormat)));
909                 m_framebuffers[imageNdx]        = FramebufferSp(new vk::Unique<vk::VkFramebuffer>(createFramebuffer(context,
910                                                                                                                                                                                                                 renderSize.x(),
911                                                                                                                                                                                                                 renderSize.y(),
912                                                                                                                                                                                                                 *m_renderPass,
913                                                                                                                                                                                                                 **m_attachmentViews[imageNdx])));
914         }
915
916         // Upload vertex data
917         {
918                 const tcu::Vec4                         vertices[]      =
919                 {
920                         tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
921                         tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
922                         tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
923                 };
924                 DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
925
926                 deMemcpy(m_vertexBuffer->getAllocation().getHostPtr(), &vertices[0], sizeof(vertices));
927                 vk::flushMappedMemoryRange(m_vkd, context.getDevice(), m_vertexBuffer->getAllocation().getMemory(), m_vertexBuffer->getAllocation().getOffset(), sizeof(vertices));
928         }
929 }
930
931 TriangleRenderer::~TriangleRenderer (void)
932 {
933 }
934
935 void TriangleRenderer::recordFrame (vk::VkCommandBuffer cmdBuffer,
936                                                                         deUint32                        imageNdx,
937                                                                         deUint32                        frameNdx) const
938 {
939         const vk::VkFramebuffer curFramebuffer  = **m_framebuffers[imageNdx];
940
941         beginCommandBuffer(m_vkd, cmdBuffer, 0u);
942
943         beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer, vk::makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
944         m_vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
945
946         {
947                 const vk::VkDeviceSize bindingOffset = 0;
948                 m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer->get(), &bindingOffset);
949         }
950
951         m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
952         m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
953         endRenderPass(m_vkd, cmdBuffer);
954
955         endCommandBuffer(m_vkd, cmdBuffer);
956 }
957
958 void TriangleRenderer::getPrograms (vk::SourceCollections& dst)
959 {
960         dst.glslSources.add("tri-vert") << glu::VertexSource(
961                 "#version 310 es\n"
962                 "layout(location = 0) in highp vec4 a_position;\n"
963                 "layout(push_constant) uniform FrameData\n"
964                 "{\n"
965                 "    highp uint frameNdx;\n"
966                 "} frameData;\n"
967                 "void main (void)\n"
968                 "{\n"
969                 "    highp float angle = float(frameData.frameNdx) / 100.0;\n"
970                 "    highp float c     = cos(angle);\n"
971                 "    highp float s     = sin(angle);\n"
972                 "    highp mat4  t     = mat4( c, -s,  0,  0,\n"
973                 "                              s,  c,  0,  0,\n"
974                 "                              0,  0,  1,  0,\n"
975                 "                              0,  0,  0,  1);\n"
976                 "    gl_Position = t * a_position;\n"
977                 "}\n");
978         dst.glslSources.add("tri-frag") << glu::FragmentSource(
979                 "#version 310 es\n"
980                 "layout(location = 0) out lowp vec4 o_color;\n"
981                 "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
982 }
983
984 typedef de::SharedPtr<vk::Unique<vk::VkCommandBuffer> > CommandBufferSp;
985 typedef de::SharedPtr<vk::Unique<vk::VkFence> >                 FenceSp;
986 typedef de::SharedPtr<vk::Unique<vk::VkSemaphore> >             SemaphoreSp;
987
988 std::vector<FenceSp> createFences (const vk::DeviceInterface&   vkd,
989                                                                    const vk::VkDevice                   device,
990                                                                    size_t                                               numFences)
991 {
992         std::vector<FenceSp> fences(numFences);
993
994         for (size_t ndx = 0; ndx < numFences; ++ndx)
995                 fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device)));
996
997         return fences;
998 }
999
1000 std::vector<SemaphoreSp> createSemaphores (const vk::DeviceInterface&   vkd,
1001                                                                                    const vk::VkDevice                   device,
1002                                                                                    size_t                                               numSemaphores)
1003 {
1004         std::vector<SemaphoreSp> semaphores(numSemaphores);
1005
1006         for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1007                 semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
1008
1009         return semaphores;
1010 }
1011
1012 std::vector<CommandBufferSp> allocateCommandBuffers (const vk::DeviceInterface&         vkd,
1013                                                                                                          const vk::VkDevice                             device,
1014                                                                                                          const vk::VkCommandPool                commandPool,
1015                                                                                                          const vk::VkCommandBufferLevel level,
1016                                                                                                          const size_t                                   numCommandBuffers)
1017 {
1018         std::vector<CommandBufferSp>                    buffers         (numCommandBuffers);
1019
1020         for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1021                 buffers[ndx] = CommandBufferSp(new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1022
1023         return buffers;
1024 }
1025
1026 tcu::TestStatus basicRenderTest (Context& baseCtx, vk::wsi::Type wsiType)
1027 {
1028         std::vector<vk::VkExtensionProperties>  supportedExtensions                     (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
1029         std::vector<std::string>                                instExts                                        = getRequiredWsiExtensions(supportedExtensions, wsiType);
1030         std::vector<std::string>                                devExts;
1031         devExts.push_back("VK_KHR_swapchain");
1032
1033         const tcu::UVec2                                                desiredSize                                     (256, 256);
1034         const NativeObjects                                             native                                          (baseCtx,  supportedExtensions, wsiType, tcu::just(desiredSize));
1035         ProtectedContext                                                context                                         (baseCtx, wsiType, *native.display, *native.window, instExts, devExts);
1036         vk::VkSurfaceKHR                                                surface                                         = context.getSurface();
1037         const vk::DeviceInterface&                              vkd                                                     = context.getDeviceInterface();
1038         const vk::VkDevice                                              device                                          = context.getDevice();
1039         const vk::VkSwapchainCreateInfoKHR              swapchainInfo                           = getBasicSwapchainParameters(wsiType,
1040                                                                                                                                                                                                   context.getInstanceDriver(),
1041                                                                                                                                                                                                   context.getPhysicalDevice(),
1042                                                                                                                                                                                                   surface,
1043                                                                                                                                                                                                   desiredSize,
1044                                                                                                                                                                                                   2);
1045         const vk::Unique<vk::VkSwapchainKHR>    swapchain                                       (createSwapchainKHR(vkd, device, &swapchainInfo));
1046         const std::vector<vk::VkImage>                  swapchainImages                         = vk::wsi::getSwapchainImages(vkd, device, *swapchain);
1047
1048         const TriangleRenderer                                  renderer                                        (context,
1049                                                                                                                                                  context.getBinaryCollection(),
1050                                                                                                                                                  swapchainImages,
1051                                                                                                                                                  swapchainInfo.imageFormat,
1052                                                                                                                                                  tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1053
1054         const vk::Unique<vk::VkCommandPool>             commandPool                                     (makeCommandPool(vkd, device, PROTECTION_ENABLED,
1055                                                                                                                                                                          context.getQueueFamilyIndex()));
1056
1057         const size_t                                                    maxQueuedFrames                         = swapchainImages.size()*2;
1058
1059         // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1060         // limit number of frames we allow to be queued.
1061         const std::vector<FenceSp>                              imageReadyFences                        (createFences(vkd, device, maxQueuedFrames));
1062
1063         // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1064         // the semaphore in same time as the fence we use to meter rendering.
1065         const std::vector<SemaphoreSp>                  imageReadySemaphores            (createSemaphores(vkd, device, maxQueuedFrames+1));
1066
1067         // For rest we simply need maxQueuedFrames as we will wait for image
1068         // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1069         // previous uses must have completed.
1070         const std::vector<SemaphoreSp>                  renderingCompleteSemaphores     (createSemaphores(vkd, device, maxQueuedFrames));
1071         const std::vector<CommandBufferSp>              commandBuffers                          (allocateCommandBuffers(vkd,
1072                                                                                                                                                                                                 device,
1073                                                                                                                                                                                                 *commandPool,
1074                                                                                                                                                                                                 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1075                                                                                                                                                                                                 maxQueuedFrames));
1076
1077         try
1078         {
1079                 const deUint32  numFramesToRender       = 60*10;
1080
1081                 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1082                 {
1083                         const vk::VkFence               imageReadyFence         = **imageReadyFences[frameNdx%imageReadyFences.size()];
1084                         const vk::VkSemaphore   imageReadySemaphore     = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1085                         deUint32                                imageNdx                        = ~0u;
1086
1087                         if (frameNdx >= maxQueuedFrames)
1088                                 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1089
1090                         VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1091
1092                         {
1093                                 const vk::VkResult      acquireResult   = vkd.acquireNextImageKHR(device,
1094                                                                                                                                                           *swapchain,
1095                                                                                                                                                           std::numeric_limits<deUint64>::max(),
1096                                                                                                                                                           imageReadySemaphore,
1097                                                                                                                                                           imageReadyFence,
1098                                                                                                                                                           &imageNdx);
1099
1100                                 if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
1101                                         context.getTestContext().getLog() << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << tcu::TestLog::EndMessage;
1102                                 else
1103                                         VK_CHECK(acquireResult);
1104                         }
1105
1106                         TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1107
1108                         {
1109                                 const vk::VkSemaphore                   renderingCompleteSemaphore      = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1110                                 const vk::VkCommandBuffer               commandBuffer                           = **commandBuffers[frameNdx%commandBuffers.size()];
1111                                 const vk::VkPipelineStageFlags  waitDstStage                            = vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1112                                 vk::VkSubmitInfo                                submitInfo                                      =
1113                                 {
1114                                         vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1115                                         DE_NULL,
1116                                         1u,
1117                                         &imageReadySemaphore,
1118                                         &waitDstStage,
1119                                         1u,
1120                                         &commandBuffer,
1121                                         1u,
1122                                         &renderingCompleteSemaphore
1123                                 };
1124
1125                                 const vk::VkProtectedSubmitInfo         protectedInfo   =
1126                                 {
1127                                         vk::VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO,            // sType
1128                                         DE_NULL,                                                                                        // pNext
1129                                         VK_TRUE,                                                                                        // protectedSubmit
1130                                 };
1131                                 submitInfo.pNext = &protectedInfo;
1132
1133                                 const vk::VkPresentInfoKHR              presentInfo                                     =
1134                                 {
1135                                         vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1136                                         DE_NULL,
1137                                         1u,
1138                                         &renderingCompleteSemaphore,
1139                                         1u,
1140                                         &*swapchain,
1141                                         &imageNdx,
1142                                         (vk::VkResult*)DE_NULL
1143                                 };
1144
1145                                 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1146                                 VK_CHECK(vkd.queueSubmit(context.getQueue(), 1u, &submitInfo, (vk::VkFence)0));
1147                                 VK_CHECK(vkd.queuePresentKHR(context.getQueue(), &presentInfo));
1148                         }
1149                 }
1150
1151                 VK_CHECK(vkd.deviceWaitIdle(device));
1152         }
1153         catch (...)
1154         {
1155                 // Make sure device is idle before destroying resources
1156                 vkd.deviceWaitIdle(device);
1157                 throw;
1158         }
1159
1160         return tcu::TestStatus::pass("Rendering tests succeeded");
1161 }
1162
1163 void getBasicRenderPrograms (vk::SourceCollections& dst, vk::wsi::Type)
1164 {
1165         TriangleRenderer::getPrograms(dst);
1166 }
1167
1168 void populateRenderGroup (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1169 {
1170         addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
1171 }
1172
1173 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1174 {
1175         addTestGroup(testGroup, "create",                       "Create VkSwapchain with various parameters",                                   populateSwapchainGroup,         GroupParameters(wsiType, createSwapchainTest));
1176         addTestGroup(testGroup, "render",                       "Rendering Tests",                                                                                              populateRenderGroup,            wsiType);
1177 }
1178
1179 void createTypeSpecificTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1180 {
1181         addTestGroup(testGroup, "swapchain", "VkSwapchain Tests", createSwapchainTests, wsiType);
1182 }
1183
1184 } // anonymous
1185
1186 tcu::TestCaseGroup* createSwapchainTests (tcu::TestContext& testCtx)
1187 {
1188         de::MovePtr<tcu::TestCaseGroup> wsiTestGroup (new tcu::TestCaseGroup(testCtx, "wsi", "WSI Tests"));
1189
1190         for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
1191         {
1192                 const vk::wsi::Type     wsiType         = (vk::wsi::Type)typeNdx;
1193
1194                 addTestGroup(&*wsiTestGroup, getName(wsiType), "", createTypeSpecificTests, wsiType);
1195         }
1196
1197         return wsiTestGroup.release();
1198 }
1199
1200 } // wsi
1201 } // vkt