Merge remote-tracking branch 'khronos/master' into deqp-dev
[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 static vk::VkCompositeAlphaFlagBitsKHR firstSupportedCompositeAlpha(const vk::VkSurfaceCapabilitiesKHR& capabilities)
208 {
209         deUint32 alphaMode = 1u;
210
211         for (;alphaMode < capabilities.supportedCompositeAlpha; alphaMode = alphaMode<<1u)
212         {
213                 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
214                 {
215                         break;
216                 }
217         }
218
219         return (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
220 }
221
222 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type                                                                wsiType,
223                                                                                                                                                    TestDimension                                                                dimension,
224                                                                                                                                                    const ProtectedContext&                                              context,
225                                                                                                                                                    const vk::VkSurfaceCapabilitiesKHR&                  capabilities,
226                                                                                                                                                    const std::vector<vk::VkSurfaceFormatKHR>&   formats,
227                                                                                                                                                    const std::vector<vk::VkPresentModeKHR>&             presentModes)
228 {
229         std::vector<vk::VkSwapchainCreateInfoKHR>       cases;
230         const vk::wsi::PlatformProperties&                      platformProperties      = getPlatformProperties(wsiType);
231         const vk::VkSurfaceTransformFlagBitsKHR         defaultTransform        = (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
232                                                                                                                                                 ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
233         const vk::VkSwapchainCreateInfoKHR                      baseParameters          =
234         {
235                 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
236                 DE_NULL,
237                 vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
238                 (vk::VkSurfaceKHR)0,
239                 capabilities.minImageCount,
240                 formats[0].format,
241                 formats[0].colorSpace,
242                 (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
243                         ? capabilities.minImageExtent : capabilities.currentExtent),
244                 1u,                                                                     // imageArrayLayers
245                 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
246                 vk::VK_SHARING_MODE_EXCLUSIVE,
247                 0u,
248                 (const deUint32*)DE_NULL,
249                 defaultTransform,
250                 firstSupportedCompositeAlpha(capabilities),
251                 vk::VK_PRESENT_MODE_FIFO_KHR,
252                 VK_FALSE,                                                       // clipped
253                 (vk::VkSwapchainKHR)0                           // oldSwapchain
254         };
255
256         switch (dimension)
257         {
258                 case TEST_DIMENSION_MIN_IMAGE_COUNT:
259                 {
260                         // Estimate how much memory each swapchain image consumes. This isn't perfect, since
261                         // swapchain images may have additional constraints that equivalent non-swapchain
262                         // images don't have. But it's the best we can do.
263                         const vk::DeviceInterface&                              vkd                                     = context.getDeviceInterface();
264                         vk::VkDevice                                                    device                          = context.getDevice();
265                         vk::VkMemoryRequirements                                memoryRequirements;
266                         {
267                                 const vk::VkImageCreateInfo                     imageInfo                       =
268                                 {
269                                         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
270                                         DE_NULL,
271                                         vk::VK_IMAGE_CREATE_PROTECTED_BIT,
272                                         vk::VK_IMAGE_TYPE_2D,
273                                         baseParameters.imageFormat,
274                                         {
275                                                 baseParameters.imageExtent.width,
276                                                 baseParameters.imageExtent.height,
277                                                 1,
278                                         },
279                                         1,      // mipLevels
280                                         baseParameters.imageArrayLayers,
281                                         vk::VK_SAMPLE_COUNT_1_BIT,
282                                         vk::VK_IMAGE_TILING_OPTIMAL,
283                                         baseParameters.imageUsage,
284                                         baseParameters.imageSharingMode,
285                                         baseParameters.queueFamilyIndexCount,
286                                         baseParameters.pQueueFamilyIndices,
287                                         vk::VK_IMAGE_LAYOUT_UNDEFINED
288                                 };
289                                 vk::Move<vk::VkImage>                           image                           = vk::createImage(vkd, device, &imageInfo);
290
291                                 memoryRequirements      = vk::getImageMemoryRequirements(vkd, device, *image);
292                         }
293
294                         // Determine the maximum memory heap space available for protected images
295                         vk::VkPhysicalDeviceMemoryProperties    memoryProperties        = vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
296                         vk::VkDeviceSize                                                protectedHeapSize       = 0;
297                         vk::VkDeviceSize                                                maxMemoryUsage          = 0;
298                         deUint32                                                                protectedHeapMask       = 0;
299
300                         for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
301                         {
302                                 deUint32 heapIndex      = memoryProperties.memoryTypes[memType].heapIndex;
303                                 if ((memoryRequirements.memoryTypeBits & (1u << memType)) != 0 &&
304                                         (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0 &&
305                                         (protectedHeapMask & (1u << heapIndex)) == 0)
306                                 {
307                                         protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
308                                         maxMemoryUsage    = protectedHeapSize / 4 ; /* Use at maximum 25% of heap */
309                                         protectedHeapMask |= 1u << heapIndex;
310                                 }
311                         }
312
313                         // If the implementation doesn't have a max image count, min+16 means we won't clamp.
314                         // Limit it to how many protected images we estimate can be allocated - 25% of heap size
315                         const deUint32  maxImageCount           = de::min((capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u,
316                                                                                                                   deUint32(maxMemoryUsage / memoryRequirements.size));
317                         if (maxImageCount < capabilities.minImageCount)
318                                 TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory!.");
319
320                         const deUint32  maxImageCountToTest     = de::clamp(16u, capabilities.minImageCount, maxImageCount);
321                         for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
322                         {
323                                 cases.push_back(baseParameters);
324                                 cases.back().minImageCount = imageCount;
325                         }
326
327                         break;
328                 }
329
330                 case TEST_DIMENSION_IMAGE_FORMAT:
331                 {
332                         for (std::vector<vk::VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
333                         {
334                                 cases.push_back(baseParameters);
335                                 cases.back().imageFormat                = curFmt->format;
336                                 cases.back().imageColorSpace    = curFmt->colorSpace;
337                         }
338
339                         break;
340                 }
341
342                 case TEST_DIMENSION_IMAGE_EXTENT:
343                 {
344                         static const vk::VkExtent2D     s_testSizes[]   =
345                         {
346                                 { 1, 1 },
347                                 { 16, 32 },
348                                 { 32, 16 },
349                                 { 632, 231 },
350                                 { 117, 998 },
351                         };
352
353                         const vk::DeviceInterface&                              vkd                                     = context.getDeviceInterface();
354                         vk::VkDevice                                                    device                          = context.getDevice();
355                         vk::VkPhysicalDeviceMemoryProperties    memoryProperties        = vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
356                         vk::VkDeviceSize                                                protectedHeapSize       = 0;
357                         vk::VkDeviceSize                                                maxMemoryUsage          = 0;
358
359                         for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
360                         {
361                                 deUint32 heapIndex      = memoryProperties.memoryTypes[memType].heapIndex;
362                                 if (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT)
363                                 {
364                                         protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
365                                         maxMemoryUsage    = protectedHeapSize / 4 ; /* Use at maximum 25% of heap */
366                                 }
367                         }
368
369                         if (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
370                                 platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
371                         {
372                                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
373                                 {
374                                         vk::VkMemoryRequirements memoryRequirements;
375                                         {
376                                                 const vk::VkImageCreateInfo imageInfo =
377                                                 {
378                                                         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
379                                                         DE_NULL,
380                                                         vk::VK_IMAGE_CREATE_PROTECTED_BIT,
381                                                         vk::VK_IMAGE_TYPE_2D,
382                                                         baseParameters.imageFormat,
383                                                         {
384                                                                 s_testSizes[ndx].width,
385                                                                 s_testSizes[ndx].height,
386                                                                 1,
387                                                         },
388                                                         1,      // mipLevels
389                                                         baseParameters.imageArrayLayers,
390                                                         vk::VK_SAMPLE_COUNT_1_BIT,
391                                                         vk::VK_IMAGE_TILING_OPTIMAL,
392                                                         baseParameters.imageUsage,
393                                                         baseParameters.imageSharingMode,
394                                                         baseParameters.queueFamilyIndexCount,
395                                                         baseParameters.pQueueFamilyIndices,
396                                                         vk::VK_IMAGE_LAYOUT_UNDEFINED
397                                                 };
398
399                                                 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
400
401                                                 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
402                                         }
403
404                                         // Check for the image size requirement based on double/triple buffering
405                                         if (memoryRequirements.size  * capabilities.minImageCount < maxMemoryUsage)
406                                         {
407                                                 cases.push_back(baseParameters);
408                                                 cases.back().imageExtent.width  = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
409                                                 cases.back().imageExtent.height = de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
410                                         }
411                                 }
412                         }
413
414                         if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
415                         {
416                                 vk::VkMemoryRequirements memoryRequirements;
417                                 {
418                                         const vk::VkImageCreateInfo imageInfo =
419                                         {
420                                                 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
421                                                 DE_NULL,
422                                                 vk::VK_IMAGE_CREATE_PROTECTED_BIT,
423                                                 vk::VK_IMAGE_TYPE_2D,
424                                                 baseParameters.imageFormat,
425                                                 {
426                                                         capabilities.currentExtent.width,
427                                                         capabilities.currentExtent.height,
428                                                         1,
429                                                 },
430                                                 1,      // mipLevels
431                                                 baseParameters.imageArrayLayers,
432                                                 vk::VK_SAMPLE_COUNT_1_BIT,
433                                                 vk::VK_IMAGE_TILING_OPTIMAL,
434                                                 baseParameters.imageUsage,
435                                                 baseParameters.imageSharingMode,
436                                                 baseParameters.queueFamilyIndexCount,
437                                                 baseParameters.pQueueFamilyIndices,
438                                                 vk::VK_IMAGE_LAYOUT_UNDEFINED
439                                         };
440
441                                         vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
442
443                                         memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
444                                 }
445
446                                 // Check for the image size requirement based on double/triple buffering
447                                 if (memoryRequirements.size  * capabilities.minImageCount < maxMemoryUsage)
448                                 {
449                                         cases.push_back(baseParameters);
450                                         cases.back().imageExtent = capabilities.currentExtent;
451                                 }
452                         }
453
454                         if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
455                         {
456                                 static const vk::VkExtent2D     s_testExtentSizes[]     =
457                                 {
458                                         { capabilities.minImageExtent.width, capabilities.minImageExtent.height },
459                                         { capabilities.maxImageExtent.width, capabilities.maxImageExtent.height },
460                                 };
461
462                                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testExtentSizes); ++ndx)
463                                 {
464                                         vk::VkMemoryRequirements memoryRequirements;
465                                         {
466                                                 const vk::VkImageCreateInfo     imageInfo =
467                                                 {
468                                                         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
469                                                         DE_NULL,
470                                                         vk::VK_IMAGE_CREATE_PROTECTED_BIT,
471                                                         vk::VK_IMAGE_TYPE_2D,
472                                                         baseParameters.imageFormat,
473                                                         {
474                                                                 s_testExtentSizes[ndx].width,
475                                                                 s_testExtentSizes[ndx].height,
476                                                                 1,
477                                                         },
478                                                         1,      // mipLevels
479                                                         baseParameters.imageArrayLayers,
480                                                         vk::VK_SAMPLE_COUNT_1_BIT,
481                                                         vk::VK_IMAGE_TILING_OPTIMAL,
482                                                         baseParameters.imageUsage,
483                                                         baseParameters.imageSharingMode,
484                                                         baseParameters.queueFamilyIndexCount,
485                                                         baseParameters.pQueueFamilyIndices,
486                                                         vk::VK_IMAGE_LAYOUT_UNDEFINED
487                                                 };
488
489                                                 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
490
491                                                 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
492                                         }
493
494                                         // Check for the image size requirement based on double/triple buffering
495                                         if (memoryRequirements.size  * capabilities.minImageCount < maxMemoryUsage)
496                                         {
497                                                 cases.push_back(baseParameters);
498                                                 cases.back().imageExtent =s_testExtentSizes[ndx];
499                                         }
500                                 }
501                         }
502
503                         break;
504                 }
505
506                 case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
507                 {
508                         const deUint32  maxLayers       = de::min(capabilities.maxImageArrayLayers, 16u);
509
510                         for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
511                         {
512                                 cases.push_back(baseParameters);
513                                 cases.back().imageArrayLayers = numLayers;
514                         }
515
516                         break;
517                 }
518
519                 case TEST_DIMENSION_IMAGE_USAGE:
520                 {
521                         for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
522                         {
523                                 if ((flags & ~capabilities.supportedUsageFlags) == 0)
524                                 {
525                                         cases.push_back(baseParameters);
526                                         cases.back().imageUsage = flags;
527                                 }
528                         }
529
530                         break;
531                 }
532
533                 case TEST_DIMENSION_IMAGE_SHARING_MODE:
534                 {
535                         cases.push_back(baseParameters);
536                         cases.back().imageSharingMode = vk::VK_SHARING_MODE_EXCLUSIVE;
537
538                         cases.push_back(baseParameters);
539                         cases.back().imageSharingMode = vk::VK_SHARING_MODE_CONCURRENT;
540
541                         break;
542                 }
543
544                 case TEST_DIMENSION_PRE_TRANSFORM:
545                 {
546                         for (deUint32 transform = 1u;
547                                  transform <= capabilities.supportedTransforms;
548                                  transform = transform<<1u)
549                         {
550                                 if ((transform & capabilities.supportedTransforms) != 0)
551                                 {
552                                         cases.push_back(baseParameters);
553                                         cases.back().preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
554                                 }
555                         }
556
557                         break;
558                 }
559
560                 case TEST_DIMENSION_COMPOSITE_ALPHA:
561                 {
562                         for (deUint32 alphaMode = 1u;
563                                  alphaMode <= capabilities.supportedCompositeAlpha;
564                                  alphaMode = alphaMode<<1u)
565                         {
566                                 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
567                                 {
568                                         cases.push_back(baseParameters);
569                                         cases.back().compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
570                                 }
571                         }
572
573                         break;
574                 }
575
576                 case TEST_DIMENSION_PRESENT_MODE:
577                 {
578                         for (std::vector<vk::VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
579                         {
580                                 cases.push_back(baseParameters);
581                                 cases.back().presentMode = *curMode;
582                         }
583
584                         break;
585                 }
586
587                 case TEST_DIMENSION_CLIPPED:
588                 {
589                         cases.push_back(baseParameters);
590                         cases.back().clipped = VK_FALSE;
591
592                         cases.push_back(baseParameters);
593                         cases.back().clipped = VK_TRUE;
594
595                         break;
596                 }
597
598                 default:
599                         DE_FATAL("Impossible");
600         }
601
602         DE_ASSERT(!cases.empty());
603         return cases;
604 }
605
606 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type                                        wsiType,
607                                                                                                                                                    TestDimension                                        dimension,
608                                                                                                                                                    const ProtectedContext&                      context,
609                                                                                                                                                    vk::VkSurfaceKHR                                     surface)
610 {
611         const vk::InstanceInterface&                            vki                             = context.getInstanceDriver();
612         vk::VkPhysicalDevice                                            physicalDevice  = context.getPhysicalDevice();
613         const vk::VkSurfaceCapabilitiesKHR                      capabilities    = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
614                                                                                                                                                                                                                            physicalDevice,
615                                                                                                                                                                                                                            surface);
616         const std::vector<vk::VkSurfaceFormatKHR>       formats                 = vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
617                                                                                                                                                                                                                    physicalDevice,
618                                                                                                                                                                                                                    surface);
619         const std::vector<vk::VkPresentModeKHR>         presentModes    = vk::wsi::getPhysicalDeviceSurfacePresentModes(vki,
620                                                                                                                                                                                                                             physicalDevice,
621                                                                                                                                                                                                                             surface);
622
623         return generateSwapchainParameterCases(wsiType, dimension, context, capabilities, formats, presentModes);
624 }
625
626 tcu::TestStatus createSwapchainTest (Context& baseCtx, TestParameters params)
627 {
628         std::vector<vk::VkExtensionProperties>                  supportedExtensions (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
629         std::vector<std::string>                                                instExts        = getRequiredWsiExtensions(supportedExtensions, params.wsiType);
630         std::vector<std::string>                                                devExts;
631         devExts.push_back("VK_KHR_swapchain");
632
633         const NativeObjects                                                             native          (baseCtx, supportedExtensions, params.wsiType);
634         ProtectedContext                                                                context         (baseCtx, params.wsiType, *native.display, *native.window, instExts, devExts);
635         vk::VkSurfaceKHR                                                                surface         = context.getSurface();
636         const std::vector<vk::VkSwapchainCreateInfoKHR> cases           (generateSwapchainParameterCases(params.wsiType,
637                                                                                                                                                                                                  params.dimension,
638                                                                                                                                                                                                  context,
639                                                                                                                                                                                                  surface));
640         deUint32                                                                                queueIdx        = context.getQueueFamilyIndex();
641         for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
642         {
643                 vk::VkSwapchainCreateInfoKHR    curParams       = cases[caseNdx];
644
645                 curParams.surface                               = surface;
646                 curParams.queueFamilyIndexCount = 1u;
647                 curParams.pQueueFamilyIndices   = &queueIdx;
648
649                 context.getTestContext().getLog()
650                         << tcu::TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": " << curParams << tcu::TestLog::EndMessage;
651
652                 {
653                         const vk::Unique<vk::VkSwapchainKHR>    swapchain       (createSwapchainKHR(context.getDeviceDriver(), context.getDevice(), &curParams));
654                 }
655         }
656
657         return tcu::TestStatus::pass("Creating swapchain succeeded");
658 }
659
660 struct GroupParameters
661 {
662         typedef FunctionInstance1<TestParameters>::Function     Function;
663
664         vk::wsi::Type   wsiType;
665         Function                function;
666
667         GroupParameters (vk::wsi::Type wsiType_, Function function_)
668                 : wsiType       (wsiType_)
669                 , function      (function_)
670         {}
671
672         GroupParameters (void)
673                 : wsiType       (vk::wsi::TYPE_LAST)
674                 , function      ((Function)DE_NULL)
675         {}
676 };
677
678 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
679 {
680         for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
681         {
682                 const TestDimension             testDimension   = (TestDimension)dimensionNdx;
683
684                 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
685         }
686 }
687
688 vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters (vk::wsi::Type                                 wsiType,
689                                                                                                                   const vk::InstanceInterface&  vki,
690                                                                                                                   vk::VkPhysicalDevice                  physicalDevice,
691                                                                                                                   vk::VkSurfaceKHR                              surface,
692                                                                                                                   const tcu::UVec2&                             desiredSize,
693                                                                                                                   deUint32                                              desiredImageCount)
694 {
695         const vk::VkSurfaceCapabilitiesKHR                      capabilities            = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
696                                                                                                                                                                                                                                     physicalDevice,
697                                                                                                                                                                                                                                     surface);
698         const std::vector<vk::VkSurfaceFormatKHR>       formats                         = vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
699                                                                                                                                                                                                                            physicalDevice,
700                                                                                                                                                                                                                            surface);
701         const vk::wsi::PlatformProperties&                      platformProperties      = vk::wsi::getPlatformProperties(wsiType);
702         const vk::VkSurfaceTransformFlagBitsKHR         transform                       = (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
703                                                                                                                                                 ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
704         const vk::VkSwapchainCreateInfoKHR                      parameters                      =
705         {
706                 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
707                 DE_NULL,
708                 vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
709                 surface,
710                 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
711                 formats[0].format,
712                 formats[0].colorSpace,
713                 (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
714                         ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
715                 1u,                                                                     // imageArrayLayers
716                 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
717                 vk::VK_SHARING_MODE_EXCLUSIVE,
718                 0u,
719                 (const deUint32*)DE_NULL,
720                 transform,
721                 firstSupportedCompositeAlpha(capabilities),
722                 vk::VK_PRESENT_MODE_FIFO_KHR,
723                 VK_FALSE,                                                       // clipped
724                 (vk::VkSwapchainKHR)0                           // oldSwapchain
725         };
726
727         return parameters;
728 }
729
730 typedef de::SharedPtr<vk::Unique<vk::VkImageView> >             ImageViewSp;
731 typedef de::SharedPtr<vk::Unique<vk::VkFramebuffer> >   FramebufferSp;
732
733 class TriangleRenderer
734 {
735 public:
736                                                                                                 TriangleRenderer        (ProtectedContext&                              context,
737                                                                                                                                          const vk::BinaryCollection&    binaryRegistry,
738                                                                                                                                          const std::vector<vk::VkImage> swapchainImages,
739                                                                                                                                          const vk::VkFormat                             framebufferFormat,
740                                                                                                                                          const tcu::UVec2&                              renderSize);
741                                                                                                 ~TriangleRenderer       (void);
742
743         void                                                                            recordFrame                     (vk::VkCommandBuffer                    cmdBuffer,
744                                                                                                                                          deUint32                                               imageNdx,
745                                                                                                                                          deUint32                                               frameNdx) const;
746
747         static void                                                                     getPrograms                     (vk::SourceCollections&                 dst);
748
749 private:
750         static vk::Move<vk::VkRenderPass>                       createRenderPass        (const vk::DeviceInterface&             vkd,
751                                                                                                                                          const vk::VkDevice                             device,
752                                                                                                                                          const vk::VkFormat                             colorAttachmentFormat);
753         static vk::Move<vk::VkPipelineLayout>           createPipelineLayout(const vk::DeviceInterface&         vkd,
754                                                                                                                                          vk::VkDevice                                   device);
755         static vk::Move<vk::VkPipeline>                         createPipeline          (const vk::DeviceInterface&             vkd,
756                                                                                                                                          const vk::VkDevice                             device,
757                                                                                                                                          const vk::VkRenderPass                 renderPass,
758                                                                                                                                          const vk::VkPipelineLayout             pipelineLayout,
759                                                                                                                                          const vk::BinaryCollection&    binaryCollection,
760                                                                                                                                          const tcu::UVec2&                              renderSize);
761
762         const vk::DeviceInterface&                                      m_vkd;
763
764         const std::vector<vk::VkImage>                          m_swapchainImages;
765         const tcu::UVec2                                                        m_renderSize;
766
767         const vk::Unique<vk::VkRenderPass>                      m_renderPass;
768         const vk::Unique<vk::VkPipelineLayout>          m_pipelineLayout;
769         const vk::Unique<vk::VkPipeline>                        m_pipeline;
770
771         const de::UniquePtr<vk::BufferWithMemory>       m_vertexBuffer;
772
773         std::vector<ImageViewSp>                                        m_attachmentViews;
774         std::vector<FramebufferSp>                                      m_framebuffers;
775 };
776
777 vk::Move<vk::VkRenderPass> TriangleRenderer::createRenderPass (const vk::DeviceInterface&       vkd,
778                                                                                                                            const vk::VkDevice                   device,
779                                                                                                                            const vk::VkFormat                   colorAttachmentFormat)
780 {
781         const vk::VkAttachmentDescription       colorAttDesc            =
782         {
783                 (vk::VkAttachmentDescriptionFlags)0,
784                 colorAttachmentFormat,
785                 vk::VK_SAMPLE_COUNT_1_BIT,
786                 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
787                 vk::VK_ATTACHMENT_STORE_OP_STORE,
788                 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
789                 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
790                 vk::VK_IMAGE_LAYOUT_UNDEFINED,
791                 vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
792         };
793         const vk::VkAttachmentReference         colorAttRef                     =
794         {
795                 0u,
796                 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
797         };
798         const vk::VkSubpassDescription          subpassDesc                     =
799         {
800                 (vk::VkSubpassDescriptionFlags)0u,
801                 vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
802                 0u,                                                     // inputAttachmentCount
803                 DE_NULL,                                        // pInputAttachments
804                 1u,                                                     // colorAttachmentCount
805                 &colorAttRef,                           // pColorAttachments
806                 DE_NULL,                                        // pResolveAttachments
807                 DE_NULL,                                        // depthStencilAttachment
808                 0u,                                                     // preserveAttachmentCount
809                 DE_NULL,                                        // pPreserveAttachments
810         };
811         const vk::VkSubpassDependency           dependencies[]          =
812         {
813                 {
814                         VK_SUBPASS_EXTERNAL,    // srcSubpass
815                         0u,                                             // dstSubpass
816                         vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
817                         vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
818                         vk::VK_ACCESS_MEMORY_READ_BIT,
819                         (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
820                          vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
821                         vk::VK_DEPENDENCY_BY_REGION_BIT
822                 },
823                 {
824                         0u,                                             // srcSubpass
825                         VK_SUBPASS_EXTERNAL,    // dstSubpass
826                         vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
827                         vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
828                         (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
829                          vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
830                         vk::VK_ACCESS_MEMORY_READ_BIT,
831                         vk::VK_DEPENDENCY_BY_REGION_BIT
832                 },
833         };
834         const vk::VkRenderPassCreateInfo        renderPassParams        =
835         {
836                 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
837                 DE_NULL,
838                 (vk::VkRenderPassCreateFlags)0,
839                 1u,
840                 &colorAttDesc,
841                 1u,
842                 &subpassDesc,
843                 DE_LENGTH_OF_ARRAY(dependencies),
844                 dependencies,
845         };
846
847         return vk::createRenderPass(vkd, device, &renderPassParams);
848 }
849
850 vk::Move<vk::VkPipelineLayout> TriangleRenderer::createPipelineLayout (const vk::DeviceInterface&       vkd,
851                                                                                                                                            const vk::VkDevice                   device)
852 {
853         const vk::VkPushConstantRange                                   pushConstantRange               =
854         {
855                 vk::VK_SHADER_STAGE_VERTEX_BIT,
856                 0u,                                                                                     // offset
857                 (deUint32)sizeof(deUint32),                                     // size
858         };
859         const vk::VkPipelineLayoutCreateInfo                    pipelineLayoutParams    =
860         {
861                 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
862                 DE_NULL,
863                 (vk::VkPipelineLayoutCreateFlags)0,
864                 0u,                                                                                     // setLayoutCount
865                 DE_NULL,                                                                        // pSetLayouts
866                 1u,
867                 &pushConstantRange,
868         };
869
870         return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
871 }
872
873 vk::Move<vk::VkPipeline> TriangleRenderer::createPipeline (const vk::DeviceInterface&   vkd,
874                                                                                                                    const vk::VkDevice                   device,
875                                                                                                                    const vk::VkRenderPass               renderPass,
876                                                                                                                    const vk::VkPipelineLayout   pipelineLayout,
877                                                                                                                    const vk::BinaryCollection&  binaryCollection,
878                                                                                                                    const tcu::UVec2&                    renderSize)
879 {
880         // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
881         //               and can be deleted immediately following that call.
882         const vk::Unique<vk::VkShaderModule>                            vertShaderModule                (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
883         const vk::Unique<vk::VkShaderModule>                            fragShaderModule                (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
884         const std::vector<vk::VkViewport>                                       viewports                               (1, vk::makeViewport(renderSize));
885         const std::vector<vk::VkRect2D>                                         scissors                                (1, vk::makeRect2D(renderSize));
886
887         return vk::makeGraphicsPipeline(vkd,                            // const DeviceInterface&            vk
888                                                                         device,                         // const VkDevice                    device
889                                                                         pipelineLayout,         // const VkPipelineLayout            pipelineLayout
890                                                                         *vertShaderModule,      // const VkShaderModule              vertexShaderModule
891                                                                         DE_NULL,                        // const VkShaderModule              tessellationControlShaderModule
892                                                                         DE_NULL,                        // const VkShaderModule              tessellationEvalShaderModule
893                                                                         DE_NULL,                        // const VkShaderModule              geometryShaderModule
894                                                                         *fragShaderModule,      // const VkShaderModule              fragmentShaderModule
895                                                                         renderPass,                     // const VkRenderPass                renderPass
896                                                                         viewports,                      // const std::vector<VkViewport>&    viewports
897                                                                         scissors);                      // const std::vector<VkRect2D>&      scissors
898 }
899
900 TriangleRenderer::TriangleRenderer (ProtectedContext&                           context,
901                                                                         const vk::BinaryCollection&             binaryRegistry,
902                                                                         const std::vector<vk::VkImage>  swapchainImages,
903                                                                         const vk::VkFormat                              framebufferFormat,
904                                                                         const tcu::UVec2&                               renderSize)
905         : m_vkd                                 (context.getDeviceInterface())
906         , m_swapchainImages             (swapchainImages)
907         , m_renderSize                  (renderSize)
908         , m_renderPass                  (createRenderPass(m_vkd, context.getDevice(), framebufferFormat))
909         , m_pipelineLayout              (createPipelineLayout(m_vkd, context.getDevice()))
910         , m_pipeline                    (createPipeline(m_vkd, context.getDevice(), *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
911         , m_vertexBuffer                (makeBuffer(context,
912                                                                         PROTECTION_DISABLED,
913                                                                         context.getQueueFamilyIndex(),
914                                                                         (deUint32)(sizeof(float)*4*3),
915                                                                         vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
916                                                                         vk::MemoryRequirement::HostVisible))
917 {
918         m_attachmentViews.resize(swapchainImages.size());
919         m_framebuffers.resize(swapchainImages.size());
920
921         for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
922         {
923                 m_attachmentViews[imageNdx]     = ImageViewSp(new vk::Unique<vk::VkImageView>(createImageView(context, swapchainImages[imageNdx], framebufferFormat)));
924                 m_framebuffers[imageNdx]        = FramebufferSp(new vk::Unique<vk::VkFramebuffer>(createFramebuffer(context,
925                                                                                                                                                                                                                 renderSize.x(),
926                                                                                                                                                                                                                 renderSize.y(),
927                                                                                                                                                                                                                 *m_renderPass,
928                                                                                                                                                                                                                 **m_attachmentViews[imageNdx])));
929         }
930
931         // Upload vertex data
932         {
933                 const tcu::Vec4                         vertices[]      =
934                 {
935                         tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
936                         tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
937                         tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
938                 };
939                 DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
940
941                 deMemcpy(m_vertexBuffer->getAllocation().getHostPtr(), &vertices[0], sizeof(vertices));
942                 vk::flushMappedMemoryRange(m_vkd, context.getDevice(), m_vertexBuffer->getAllocation().getMemory(), m_vertexBuffer->getAllocation().getOffset(), sizeof(vertices));
943         }
944 }
945
946 TriangleRenderer::~TriangleRenderer (void)
947 {
948 }
949
950 void TriangleRenderer::recordFrame (vk::VkCommandBuffer cmdBuffer,
951                                                                         deUint32                        imageNdx,
952                                                                         deUint32                        frameNdx) const
953 {
954         const vk::VkFramebuffer curFramebuffer  = **m_framebuffers[imageNdx];
955
956         beginCommandBuffer(m_vkd, cmdBuffer, 0u);
957
958         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));
959         m_vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
960
961         {
962                 const vk::VkDeviceSize bindingOffset = 0;
963                 m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer->get(), &bindingOffset);
964         }
965
966         m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
967         m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
968         endRenderPass(m_vkd, cmdBuffer);
969
970         endCommandBuffer(m_vkd, cmdBuffer);
971 }
972
973 void TriangleRenderer::getPrograms (vk::SourceCollections& dst)
974 {
975         dst.glslSources.add("tri-vert") << glu::VertexSource(
976                 "#version 310 es\n"
977                 "layout(location = 0) in highp vec4 a_position;\n"
978                 "layout(push_constant) uniform FrameData\n"
979                 "{\n"
980                 "    highp uint frameNdx;\n"
981                 "} frameData;\n"
982                 "void main (void)\n"
983                 "{\n"
984                 "    highp float angle = float(frameData.frameNdx) / 100.0;\n"
985                 "    highp float c     = cos(angle);\n"
986                 "    highp float s     = sin(angle);\n"
987                 "    highp mat4  t     = mat4( c, -s,  0,  0,\n"
988                 "                              s,  c,  0,  0,\n"
989                 "                              0,  0,  1,  0,\n"
990                 "                              0,  0,  0,  1);\n"
991                 "    gl_Position = t * a_position;\n"
992                 "}\n");
993         dst.glslSources.add("tri-frag") << glu::FragmentSource(
994                 "#version 310 es\n"
995                 "layout(location = 0) out lowp vec4 o_color;\n"
996                 "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
997 }
998
999 typedef de::SharedPtr<vk::Unique<vk::VkCommandBuffer> > CommandBufferSp;
1000 typedef de::SharedPtr<vk::Unique<vk::VkFence> >                 FenceSp;
1001 typedef de::SharedPtr<vk::Unique<vk::VkSemaphore> >             SemaphoreSp;
1002
1003 std::vector<FenceSp> createFences (const vk::DeviceInterface&   vkd,
1004                                                                    const vk::VkDevice                   device,
1005                                                                    size_t                                               numFences)
1006 {
1007         std::vector<FenceSp> fences(numFences);
1008
1009         for (size_t ndx = 0; ndx < numFences; ++ndx)
1010                 fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device)));
1011
1012         return fences;
1013 }
1014
1015 std::vector<SemaphoreSp> createSemaphores (const vk::DeviceInterface&   vkd,
1016                                                                                    const vk::VkDevice                   device,
1017                                                                                    size_t                                               numSemaphores)
1018 {
1019         std::vector<SemaphoreSp> semaphores(numSemaphores);
1020
1021         for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1022                 semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
1023
1024         return semaphores;
1025 }
1026
1027 std::vector<CommandBufferSp> allocateCommandBuffers (const vk::DeviceInterface&         vkd,
1028                                                                                                          const vk::VkDevice                             device,
1029                                                                                                          const vk::VkCommandPool                commandPool,
1030                                                                                                          const vk::VkCommandBufferLevel level,
1031                                                                                                          const size_t                                   numCommandBuffers)
1032 {
1033         std::vector<CommandBufferSp>                    buffers         (numCommandBuffers);
1034
1035         for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1036                 buffers[ndx] = CommandBufferSp(new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1037
1038         return buffers;
1039 }
1040
1041 tcu::TestStatus basicRenderTest (Context& baseCtx, vk::wsi::Type wsiType)
1042 {
1043         std::vector<vk::VkExtensionProperties>  supportedExtensions                     (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
1044         std::vector<std::string>                                instExts                                        = getRequiredWsiExtensions(supportedExtensions, wsiType);
1045         std::vector<std::string>                                devExts;
1046         devExts.push_back("VK_KHR_swapchain");
1047
1048         const tcu::UVec2                                                desiredSize                                     (256, 256);
1049         const NativeObjects                                             native                                          (baseCtx,  supportedExtensions, wsiType, tcu::just(desiredSize));
1050         ProtectedContext                                                context                                         (baseCtx, wsiType, *native.display, *native.window, instExts, devExts);
1051         vk::VkSurfaceKHR                                                surface                                         = context.getSurface();
1052         const vk::DeviceInterface&                              vkd                                                     = context.getDeviceInterface();
1053         const vk::VkDevice                                              device                                          = context.getDevice();
1054         const vk::VkSwapchainCreateInfoKHR              swapchainInfo                           = getBasicSwapchainParameters(wsiType,
1055                                                                                                                                                                                                   context.getInstanceDriver(),
1056                                                                                                                                                                                                   context.getPhysicalDevice(),
1057                                                                                                                                                                                                   surface,
1058                                                                                                                                                                                                   desiredSize,
1059                                                                                                                                                                                                   2);
1060         const vk::Unique<vk::VkSwapchainKHR>    swapchain                                       (createSwapchainKHR(vkd, device, &swapchainInfo));
1061         const std::vector<vk::VkImage>                  swapchainImages                         = vk::wsi::getSwapchainImages(vkd, device, *swapchain);
1062
1063         const TriangleRenderer                                  renderer                                        (context,
1064                                                                                                                                                  context.getBinaryCollection(),
1065                                                                                                                                                  swapchainImages,
1066                                                                                                                                                  swapchainInfo.imageFormat,
1067                                                                                                                                                  tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1068
1069         const vk::Unique<vk::VkCommandPool>             commandPool                                     (makeCommandPool(vkd, device, PROTECTION_ENABLED,
1070                                                                                                                                                                          context.getQueueFamilyIndex()));
1071
1072         const size_t                                                    maxQueuedFrames                         = swapchainImages.size()*2;
1073
1074         // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1075         // limit number of frames we allow to be queued.
1076         const std::vector<FenceSp>                              imageReadyFences                        (createFences(vkd, device, maxQueuedFrames));
1077
1078         // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1079         // the semaphore in same time as the fence we use to meter rendering.
1080         const std::vector<SemaphoreSp>                  imageReadySemaphores            (createSemaphores(vkd, device, maxQueuedFrames+1));
1081
1082         // For rest we simply need maxQueuedFrames as we will wait for image
1083         // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1084         // previous uses must have completed.
1085         const std::vector<SemaphoreSp>                  renderingCompleteSemaphores     (createSemaphores(vkd, device, maxQueuedFrames));
1086         const std::vector<CommandBufferSp>              commandBuffers                          (allocateCommandBuffers(vkd,
1087                                                                                                                                                                                                 device,
1088                                                                                                                                                                                                 *commandPool,
1089                                                                                                                                                                                                 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1090                                                                                                                                                                                                 maxQueuedFrames));
1091
1092         try
1093         {
1094                 const deUint32  numFramesToRender       = 60*10;
1095
1096                 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1097                 {
1098                         const vk::VkFence               imageReadyFence         = **imageReadyFences[frameNdx%imageReadyFences.size()];
1099                         const vk::VkSemaphore   imageReadySemaphore     = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1100                         deUint32                                imageNdx                        = ~0u;
1101
1102                         if (frameNdx >= maxQueuedFrames)
1103                                 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1104
1105                         VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1106
1107                         {
1108                                 const vk::VkResult      acquireResult   = vkd.acquireNextImageKHR(device,
1109                                                                                                                                                           *swapchain,
1110                                                                                                                                                           std::numeric_limits<deUint64>::max(),
1111                                                                                                                                                           imageReadySemaphore,
1112                                                                                                                                                           0,
1113                                                                                                                                                           &imageNdx);
1114
1115                                 if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
1116                                         context.getTestContext().getLog() << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << tcu::TestLog::EndMessage;
1117                                 else
1118                                         VK_CHECK(acquireResult);
1119                         }
1120
1121                         TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1122
1123                         {
1124                                 const vk::VkSemaphore                   renderingCompleteSemaphore      = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1125                                 const vk::VkCommandBuffer               commandBuffer                           = **commandBuffers[frameNdx%commandBuffers.size()];
1126                                 const vk::VkPipelineStageFlags  waitDstStage                            = vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1127                                 vk::VkSubmitInfo                                submitInfo                                      =
1128                                 {
1129                                         vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1130                                         DE_NULL,
1131                                         1u,
1132                                         &imageReadySemaphore,
1133                                         &waitDstStage,
1134                                         1u,
1135                                         &commandBuffer,
1136                                         1u,
1137                                         &renderingCompleteSemaphore
1138                                 };
1139
1140                                 const vk::VkProtectedSubmitInfo         protectedInfo   =
1141                                 {
1142                                         vk::VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO,            // sType
1143                                         DE_NULL,                                                                                        // pNext
1144                                         VK_TRUE,                                                                                        // protectedSubmit
1145                                 };
1146                                 submitInfo.pNext = &protectedInfo;
1147
1148                                 const vk::VkPresentInfoKHR              presentInfo                                     =
1149                                 {
1150                                         vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1151                                         DE_NULL,
1152                                         1u,
1153                                         &renderingCompleteSemaphore,
1154                                         1u,
1155                                         &*swapchain,
1156                                         &imageNdx,
1157                                         (vk::VkResult*)DE_NULL
1158                                 };
1159
1160                                 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1161                                 VK_CHECK(vkd.queueSubmit(context.getQueue(), 1u, &submitInfo, imageReadyFence));
1162                                 VK_CHECK(vkd.queuePresentKHR(context.getQueue(), &presentInfo));
1163                         }
1164                 }
1165
1166                 VK_CHECK(vkd.deviceWaitIdle(device));
1167         }
1168         catch (...)
1169         {
1170                 // Make sure device is idle before destroying resources
1171                 vkd.deviceWaitIdle(device);
1172                 throw;
1173         }
1174
1175         return tcu::TestStatus::pass("Rendering tests succeeded");
1176 }
1177
1178 void getBasicRenderPrograms (vk::SourceCollections& dst, vk::wsi::Type)
1179 {
1180         TriangleRenderer::getPrograms(dst);
1181 }
1182
1183 void populateRenderGroup (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1184 {
1185         addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
1186 }
1187
1188 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1189 {
1190         addTestGroup(testGroup, "create",                       "Create VkSwapchain with various parameters",                                   populateSwapchainGroup,         GroupParameters(wsiType, createSwapchainTest));
1191         addTestGroup(testGroup, "render",                       "Rendering Tests",                                                                                              populateRenderGroup,            wsiType);
1192 }
1193
1194 void createTypeSpecificTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1195 {
1196         addTestGroup(testGroup, "swapchain", "VkSwapchain Tests", createSwapchainTests, wsiType);
1197 }
1198
1199 } // anonymous
1200
1201 tcu::TestCaseGroup* createSwapchainTests (tcu::TestContext& testCtx)
1202 {
1203         de::MovePtr<tcu::TestCaseGroup> wsiTestGroup (new tcu::TestCaseGroup(testCtx, "wsi", "WSI Tests"));
1204
1205         for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
1206         {
1207                 const vk::wsi::Type     wsiType         = (vk::wsi::Type)typeNdx;
1208
1209                 addTestGroup(&*wsiTestGroup, getName(wsiType), "", createTypeSpecificTests, wsiType);
1210         }
1211
1212         return wsiTestGroup.release();
1213 }
1214
1215 } // wsi
1216 } // vkt