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