1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2017 The Khronos Group Inc.
6 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Protected memory interaction with VkSwapchain Tests
23 *//*--------------------------------------------------------------------*/
25 #include "vktProtectedMemWsiSwapchainTests.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
31 #include "vkPlatform.hpp"
32 #include "vkStrUtil.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"
46 #include "tcuTestLog.hpp"
47 #include "tcuFormatUtil.hpp"
48 #include "tcuPlatform.hpp"
49 #include "tcuResultCollector.hpp"
51 #include "deUniquePtr.hpp"
52 #include "deStringUtil.hpp"
53 #include "deArrayUtil.hpp"
54 #include "deSharedPtr.hpp"
58 #include "vktProtectedMemContext.hpp"
59 #include "vktProtectedMemUtils.hpp"
63 namespace ProtectedMem
69 typedef std::vector<vk::VkExtensionProperties> Extensions;
71 void checkAllSupported (const Extensions& supportedExtensions, const std::vector<std::string>& requiredExtensions)
73 for (std::vector<std::string>::const_iterator requiredExtName = requiredExtensions.begin();
74 requiredExtName != requiredExtensions.end();
77 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
78 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
82 std::vector<std::string> getRequiredWsiExtensions (const Extensions& supportedExtensions,
83 vk::wsi::Type wsiType)
85 std::vector<std::string> extensions;
87 extensions.push_back("VK_KHR_surface");
88 extensions.push_back(getExtensionName(wsiType));
90 // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
91 // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
92 // but using them without enabling the extension is not allowed. Thus we have
95 // 1) Filter out non-core formats to stay within valid usage.
97 // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
99 // We opt for (2) as it provides basic coverage for the extension as a bonus.
100 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension("VK_EXT_swapchain_colorspace")))
101 extensions.push_back("VK_EXT_swapchain_colorspace");
103 checkAllSupported(supportedExtensions, extensions);
108 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform& platform,
109 const Extensions& supportedExtensions,
110 vk::wsi::Type wsiType)
114 return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
116 catch (const tcu::NotSupportedError& e)
118 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))))
120 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
121 // must support creating native display & window for that WSI type.
122 throw tcu::TestError(e.getMessage());
129 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const tcu::Maybe<tcu::UVec2>& initialSize)
133 return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
135 catch (const tcu::NotSupportedError& e)
137 // See createDisplay - assuming that wsi::Display was supported platform port
138 // should also support creating a window.
139 throw tcu::TestError(e.getMessage());
145 const de::UniquePtr<vk::wsi::Display> display;
146 const de::UniquePtr<vk::wsi::Window> window;
148 NativeObjects (Context& context,
149 const Extensions& supportedExtensions,
150 vk::wsi::Type wsiType,
151 const tcu::Maybe<tcu::UVec2>& initialWindowSize = tcu::nothing<tcu::UVec2>())
152 : display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
153 , window (createWindow(*display, initialWindowSize))
159 TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
160 TEST_DIMENSION_IMAGE_FORMAT, //!< Test all supported formats
161 TEST_DIMENSION_IMAGE_EXTENT, //!< Test various (supported) extents
162 TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
163 TEST_DIMENSION_IMAGE_USAGE,
164 TEST_DIMENSION_IMAGE_SHARING_MODE,
165 TEST_DIMENSION_PRE_TRANSFORM,
166 TEST_DIMENSION_COMPOSITE_ALPHA,
167 TEST_DIMENSION_PRESENT_MODE,
168 TEST_DIMENSION_CLIPPED,
173 const char* getTestDimensionName (TestDimension dimension)
175 static const char* const s_names[] =
180 "image_array_layers",
182 "image_sharing_mode",
188 return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
191 struct TestParameters
193 vk::wsi::Type wsiType;
194 TestDimension dimension;
196 TestParameters (vk::wsi::Type wsiType_, TestDimension dimension_)
198 , dimension (dimension_)
201 TestParameters (void)
202 : wsiType (vk::wsi::TYPE_LAST)
203 , dimension (TEST_DIMENSION_LAST)
207 static vk::VkCompositeAlphaFlagBitsKHR firstSupportedCompositeAlpha(const vk::VkSurfaceCapabilitiesKHR& capabilities)
209 deUint32 alphaMode = 1u;
211 for (;alphaMode < capabilities.supportedCompositeAlpha; alphaMode = alphaMode<<1u)
213 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
219 return (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
222 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type wsiType,
223 TestDimension dimension,
224 const ProtectedContext& context,
225 const vk::VkSurfaceCapabilitiesKHR& capabilities,
226 const std::vector<vk::VkSurfaceFormatKHR>& formats,
227 const std::vector<vk::VkPresentModeKHR>& presentModes)
229 std::vector<vk::VkSwapchainCreateInfoKHR> cases;
230 const vk::wsi::PlatformProperties& platformProperties = getPlatformProperties(wsiType);
231 const vk::VkSurfaceTransformFlagBitsKHR defaultTransform = (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
232 ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
233 const vk::VkSwapchainCreateInfoKHR baseParameters =
235 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
237 vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
239 capabilities.minImageCount,
241 formats[0].colorSpace,
242 (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
243 ? capabilities.minImageExtent : capabilities.currentExtent),
244 1u, // imageArrayLayers
245 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
246 vk::VK_SHARING_MODE_EXCLUSIVE,
248 (const deUint32*)DE_NULL,
250 firstSupportedCompositeAlpha(capabilities),
251 vk::VK_PRESENT_MODE_FIFO_KHR,
253 (vk::VkSwapchainKHR)0 // oldSwapchain
258 case TEST_DIMENSION_MIN_IMAGE_COUNT:
260 // Estimate how much memory each swapchain image consumes. This isn't perfect, since
261 // swapchain images may have additional constraints that equivalent non-swapchain
262 // images don't have. But it's the best we can do.
263 const vk::DeviceInterface& vkd = context.getDeviceInterface();
264 vk::VkDevice device = context.getDevice();
265 vk::VkMemoryRequirements memoryRequirements;
267 const vk::VkImageCreateInfo imageInfo =
269 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
271 vk::VK_IMAGE_CREATE_PROTECTED_BIT,
272 vk::VK_IMAGE_TYPE_2D,
273 baseParameters.imageFormat,
275 baseParameters.imageExtent.width,
276 baseParameters.imageExtent.height,
280 baseParameters.imageArrayLayers,
281 vk::VK_SAMPLE_COUNT_1_BIT,
282 vk::VK_IMAGE_TILING_OPTIMAL,
283 baseParameters.imageUsage,
284 baseParameters.imageSharingMode,
285 baseParameters.queueFamilyIndexCount,
286 baseParameters.pQueueFamilyIndices,
287 vk::VK_IMAGE_LAYOUT_UNDEFINED
289 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
291 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
294 // Determine the maximum memory heap space available for protected images
295 vk::VkPhysicalDeviceMemoryProperties memoryProperties = vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
296 vk::VkDeviceSize protectedHeapSize = 0;
297 vk::VkDeviceSize maxMemoryUsage = 0;
298 deUint32 protectedHeapMask = 0;
300 for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
302 deUint32 heapIndex = memoryProperties.memoryTypes[memType].heapIndex;
303 if ((memoryRequirements.memoryTypeBits & (1u << memType)) != 0 &&
304 (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0 &&
305 (protectedHeapMask & (1u << heapIndex)) == 0)
307 protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
308 maxMemoryUsage = protectedHeapSize / 4 ; /* Use at maximum 25% of heap */
309 protectedHeapMask |= 1u << heapIndex;
313 // If the implementation doesn't have a max image count, min+16 means we won't clamp.
314 // Limit it to how many protected images we estimate can be allocated - 25% of heap size
315 const deUint32 maxImageCount = de::min((capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u,
316 deUint32(maxMemoryUsage / memoryRequirements.size));
317 if (maxImageCount < capabilities.minImageCount)
318 TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory!.");
320 const deUint32 maxImageCountToTest = de::clamp(16u, capabilities.minImageCount, maxImageCount);
321 for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
323 cases.push_back(baseParameters);
324 cases.back().minImageCount = imageCount;
330 case TEST_DIMENSION_IMAGE_FORMAT:
332 for (std::vector<vk::VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
334 cases.push_back(baseParameters);
335 cases.back().imageFormat = curFmt->format;
336 cases.back().imageColorSpace = curFmt->colorSpace;
342 case TEST_DIMENSION_IMAGE_EXTENT:
344 static const vk::VkExtent2D s_testSizes[] =
353 const vk::DeviceInterface& vkd = context.getDeviceInterface();
354 vk::VkDevice device = context.getDevice();
355 vk::VkPhysicalDeviceMemoryProperties memoryProperties = vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
356 vk::VkDeviceSize protectedHeapSize = 0;
357 vk::VkDeviceSize maxMemoryUsage = 0;
359 for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
361 deUint32 heapIndex = memoryProperties.memoryTypes[memType].heapIndex;
362 if (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT)
364 protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
365 maxMemoryUsage = protectedHeapSize / 4 ; /* Use at maximum 25% of heap */
369 if (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
370 platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
372 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
374 vk::VkMemoryRequirements memoryRequirements;
376 const vk::VkImageCreateInfo imageInfo =
378 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
380 vk::VK_IMAGE_CREATE_PROTECTED_BIT,
381 vk::VK_IMAGE_TYPE_2D,
382 baseParameters.imageFormat,
384 s_testSizes[ndx].width,
385 s_testSizes[ndx].height,
389 baseParameters.imageArrayLayers,
390 vk::VK_SAMPLE_COUNT_1_BIT,
391 vk::VK_IMAGE_TILING_OPTIMAL,
392 baseParameters.imageUsage,
393 baseParameters.imageSharingMode,
394 baseParameters.queueFamilyIndexCount,
395 baseParameters.pQueueFamilyIndices,
396 vk::VK_IMAGE_LAYOUT_UNDEFINED
399 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
401 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
404 // Check for the image size requirement based on double/triple buffering
405 if (memoryRequirements.size * capabilities.minImageCount < maxMemoryUsage)
407 cases.push_back(baseParameters);
408 cases.back().imageExtent.width = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
409 cases.back().imageExtent.height = de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
414 if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
416 vk::VkMemoryRequirements memoryRequirements;
418 const vk::VkImageCreateInfo imageInfo =
420 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
422 vk::VK_IMAGE_CREATE_PROTECTED_BIT,
423 vk::VK_IMAGE_TYPE_2D,
424 baseParameters.imageFormat,
426 capabilities.currentExtent.width,
427 capabilities.currentExtent.height,
431 baseParameters.imageArrayLayers,
432 vk::VK_SAMPLE_COUNT_1_BIT,
433 vk::VK_IMAGE_TILING_OPTIMAL,
434 baseParameters.imageUsage,
435 baseParameters.imageSharingMode,
436 baseParameters.queueFamilyIndexCount,
437 baseParameters.pQueueFamilyIndices,
438 vk::VK_IMAGE_LAYOUT_UNDEFINED
441 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
443 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
446 // Check for the image size requirement based on double/triple buffering
447 if (memoryRequirements.size * capabilities.minImageCount < maxMemoryUsage)
449 cases.push_back(baseParameters);
450 cases.back().imageExtent = capabilities.currentExtent;
454 if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
456 static const vk::VkExtent2D s_testExtentSizes[] =
458 { capabilities.minImageExtent.width, capabilities.minImageExtent.height },
459 { capabilities.maxImageExtent.width, capabilities.maxImageExtent.height },
462 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testExtentSizes); ++ndx)
464 vk::VkMemoryRequirements memoryRequirements;
466 const vk::VkImageCreateInfo imageInfo =
468 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
470 vk::VK_IMAGE_CREATE_PROTECTED_BIT,
471 vk::VK_IMAGE_TYPE_2D,
472 baseParameters.imageFormat,
474 s_testExtentSizes[ndx].width,
475 s_testExtentSizes[ndx].height,
479 baseParameters.imageArrayLayers,
480 vk::VK_SAMPLE_COUNT_1_BIT,
481 vk::VK_IMAGE_TILING_OPTIMAL,
482 baseParameters.imageUsage,
483 baseParameters.imageSharingMode,
484 baseParameters.queueFamilyIndexCount,
485 baseParameters.pQueueFamilyIndices,
486 vk::VK_IMAGE_LAYOUT_UNDEFINED
489 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &imageInfo);
491 memoryRequirements = vk::getImageMemoryRequirements(vkd, device, *image);
494 // Check for the image size requirement based on double/triple buffering
495 if (memoryRequirements.size * capabilities.minImageCount < maxMemoryUsage)
497 cases.push_back(baseParameters);
498 cases.back().imageExtent =s_testExtentSizes[ndx];
506 case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
508 const deUint32 maxLayers = de::min(capabilities.maxImageArrayLayers, 16u);
510 for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
512 cases.push_back(baseParameters);
513 cases.back().imageArrayLayers = numLayers;
519 case TEST_DIMENSION_IMAGE_USAGE:
521 for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
523 if ((flags & ~capabilities.supportedUsageFlags) == 0)
525 cases.push_back(baseParameters);
526 cases.back().imageUsage = flags;
533 case TEST_DIMENSION_IMAGE_SHARING_MODE:
535 cases.push_back(baseParameters);
536 cases.back().imageSharingMode = vk::VK_SHARING_MODE_EXCLUSIVE;
538 cases.push_back(baseParameters);
539 cases.back().imageSharingMode = vk::VK_SHARING_MODE_CONCURRENT;
544 case TEST_DIMENSION_PRE_TRANSFORM:
546 for (deUint32 transform = 1u;
547 transform <= capabilities.supportedTransforms;
548 transform = transform<<1u)
550 if ((transform & capabilities.supportedTransforms) != 0)
552 cases.push_back(baseParameters);
553 cases.back().preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
560 case TEST_DIMENSION_COMPOSITE_ALPHA:
562 for (deUint32 alphaMode = 1u;
563 alphaMode <= capabilities.supportedCompositeAlpha;
564 alphaMode = alphaMode<<1u)
566 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
568 cases.push_back(baseParameters);
569 cases.back().compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
576 case TEST_DIMENSION_PRESENT_MODE:
578 for (std::vector<vk::VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
580 cases.push_back(baseParameters);
581 cases.back().presentMode = *curMode;
587 case TEST_DIMENSION_CLIPPED:
589 cases.push_back(baseParameters);
590 cases.back().clipped = VK_FALSE;
592 cases.push_back(baseParameters);
593 cases.back().clipped = VK_TRUE;
599 DE_FATAL("Impossible");
602 DE_ASSERT(!cases.empty());
606 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type wsiType,
607 TestDimension dimension,
608 const ProtectedContext& context,
609 vk::VkSurfaceKHR surface)
611 const vk::InstanceInterface& vki = context.getInstanceDriver();
612 vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
613 const vk::VkSurfaceCapabilitiesKHR capabilities = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
616 const std::vector<vk::VkSurfaceFormatKHR> formats = vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
619 const std::vector<vk::VkPresentModeKHR> presentModes = vk::wsi::getPhysicalDeviceSurfacePresentModes(vki,
623 return generateSwapchainParameterCases(wsiType, dimension, context, capabilities, formats, presentModes);
626 tcu::TestStatus createSwapchainTest (Context& baseCtx, TestParameters params)
628 std::vector<vk::VkExtensionProperties> supportedExtensions (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
629 std::vector<std::string> instExts = getRequiredWsiExtensions(supportedExtensions, params.wsiType);
630 std::vector<std::string> devExts;
631 devExts.push_back("VK_KHR_swapchain");
633 const NativeObjects native (baseCtx, supportedExtensions, params.wsiType);
634 ProtectedContext context (baseCtx, params.wsiType, *native.display, *native.window, instExts, devExts);
635 vk::VkSurfaceKHR surface = context.getSurface();
636 const std::vector<vk::VkSwapchainCreateInfoKHR> cases (generateSwapchainParameterCases(params.wsiType,
640 deUint32 queueIdx = context.getQueueFamilyIndex();
641 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
643 vk::VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
645 curParams.surface = surface;
646 curParams.queueFamilyIndexCount = 1u;
647 curParams.pQueueFamilyIndices = &queueIdx;
649 context.getTestContext().getLog()
650 << tcu::TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": " << curParams << tcu::TestLog::EndMessage;
653 const vk::Unique<vk::VkSwapchainKHR> swapchain (createSwapchainKHR(context.getDeviceDriver(), context.getDevice(), &curParams));
657 return tcu::TestStatus::pass("Creating swapchain succeeded");
660 struct GroupParameters
662 typedef FunctionInstance1<TestParameters>::Function Function;
664 vk::wsi::Type wsiType;
667 GroupParameters (vk::wsi::Type wsiType_, Function function_)
669 , function (function_)
672 GroupParameters (void)
673 : wsiType (vk::wsi::TYPE_LAST)
674 , function ((Function)DE_NULL)
678 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
680 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
682 const TestDimension testDimension = (TestDimension)dimensionNdx;
684 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
688 vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters (vk::wsi::Type wsiType,
689 const vk::InstanceInterface& vki,
690 vk::VkPhysicalDevice physicalDevice,
691 vk::VkSurfaceKHR surface,
692 const tcu::UVec2& desiredSize,
693 deUint32 desiredImageCount)
695 const vk::VkSurfaceCapabilitiesKHR capabilities = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
698 const std::vector<vk::VkSurfaceFormatKHR> formats = vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
701 const vk::wsi::PlatformProperties& platformProperties = vk::wsi::getPlatformProperties(wsiType);
702 const vk::VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
703 ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
704 const vk::VkSwapchainCreateInfoKHR parameters =
706 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
708 vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
710 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
712 formats[0].colorSpace,
713 (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
714 ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
715 1u, // imageArrayLayers
716 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
717 vk::VK_SHARING_MODE_EXCLUSIVE,
719 (const deUint32*)DE_NULL,
721 firstSupportedCompositeAlpha(capabilities),
722 vk::VK_PRESENT_MODE_FIFO_KHR,
724 (vk::VkSwapchainKHR)0 // oldSwapchain
730 typedef de::SharedPtr<vk::Unique<vk::VkImageView> > ImageViewSp;
731 typedef de::SharedPtr<vk::Unique<vk::VkFramebuffer> > FramebufferSp;
733 class TriangleRenderer
736 TriangleRenderer (ProtectedContext& context,
737 const vk::BinaryCollection& binaryRegistry,
738 const std::vector<vk::VkImage> swapchainImages,
739 const vk::VkFormat framebufferFormat,
740 const tcu::UVec2& renderSize);
741 ~TriangleRenderer (void);
743 void recordFrame (vk::VkCommandBuffer cmdBuffer,
745 deUint32 frameNdx) const;
747 static void getPrograms (vk::SourceCollections& dst);
750 static vk::Move<vk::VkRenderPass> createRenderPass (const vk::DeviceInterface& vkd,
751 const vk::VkDevice device,
752 const vk::VkFormat colorAttachmentFormat);
753 static vk::Move<vk::VkPipelineLayout> createPipelineLayout(const vk::DeviceInterface& vkd,
754 vk::VkDevice device);
755 static vk::Move<vk::VkPipeline> createPipeline (const vk::DeviceInterface& vkd,
756 const vk::VkDevice device,
757 const vk::VkRenderPass renderPass,
758 const vk::VkPipelineLayout pipelineLayout,
759 const vk::BinaryCollection& binaryCollection,
760 const tcu::UVec2& renderSize);
762 const vk::DeviceInterface& m_vkd;
764 const std::vector<vk::VkImage> m_swapchainImages;
765 const tcu::UVec2 m_renderSize;
767 const vk::Unique<vk::VkRenderPass> m_renderPass;
768 const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
769 const vk::Unique<vk::VkPipeline> m_pipeline;
771 const de::UniquePtr<vk::BufferWithMemory> m_vertexBuffer;
773 std::vector<ImageViewSp> m_attachmentViews;
774 std::vector<FramebufferSp> m_framebuffers;
777 vk::Move<vk::VkRenderPass> TriangleRenderer::createRenderPass (const vk::DeviceInterface& vkd,
778 const vk::VkDevice device,
779 const vk::VkFormat colorAttachmentFormat)
781 const vk::VkAttachmentDescription colorAttDesc =
783 (vk::VkAttachmentDescriptionFlags)0,
784 colorAttachmentFormat,
785 vk::VK_SAMPLE_COUNT_1_BIT,
786 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
787 vk::VK_ATTACHMENT_STORE_OP_STORE,
788 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
789 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
790 vk::VK_IMAGE_LAYOUT_UNDEFINED,
791 vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
793 const vk::VkAttachmentReference colorAttRef =
796 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
798 const vk::VkSubpassDescription subpassDesc =
800 (vk::VkSubpassDescriptionFlags)0u,
801 vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
802 0u, // inputAttachmentCount
803 DE_NULL, // pInputAttachments
804 1u, // colorAttachmentCount
805 &colorAttRef, // pColorAttachments
806 DE_NULL, // pResolveAttachments
807 DE_NULL, // depthStencilAttachment
808 0u, // preserveAttachmentCount
809 DE_NULL, // pPreserveAttachments
811 const vk::VkSubpassDependency dependencies[] =
814 VK_SUBPASS_EXTERNAL, // srcSubpass
816 vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
817 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
818 vk::VK_ACCESS_MEMORY_READ_BIT,
819 (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
820 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
821 vk::VK_DEPENDENCY_BY_REGION_BIT
825 VK_SUBPASS_EXTERNAL, // dstSubpass
826 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
827 vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
828 (vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
829 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
830 vk::VK_ACCESS_MEMORY_READ_BIT,
831 vk::VK_DEPENDENCY_BY_REGION_BIT
834 const vk::VkRenderPassCreateInfo renderPassParams =
836 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
838 (vk::VkRenderPassCreateFlags)0,
843 DE_LENGTH_OF_ARRAY(dependencies),
847 return vk::createRenderPass(vkd, device, &renderPassParams);
850 vk::Move<vk::VkPipelineLayout> TriangleRenderer::createPipelineLayout (const vk::DeviceInterface& vkd,
851 const vk::VkDevice device)
853 const vk::VkPushConstantRange pushConstantRange =
855 vk::VK_SHADER_STAGE_VERTEX_BIT,
857 (deUint32)sizeof(deUint32), // size
859 const vk::VkPipelineLayoutCreateInfo pipelineLayoutParams =
861 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
863 (vk::VkPipelineLayoutCreateFlags)0,
864 0u, // setLayoutCount
865 DE_NULL, // pSetLayouts
870 return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
873 vk::Move<vk::VkPipeline> TriangleRenderer::createPipeline (const vk::DeviceInterface& vkd,
874 const vk::VkDevice device,
875 const vk::VkRenderPass renderPass,
876 const vk::VkPipelineLayout pipelineLayout,
877 const vk::BinaryCollection& binaryCollection,
878 const tcu::UVec2& renderSize)
880 // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
881 // and can be deleted immediately following that call.
882 const vk::Unique<vk::VkShaderModule> vertShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
883 const vk::Unique<vk::VkShaderModule> fragShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
884 const std::vector<vk::VkViewport> viewports (1, vk::makeViewport(renderSize));
885 const std::vector<vk::VkRect2D> scissors (1, vk::makeRect2D(renderSize));
887 return vk::makeGraphicsPipeline(vkd, // const DeviceInterface& vk
888 device, // const VkDevice device
889 pipelineLayout, // const VkPipelineLayout pipelineLayout
890 *vertShaderModule, // const VkShaderModule vertexShaderModule
891 DE_NULL, // const VkShaderModule tessellationControlShaderModule
892 DE_NULL, // const VkShaderModule tessellationEvalShaderModule
893 DE_NULL, // const VkShaderModule geometryShaderModule
894 *fragShaderModule, // const VkShaderModule fragmentShaderModule
895 renderPass, // const VkRenderPass renderPass
896 viewports, // const std::vector<VkViewport>& viewports
897 scissors); // const std::vector<VkRect2D>& scissors
900 TriangleRenderer::TriangleRenderer (ProtectedContext& context,
901 const vk::BinaryCollection& binaryRegistry,
902 const std::vector<vk::VkImage> swapchainImages,
903 const vk::VkFormat framebufferFormat,
904 const tcu::UVec2& renderSize)
905 : m_vkd (context.getDeviceInterface())
906 , m_swapchainImages (swapchainImages)
907 , m_renderSize (renderSize)
908 , m_renderPass (createRenderPass(m_vkd, context.getDevice(), framebufferFormat))
909 , m_pipelineLayout (createPipelineLayout(m_vkd, context.getDevice()))
910 , m_pipeline (createPipeline(m_vkd, context.getDevice(), *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
911 , m_vertexBuffer (makeBuffer(context,
913 context.getQueueFamilyIndex(),
914 (deUint32)(sizeof(float)*4*3),
915 vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
916 vk::MemoryRequirement::HostVisible))
918 m_attachmentViews.resize(swapchainImages.size());
919 m_framebuffers.resize(swapchainImages.size());
921 for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
923 m_attachmentViews[imageNdx] = ImageViewSp(new vk::Unique<vk::VkImageView>(createImageView(context, swapchainImages[imageNdx], framebufferFormat)));
924 m_framebuffers[imageNdx] = FramebufferSp(new vk::Unique<vk::VkFramebuffer>(createFramebuffer(context,
928 **m_attachmentViews[imageNdx])));
931 // Upload vertex data
933 const tcu::Vec4 vertices[] =
935 tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
936 tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
937 tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
939 DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
941 deMemcpy(m_vertexBuffer->getAllocation().getHostPtr(), &vertices[0], sizeof(vertices));
942 vk::flushMappedMemoryRange(m_vkd, context.getDevice(), m_vertexBuffer->getAllocation().getMemory(), m_vertexBuffer->getAllocation().getOffset(), sizeof(vertices));
946 TriangleRenderer::~TriangleRenderer (void)
950 void TriangleRenderer::recordFrame (vk::VkCommandBuffer cmdBuffer,
952 deUint32 frameNdx) const
954 const vk::VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
956 beginCommandBuffer(m_vkd, cmdBuffer, 0u);
958 beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer, vk::makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
959 m_vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
962 const vk::VkDeviceSize bindingOffset = 0;
963 m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer->get(), &bindingOffset);
966 m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
967 m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
968 endRenderPass(m_vkd, cmdBuffer);
970 endCommandBuffer(m_vkd, cmdBuffer);
973 void TriangleRenderer::getPrograms (vk::SourceCollections& dst)
975 dst.glslSources.add("tri-vert") << glu::VertexSource(
977 "layout(location = 0) in highp vec4 a_position;\n"
978 "layout(push_constant) uniform FrameData\n"
980 " highp uint frameNdx;\n"
984 " highp float angle = float(frameData.frameNdx) / 100.0;\n"
985 " highp float c = cos(angle);\n"
986 " highp float s = sin(angle);\n"
987 " highp mat4 t = mat4( c, -s, 0, 0,\n"
991 " gl_Position = t * a_position;\n"
993 dst.glslSources.add("tri-frag") << glu::FragmentSource(
995 "layout(location = 0) out lowp vec4 o_color;\n"
996 "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
999 typedef de::SharedPtr<vk::Unique<vk::VkCommandBuffer> > CommandBufferSp;
1000 typedef de::SharedPtr<vk::Unique<vk::VkFence> > FenceSp;
1001 typedef de::SharedPtr<vk::Unique<vk::VkSemaphore> > SemaphoreSp;
1003 std::vector<FenceSp> createFences (const vk::DeviceInterface& vkd,
1004 const vk::VkDevice device,
1007 std::vector<FenceSp> fences(numFences);
1009 for (size_t ndx = 0; ndx < numFences; ++ndx)
1010 fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device)));
1015 std::vector<SemaphoreSp> createSemaphores (const vk::DeviceInterface& vkd,
1016 const vk::VkDevice device,
1017 size_t numSemaphores)
1019 std::vector<SemaphoreSp> semaphores(numSemaphores);
1021 for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1022 semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
1027 std::vector<CommandBufferSp> allocateCommandBuffers (const vk::DeviceInterface& vkd,
1028 const vk::VkDevice device,
1029 const vk::VkCommandPool commandPool,
1030 const vk::VkCommandBufferLevel level,
1031 const size_t numCommandBuffers)
1033 std::vector<CommandBufferSp> buffers (numCommandBuffers);
1035 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1036 buffers[ndx] = CommandBufferSp(new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1041 tcu::TestStatus basicRenderTest (Context& baseCtx, vk::wsi::Type wsiType)
1043 std::vector<vk::VkExtensionProperties> supportedExtensions (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
1044 std::vector<std::string> instExts = getRequiredWsiExtensions(supportedExtensions, wsiType);
1045 std::vector<std::string> devExts;
1046 devExts.push_back("VK_KHR_swapchain");
1048 const tcu::UVec2 desiredSize (256, 256);
1049 const NativeObjects native (baseCtx, supportedExtensions, wsiType, tcu::just(desiredSize));
1050 ProtectedContext context (baseCtx, wsiType, *native.display, *native.window, instExts, devExts);
1051 vk::VkSurfaceKHR surface = context.getSurface();
1052 const vk::DeviceInterface& vkd = context.getDeviceInterface();
1053 const vk::VkDevice device = context.getDevice();
1054 const vk::VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType,
1055 context.getInstanceDriver(),
1056 context.getPhysicalDevice(),
1060 const vk::Unique<vk::VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
1061 const std::vector<vk::VkImage> swapchainImages = vk::wsi::getSwapchainImages(vkd, device, *swapchain);
1063 const TriangleRenderer renderer (context,
1064 context.getBinaryCollection(),
1066 swapchainInfo.imageFormat,
1067 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1069 const vk::Unique<vk::VkCommandPool> commandPool (makeCommandPool(vkd, device, PROTECTION_ENABLED,
1070 context.getQueueFamilyIndex()));
1072 const size_t maxQueuedFrames = swapchainImages.size()*2;
1074 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1075 // limit number of frames we allow to be queued.
1076 const std::vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
1078 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1079 // the semaphore in same time as the fence we use to meter rendering.
1080 const std::vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
1082 // For rest we simply need maxQueuedFrames as we will wait for image
1083 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1084 // previous uses must have completed.
1085 const std::vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
1086 const std::vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd,
1089 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1094 const deUint32 numFramesToRender = 60*10;
1096 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1098 const vk::VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
1099 const vk::VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1100 deUint32 imageNdx = ~0u;
1102 if (frameNdx >= maxQueuedFrames)
1103 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1105 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1108 const vk::VkResult acquireResult = vkd.acquireNextImageKHR(device,
1110 std::numeric_limits<deUint64>::max(),
1111 imageReadySemaphore,
1115 if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
1116 context.getTestContext().getLog() << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << tcu::TestLog::EndMessage;
1118 VK_CHECK(acquireResult);
1121 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1124 const vk::VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1125 const vk::VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
1126 const vk::VkPipelineStageFlags waitDstStage = vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1127 vk::VkSubmitInfo submitInfo =
1129 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1132 &imageReadySemaphore,
1137 &renderingCompleteSemaphore
1140 const vk::VkProtectedSubmitInfo protectedInfo =
1142 vk::VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO, // sType
1144 VK_TRUE, // protectedSubmit
1146 submitInfo.pNext = &protectedInfo;
1148 const vk::VkPresentInfoKHR presentInfo =
1150 vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1153 &renderingCompleteSemaphore,
1157 (vk::VkResult*)DE_NULL
1160 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1161 VK_CHECK(vkd.queueSubmit(context.getQueue(), 1u, &submitInfo, imageReadyFence));
1162 VK_CHECK(vkd.queuePresentKHR(context.getQueue(), &presentInfo));
1166 VK_CHECK(vkd.deviceWaitIdle(device));
1170 // Make sure device is idle before destroying resources
1171 vkd.deviceWaitIdle(device);
1175 return tcu::TestStatus::pass("Rendering tests succeeded");
1178 void getBasicRenderPrograms (vk::SourceCollections& dst, vk::wsi::Type)
1180 TriangleRenderer::getPrograms(dst);
1183 void populateRenderGroup (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1185 addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
1188 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1190 addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
1191 addTestGroup(testGroup, "render", "Rendering Tests", populateRenderGroup, wsiType);
1194 void createTypeSpecificTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1196 addTestGroup(testGroup, "swapchain", "VkSwapchain Tests", createSwapchainTests, wsiType);
1201 tcu::TestCaseGroup* createSwapchainTests (tcu::TestContext& testCtx)
1203 de::MovePtr<tcu::TestCaseGroup> wsiTestGroup (new tcu::TestCaseGroup(testCtx, "wsi", "WSI Tests"));
1205 for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
1207 const vk::wsi::Type wsiType = (vk::wsi::Type)typeNdx;
1209 addTestGroup(&*wsiTestGroup, getName(wsiType), "", createTypeSpecificTests, wsiType);
1212 return wsiTestGroup.release();