1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2016 Google Inc.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 * \brief VkSwapchain Tests
22 *//*--------------------------------------------------------------------*/
24 #include "vktWsiSwapchainTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
30 #include "vkPlatform.hpp"
31 #include "vkStrUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkDeviceUtil.hpp"
37 #include "vkPrograms.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkWsiPlatform.hpp"
40 #include "vkWsiUtil.hpp"
41 #include "vkAllocationCallbackUtil.hpp"
42 #include "vkCmdUtil.hpp"
43 #include "vkObjUtil.hpp"
45 #include "tcuTestLog.hpp"
46 #include "tcuFormatUtil.hpp"
47 #include "tcuPlatform.hpp"
48 #include "tcuResultCollector.hpp"
50 #include "deUniquePtr.hpp"
51 #include "deStringUtil.hpp"
52 #include "deArrayUtil.hpp"
53 #include "deSharedPtr.hpp"
66 using namespace vk::wsi;
78 typedef vector<VkExtensionProperties> Extensions;
80 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
82 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
83 requiredExtName != requiredExtensions.end();
86 if (!isExtensionSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
87 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
91 Move<VkInstance> createInstanceWithWsi (const PlatformInterface& vkp,
93 const Extensions& supportedExtensions,
95 const VkAllocationCallbacks* pAllocator = DE_NULL)
97 vector<string> extensions;
99 extensions.push_back("VK_KHR_surface");
100 extensions.push_back(getExtensionName(wsiType));
102 // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
103 // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
104 // but using them without enabling the extension is not allowed. Thus we have
107 // 1) Filter out non-core formats to stay within valid usage.
109 // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
111 // We opt for (2) as it provides basic coverage for the extension as a bonus.
112 if (isExtensionSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
113 extensions.push_back("VK_EXT_swapchain_colorspace");
115 checkAllSupported(supportedExtensions, extensions);
117 return vk::createDefaultInstance(vkp, version, vector<string>(), extensions, pAllocator);
120 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
122 VkPhysicalDeviceFeatures features;
123 deMemset(&features, 0, sizeof(features));
127 Move<VkDevice> createDeviceWithWsi (const PlatformInterface& vkp,
129 const InstanceInterface& vki,
130 VkPhysicalDevice physicalDevice,
131 const Extensions& supportedExtensions,
132 const deUint32 queueFamilyIndex,
133 const VkAllocationCallbacks* pAllocator = DE_NULL)
135 const float queuePriorities[] = { 1.0f };
136 const VkDeviceQueueCreateInfo queueInfos[] =
139 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
141 (VkDeviceQueueCreateFlags)0,
143 DE_LENGTH_OF_ARRAY(queuePriorities),
147 const VkPhysicalDeviceFeatures features = getDeviceFeaturesForWsi();
148 const char* const extensions[] = { "VK_KHR_swapchain" };
149 const VkDeviceCreateInfo deviceParams =
151 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
153 (VkDeviceCreateFlags)0,
154 DE_LENGTH_OF_ARRAY(queueInfos),
156 0u, // enabledLayerCount
157 DE_NULL, // ppEnabledLayerNames
158 DE_LENGTH_OF_ARRAY(extensions), // enabledExtensionCount
159 DE_ARRAY_BEGIN(extensions), // ppEnabledExtensionNames
163 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
165 if (!isExtensionSupported(supportedExtensions, RequiredExtension(extensions[ndx])))
166 TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
169 return createDevice(vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
172 deUint32 getNumQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
174 deUint32 numFamilies = 0;
176 vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
181 vector<deUint32> getSupportedQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
183 const deUint32 numTotalFamilyIndices = getNumQueueFamilyIndices(vki, physicalDevice);
184 vector<deUint32> supportedFamilyIndices;
186 for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
188 if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
189 supportedFamilyIndices.push_back(queueFamilyNdx);
192 return supportedFamilyIndices;
195 deUint32 chooseQueueFamilyIndex (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
197 const vector<deUint32> supportedFamilyIndices = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
199 if (supportedFamilyIndices.empty())
200 TCU_THROW(NotSupportedError, "Device doesn't support presentation");
202 return supportedFamilyIndices[0];
205 struct InstanceHelper
207 const vector<VkExtensionProperties> supportedExtensions;
208 const Unique<VkInstance> instance;
209 const InstanceDriver vki;
211 InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
212 : supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
214 , instance (createInstanceWithWsi(context.getPlatformInterface(),
215 context.getUsedApiVersion(),
219 , vki (context.getPlatformInterface(), *instance)
225 const VkPhysicalDevice physicalDevice;
226 const deUint32 queueFamilyIndex;
227 const Unique<VkDevice> device;
228 const DeviceDriver vkd;
231 DeviceHelper (Context& context,
232 const InstanceInterface& vki,
234 VkSurfaceKHR surface,
235 const VkAllocationCallbacks* pAllocator = DE_NULL)
236 : physicalDevice (chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
237 , queueFamilyIndex (chooseQueueFamilyIndex(vki, physicalDevice, surface))
238 , device (createDeviceWithWsi(context.getPlatformInterface(),
239 context.getInstance(),
242 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
245 , vkd (context.getPlatformInterface(), context.getInstance(), *device)
246 , queue (getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
251 MovePtr<Display> createDisplay (const vk::Platform& platform,
252 const Extensions& supportedExtensions,
257 return MovePtr<Display>(platform.createWsiDisplay(wsiType));
259 catch (const tcu::NotSupportedError& e)
261 if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))) &&
262 platform.hasDisplay(wsiType))
264 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
265 // must support creating native display & window for that WSI type.
266 throw tcu::TestError(e.getMessage());
273 MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
277 return MovePtr<Window>(display.createWindow(initialSize));
279 catch (const tcu::NotSupportedError& e)
281 // See createDisplay - assuming that wsi::Display was supported platform port
282 // should also support creating a window.
283 throw tcu::TestError(e.getMessage());
289 const UniquePtr<Display> display;
290 const UniquePtr<Window> window;
292 NativeObjects (Context& context,
293 const Extensions& supportedExtensions,
295 const Maybe<UVec2>& initialWindowSize = tcu::nothing<UVec2>())
296 : display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
297 , window (createWindow(*display, initialWindowSize))
303 TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
304 TEST_DIMENSION_IMAGE_FORMAT, //!< Test all supported formats
305 TEST_DIMENSION_IMAGE_EXTENT, //!< Test various (supported) extents
306 TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
307 TEST_DIMENSION_IMAGE_USAGE,
308 TEST_DIMENSION_IMAGE_SHARING_MODE,
309 TEST_DIMENSION_PRE_TRANSFORM,
310 TEST_DIMENSION_COMPOSITE_ALPHA,
311 TEST_DIMENSION_PRESENT_MODE,
312 TEST_DIMENSION_CLIPPED,
317 const char* getTestDimensionName (TestDimension dimension)
319 static const char* const s_names[] =
324 "image_array_layers",
326 "image_sharing_mode",
332 return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
335 struct TestParameters
338 TestDimension dimension;
340 TestParameters (Type wsiType_, TestDimension dimension_)
342 , dimension (dimension_)
345 TestParameters (void)
346 : wsiType (TYPE_LAST)
347 , dimension (TEST_DIMENSION_LAST)
351 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type wsiType,
352 TestDimension dimension,
353 const VkSurfaceCapabilitiesKHR& capabilities,
354 const vector<VkSurfaceFormatKHR>& formats,
355 const vector<VkPresentModeKHR>& presentModes)
357 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
358 vector<VkSwapchainCreateInfoKHR> cases;
359 const VkSurfaceTransformFlagBitsKHR defaultTransform = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
360 const VkSwapchainCreateInfoKHR baseParameters =
362 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
364 (VkSwapchainCreateFlagsKHR)0,
366 capabilities.minImageCount,
368 formats[0].colorSpace,
369 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
370 ? capabilities.minImageExtent : capabilities.currentExtent),
371 1u, // imageArrayLayers
372 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
373 VK_SHARING_MODE_EXCLUSIVE,
375 (const deUint32*)DE_NULL,
377 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
378 VK_PRESENT_MODE_FIFO_KHR,
380 (VkSwapchainKHR)0 // oldSwapchain
385 case TEST_DIMENSION_MIN_IMAGE_COUNT:
387 const deUint32 maxImageCountToTest = de::clamp(16u, capabilities.minImageCount, (capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u);
389 for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
391 cases.push_back(baseParameters);
392 cases.back().minImageCount = imageCount;
398 case TEST_DIMENSION_IMAGE_FORMAT:
400 for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
402 cases.push_back(baseParameters);
403 cases.back().imageFormat = curFmt->format;
404 cases.back().imageColorSpace = curFmt->colorSpace;
410 case TEST_DIMENSION_IMAGE_EXTENT:
412 static const VkExtent2D s_testSizes[] =
421 if (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
422 platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
424 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
426 cases.push_back(baseParameters);
427 cases.back().imageExtent.width = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
428 cases.back().imageExtent.height = de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
432 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
434 cases.push_back(baseParameters);
435 cases.back().imageExtent = capabilities.currentExtent;
438 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
440 cases.push_back(baseParameters);
441 cases.back().imageExtent = capabilities.minImageExtent;
443 cases.push_back(baseParameters);
444 cases.back().imageExtent = capabilities.maxImageExtent;
450 case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
452 const deUint32 maxLayers = de::min(capabilities.maxImageArrayLayers, 16u);
454 for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
456 cases.push_back(baseParameters);
457 cases.back().imageArrayLayers = numLayers;
463 case TEST_DIMENSION_IMAGE_USAGE:
465 for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
467 if ((flags & ~capabilities.supportedUsageFlags) == 0)
469 cases.push_back(baseParameters);
470 cases.back().imageUsage = flags;
477 case TEST_DIMENSION_IMAGE_SHARING_MODE:
479 cases.push_back(baseParameters);
480 cases.back().imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
482 cases.push_back(baseParameters);
483 cases.back().imageSharingMode = VK_SHARING_MODE_CONCURRENT;
488 case TEST_DIMENSION_PRE_TRANSFORM:
490 for (deUint32 transform = 1u;
491 transform <= capabilities.supportedTransforms;
492 transform = transform<<1u)
494 if ((transform & capabilities.supportedTransforms) != 0)
496 cases.push_back(baseParameters);
497 cases.back().preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
504 case TEST_DIMENSION_COMPOSITE_ALPHA:
506 for (deUint32 alphaMode = 1u;
507 alphaMode <= capabilities.supportedCompositeAlpha;
508 alphaMode = alphaMode<<1u)
510 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
512 cases.push_back(baseParameters);
513 cases.back().compositeAlpha = (VkCompositeAlphaFlagBitsKHR)alphaMode;
520 case TEST_DIMENSION_PRESENT_MODE:
522 for (vector<VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
524 cases.push_back(baseParameters);
525 cases.back().presentMode = *curMode;
531 case TEST_DIMENSION_CLIPPED:
533 cases.push_back(baseParameters);
534 cases.back().clipped = VK_FALSE;
536 cases.push_back(baseParameters);
537 cases.back().clipped = VK_TRUE;
543 DE_FATAL("Impossible");
546 DE_ASSERT(!cases.empty());
550 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type wsiType,
551 TestDimension dimension,
552 const InstanceInterface& vki,
553 VkPhysicalDevice physicalDevice,
554 VkSurfaceKHR surface)
556 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki,
559 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(vki,
562 const vector<VkPresentModeKHR> presentModes = getPhysicalDeviceSurfacePresentModes(vki,
566 return generateSwapchainParameterCases(wsiType, dimension, capabilities, formats, presentModes);
569 tcu::TestStatus createSwapchainTest (Context& context, TestParameters params)
571 tcu::TestLog& log = context.getTestContext().getLog();
572 const InstanceHelper instHelper (context, params.wsiType);
573 const NativeObjects native (context, instHelper.supportedExtensions, params.wsiType);
574 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, params.wsiType, *native.display, *native.window));
575 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
576 const vector<VkSwapchainCreateInfoKHR> cases (generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
577 const VkSurfaceCapabilitiesKHR capabilities(getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface));
579 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
581 std::ostringstream subcase;
582 subcase << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": ";
584 VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
586 curParams.surface = *surface;
587 curParams.queueFamilyIndexCount = 1u;
588 curParams.pQueueFamilyIndices = &devHelper.queueFamilyIndex;
590 log << TestLog::Message << subcase.str() << curParams << TestLog::EndMessage;
592 // The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
594 // * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
595 // VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
596 VkImageFormatProperties properties;
597 const VkResult propertiesResult = instHelper.vki.getPhysicalDeviceImageFormatProperties(devHelper.physicalDevice,
598 curParams.imageFormat,
600 VK_IMAGE_TILING_OPTIMAL,
601 curParams.imageUsage,
605 log << TestLog::Message << subcase.str()
606 << "vkGetPhysicalDeviceImageFormatProperties => "
607 << getResultStr(propertiesResult) << TestLog::EndMessage;
609 switch (propertiesResult) {
612 // The maxExtents case might not be able to create the requested surface due to insufficient
613 // memory, so in this case *only* we handle the OOM exception.
614 if (params.dimension == TEST_DIMENSION_IMAGE_EXTENT &&
615 capabilities.maxImageExtent.width == curParams.imageExtent.width &&
616 capabilities.maxImageExtent.height == curParams.imageExtent.height)
620 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
622 log << TestLog::Message << subcase.str()
623 << "Creating swapchain succeeded" << TestLog::EndMessage;
625 catch (const OutOfMemoryError& e)
627 log << TestLog::Message << subcase.str() << "vkCreateSwapchainKHR with maxImageExtent encountered " << e.getError() << TestLog::EndMessage;
632 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
634 log << TestLog::Message << subcase.str()
635 << "Creating swapchain succeeded" << TestLog::EndMessage;
639 case VK_ERROR_FORMAT_NOT_SUPPORTED:
640 log << TestLog::Message << subcase.str()
641 << "Skip because vkGetPhysicalDeviceImageFormatProperties returned VK_ERROR_FORMAT_NOT_SUPPORTED" << TestLog::EndMessage;
644 log << TestLog::Message << subcase.str()
645 << "Fail because vkGetPhysicalDeviceImageFormatProperties returned "
646 << getResultStr(propertiesResult) << TestLog::EndMessage;
647 return tcu::TestStatus::fail("Unexpected result from vkGetPhysicalDeviceImageFormatProperties");
651 return tcu::TestStatus::pass("No sub-case failed");
654 tcu::TestStatus createSwapchainSimulateOOMTest (Context& context, TestParameters params)
656 const size_t maxCases = 300u;
657 const deUint32 maxAllocs = 1024u;
659 tcu::TestLog& log = context.getTestContext().getLog();
660 tcu::ResultCollector results (log);
662 AllocationCallbackRecorder allocationRecorder (getSystemAllocator());
663 DeterministicFailAllocator failingAllocator (allocationRecorder.getCallbacks(),
664 DeterministicFailAllocator::MODE_DO_NOT_COUNT,
667 const InstanceHelper instHelper (context, params.wsiType, failingAllocator.getCallbacks());
668 const NativeObjects native (context, instHelper.supportedExtensions, params.wsiType);
669 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
670 *instHelper.instance,
674 failingAllocator.getCallbacks()));
675 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface, failingAllocator.getCallbacks());
676 const vector<VkSwapchainCreateInfoKHR> allCases (generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
678 if (maxCases < allCases.size())
679 log << TestLog::Message << "Note: Will only test first " << maxCases << " cases out of total of " << allCases.size() << " parameter combinations" << TestLog::EndMessage;
681 for (size_t caseNdx = 0; caseNdx < de::min(maxCases, allCases.size()); ++caseNdx)
683 log << TestLog::Message << "Testing parameter case " << caseNdx << ": " << allCases[caseNdx] << TestLog::EndMessage;
685 for (deUint32 numPassingAllocs = 0; numPassingAllocs <= maxAllocs; ++numPassingAllocs)
689 failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
691 log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
695 VkSwapchainCreateInfoKHR curParams = allCases[caseNdx];
697 curParams.surface = *surface;
698 curParams.queueFamilyIndexCount = 1u;
699 curParams.pQueueFamilyIndices = &devHelper.queueFamilyIndex;
702 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
705 catch (const OutOfMemoryError& e)
707 log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
713 log << TestLog::Message << "Creating swapchain succeeded!" << TestLog::EndMessage;
715 if (numPassingAllocs == 0)
716 results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
720 else if (numPassingAllocs == maxAllocs)
721 results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
724 context.getTestContext().touchWatchdog();
728 if (!validateAndLog(log, allocationRecorder, 0u))
729 results.fail("Detected invalid system allocation callback");
731 return tcu::TestStatus(results.getResult(), results.getMessage());
734 struct GroupParameters
736 typedef FunctionInstance1<TestParameters>::Function Function;
741 GroupParameters (Type wsiType_, Function function_)
743 , function (function_)
746 GroupParameters (void)
747 : wsiType (TYPE_LAST)
748 , function ((Function)DE_NULL)
752 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
754 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
756 const TestDimension testDimension = (TestDimension)dimensionNdx;
758 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
762 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type wsiType,
763 const InstanceInterface& vki,
764 VkPhysicalDevice physicalDevice,
765 VkSurfaceKHR surface,
766 const tcu::UVec2& desiredSize,
767 deUint32 desiredImageCount)
769 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki,
772 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(vki,
775 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
776 const VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
777 const VkSwapchainCreateInfoKHR parameters =
779 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
781 (VkSwapchainCreateFlagsKHR)0,
783 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
785 formats[0].colorSpace,
786 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
787 ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
788 1u, // imageArrayLayers
789 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
790 VK_SHARING_MODE_EXCLUSIVE,
792 (const deUint32*)DE_NULL,
794 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
795 VK_PRESENT_MODE_FIFO_KHR,
797 (VkSwapchainKHR)0 // oldSwapchain
803 typedef de::SharedPtr<Unique<VkImageView> > ImageViewSp;
804 typedef de::SharedPtr<Unique<VkFramebuffer> > FramebufferSp;
806 class TriangleRenderer
809 TriangleRenderer (const DeviceInterface& vkd,
810 const VkDevice device,
811 Allocator& allocator,
812 const BinaryCollection& binaryRegistry,
813 const vector<VkImage> swapchainImages,
814 const VkFormat framebufferFormat,
815 const UVec2& renderSize);
816 ~TriangleRenderer (void);
818 void recordFrame (VkCommandBuffer cmdBuffer,
820 deUint32 frameNdx) const;
822 static void getPrograms (SourceCollections& dst);
825 static Move<VkRenderPass> createRenderPass (const DeviceInterface& vkd,
826 const VkDevice device,
827 const VkFormat colorAttachmentFormat);
828 static Move<VkPipelineLayout> createPipelineLayout(const DeviceInterface& vkd,
830 static Move<VkPipeline> createPipeline (const DeviceInterface& vkd,
831 const VkDevice device,
832 const VkRenderPass renderPass,
833 const VkPipelineLayout pipelineLayout,
834 const BinaryCollection& binaryCollection,
835 const UVec2& renderSize);
837 static Move<VkImageView> createAttachmentView(const DeviceInterface& vkd,
838 const VkDevice device,
840 const VkFormat format);
841 static Move<VkFramebuffer> createFramebuffer (const DeviceInterface& vkd,
842 const VkDevice device,
843 const VkRenderPass renderPass,
844 const VkImageView colorAttachment,
845 const UVec2& renderSize);
847 static Move<VkBuffer> createBuffer (const DeviceInterface& vkd,
850 VkBufferUsageFlags usage);
852 const DeviceInterface& m_vkd;
854 const vector<VkImage> m_swapchainImages;
855 const tcu::UVec2 m_renderSize;
857 const Unique<VkRenderPass> m_renderPass;
858 const Unique<VkPipelineLayout> m_pipelineLayout;
859 const Unique<VkPipeline> m_pipeline;
861 const Unique<VkBuffer> m_vertexBuffer;
862 const UniquePtr<Allocation> m_vertexBufferMemory;
864 vector<ImageViewSp> m_attachmentViews;
865 vector<FramebufferSp> m_framebuffers;
868 Move<VkRenderPass> TriangleRenderer::createRenderPass (const DeviceInterface& vkd,
869 const VkDevice device,
870 const VkFormat colorAttachmentFormat)
872 const VkAttachmentDescription colorAttDesc =
874 (VkAttachmentDescriptionFlags)0,
875 colorAttachmentFormat,
876 VK_SAMPLE_COUNT_1_BIT,
877 VK_ATTACHMENT_LOAD_OP_CLEAR,
878 VK_ATTACHMENT_STORE_OP_STORE,
879 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
880 VK_ATTACHMENT_STORE_OP_DONT_CARE,
881 VK_IMAGE_LAYOUT_UNDEFINED,
882 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
884 const VkAttachmentReference colorAttRef =
887 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
889 const VkSubpassDescription subpassDesc =
891 (VkSubpassDescriptionFlags)0u,
892 VK_PIPELINE_BIND_POINT_GRAPHICS,
893 0u, // inputAttachmentCount
894 DE_NULL, // pInputAttachments
895 1u, // colorAttachmentCount
896 &colorAttRef, // pColorAttachments
897 DE_NULL, // pResolveAttachments
898 DE_NULL, // depthStencilAttachment
899 0u, // preserveAttachmentCount
900 DE_NULL, // pPreserveAttachments
902 const VkSubpassDependency dependencies[] =
905 VK_SUBPASS_EXTERNAL, // srcSubpass
907 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
908 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
909 VK_ACCESS_MEMORY_READ_BIT,
910 (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
911 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
912 VK_DEPENDENCY_BY_REGION_BIT
916 VK_SUBPASS_EXTERNAL, // dstSubpass
917 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
918 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
919 (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
920 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
921 VK_ACCESS_MEMORY_READ_BIT,
922 VK_DEPENDENCY_BY_REGION_BIT
925 const VkRenderPassCreateInfo renderPassParams =
927 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
929 (VkRenderPassCreateFlags)0,
934 DE_LENGTH_OF_ARRAY(dependencies),
938 return vk::createRenderPass(vkd, device, &renderPassParams);
941 Move<VkPipelineLayout> TriangleRenderer::createPipelineLayout (const DeviceInterface& vkd,
942 const VkDevice device)
944 const VkPushConstantRange pushConstantRange =
946 VK_SHADER_STAGE_VERTEX_BIT,
948 (deUint32)sizeof(deUint32), // size
950 const VkPipelineLayoutCreateInfo pipelineLayoutParams =
952 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
954 (vk::VkPipelineLayoutCreateFlags)0,
955 0u, // setLayoutCount
956 DE_NULL, // pSetLayouts
961 return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
964 Move<VkPipeline> TriangleRenderer::createPipeline (const DeviceInterface& vkd,
965 const VkDevice device,
966 const VkRenderPass renderPass,
967 const VkPipelineLayout pipelineLayout,
968 const BinaryCollection& binaryCollection,
969 const UVec2& renderSize)
971 // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
972 // and can be deleted immediately following that call.
973 const Unique<VkShaderModule> vertShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
974 const Unique<VkShaderModule> fragShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
975 const std::vector<VkViewport> viewports (1, makeViewport(renderSize));
976 const std::vector<VkRect2D> scissors (1, makeRect2D(renderSize));
978 return vk::makeGraphicsPipeline(vkd, // const DeviceInterface& vk
979 device, // const VkDevice device
980 pipelineLayout, // const VkPipelineLayout pipelineLayout
981 *vertShaderModule, // const VkShaderModule vertexShaderModule
982 DE_NULL, // const VkShaderModule tessellationControlShaderModule
983 DE_NULL, // const VkShaderModule tessellationEvalShaderModule
984 DE_NULL, // const VkShaderModule geometryShaderModule
985 *fragShaderModule, // const VkShaderModule fragmentShaderModule
986 renderPass, // const VkRenderPass renderPass
987 viewports, // const std::vector<VkViewport>& viewports
988 scissors); // const std::vector<VkRect2D>& scissors
991 Move<VkImageView> TriangleRenderer::createAttachmentView (const DeviceInterface& vkd,
992 const VkDevice device,
994 const VkFormat format)
996 const VkImageViewCreateInfo viewParams =
998 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1000 (VkImageViewCreateFlags)0,
1002 VK_IMAGE_VIEW_TYPE_2D,
1004 vk::makeComponentMappingRGBA(),
1006 VK_IMAGE_ASPECT_COLOR_BIT,
1009 0u, // baseArrayLayer
1014 return vk::createImageView(vkd, device, &viewParams);
1017 Move<VkFramebuffer> TriangleRenderer::createFramebuffer (const DeviceInterface& vkd,
1018 const VkDevice device,
1019 const VkRenderPass renderPass,
1020 const VkImageView colorAttachment,
1021 const UVec2& renderSize)
1023 const VkFramebufferCreateInfo framebufferParams =
1025 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1027 (VkFramebufferCreateFlags)0,
1036 return vk::createFramebuffer(vkd, device, &framebufferParams);
1039 Move<VkBuffer> TriangleRenderer::createBuffer (const DeviceInterface& vkd,
1042 VkBufferUsageFlags usage)
1044 const VkBufferCreateInfo bufferParams =
1046 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1048 (VkBufferCreateFlags)0,
1051 VK_SHARING_MODE_EXCLUSIVE,
1056 return vk::createBuffer(vkd, device, &bufferParams);
1059 TriangleRenderer::TriangleRenderer (const DeviceInterface& vkd,
1060 const VkDevice device,
1061 Allocator& allocator,
1062 const BinaryCollection& binaryRegistry,
1063 const vector<VkImage> swapchainImages,
1064 const VkFormat framebufferFormat,
1065 const UVec2& renderSize)
1067 , m_swapchainImages (swapchainImages)
1068 , m_renderSize (renderSize)
1069 , m_renderPass (createRenderPass(vkd, device, framebufferFormat))
1070 , m_pipelineLayout (createPipelineLayout(vkd, device))
1071 , m_pipeline (createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
1072 , m_vertexBuffer (createBuffer(vkd, device, (VkDeviceSize)(sizeof(float)*4*3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
1073 , m_vertexBufferMemory (allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer),
1074 MemoryRequirement::HostVisible))
1076 m_attachmentViews.resize(swapchainImages.size());
1077 m_framebuffers.resize(swapchainImages.size());
1079 for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
1081 m_attachmentViews[imageNdx] = ImageViewSp(new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
1082 m_framebuffers[imageNdx] = FramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
1085 VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset()));
1088 const VkMappedMemoryRange memRange =
1090 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
1092 m_vertexBufferMemory->getMemory(),
1093 m_vertexBufferMemory->getOffset(),
1096 const tcu::Vec4 vertices[] =
1098 tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
1099 tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
1100 tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
1102 DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
1104 deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
1105 VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
1109 TriangleRenderer::~TriangleRenderer (void)
1113 void TriangleRenderer::recordFrame (VkCommandBuffer cmdBuffer,
1115 deUint32 frameNdx) const
1117 const VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
1119 beginCommandBuffer(m_vkd, cmdBuffer, 0u);
1121 beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
1123 m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1126 const VkDeviceSize bindingOffset = 0;
1127 m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
1130 m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
1131 m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1132 endRenderPass(m_vkd, cmdBuffer);
1134 endCommandBuffer(m_vkd, cmdBuffer);
1137 void TriangleRenderer::getPrograms (SourceCollections& dst)
1139 dst.glslSources.add("tri-vert") << glu::VertexSource(
1141 "layout(location = 0) in highp vec4 a_position;\n"
1142 "layout(push_constant) uniform FrameData\n"
1144 " highp uint frameNdx;\n"
1146 "void main (void)\n"
1148 " highp float angle = float(frameData.frameNdx) / 100.0;\n"
1149 " highp float c = cos(angle);\n"
1150 " highp float s = sin(angle);\n"
1151 " highp mat4 t = mat4( c, -s, 0, 0,\n"
1155 " gl_Position = t * a_position;\n"
1157 dst.glslSources.add("tri-frag") << glu::FragmentSource(
1159 "layout(location = 0) out lowp vec4 o_color;\n"
1160 "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1163 typedef de::SharedPtr<Unique<VkCommandBuffer> > CommandBufferSp;
1164 typedef de::SharedPtr<Unique<VkFence> > FenceSp;
1165 typedef de::SharedPtr<Unique<VkSemaphore> > SemaphoreSp;
1167 vector<FenceSp> createFences (const DeviceInterface& vkd,
1168 const VkDevice device,
1171 vector<FenceSp> fences(numFences);
1173 for (size_t ndx = 0; ndx < numFences; ++ndx)
1174 fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
1179 vector<SemaphoreSp> createSemaphores (const DeviceInterface& vkd,
1180 const VkDevice device,
1181 size_t numSemaphores)
1183 vector<SemaphoreSp> semaphores(numSemaphores);
1185 for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1186 semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
1191 vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface& vkd,
1192 const VkDevice device,
1193 const VkCommandPool commandPool,
1194 const VkCommandBufferLevel level,
1195 const size_t numCommandBuffers)
1197 vector<CommandBufferSp> buffers (numCommandBuffers);
1199 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1200 buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1205 tcu::TestStatus basicRenderTest (Context& context, Type wsiType)
1207 const tcu::UVec2 desiredSize (256, 256);
1208 const InstanceHelper instHelper (context, wsiType);
1209 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1210 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1211 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
1212 const DeviceInterface& vkd = devHelper.vkd;
1213 const VkDevice device = *devHelper.device;
1214 SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1215 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1216 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
1217 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
1219 const TriangleRenderer renderer (vkd,
1222 context.getBinaryCollection(),
1224 swapchainInfo.imageFormat,
1225 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1227 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1229 const size_t maxQueuedFrames = swapchainImages.size()*2;
1231 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1232 // limit number of frames we allow to be queued.
1233 const vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
1235 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1236 // the semaphore in same time as the fence we use to meter rendering.
1237 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
1239 // For rest we simply need maxQueuedFrames as we will wait for image
1240 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1241 // previous uses must have completed.
1242 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
1243 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1247 const deUint32 numFramesToRender = 60*10;
1249 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1251 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
1252 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1253 deUint32 imageNdx = ~0u;
1255 if (frameNdx >= maxQueuedFrames)
1256 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1258 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1261 const VkResult acquireResult = vkd.acquireNextImageKHR(device,
1263 std::numeric_limits<deUint64>::max(),
1264 imageReadySemaphore,
1268 if (acquireResult == VK_SUBOPTIMAL_KHR)
1269 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1271 VK_CHECK(acquireResult);
1274 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1277 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1278 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
1279 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1280 const VkSubmitInfo submitInfo =
1282 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1285 &imageReadySemaphore,
1290 &renderingCompleteSemaphore
1292 const VkPresentInfoKHR presentInfo =
1294 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1297 &renderingCompleteSemaphore,
1304 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1305 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
1306 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1310 VK_CHECK(vkd.deviceWaitIdle(device));
1314 // Make sure device is idle before destroying resources
1315 vkd.deviceWaitIdle(device);
1319 return tcu::TestStatus::pass("Rendering tests succeeded");
1322 vector<tcu::UVec2> getSwapchainSizeSequence (const VkSurfaceCapabilitiesKHR& capabilities, const tcu::UVec2& defaultSize)
1324 vector<tcu::UVec2> sizes(3);
1325 sizes[0] = defaultSize / 2u;
1326 sizes[1] = defaultSize;
1327 sizes[2] = defaultSize * 2u;
1329 for (deUint32 i = 0; i < sizes.size(); ++i)
1331 sizes[i].x() = de::clamp(sizes[i].x(), capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
1332 sizes[i].y() = de::clamp(sizes[i].y(), capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
1338 tcu::TestStatus resizeSwapchainTest (Context& context, Type wsiType)
1340 const tcu::UVec2 desiredSize (256, 256);
1341 const InstanceHelper instHelper (context, wsiType);
1342 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1343 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1344 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
1345 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
1346 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
1347 const DeviceInterface& vkd = devHelper.vkd;
1348 const VkDevice device = *devHelper.device;
1349 SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1350 vector<tcu::UVec2> sizes = getSwapchainSizeSequence(capabilities, desiredSize);
1351 Move<VkSwapchainKHR> prevSwapchain;
1353 DE_ASSERT(platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE);
1354 DE_UNREF(platformProperties);
1356 for (deUint32 sizeNdx = 0; sizeNdx < sizes.size(); ++sizeNdx)
1358 // \todo [2016-05-30 jesse] This test currently waits for idle and
1359 // recreates way more than necessary when recreating the swapchain. Make
1360 // it match expected real app behavior better by smoothly switching from
1361 // old to new swapchain. Once that is done, it will also be possible to
1362 // test creating a new swapchain while images from the previous one are
1365 VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, sizes[sizeNdx], 2);
1366 swapchainInfo.oldSwapchain = *prevSwapchain;
1368 Move<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
1369 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
1370 const TriangleRenderer renderer (vkd,
1373 context.getBinaryCollection(),
1375 swapchainInfo.imageFormat,
1376 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1377 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1378 const size_t maxQueuedFrames = swapchainImages.size()*2;
1380 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1381 // limit number of frames we allow to be queued.
1382 const vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
1384 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1385 // the semaphore in same time as the fence we use to meter rendering.
1386 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
1388 // For rest we simply need maxQueuedFrames as we will wait for image
1389 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1390 // previous uses must have completed.
1391 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
1392 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1396 const deUint32 numFramesToRender = 60;
1398 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1400 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
1401 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1402 deUint32 imageNdx = ~0u;
1404 if (frameNdx >= maxQueuedFrames)
1405 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1407 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1410 const VkResult acquireResult = vkd.acquireNextImageKHR(device,
1412 std::numeric_limits<deUint64>::max(),
1413 imageReadySemaphore,
1417 if (acquireResult == VK_SUBOPTIMAL_KHR)
1418 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1420 VK_CHECK(acquireResult);
1423 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1426 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1427 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
1428 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1429 const VkSubmitInfo submitInfo =
1431 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1434 &imageReadySemaphore,
1439 &renderingCompleteSemaphore
1441 const VkPresentInfoKHR presentInfo =
1443 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1446 &renderingCompleteSemaphore,
1453 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1454 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, (VkFence)0));
1455 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1459 VK_CHECK(vkd.deviceWaitIdle(device));
1461 prevSwapchain = swapchain;
1465 // Make sure device is idle before destroying resources
1466 vkd.deviceWaitIdle(device);
1471 return tcu::TestStatus::pass("Resizing tests succeeded");
1474 tcu::TestStatus getImagesIncompleteResultTest (Context& context, Type wsiType)
1476 const tcu::UVec2 desiredSize (256, 256);
1477 const InstanceHelper instHelper (context, wsiType);
1478 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1479 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1480 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
1481 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1482 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
1484 vector<VkImage> swapchainImages = getSwapchainImages(devHelper.vkd, *devHelper.device, *swapchain);
1486 ValidateQueryBits::fillBits(swapchainImages.begin(), swapchainImages.end());
1488 const deUint32 usedCount = static_cast<deUint32>(swapchainImages.size() / 2);
1489 deUint32 count = usedCount;
1490 const VkResult result = devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &count, &swapchainImages[0]);
1492 if (count != usedCount || result != VK_INCOMPLETE || !ValidateQueryBits::checkBits(swapchainImages.begin() + count, swapchainImages.end()))
1493 return tcu::TestStatus::fail("Get swapchain images didn't return VK_INCOMPLETE");
1495 return tcu::TestStatus::pass("Get swapchain images tests succeeded");
1498 tcu::TestStatus getImagesResultsCountTest (Context& context, Type wsiType)
1500 const tcu::UVec2 desiredSize(256, 256);
1501 const InstanceHelper instHelper(context, wsiType);
1502 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1503 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1504 const DeviceHelper devHelper(context, instHelper.vki, *instHelper.instance, *surface);
1505 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1506 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
1508 deUint32 numImages = 0;
1510 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
1514 std::vector<VkImage> images (numImages + 1);
1515 const deUint32 numImagesOrig = numImages;
1517 // check if below call properly overwrites formats count
1520 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, &images[0]));
1522 if ((size_t)numImages != numImagesOrig)
1523 TCU_FAIL("Image count changed between calls");
1525 return tcu::TestStatus::pass("Get swapchain images tests succeeded");
1528 tcu::TestStatus destroyNullHandleSwapchainTest (Context& context, Type wsiType)
1530 const InstanceHelper instHelper (context, wsiType);
1531 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
1532 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1533 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
1534 const VkSwapchainKHR nullHandle = DE_NULL;
1536 // Default allocator
1537 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, DE_NULL);
1541 AllocationCallbackRecorder recordingAllocator (getSystemAllocator(), 1u);
1543 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, recordingAllocator.getCallbacks());
1545 if (recordingAllocator.getNumRecords() != 0u)
1546 return tcu::TestStatus::fail("Implementation allocated/freed the memory");
1549 return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
1552 void getBasicRenderPrograms (SourceCollections& dst, Type)
1554 TriangleRenderer::getPrograms(dst);
1557 void populateRenderGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1559 addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
1562 void populateGetImagesGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1564 addFunctionCase(testGroup, "incomplete", "Test VK_INCOMPLETE return code", getImagesIncompleteResultTest, wsiType);
1565 addFunctionCase(testGroup, "count", "Test proper count of images", getImagesResultsCountTest, wsiType);
1568 void populateModifyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1570 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
1572 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
1574 addFunctionCaseWithPrograms(testGroup, "resize", "Resize Swapchain Test", getBasicRenderPrograms, resizeSwapchainTest, wsiType);
1577 // \todo [2016-05-30 jesse] Add tests for modifying preTransform, compositeAlpha, presentMode
1580 void populateDestroyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1582 addFunctionCase(testGroup, "null_handle", "Destroying a VK_NULL_HANDLE swapchain", destroyNullHandleSwapchainTest, wsiType);
1587 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1589 addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
1590 addTestGroup(testGroup, "simulate_oom", "Simulate OOM using callbacks during swapchain construction", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainSimulateOOMTest));
1591 addTestGroup(testGroup, "render", "Rendering Tests", populateRenderGroup, wsiType);
1592 addTestGroup(testGroup, "modify", "Modify VkSwapchain", populateModifyGroup, wsiType);
1593 addTestGroup(testGroup, "destroy", "Destroy VkSwapchain", populateDestroyGroup, wsiType);
1594 addTestGroup(testGroup, "get_images", "Get swapchain images", populateGetImagesGroup, wsiType);