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 #include <cstring>
58 
59 #include "vktProtectedMemContext.hpp"
60 #include "vktProtectedMemUtils.hpp"
61 
62 namespace vkt
63 {
64 namespace ProtectedMem
65 {
66 
67 namespace
68 {
69 
70 typedef std::vector<vk::VkExtensionProperties> Extensions;
71 
checkAllSupported(const Extensions & supportedExtensions,const std::vector<std::string> & requiredExtensions)72 void checkAllSupported(const Extensions &supportedExtensions, const std::vector<std::string> &requiredExtensions)
73 {
74     for (std::vector<std::string>::const_iterator requiredExtName = requiredExtensions.begin();
75          requiredExtName != requiredExtensions.end(); ++requiredExtName)
76     {
77         if (!isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
78             TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
79     }
80 }
81 
getRequiredWsiExtensions(const Extensions & supportedExtensions,vk::wsi::Type wsiType)82 std::vector<std::string> getRequiredWsiExtensions(const Extensions &supportedExtensions, vk::wsi::Type wsiType)
83 {
84     std::vector<std::string> extensions;
85 
86     extensions.push_back("VK_KHR_surface");
87     extensions.push_back(getExtensionName(wsiType));
88     if (isDisplaySurface(wsiType))
89         extensions.push_back("VK_KHR_display");
90 
91     // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
92     // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
93     // but using them without enabling the extension is not allowed. Thus we have
94     // two options:
95     //
96     // 1) Filter out non-core formats to stay within valid usage.
97     //
98     // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
99     //
100     // We opt for (2) as it provides basic coverage for the extension as a bonus.
101     if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension("VK_EXT_swapchain_colorspace")))
102         extensions.push_back("VK_EXT_swapchain_colorspace");
103 
104     // VK_KHR_surface_protected_capabilities adds a way to check if swapchain can be
105     // created for protected VkSurface, so if this extension is enabled then we can
106     // check for that capability.
107     // To check this capability, vkGetPhysicalDeviceSurfaceCapabilities2KHR needs
108     // to be called so add VK_KHR_get_surface_capabilities2 for this.
109     if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension("VK_KHR_surface_protected_capabilities")))
110     {
111         extensions.push_back("VK_KHR_get_surface_capabilities2");
112         extensions.push_back("VK_KHR_surface_protected_capabilities");
113     }
114 
115     checkAllSupported(supportedExtensions, extensions);
116 
117     return extensions;
118 }
119 
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,vk::wsi::Type wsiType)120 de::MovePtr<vk::wsi::Display> createDisplay(const vk::Platform &platform, const Extensions &supportedExtensions,
121                                             vk::wsi::Type wsiType)
122 {
123     try
124     {
125         return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
126     }
127     catch (const tcu::NotSupportedError &e)
128     {
129         if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))) &&
130             platform.hasDisplay(wsiType))
131         {
132             // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
133             // must support creating native display & window for that WSI type.
134             throw tcu::TestError(e.getMessage());
135         }
136         else
137             throw;
138     }
139 }
140 
createWindow(const vk::wsi::Display & display,const tcu::Maybe<tcu::UVec2> & initialSize)141 de::MovePtr<vk::wsi::Window> createWindow(const vk::wsi::Display &display, const tcu::Maybe<tcu::UVec2> &initialSize)
142 {
143     try
144     {
145         return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
146     }
147     catch (const tcu::NotSupportedError &e)
148     {
149         // See createDisplay - assuming that wsi::Display was supported platform port
150         // should also support creating a window.
151         throw tcu::TestError(e.getMessage());
152     }
153 }
154 
155 struct NativeObjects
156 {
157     const de::UniquePtr<vk::wsi::Display> display;
158     const de::UniquePtr<vk::wsi::Window> window;
159 
NativeObjectsvkt::ProtectedMem::__anon98a108480111::NativeObjects160     NativeObjects(Context &context, const Extensions &supportedExtensions, vk::wsi::Type wsiType,
161                   const tcu::Maybe<tcu::UVec2> &initialWindowSize = tcu::Nothing)
162         : display(
163               createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
164         , window(createWindow(*display, initialWindowSize))
165     {
166     }
167 };
168 
169 enum TestDimension
170 {
171     TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
172     TEST_DIMENSION_IMAGE_FORMAT,        //!< Test all supported formats
173     TEST_DIMENSION_IMAGE_EXTENT,        //!< Test various (supported) extents
174     TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
175     TEST_DIMENSION_IMAGE_USAGE,
176     TEST_DIMENSION_IMAGE_SHARING_MODE,
177     TEST_DIMENSION_PRE_TRANSFORM,
178     TEST_DIMENSION_COMPOSITE_ALPHA,
179     TEST_DIMENSION_PRESENT_MODE,
180     TEST_DIMENSION_CLIPPED,
181 
182     TEST_DIMENSION_LAST
183 };
184 
getTestDimensionName(TestDimension dimension)185 const char *getTestDimensionName(TestDimension dimension)
186 {
187     static const char *const s_names[] = {
188         "min_image_count",    "image_format",  "image_extent",    "image_array_layers", "image_usage",
189         "image_sharing_mode", "pre_transform", "composite_alpha", "present_mode",       "clipped"};
190     return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
191 }
192 
193 struct TestParameters
194 {
195     vk::wsi::Type wsiType;
196     TestDimension dimension;
197 
TestParametersvkt::ProtectedMem::__anon98a108480111::TestParameters198     TestParameters(vk::wsi::Type wsiType_, TestDimension dimension_) : wsiType(wsiType_), dimension(dimension_)
199     {
200     }
201 
TestParametersvkt::ProtectedMem::__anon98a108480111::TestParameters202     TestParameters(void) : wsiType(vk::wsi::TYPE_LAST), dimension(TEST_DIMENSION_LAST)
203     {
204     }
205 };
206 
firstSupportedCompositeAlpha(const vk::VkSurfaceCapabilitiesKHR & capabilities)207 static vk::VkCompositeAlphaFlagBitsKHR firstSupportedCompositeAlpha(const vk::VkSurfaceCapabilitiesKHR &capabilities)
208 {
209     uint32_t 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 using SwapchainCreationExecutor = void (*)(const vk::DeviceDriver &, vk::VkDevice, const vk::VkSwapchainCreateInfoKHR &,
223                                            tcu::TestLog &, uint32_t, uint32_t);
swapchainCreateExecutor(const vk::DeviceDriver & vk,vk::VkDevice device,const vk::VkSwapchainCreateInfoKHR & createInfo,tcu::TestLog & log,uint32_t caseIndex,uint32_t caseCount)224 void swapchainCreateExecutor(const vk::DeviceDriver &vk, vk::VkDevice device,
225                              const vk::VkSwapchainCreateInfoKHR &createInfo, tcu::TestLog &log, uint32_t caseIndex,
226                              uint32_t caseCount)
227 {
228     log << tcu::TestLog::Message << "Sub-case " << caseIndex << " / " << caseCount << ": " << createInfo
229         << tcu::TestLog::EndMessage;
230     const vk::Unique<vk::VkSwapchainKHR> swapchain(createSwapchainKHR(vk, device, &createInfo));
231 }
232 
executeSwapchainParameterCases(vk::wsi::Type wsiType,TestDimension dimension,const ProtectedContext & context,const vk::VkSurfaceCapabilitiesKHR & capabilities,const std::vector<vk::VkSurfaceFormatKHR> & formats,const std::vector<vk::VkPresentModeKHR> & presentModes,bool isExtensionForPresentModeEnabled,SwapchainCreationExecutor testExecutor)233 tcu::TestStatus executeSwapchainParameterCases(vk::wsi::Type wsiType, TestDimension dimension,
234                                                const ProtectedContext &context,
235                                                const vk::VkSurfaceCapabilitiesKHR &capabilities,
236                                                const std::vector<vk::VkSurfaceFormatKHR> &formats,
237                                                const std::vector<vk::VkPresentModeKHR> &presentModes,
238                                                bool isExtensionForPresentModeEnabled,
239                                                SwapchainCreationExecutor testExecutor)
240 {
241     tcu::TestLog &log                                     = context.getTestContext().getLog();
242     const vk::DeviceInterface &vki                        = context.getDeviceInterface();
243     const vk::DeviceDriver &vkd                           = context.getDeviceDriver();
244     vk::VkDevice device                                   = context.getDevice();
245     const vk::wsi::PlatformProperties &platformProperties = getPlatformProperties(wsiType);
246     const vk::VkSurfaceTransformFlagBitsKHR defaultTransform =
247         (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
248             vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
249             capabilities.currentTransform;
250     uint32_t queueIdx                                 = context.getQueueFamilyIndex();
251     const vk::VkSurfaceKHR surface                    = context.getSurface();
252     const vk::VkSwapchainCreateInfoKHR baseParameters = {
253         vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
254         DE_NULL,
255 #ifndef NOT_PROTECTED
256         vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
257 #else
258         (vk::VkSwapchainCreateFlagsKHR)0,
259 #endif
260         surface,
261         capabilities.minImageCount,
262         formats[0].format,
263         formats[0].colorSpace,
264         (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ?
265              capabilities.minImageExtent :
266              capabilities.currentExtent),
267         1u, // imageArrayLayers
268         vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
269         vk::VK_SHARING_MODE_EXCLUSIVE,
270         1u,
271         &queueIdx,
272         defaultTransform,
273         firstSupportedCompositeAlpha(capabilities),
274         vk::VK_PRESENT_MODE_FIFO_KHR,
275         VK_FALSE,             // clipped
276         (vk::VkSwapchainKHR)0 // oldSwapchain
277     };
278 
279     vk::VkImageCreateFlags imageCreateFlag =
280 #ifndef NOT_PROTECTED
281         vk::VK_IMAGE_CREATE_PROTECTED_BIT;
282 #else
283         (vk::VkImageCreateFlags)0u;
284 #endif
285 
286     switch (dimension)
287     {
288     case TEST_DIMENSION_MIN_IMAGE_COUNT:
289     {
290         // Estimate how much memory each swapchain image consumes. This isn't perfect, since
291         // swapchain images may have additional constraints that equivalent non-swapchain
292         // images don't have. But it's the best we can do.
293         vk::VkMemoryRequirements memoryRequirements;
294         {
295             const vk::VkImageCreateInfo imageInfo = {vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
296                                                      DE_NULL,
297                                                      imageCreateFlag,
298                                                      vk::VK_IMAGE_TYPE_2D,
299                                                      baseParameters.imageFormat,
300                                                      {
301                                                          baseParameters.imageExtent.width,
302                                                          baseParameters.imageExtent.height,
303                                                          1,
304                                                      },
305                                                      1, // mipLevels
306                                                      baseParameters.imageArrayLayers,
307                                                      vk::VK_SAMPLE_COUNT_1_BIT,
308                                                      vk::VK_IMAGE_TILING_OPTIMAL,
309                                                      baseParameters.imageUsage,
310                                                      baseParameters.imageSharingMode,
311                                                      baseParameters.queueFamilyIndexCount,
312                                                      baseParameters.pQueueFamilyIndices,
313                                                      vk::VK_IMAGE_LAYOUT_UNDEFINED};
314             vk::Move<vk::VkImage> image           = vk::createImage(vki, device, &imageInfo);
315 
316             memoryRequirements = vk::getImageMemoryRequirements(vki, device, *image);
317         }
318 
319         // Determine the maximum memory heap space available for protected images
320         vk::VkPhysicalDeviceMemoryProperties memoryProperties =
321             vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
322         vk::VkDeviceSize protectedHeapSize = 0;
323         uint32_t protectedHeapMask         = 0;
324 
325         for (uint32_t memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
326         {
327             uint32_t heapIndex = memoryProperties.memoryTypes[memType].heapIndex;
328             if ((memoryRequirements.memoryTypeBits & (1u << memType)) != 0 &&
329 #ifndef NOT_PROTECTED
330                 (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0 &&
331 #endif
332                 (protectedHeapMask & (1u << heapIndex)) == 0)
333             {
334                 protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
335                 protectedHeapMask |= 1u << heapIndex;
336             }
337         }
338 
339         vk::VkDeviceSize minProtectedHeapSize = 0u;
340         vk::VkDeviceSize maxProtectedHeapSize = protectedHeapSize;
341         bool passed                           = false;
342         // Apply binary search to see if we have suitable memory amount for test
343         while (minProtectedHeapSize <= maxProtectedHeapSize)
344         {
345             // If the implementation doesn't have a max image count, min+16 means we won't clamp.
346             // Limit it to how many protected images we estimate can be allocated
347             const uint32_t maxImageCount = de::min((capabilities.maxImageCount > 0u) ? capabilities.maxImageCount :
348                                                                                        capabilities.minImageCount + 16u,
349                                                    uint32_t(protectedHeapSize / memoryRequirements.size));
350             if (maxImageCount < capabilities.minImageCount)
351             {
352                 minProtectedHeapSize = protectedHeapSize + 1u;
353                 protectedHeapSize    = minProtectedHeapSize + (maxProtectedHeapSize - minProtectedHeapSize) / 2u;
354                 continue;
355             }
356 
357             try
358             {
359                 log << tcu::TestLog::Message << "Starting test cases with protectedHeapSize of " << protectedHeapSize
360                     << tcu::TestLog::EndMessage;
361                 const uint32_t maxImageCountToTest = de::clamp(16u, capabilities.minImageCount, maxImageCount);
362                 uint32_t testCount                 = maxImageCount - capabilities.minImageCount + 1u;
363                 uint32_t testIndex                 = 0u;
364                 // Loop downwards since we want to catch OOM errors as fast as possible
365                 for (uint32_t imageCount = maxImageCountToTest; capabilities.minImageCount <= imageCount; --imageCount)
366                 {
367                     vk::VkSwapchainCreateInfoKHR createInfo = baseParameters;
368                     createInfo.minImageCount                = imageCount;
369                     testExecutor(vkd, device, createInfo, log, ++testIndex, testCount);
370                 }
371                 passed = true;
372             }
373             catch (vk::OutOfMemoryError &)
374             {
375                 log << tcu::TestLog::Message
376                     << "Test cases failed with OOM error. Checking if smaller heap size is possible."
377                     << tcu::TestLog::EndMessage;
378                 maxProtectedHeapSize = protectedHeapSize - 1u;
379                 protectedHeapSize    = minProtectedHeapSize + (maxProtectedHeapSize - minProtectedHeapSize) / 2u;
380                 continue;
381             }
382 
383             break;
384         }
385 
386         if (!passed)
387             TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory!");
388 
389         break;
390     }
391 
392     case TEST_DIMENSION_IMAGE_FORMAT:
393     {
394         vk::VkPhysicalDeviceMemoryProperties memoryProperties =
395             vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
396         vk::VkDeviceSize protectedHeapSize = 0;
397 
398         for (uint32_t memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
399         {
400             uint32_t heapIndex = memoryProperties.memoryTypes[memType].heapIndex;
401 #ifndef NOT_PROTECTED
402             if (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT)
403 #endif
404             {
405                 protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
406             }
407         }
408 
409         bool atLeastOnePassed = false;
410         uint32_t testIndex    = 0u;
411         uint32_t testCount    = static_cast<uint32_t>(formats.size());
412         for (std::vector<vk::VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end();
413              ++curFmt)
414         {
415             vk::VkMemoryRequirements memoryRequirements;
416             {
417                 const vk::VkImageCreateInfo imageInfo = {
418                     vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
419                     DE_NULL,
420                     imageCreateFlag,
421                     vk::VK_IMAGE_TYPE_2D,
422                     curFmt->format,
423                     {
424                         platformProperties.swapchainExtent ==
425                                 vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ?
426                             capabilities.minImageExtent.width :
427                             capabilities.currentExtent.width,
428                         platformProperties.swapchainExtent ==
429                                 vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ?
430                             capabilities.minImageExtent.height :
431                             capabilities.currentExtent.height,
432                         1,
433                     },
434                     1, // mipLevels
435                     baseParameters.imageArrayLayers,
436                     vk::VK_SAMPLE_COUNT_1_BIT,
437                     vk::VK_IMAGE_TILING_OPTIMAL,
438                     baseParameters.imageUsage,
439                     baseParameters.imageSharingMode,
440                     baseParameters.queueFamilyIndexCount,
441                     baseParameters.pQueueFamilyIndices,
442                     vk::VK_IMAGE_LAYOUT_UNDEFINED};
443 
444                 vk::Move<vk::VkImage> image = vk::createImage(vki, device, &imageInfo);
445 
446                 memoryRequirements = vk::getImageMemoryRequirements(vki, device, *image);
447             }
448 
449             // Check for the image size requirement based on double/triple buffering
450             if (memoryRequirements.size * capabilities.minImageCount < protectedHeapSize)
451             {
452                 vk::VkSwapchainCreateInfoKHR createInfo = baseParameters;
453                 createInfo.imageFormat                  = curFmt->format;
454                 createInfo.imageColorSpace              = curFmt->colorSpace;
455                 try
456                 {
457                     testExecutor(vkd, device, createInfo, log, ++testIndex, testCount);
458                     atLeastOnePassed |= true;
459                 }
460                 catch (vk::OutOfMemoryError &)
461                 {
462                     log << tcu::TestLog::Message << "Previous test case failed with OOM error."
463                         << tcu::TestLog::EndMessage;
464                     continue;
465                 }
466             }
467             else
468                 log << tcu::TestLog::Message << "Skipping test case " << ++testIndex << "/" << testCount
469                     << tcu::TestLog::EndMessage;
470         }
471 
472         if (!atLeastOnePassed)
473             TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory!");
474 
475         break;
476     }
477 
478     case TEST_DIMENSION_IMAGE_EXTENT:
479     {
480         static const vk::VkExtent2D s_testSizes[] = {
481             {1, 1}, {16, 32}, {32, 16}, {632, 231}, {117, 998},
482         };
483 
484         vk::VkPhysicalDeviceMemoryProperties memoryProperties =
485             vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
486         vk::VkDeviceSize protectedHeapSize = 0;
487 
488         for (uint32_t memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
489         {
490             uint32_t heapIndex = memoryProperties.memoryTypes[memType].heapIndex;
491 #ifndef NOT_PROTECTED
492             if (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT)
493 #endif
494             {
495                 protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
496             }
497         }
498 
499         bool atLeastOnePassed = false;
500         if (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
501             platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
502         {
503             uint32_t testCount = DE_LENGTH_OF_ARRAY(s_testSizes);
504             for (uint32_t ndx = 0; ndx < testCount; ++ndx)
505             {
506                 vk::VkMemoryRequirements memoryRequirements;
507                 {
508                     const vk::VkImageCreateInfo imageInfo = {vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
509                                                              DE_NULL,
510                                                              imageCreateFlag,
511                                                              vk::VK_IMAGE_TYPE_2D,
512                                                              baseParameters.imageFormat,
513                                                              {
514                                                                  s_testSizes[ndx].width,
515                                                                  s_testSizes[ndx].height,
516                                                                  1,
517                                                              },
518                                                              1, // mipLevels
519                                                              baseParameters.imageArrayLayers,
520                                                              vk::VK_SAMPLE_COUNT_1_BIT,
521                                                              vk::VK_IMAGE_TILING_OPTIMAL,
522                                                              baseParameters.imageUsage,
523                                                              baseParameters.imageSharingMode,
524                                                              baseParameters.queueFamilyIndexCount,
525                                                              baseParameters.pQueueFamilyIndices,
526                                                              vk::VK_IMAGE_LAYOUT_UNDEFINED};
527 
528                     vk::Move<vk::VkImage> image = vk::createImage(vki, device, &imageInfo);
529 
530                     memoryRequirements = vk::getImageMemoryRequirements(vki, device, *image);
531                 }
532 
533                 // Check for the image size requirement based on double/triple buffering
534                 if (memoryRequirements.size * capabilities.minImageCount < protectedHeapSize)
535                 {
536                     vk::VkSwapchainCreateInfoKHR createInfo = baseParameters;
537                     createInfo.imageExtent.width = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width,
538                                                              capabilities.maxImageExtent.width);
539                     createInfo.imageExtent.height =
540                         de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height,
541                                   capabilities.maxImageExtent.height);
542                     try
543                     {
544                         testExecutor(vkd, device, createInfo, log, ndx + 1u, testCount);
545                         atLeastOnePassed |= true;
546                     }
547                     catch (vk::OutOfMemoryError &)
548                     {
549                         log << tcu::TestLog::Message << "Previous test case failed with OOM error."
550                             << tcu::TestLog::EndMessage;
551                         continue;
552                     }
553                 }
554                 else
555                     log << tcu::TestLog::Message << "Skipping test case " << ndx + 1u << "/" << testCount
556                         << tcu::TestLog::EndMessage;
557             }
558         }
559 
560         if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
561         {
562             vk::VkMemoryRequirements memoryRequirements;
563             {
564                 const vk::VkImageCreateInfo imageInfo = {vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
565                                                          DE_NULL,
566                                                          imageCreateFlag,
567                                                          vk::VK_IMAGE_TYPE_2D,
568                                                          baseParameters.imageFormat,
569                                                          {
570                                                              capabilities.currentExtent.width,
571                                                              capabilities.currentExtent.height,
572                                                              1,
573                                                          },
574                                                          1, // mipLevels
575                                                          baseParameters.imageArrayLayers,
576                                                          vk::VK_SAMPLE_COUNT_1_BIT,
577                                                          vk::VK_IMAGE_TILING_OPTIMAL,
578                                                          baseParameters.imageUsage,
579                                                          baseParameters.imageSharingMode,
580                                                          baseParameters.queueFamilyIndexCount,
581                                                          baseParameters.pQueueFamilyIndices,
582                                                          vk::VK_IMAGE_LAYOUT_UNDEFINED};
583 
584                 vk::Move<vk::VkImage> image = vk::createImage(vki, device, &imageInfo);
585 
586                 memoryRequirements = vk::getImageMemoryRequirements(vki, device, *image);
587             }
588 
589             // Check for the image size requirement based on double/triple buffering
590             if (memoryRequirements.size * capabilities.minImageCount < protectedHeapSize)
591             {
592                 vk::VkSwapchainCreateInfoKHR createInfo = baseParameters;
593                 createInfo.imageExtent                  = capabilities.currentExtent;
594                 try
595                 {
596                     testExecutor(vkd, device, createInfo, log, 1u, 1u);
597                     atLeastOnePassed |= true;
598                 }
599                 catch (vk::OutOfMemoryError &)
600                 {
601                     log << tcu::TestLog::Message << "Previous test case failed with OOM error."
602                         << tcu::TestLog::EndMessage;
603                 }
604             }
605             else
606                 log << tcu::TestLog::Message << "Skipping test case " << 1u << "/" << 1u << tcu::TestLog::EndMessage;
607         }
608 
609         if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
610         {
611             static const vk::VkExtent2D s_testExtentSizes[] = {
612                 {capabilities.minImageExtent.width, capabilities.minImageExtent.height},
613                 {capabilities.maxImageExtent.width, capabilities.maxImageExtent.height},
614             };
615 
616             uint32_t testCount = DE_LENGTH_OF_ARRAY(s_testExtentSizes);
617             for (uint32_t ndx = 0; ndx < testCount; ++ndx)
618             {
619                 vk::VkMemoryRequirements memoryRequirements;
620                 {
621                     const vk::VkImageCreateInfo imageInfo = {vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
622                                                              DE_NULL,
623                                                              imageCreateFlag,
624                                                              vk::VK_IMAGE_TYPE_2D,
625                                                              baseParameters.imageFormat,
626                                                              {
627                                                                  s_testExtentSizes[ndx].width,
628                                                                  s_testExtentSizes[ndx].height,
629                                                                  1,
630                                                              },
631                                                              1, // mipLevels
632                                                              baseParameters.imageArrayLayers,
633                                                              vk::VK_SAMPLE_COUNT_1_BIT,
634                                                              vk::VK_IMAGE_TILING_OPTIMAL,
635                                                              baseParameters.imageUsage,
636                                                              baseParameters.imageSharingMode,
637                                                              baseParameters.queueFamilyIndexCount,
638                                                              baseParameters.pQueueFamilyIndices,
639                                                              vk::VK_IMAGE_LAYOUT_UNDEFINED};
640 
641                     vk::Move<vk::VkImage> image = vk::createImage(vki, device, &imageInfo);
642 
643                     memoryRequirements = vk::getImageMemoryRequirements(vki, device, *image);
644                 }
645 
646                 // Check for the image size requirement based on double/triple buffering
647                 if (memoryRequirements.size * capabilities.minImageCount < protectedHeapSize)
648                 {
649                     vk::VkSwapchainCreateInfoKHR createInfo = baseParameters;
650                     createInfo.imageExtent                  = s_testExtentSizes[ndx];
651                     try
652                     {
653                         testExecutor(vkd, device, createInfo, log, ndx + 1u, testCount);
654                         atLeastOnePassed |= true;
655                     }
656                     catch (vk::OutOfMemoryError &)
657                     {
658                         log << tcu::TestLog::Message << "Previous test case failed with OOM error."
659                             << tcu::TestLog::EndMessage;
660                         continue;
661                     }
662                 }
663                 else
664                     log << tcu::TestLog::Message << "Skipping test case " << ndx + 1u << "/" << testCount
665                         << tcu::TestLog::EndMessage;
666             }
667         }
668 
669         if (!atLeastOnePassed)
670             TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory!");
671 
672         break;
673     }
674 
675     case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
676     {
677         const uint32_t maxLayers = de::min(capabilities.maxImageArrayLayers, 16u);
678 
679         for (uint32_t numLayers = 1; numLayers <= maxLayers; ++numLayers)
680         {
681             vk::VkSwapchainCreateInfoKHR createInfo = baseParameters;
682             createInfo.imageArrayLayers             = numLayers;
683             testExecutor(vkd, device, createInfo, log, numLayers, maxLayers + 1u);
684         }
685 
686         break;
687     }
688 
689     case TEST_DIMENSION_IMAGE_USAGE:
690     {
691         const vk::InstanceDriver &instanceDriver  = context.getInstanceDriver();
692         const vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
693         std::vector<vk::VkSwapchainCreateInfoKHR> cases;
694 
695         for (uint32_t flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
696         {
697             if ((flags & ~capabilities.supportedUsageFlags) == 0)
698             {
699                 vk::VkImageFormatProperties imageProps;
700 
701                 // The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
702                 //
703                 //     * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
704                 //     VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
705                 if (instanceDriver.getPhysicalDeviceImageFormatProperties(
706                         physicalDevice, baseParameters.imageFormat, vk::VK_IMAGE_TYPE_2D, vk::VK_IMAGE_TILING_OPTIMAL,
707                         flags, (vk::VkImageCreateFlags)0u, &imageProps) != vk::VK_SUCCESS)
708                     continue;
709 
710                 cases.push_back(baseParameters);
711                 cases.back().imageUsage = flags;
712             }
713         }
714         for (uint32_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
715             testExecutor(vkd, device, cases[caseNdx], log, caseNdx + 1, (uint32_t)cases.size());
716 
717         break;
718     }
719 
720     case TEST_DIMENSION_IMAGE_SHARING_MODE:
721     {
722         vk::VkSwapchainCreateInfoKHR createInfo = baseParameters;
723         createInfo.imageSharingMode             = vk::VK_SHARING_MODE_EXCLUSIVE;
724         testExecutor(vkd, device, createInfo, log, 1u, 2u);
725 
726         uint32_t additionalQueueIndex = std::numeric_limits<uint32_t>::max();
727         {
728             const vk::InstanceDriver &instanceDriver  = context.getInstanceDriver();
729             const vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
730             std::vector<vk::VkQueueFamilyProperties> properties;
731             uint32_t numFamilies = 0;
732 
733             instanceDriver.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
734             DE_ASSERT(numFamilies > 0);
735             properties.resize(numFamilies);
736 
737             instanceDriver.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, properties.data());
738 
739             vk::VkQueueFlags requiredFlags = vk::VK_QUEUE_PROTECTED_BIT;
740             for (size_t idx = 0; idx < properties.size(); ++idx)
741             {
742                 vk::VkQueueFlags flags = properties[idx].queueFlags;
743 
744                 if ((flags & requiredFlags) == requiredFlags && idx != queueIdx)
745                 {
746                     additionalQueueIndex = static_cast<uint32_t>(idx);
747                     break;
748                 }
749             }
750         }
751 
752         // Can only test if we have multiple queues with required flags
753         if (additionalQueueIndex != std::numeric_limits<uint32_t>::max())
754         {
755             uint32_t queueIndices[2]         = {queueIdx, additionalQueueIndex};
756             createInfo.imageSharingMode      = vk::VK_SHARING_MODE_CONCURRENT;
757             createInfo.queueFamilyIndexCount = 2u;
758             createInfo.pQueueFamilyIndices   = queueIndices;
759             testExecutor(vkd, device, createInfo, log, 2u, 2u);
760         }
761         else
762             log << tcu::TestLog::Message
763                 << "No 2 queues with required flags (VK_QUEUE_PROTECTED_BIT) found. Skipping test case " << 2u << "/"
764                 << 2u << tcu::TestLog::EndMessage;
765 
766         break;
767     }
768 
769     case TEST_DIMENSION_PRE_TRANSFORM:
770     {
771         uint32_t testIndex = 0u;
772         uint32_t testCount = 0u;
773         for (uint32_t transform = 1u; transform <= capabilities.supportedTransforms; transform = transform << 1u)
774         {
775             if ((transform & capabilities.supportedTransforms) != 0)
776                 testCount++;
777         }
778 
779         for (uint32_t transform = 1u; transform <= capabilities.supportedTransforms; transform = transform << 1u)
780         {
781             if ((transform & capabilities.supportedTransforms) != 0)
782             {
783                 vk::VkSwapchainCreateInfoKHR createInfo = baseParameters;
784                 createInfo.preTransform                 = (vk::VkSurfaceTransformFlagBitsKHR)transform;
785                 testExecutor(vkd, device, createInfo, log, ++testIndex, testCount);
786             }
787         }
788 
789         break;
790     }
791 
792     case TEST_DIMENSION_COMPOSITE_ALPHA:
793     {
794         uint32_t testIndex = 0u;
795         uint32_t testCount = 0u;
796         for (uint32_t alphaMode = 1u; alphaMode <= capabilities.supportedCompositeAlpha; alphaMode = alphaMode << 1u)
797         {
798             if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
799                 testCount++;
800         }
801 
802         for (uint32_t alphaMode = 1u; alphaMode <= capabilities.supportedCompositeAlpha; alphaMode = alphaMode << 1u)
803         {
804             if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
805             {
806                 vk::VkSwapchainCreateInfoKHR createInfo = baseParameters;
807                 createInfo.compositeAlpha               = (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
808                 testExecutor(vkd, device, createInfo, log, ++testIndex, testCount);
809             }
810         }
811 
812         break;
813     }
814 
815     case TEST_DIMENSION_PRESENT_MODE:
816     {
817         uint32_t testIndex = 0u;
818         uint32_t testCount = static_cast<uint32_t>(presentModes.size());
819         for (std::vector<vk::VkPresentModeKHR>::const_iterator curMode = presentModes.begin();
820              curMode != presentModes.end(); ++curMode)
821         {
822             vk::VkSwapchainCreateInfoKHR createInfo = baseParameters;
823             if (*curMode == vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
824                 *curMode == vk::VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR)
825             {
826                 if (isExtensionForPresentModeEnabled)
827                     createInfo.minImageCount = 1u; // Required by VUID-VkSwapchainCreateInfoKHR-minImageCount-01383
828                 else
829                 {
830                     log << tcu::TestLog::Message << "Present mode (" << *curMode
831                         << ") not supported. Skipping test case " << ++testIndex << "/" << testCount
832                         << tcu::TestLog::EndMessage;
833                     continue;
834                 }
835             }
836             createInfo.presentMode = *curMode;
837             testExecutor(vkd, device, createInfo, log, ++testIndex, testCount);
838         }
839 
840         break;
841     }
842 
843     case TEST_DIMENSION_CLIPPED:
844     {
845         vk::VkSwapchainCreateInfoKHR createInfo = baseParameters;
846         createInfo.clipped                      = VK_FALSE;
847         testExecutor(vkd, device, createInfo, log, 1u, 2u);
848 
849         createInfo.clipped = VK_TRUE;
850         testExecutor(vkd, device, createInfo, log, 2u, 2u);
851 
852         break;
853     }
854 
855     default:
856         DE_FATAL("Impossible");
857     }
858 
859     return tcu::TestStatus::pass("Creating swapchain succeeded");
860 }
861 
executeSwapchainParameterCases(vk::wsi::Type wsiType,TestDimension dimension,const ProtectedContext & context,vk::VkSurfaceKHR surface,bool isExtensionForPresentModeEnabled,SwapchainCreationExecutor testExecutor)862 tcu::TestStatus executeSwapchainParameterCases(vk::wsi::Type wsiType, TestDimension dimension,
863                                                const ProtectedContext &context, vk::VkSurfaceKHR surface,
864                                                bool isExtensionForPresentModeEnabled,
865                                                SwapchainCreationExecutor testExecutor)
866 {
867     const vk::InstanceInterface &vki    = context.getInstanceDriver();
868     vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
869     const vk::VkSurfaceCapabilitiesKHR capabilities =
870         vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki, physicalDevice, surface);
871     const std::vector<vk::VkSurfaceFormatKHR> formats =
872         vk::wsi::getPhysicalDeviceSurfaceFormats(vki, physicalDevice, surface);
873     const std::vector<vk::VkPresentModeKHR> presentModes =
874         vk::wsi::getPhysicalDeviceSurfacePresentModes(vki, physicalDevice, surface);
875 
876     return executeSwapchainParameterCases(wsiType, dimension, context, capabilities, formats, presentModes,
877                                           isExtensionForPresentModeEnabled, testExecutor);
878 }
879 
createSwapchainTest(Context & baseCtx,TestParameters params)880 tcu::TestStatus createSwapchainTest(Context &baseCtx, TestParameters params)
881 {
882     bool isExtensionForPresentModeEnabled = false;
883     std::vector<vk::VkExtensionProperties> supportedExtensions(
884         enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
885     std::vector<std::string> instExts = getRequiredWsiExtensions(supportedExtensions, params.wsiType);
886     std::vector<std::string> devExts;
887     devExts.push_back("VK_KHR_swapchain");
888 
889     // Try to enable VK_KHR_shared_presentable_image for its respective present mode testing
890     if (params.dimension == TEST_DIMENSION_PRESENT_MODE)
891     {
892         Extensions deviceExtensions = vk::enumerateDeviceExtensionProperties(baseCtx.getInstanceInterface(),
893                                                                              baseCtx.getPhysicalDevice(), DE_NULL);
894         for (size_t i = 0u; i < deviceExtensions.size(); ++i)
895         {
896             if (std::strcmp(deviceExtensions[i].extensionName, "VK_KHR_shared_presentable_image") == 0)
897             {
898                 devExts.emplace_back("VK_KHR_shared_presentable_image");
899                 isExtensionForPresentModeEnabled = true;
900                 break;
901             }
902         }
903     }
904 
905     const NativeObjects native(baseCtx, supportedExtensions, params.wsiType);
906     ProtectedContext context(baseCtx, params.wsiType, *native.display, *native.window, instExts, devExts);
907     vk::VkSurfaceKHR surface = context.getSurface();
908 
909     if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension("VK_KHR_surface_protected_capabilities")))
910     {
911         // Check if swapchain can be created for protected surface
912         const vk::InstanceInterface &vki = context.getInstanceDriver();
913         vk::VkSurfaceCapabilities2KHR extCapabilities;
914         vk::VkSurfaceProtectedCapabilitiesKHR extProtectedCapabilities;
915         const vk::VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo = {
916             vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, DE_NULL, surface};
917 
918         extProtectedCapabilities.sType             = vk::VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR;
919         extProtectedCapabilities.pNext             = DE_NULL;
920         extProtectedCapabilities.supportsProtected = false;
921 
922         extCapabilities.sType = vk::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
923         extCapabilities.pNext = &extProtectedCapabilities;
924 
925         VK_CHECK(
926             vki.getPhysicalDeviceSurfaceCapabilities2KHR(context.getPhysicalDevice(), &surfaceInfo, &extCapabilities));
927 
928         if (extProtectedCapabilities.supportsProtected == false)
929             TCU_THROW(NotSupportedError, "Swapchain creation for Protected VkSurface is not Supported.");
930     }
931 
932     return executeSwapchainParameterCases(params.wsiType, params.dimension, context, surface,
933                                           isExtensionForPresentModeEnabled, swapchainCreateExecutor);
934 }
935 
936 struct GroupParameters
937 {
938     typedef FunctionInstance1<TestParameters>::Function Function;
939 
940     vk::wsi::Type wsiType;
941     Function function;
942 
GroupParametersvkt::ProtectedMem::__anon98a108480111::GroupParameters943     GroupParameters(vk::wsi::Type wsiType_, Function function_) : wsiType(wsiType_), function(function_)
944     {
945     }
946 
GroupParametersvkt::ProtectedMem::__anon98a108480111::GroupParameters947     GroupParameters(void) : wsiType(vk::wsi::TYPE_LAST), function((Function)DE_NULL)
948     {
949     }
950 };
951 
checkSupport(Context & context,TestParameters)952 void checkSupport(Context &context, TestParameters)
953 {
954     checkProtectedQueueSupport(context);
955 }
956 
populateSwapchainGroup(tcu::TestCaseGroup * testGroup,GroupParameters params)957 void populateSwapchainGroup(tcu::TestCaseGroup *testGroup, GroupParameters params)
958 {
959     for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
960     {
961         const TestDimension testDimension = (TestDimension)dimensionNdx;
962 
963         addFunctionCase(testGroup, getTestDimensionName(testDimension), checkSupport, params.function,
964                         TestParameters(params.wsiType, testDimension));
965     }
966 }
967 
getBasicSwapchainParameters(vk::wsi::Type wsiType,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface,const tcu::UVec2 & desiredSize,uint32_t desiredImageCount)968 vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters(vk::wsi::Type wsiType, const vk::InstanceInterface &vki,
969                                                          vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface,
970                                                          const tcu::UVec2 &desiredSize, uint32_t desiredImageCount)
971 {
972     const vk::VkSurfaceCapabilitiesKHR capabilities =
973         vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki, physicalDevice, surface);
974     const std::vector<vk::VkSurfaceFormatKHR> formats =
975         vk::wsi::getPhysicalDeviceSurfaceFormats(vki, physicalDevice, surface);
976     const vk::wsi::PlatformProperties &platformProperties = vk::wsi::getPlatformProperties(wsiType);
977     const vk::VkSurfaceTransformFlagBitsKHR transform =
978         (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
979             vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
980             capabilities.currentTransform;
981     const vk::VkSwapchainCreateInfoKHR parameters = {
982         vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
983         DE_NULL,
984         vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
985         surface,
986         de::clamp(desiredImageCount, capabilities.minImageCount,
987                   capabilities.maxImageCount > 0 ? capabilities.maxImageCount :
988                                                    capabilities.minImageCount + desiredImageCount),
989         formats[0].format,
990         formats[0].colorSpace,
991         (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ?
992              capabilities.currentExtent :
993              vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
994         1u, // imageArrayLayers
995         vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
996         vk::VK_SHARING_MODE_EXCLUSIVE,
997         0u,
998         (const uint32_t *)DE_NULL,
999         transform,
1000         firstSupportedCompositeAlpha(capabilities),
1001         vk::VK_PRESENT_MODE_FIFO_KHR,
1002         VK_FALSE,             // clipped
1003         (vk::VkSwapchainKHR)0 // oldSwapchain
1004     };
1005 
1006     return parameters;
1007 }
1008 
1009 typedef de::SharedPtr<vk::Unique<vk::VkImageView>> ImageViewSp;
1010 typedef de::SharedPtr<vk::Unique<vk::VkFramebuffer>> FramebufferSp;
1011 
1012 class TriangleRenderer
1013 {
1014 public:
1015     TriangleRenderer(ProtectedContext &context, const vk::BinaryCollection &binaryRegistry,
1016                      const std::vector<vk::VkImage> swapchainImages, const vk::VkFormat framebufferFormat,
1017                      const tcu::UVec2 &renderSize);
1018     ~TriangleRenderer(void);
1019 
1020     void recordFrame(vk::VkCommandBuffer cmdBuffer, uint32_t imageNdx, uint32_t frameNdx) const;
1021 
1022     static void getPrograms(vk::SourceCollections &dst);
1023 
1024 private:
1025     static vk::Move<vk::VkRenderPass> createRenderPass(const vk::DeviceInterface &vkd, const vk::VkDevice device,
1026                                                        const vk::VkFormat colorAttachmentFormat);
1027     static vk::Move<vk::VkPipelineLayout> createPipelineLayout(const vk::DeviceInterface &vkd, vk::VkDevice device);
1028     static vk::Move<vk::VkPipeline> createPipeline(const vk::DeviceInterface &vkd, const vk::VkDevice device,
1029                                                    const vk::VkRenderPass renderPass,
1030                                                    const vk::VkPipelineLayout pipelineLayout,
1031                                                    const vk::BinaryCollection &binaryCollection,
1032                                                    const tcu::UVec2 &renderSize);
1033 
1034     const vk::DeviceInterface &m_vkd;
1035 
1036     const std::vector<vk::VkImage> m_swapchainImages;
1037     const tcu::UVec2 m_renderSize;
1038 
1039     const vk::Unique<vk::VkRenderPass> m_renderPass;
1040     const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
1041     const vk::Unique<vk::VkPipeline> m_pipeline;
1042 
1043     const de::UniquePtr<vk::BufferWithMemory> m_vertexBuffer;
1044 
1045     std::vector<ImageViewSp> m_attachmentViews;
1046     std::vector<FramebufferSp> m_framebuffers;
1047 };
1048 
createRenderPass(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkFormat colorAttachmentFormat)1049 vk::Move<vk::VkRenderPass> TriangleRenderer::createRenderPass(const vk::DeviceInterface &vkd, const vk::VkDevice device,
1050                                                               const vk::VkFormat colorAttachmentFormat)
1051 {
1052     const vk::VkAttachmentDescription colorAttDesc = {
1053         (vk::VkAttachmentDescriptionFlags)0,
1054         colorAttachmentFormat,
1055         vk::VK_SAMPLE_COUNT_1_BIT,
1056         vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
1057         vk::VK_ATTACHMENT_STORE_OP_STORE,
1058         vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1059         vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
1060         vk::VK_IMAGE_LAYOUT_UNDEFINED,
1061         vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
1062     };
1063     const vk::VkAttachmentReference colorAttRef = {
1064         0u,
1065         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1066     };
1067     const vk::VkSubpassDescription subpassDesc = {
1068         (vk::VkSubpassDescriptionFlags)0u,
1069         vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
1070         0u,           // inputAttachmentCount
1071         DE_NULL,      // pInputAttachments
1072         1u,           // colorAttachmentCount
1073         &colorAttRef, // pColorAttachments
1074         DE_NULL,      // pResolveAttachments
1075         DE_NULL,      // depthStencilAttachment
1076         0u,           // preserveAttachmentCount
1077         DE_NULL,      // pPreserveAttachments
1078     };
1079     const vk::VkSubpassDependency dependencies[] = {
1080         {VK_SUBPASS_EXTERNAL, // srcSubpass
1081          0u,                  // dstSubpass
1082          vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1083          vk::VK_ACCESS_MEMORY_READ_BIT,
1084          (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
1085          vk::VK_DEPENDENCY_BY_REGION_BIT},
1086         {0u,                  // srcSubpass
1087          VK_SUBPASS_EXTERNAL, // dstSubpass
1088          vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1089          (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
1090          vk::VK_ACCESS_MEMORY_READ_BIT, vk::VK_DEPENDENCY_BY_REGION_BIT},
1091     };
1092     const vk::VkRenderPassCreateInfo renderPassParams = {
1093         vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
1094         DE_NULL,
1095         (vk::VkRenderPassCreateFlags)0,
1096         1u,
1097         &colorAttDesc,
1098         1u,
1099         &subpassDesc,
1100         DE_LENGTH_OF_ARRAY(dependencies),
1101         dependencies,
1102     };
1103 
1104     return vk::createRenderPass(vkd, device, &renderPassParams);
1105 }
1106 
createPipelineLayout(const vk::DeviceInterface & vkd,const vk::VkDevice device)1107 vk::Move<vk::VkPipelineLayout> TriangleRenderer::createPipelineLayout(const vk::DeviceInterface &vkd,
1108                                                                       const vk::VkDevice device)
1109 {
1110     const vk::VkPushConstantRange pushConstantRange = {
1111         vk::VK_SHADER_STAGE_VERTEX_BIT,
1112         0u,                         // offset
1113         (uint32_t)sizeof(uint32_t), // size
1114     };
1115     const vk::VkPipelineLayoutCreateInfo pipelineLayoutParams = {
1116         vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1117         DE_NULL,
1118         (vk::VkPipelineLayoutCreateFlags)0,
1119         0u,      // setLayoutCount
1120         DE_NULL, // pSetLayouts
1121         1u,
1122         &pushConstantRange,
1123     };
1124 
1125     return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
1126 }
1127 
createPipeline(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkRenderPass renderPass,const vk::VkPipelineLayout pipelineLayout,const vk::BinaryCollection & binaryCollection,const tcu::UVec2 & renderSize)1128 vk::Move<vk::VkPipeline> TriangleRenderer::createPipeline(const vk::DeviceInterface &vkd, const vk::VkDevice device,
1129                                                           const vk::VkRenderPass renderPass,
1130                                                           const vk::VkPipelineLayout pipelineLayout,
1131                                                           const vk::BinaryCollection &binaryCollection,
1132                                                           const tcu::UVec2 &renderSize)
1133 {
1134     // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
1135     //         and can be deleted immediately following that call.
1136     const vk::Unique<vk::VkShaderModule> vertShaderModule(
1137         createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
1138     const vk::Unique<vk::VkShaderModule> fragShaderModule(
1139         createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
1140     const std::vector<vk::VkViewport> viewports(1, vk::makeViewport(renderSize));
1141     const std::vector<vk::VkRect2D> scissors(1, vk::makeRect2D(renderSize));
1142 
1143     return vk::makeGraphicsPipeline(vkd,               // const DeviceInterface&            vk
1144                                     device,            // const VkDevice                    device
1145                                     pipelineLayout,    // const VkPipelineLayout            pipelineLayout
1146                                     *vertShaderModule, // const VkShaderModule              vertexShaderModule
1147                                     DE_NULL, // const VkShaderModule              tessellationControlShaderModule
1148                                     DE_NULL, // const VkShaderModule              tessellationEvalShaderModule
1149                                     DE_NULL, // const VkShaderModule              geometryShaderModule
1150                                     *fragShaderModule, // const VkShaderModule              fragmentShaderModule
1151                                     renderPass,        // const VkRenderPass                renderPass
1152                                     viewports,         // const std::vector<VkViewport>&    viewports
1153                                     scissors);         // const std::vector<VkRect2D>&      scissors
1154 }
1155 
TriangleRenderer(ProtectedContext & context,const vk::BinaryCollection & binaryRegistry,const std::vector<vk::VkImage> swapchainImages,const vk::VkFormat framebufferFormat,const tcu::UVec2 & renderSize)1156 TriangleRenderer::TriangleRenderer(ProtectedContext &context, const vk::BinaryCollection &binaryRegistry,
1157                                    const std::vector<vk::VkImage> swapchainImages, const vk::VkFormat framebufferFormat,
1158                                    const tcu::UVec2 &renderSize)
1159     : m_vkd(context.getDeviceInterface())
1160     , m_swapchainImages(swapchainImages)
1161     , m_renderSize(renderSize)
1162     , m_renderPass(createRenderPass(m_vkd, context.getDevice(), framebufferFormat))
1163     , m_pipelineLayout(createPipelineLayout(m_vkd, context.getDevice()))
1164     , m_pipeline(
1165           createPipeline(m_vkd, context.getDevice(), *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
1166     , m_vertexBuffer(makeBuffer(context, PROTECTION_DISABLED, context.getQueueFamilyIndex(),
1167                                 (uint32_t)(sizeof(float) * 4 * 3), vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
1168                                 vk::MemoryRequirement::HostVisible))
1169 {
1170     m_attachmentViews.resize(swapchainImages.size());
1171     m_framebuffers.resize(swapchainImages.size());
1172 
1173     for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
1174     {
1175         m_attachmentViews[imageNdx] = ImageViewSp(
1176             new vk::Unique<vk::VkImageView>(createImageView(context, swapchainImages[imageNdx], framebufferFormat)));
1177         m_framebuffers[imageNdx] = FramebufferSp(new vk::Unique<vk::VkFramebuffer>(
1178             createFramebuffer(context, renderSize.x(), renderSize.y(), *m_renderPass, **m_attachmentViews[imageNdx])));
1179     }
1180 
1181     // Upload vertex data
1182     {
1183         const tcu::Vec4 vertices[] = {tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f), tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
1184                                       tcu::Vec4(0.0f, +0.5f, 0.0f, 1.0f)};
1185         DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float) * 4 * 3);
1186 
1187         deMemcpy(m_vertexBuffer->getAllocation().getHostPtr(), &vertices[0], sizeof(vertices));
1188         flushAlloc(m_vkd, context.getDevice(), m_vertexBuffer->getAllocation());
1189     }
1190 }
1191 
~TriangleRenderer(void)1192 TriangleRenderer::~TriangleRenderer(void)
1193 {
1194 }
1195 
recordFrame(vk::VkCommandBuffer cmdBuffer,uint32_t imageNdx,uint32_t frameNdx) const1196 void TriangleRenderer::recordFrame(vk::VkCommandBuffer cmdBuffer, uint32_t imageNdx, uint32_t frameNdx) const
1197 {
1198     const vk::VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
1199 
1200     beginCommandBuffer(m_vkd, cmdBuffer, 0u);
1201 
1202     beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer,
1203                     vk::makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
1204     m_vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1205 
1206     {
1207         const vk::VkDeviceSize bindingOffset = 0;
1208         m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer->get(), &bindingOffset);
1209     }
1210 
1211     m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (uint32_t)sizeof(uint32_t),
1212                            &frameNdx);
1213     m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1214     endRenderPass(m_vkd, cmdBuffer);
1215 
1216     endCommandBuffer(m_vkd, cmdBuffer);
1217 }
1218 
getPrograms(vk::SourceCollections & dst)1219 void TriangleRenderer::getPrograms(vk::SourceCollections &dst)
1220 {
1221     dst.glslSources.add("tri-vert") << glu::VertexSource("#version 310 es\n"
1222                                                          "layout(location = 0) in highp vec4 a_position;\n"
1223                                                          "layout(push_constant) uniform FrameData\n"
1224                                                          "{\n"
1225                                                          "    highp uint frameNdx;\n"
1226                                                          "} frameData;\n"
1227                                                          "void main (void)\n"
1228                                                          "{\n"
1229                                                          "    highp float angle = float(frameData.frameNdx) / 100.0;\n"
1230                                                          "    highp float c     = cos(angle);\n"
1231                                                          "    highp float s     = sin(angle);\n"
1232                                                          "    highp mat4  t     = mat4( c, -s,  0,  0,\n"
1233                                                          "                              s,  c,  0,  0,\n"
1234                                                          "                              0,  0,  1,  0,\n"
1235                                                          "                              0,  0,  0,  1);\n"
1236                                                          "    gl_Position = t * a_position;\n"
1237                                                          "}\n");
1238     dst.glslSources.add("tri-frag") << glu::FragmentSource(
1239         "#version 310 es\n"
1240         "layout(location = 0) out lowp vec4 o_color;\n"
1241         "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1242 }
1243 
1244 typedef de::SharedPtr<vk::Unique<vk::VkCommandBuffer>> CommandBufferSp;
1245 typedef de::SharedPtr<vk::Unique<vk::VkFence>> FenceSp;
1246 typedef de::SharedPtr<vk::Unique<vk::VkSemaphore>> SemaphoreSp;
1247 
createFences(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numFences)1248 std::vector<FenceSp> createFences(const vk::DeviceInterface &vkd, const vk::VkDevice device, size_t numFences)
1249 {
1250     std::vector<FenceSp> fences(numFences);
1251 
1252     for (size_t ndx = 0; ndx < numFences; ++ndx)
1253         fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device)));
1254 
1255     return fences;
1256 }
1257 
createSemaphores(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numSemaphores)1258 std::vector<SemaphoreSp> createSemaphores(const vk::DeviceInterface &vkd, const vk::VkDevice device,
1259                                           size_t numSemaphores)
1260 {
1261     std::vector<SemaphoreSp> semaphores(numSemaphores);
1262 
1263     for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1264         semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
1265 
1266     return semaphores;
1267 }
1268 
allocateCommandBuffers(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkCommandPool commandPool,const vk::VkCommandBufferLevel level,const size_t numCommandBuffers)1269 std::vector<CommandBufferSp> allocateCommandBuffers(const vk::DeviceInterface &vkd, const vk::VkDevice device,
1270                                                     const vk::VkCommandPool commandPool,
1271                                                     const vk::VkCommandBufferLevel level,
1272                                                     const size_t numCommandBuffers)
1273 {
1274     std::vector<CommandBufferSp> buffers(numCommandBuffers);
1275 
1276     for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1277         buffers[ndx] = CommandBufferSp(
1278             new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1279 
1280     return buffers;
1281 }
1282 
basicRenderTest(Context & baseCtx,vk::wsi::Type wsiType)1283 tcu::TestStatus basicRenderTest(Context &baseCtx, vk::wsi::Type wsiType)
1284 {
1285     std::vector<vk::VkExtensionProperties> supportedExtensions(
1286         enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
1287     std::vector<std::string> instExts = getRequiredWsiExtensions(supportedExtensions, wsiType);
1288     std::vector<std::string> devExts;
1289     devExts.push_back("VK_KHR_swapchain");
1290 
1291     const tcu::UVec2 desiredSize(256, 256);
1292     const NativeObjects native(baseCtx, supportedExtensions, wsiType, tcu::just(desiredSize));
1293     ProtectedContext context(baseCtx, wsiType, *native.display, *native.window, instExts, devExts);
1294     vk::VkSurfaceKHR surface       = context.getSurface();
1295     const vk::DeviceInterface &vkd = context.getDeviceInterface();
1296     const vk::VkDevice device      = context.getDevice();
1297 
1298     if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension("VK_KHR_surface_protected_capabilities")))
1299     {
1300         // Check if swapchain can be created for protected surface
1301         const vk::InstanceInterface &vki = context.getInstanceDriver();
1302         vk::VkSurfaceCapabilities2KHR extCapabilities;
1303         vk::VkSurfaceProtectedCapabilitiesKHR extProtectedCapabilities;
1304         const vk::VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo = {
1305             vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, DE_NULL, surface};
1306 
1307         extProtectedCapabilities.sType             = vk::VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR;
1308         extProtectedCapabilities.pNext             = DE_NULL;
1309         extProtectedCapabilities.supportsProtected = false;
1310 
1311         extCapabilities.sType = vk::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
1312         extCapabilities.pNext = &extProtectedCapabilities;
1313 
1314         VK_CHECK(
1315             vki.getPhysicalDeviceSurfaceCapabilities2KHR(context.getPhysicalDevice(), &surfaceInfo, &extCapabilities));
1316 
1317         if (extProtectedCapabilities.supportsProtected == false)
1318             TCU_THROW(NotSupportedError, "Swapchain creation for Protected VkSurface is not Supported.");
1319     }
1320 
1321     const vk::VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(
1322         wsiType, context.getInstanceDriver(), context.getPhysicalDevice(), surface, desiredSize, 2);
1323     const vk::Unique<vk::VkSwapchainKHR> swapchain(createSwapchainKHR(vkd, device, &swapchainInfo));
1324     const std::vector<vk::VkImage> swapchainImages = vk::wsi::getSwapchainImages(vkd, device, *swapchain);
1325 
1326     const TriangleRenderer renderer(context, context.getBinaryCollection(), swapchainImages, swapchainInfo.imageFormat,
1327                                     tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1328 
1329     const vk::Unique<vk::VkCommandPool> commandPool(
1330         makeCommandPool(vkd, device, PROTECTION_ENABLED, context.getQueueFamilyIndex()));
1331 
1332     const size_t maxQueuedFrames = swapchainImages.size() * 2;
1333 
1334     // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1335     // limit number of frames we allow to be queued.
1336     const std::vector<FenceSp> imageReadyFences(createFences(vkd, device, maxQueuedFrames));
1337 
1338     // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1339     // the semaphore in same time as the fence we use to meter rendering.
1340     const std::vector<SemaphoreSp> imageReadySemaphores(createSemaphores(vkd, device, maxQueuedFrames + 1));
1341 
1342     // For rest we simply need maxQueuedFrames as we will wait for image
1343     // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1344     // previous uses must have completed.
1345     const std::vector<SemaphoreSp> renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames));
1346     const std::vector<CommandBufferSp> commandBuffers(
1347         allocateCommandBuffers(vkd, device, *commandPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1348 
1349     try
1350     {
1351         const uint32_t numFramesToRender = 60 * 10;
1352 
1353         for (uint32_t frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1354         {
1355             const vk::VkFence imageReadyFence         = **imageReadyFences[frameNdx % imageReadyFences.size()];
1356             const vk::VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx % imageReadySemaphores.size()];
1357             uint32_t imageNdx                         = ~0u;
1358 
1359             if (frameNdx >= maxQueuedFrames)
1360                 VK_CHECK(
1361                     vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<uint64_t>::max()));
1362 
1363             VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1364 
1365             {
1366                 const vk::VkResult acquireResult = vkd.acquireNextImageKHR(
1367                     device, *swapchain, std::numeric_limits<uint64_t>::max(), imageReadySemaphore, 0, &imageNdx);
1368 
1369                 if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
1370                     context.getTestContext().getLog() << tcu::TestLog::Message << "Got " << acquireResult
1371                                                       << " at frame " << frameNdx << tcu::TestLog::EndMessage;
1372                 else
1373                     VK_CHECK(acquireResult);
1374             }
1375 
1376             TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1377 
1378             {
1379                 const vk::VkSemaphore renderingCompleteSemaphore =
1380                     **renderingCompleteSemaphores[frameNdx % renderingCompleteSemaphores.size()];
1381                 const vk::VkCommandBuffer commandBuffer     = **commandBuffers[frameNdx % commandBuffers.size()];
1382                 const vk::VkPipelineStageFlags waitDstStage = vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1383                 vk::VkSubmitInfo submitInfo                 = {vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1384                                                                DE_NULL,
1385                                                                1u,
1386                                                                &imageReadySemaphore,
1387                                                                &waitDstStage,
1388                                                                1u,
1389                                                                &commandBuffer,
1390                                                                1u,
1391                                                                &renderingCompleteSemaphore};
1392 
1393                 const vk::VkProtectedSubmitInfo protectedInfo = {
1394                     vk::VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO, // sType
1395                     DE_NULL,                                     // pNext
1396                     VK_TRUE,                                     // protectedSubmit
1397                 };
1398                 submitInfo.pNext = &protectedInfo;
1399 
1400                 const vk::VkPresentInfoKHR presentInfo = {vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1401                                                           DE_NULL,
1402                                                           1u,
1403                                                           &renderingCompleteSemaphore,
1404                                                           1u,
1405                                                           &*swapchain,
1406                                                           &imageNdx,
1407                                                           (vk::VkResult *)DE_NULL};
1408 
1409                 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1410                 VK_CHECK(vkd.queueSubmit(context.getQueue(), 1u, &submitInfo, imageReadyFence));
1411                 VK_CHECK_WSI(vkd.queuePresentKHR(context.getQueue(), &presentInfo));
1412             }
1413         }
1414 
1415         VK_CHECK(vkd.deviceWaitIdle(device));
1416     }
1417     catch (...)
1418     {
1419         // Make sure device is idle before destroying resources
1420         vkd.deviceWaitIdle(device);
1421         throw;
1422     }
1423 
1424     return tcu::TestStatus::pass("Rendering tests succeeded");
1425 }
1426 
getBasicRenderPrograms(vk::SourceCollections & dst,vk::wsi::Type)1427 void getBasicRenderPrograms(vk::SourceCollections &dst, vk::wsi::Type)
1428 {
1429     TriangleRenderer::getPrograms(dst);
1430 }
1431 
checkSupport(Context & context,vk::wsi::Type)1432 void checkSupport(Context &context, vk::wsi::Type)
1433 {
1434     checkProtectedQueueSupport(context);
1435 }
1436 
populateRenderGroup(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1437 void populateRenderGroup(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
1438 {
1439     addFunctionCaseWithPrograms(testGroup, "basic", checkSupport, getBasicRenderPrograms, basicRenderTest, wsiType);
1440 }
1441 
createSwapchainTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1442 void createSwapchainTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
1443 {
1444     // Create VkSwapchain with various parameters
1445     addTestGroup(testGroup, "create", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
1446     // Rendering Tests
1447     addTestGroup(testGroup, "render", populateRenderGroup, wsiType);
1448 }
1449 
createTypeSpecificTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1450 void createTypeSpecificTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
1451 {
1452     // VkSwapchain Tests
1453     addTestGroup(testGroup, "swapchain", createSwapchainTests, wsiType);
1454 }
1455 
1456 } // namespace
1457 
createSwapchainTests(tcu::TestContext & testCtx)1458 tcu::TestCaseGroup *createSwapchainTests(tcu::TestContext &testCtx)
1459 {
1460     // WSI Tests
1461     de::MovePtr<tcu::TestCaseGroup> wsiTestGroup(new tcu::TestCaseGroup(testCtx, "wsi"));
1462 
1463     for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
1464     {
1465         const vk::wsi::Type wsiType = (vk::wsi::Type)typeNdx;
1466 
1467         addTestGroup(&*wsiTestGroup, getName(wsiType), createTypeSpecificTests, wsiType);
1468     }
1469 
1470     return wsiTestGroup.release();
1471 }
1472 
1473 } // namespace ProtectedMem
1474 } // namespace vkt
1475