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));
578 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
580 std::ostringstream subcase;
581 subcase << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": ";
583 VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
585 curParams.surface = *surface;
586 curParams.queueFamilyIndexCount = 1u;
587 curParams.pQueueFamilyIndices = &devHelper.queueFamilyIndex;
589 log << TestLog::Message << subcase.str() << curParams << TestLog::EndMessage;
591 // The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
593 // * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
594 // VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
595 VkImageFormatProperties properties;
596 const VkResult propertiesResult = instHelper.vki.getPhysicalDeviceImageFormatProperties(devHelper.physicalDevice,
597 curParams.imageFormat,
599 VK_IMAGE_TILING_OPTIMAL,
600 curParams.imageUsage,
604 log << TestLog::Message << subcase.str()
605 << "vkGetPhysicalDeviceImageFormatProperties => "
606 << getResultStr(propertiesResult) << TestLog::EndMessage;
608 switch (propertiesResult) {
611 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
613 log << TestLog::Message << subcase.str()
614 << "Creating swapchain succeeeded" << TestLog::EndMessage;
616 case VK_ERROR_FORMAT_NOT_SUPPORTED:
617 log << TestLog::Message << subcase.str()
618 << "Skip because vkGetPhysicalDeviceImageFormatProperties returned VK_ERROR_FORMAT_NOT_SUPPORTED" << TestLog::EndMessage;
621 log << TestLog::Message << subcase.str()
622 << "Fail because vkGetPhysicalDeviceImageFormatProperties returned "
623 << getResultStr(propertiesResult) << TestLog::EndMessage;
624 return tcu::TestStatus::fail("Unexpected result from vkGetPhysicalDeviceImageFormatProperties");
628 return tcu::TestStatus::pass("No sub-case failed");
631 tcu::TestStatus createSwapchainSimulateOOMTest (Context& context, TestParameters params)
633 const size_t maxCases = 300u;
634 const deUint32 maxAllocs = 1024u;
636 tcu::TestLog& log = context.getTestContext().getLog();
637 tcu::ResultCollector results (log);
639 AllocationCallbackRecorder allocationRecorder (getSystemAllocator());
640 DeterministicFailAllocator failingAllocator (allocationRecorder.getCallbacks(),
641 DeterministicFailAllocator::MODE_DO_NOT_COUNT,
644 const InstanceHelper instHelper (context, params.wsiType, failingAllocator.getCallbacks());
645 const NativeObjects native (context, instHelper.supportedExtensions, params.wsiType);
646 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
647 *instHelper.instance,
651 failingAllocator.getCallbacks()));
652 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface, failingAllocator.getCallbacks());
653 const vector<VkSwapchainCreateInfoKHR> allCases (generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
655 if (maxCases < allCases.size())
656 log << TestLog::Message << "Note: Will only test first " << maxCases << " cases out of total of " << allCases.size() << " parameter combinations" << TestLog::EndMessage;
658 for (size_t caseNdx = 0; caseNdx < de::min(maxCases, allCases.size()); ++caseNdx)
660 log << TestLog::Message << "Testing parameter case " << caseNdx << ": " << allCases[caseNdx] << TestLog::EndMessage;
662 for (deUint32 numPassingAllocs = 0; numPassingAllocs <= maxAllocs; ++numPassingAllocs)
666 failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
668 log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
672 VkSwapchainCreateInfoKHR curParams = allCases[caseNdx];
674 curParams.surface = *surface;
675 curParams.queueFamilyIndexCount = 1u;
676 curParams.pQueueFamilyIndices = &devHelper.queueFamilyIndex;
679 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
682 catch (const OutOfMemoryError& e)
684 log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
690 log << TestLog::Message << "Creating swapchain succeeded!" << TestLog::EndMessage;
692 if (numPassingAllocs == 0)
693 results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
697 else if (numPassingAllocs == maxAllocs)
698 results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
701 context.getTestContext().touchWatchdog();
705 if (!validateAndLog(log, allocationRecorder, 0u))
706 results.fail("Detected invalid system allocation callback");
708 return tcu::TestStatus(results.getResult(), results.getMessage());
711 struct GroupParameters
713 typedef FunctionInstance1<TestParameters>::Function Function;
718 GroupParameters (Type wsiType_, Function function_)
720 , function (function_)
723 GroupParameters (void)
724 : wsiType (TYPE_LAST)
725 , function ((Function)DE_NULL)
729 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
731 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
733 const TestDimension testDimension = (TestDimension)dimensionNdx;
735 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
739 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type wsiType,
740 const InstanceInterface& vki,
741 VkPhysicalDevice physicalDevice,
742 VkSurfaceKHR surface,
743 const tcu::UVec2& desiredSize,
744 deUint32 desiredImageCount)
746 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki,
749 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(vki,
752 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
753 const VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
754 const VkSwapchainCreateInfoKHR parameters =
756 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
758 (VkSwapchainCreateFlagsKHR)0,
760 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
762 formats[0].colorSpace,
763 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
764 ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
765 1u, // imageArrayLayers
766 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
767 VK_SHARING_MODE_EXCLUSIVE,
769 (const deUint32*)DE_NULL,
771 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
772 VK_PRESENT_MODE_FIFO_KHR,
774 (VkSwapchainKHR)0 // oldSwapchain
780 typedef de::SharedPtr<Unique<VkImageView> > ImageViewSp;
781 typedef de::SharedPtr<Unique<VkFramebuffer> > FramebufferSp;
783 class TriangleRenderer
786 TriangleRenderer (const DeviceInterface& vkd,
787 const VkDevice device,
788 Allocator& allocator,
789 const BinaryCollection& binaryRegistry,
790 const vector<VkImage> swapchainImages,
791 const VkFormat framebufferFormat,
792 const UVec2& renderSize);
793 ~TriangleRenderer (void);
795 void recordFrame (VkCommandBuffer cmdBuffer,
797 deUint32 frameNdx) const;
799 static void getPrograms (SourceCollections& dst);
802 static Move<VkRenderPass> createRenderPass (const DeviceInterface& vkd,
803 const VkDevice device,
804 const VkFormat colorAttachmentFormat);
805 static Move<VkPipelineLayout> createPipelineLayout(const DeviceInterface& vkd,
807 static Move<VkPipeline> createPipeline (const DeviceInterface& vkd,
808 const VkDevice device,
809 const VkRenderPass renderPass,
810 const VkPipelineLayout pipelineLayout,
811 const BinaryCollection& binaryCollection,
812 const UVec2& renderSize);
814 static Move<VkImageView> createAttachmentView(const DeviceInterface& vkd,
815 const VkDevice device,
817 const VkFormat format);
818 static Move<VkFramebuffer> createFramebuffer (const DeviceInterface& vkd,
819 const VkDevice device,
820 const VkRenderPass renderPass,
821 const VkImageView colorAttachment,
822 const UVec2& renderSize);
824 static Move<VkBuffer> createBuffer (const DeviceInterface& vkd,
827 VkBufferUsageFlags usage);
829 const DeviceInterface& m_vkd;
831 const vector<VkImage> m_swapchainImages;
832 const tcu::UVec2 m_renderSize;
834 const Unique<VkRenderPass> m_renderPass;
835 const Unique<VkPipelineLayout> m_pipelineLayout;
836 const Unique<VkPipeline> m_pipeline;
838 const Unique<VkBuffer> m_vertexBuffer;
839 const UniquePtr<Allocation> m_vertexBufferMemory;
841 vector<ImageViewSp> m_attachmentViews;
842 vector<FramebufferSp> m_framebuffers;
845 Move<VkRenderPass> TriangleRenderer::createRenderPass (const DeviceInterface& vkd,
846 const VkDevice device,
847 const VkFormat colorAttachmentFormat)
849 const VkAttachmentDescription colorAttDesc =
851 (VkAttachmentDescriptionFlags)0,
852 colorAttachmentFormat,
853 VK_SAMPLE_COUNT_1_BIT,
854 VK_ATTACHMENT_LOAD_OP_CLEAR,
855 VK_ATTACHMENT_STORE_OP_STORE,
856 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
857 VK_ATTACHMENT_STORE_OP_DONT_CARE,
858 VK_IMAGE_LAYOUT_UNDEFINED,
859 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
861 const VkAttachmentReference colorAttRef =
864 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
866 const VkSubpassDescription subpassDesc =
868 (VkSubpassDescriptionFlags)0u,
869 VK_PIPELINE_BIND_POINT_GRAPHICS,
870 0u, // inputAttachmentCount
871 DE_NULL, // pInputAttachments
872 1u, // colorAttachmentCount
873 &colorAttRef, // pColorAttachments
874 DE_NULL, // pResolveAttachments
875 DE_NULL, // depthStencilAttachment
876 0u, // preserveAttachmentCount
877 DE_NULL, // pPreserveAttachments
879 const VkSubpassDependency dependencies[] =
882 VK_SUBPASS_EXTERNAL, // srcSubpass
884 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
885 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
886 VK_ACCESS_MEMORY_READ_BIT,
887 (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
888 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
889 VK_DEPENDENCY_BY_REGION_BIT
893 VK_SUBPASS_EXTERNAL, // dstSubpass
894 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
895 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
896 (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
897 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
898 VK_ACCESS_MEMORY_READ_BIT,
899 VK_DEPENDENCY_BY_REGION_BIT
902 const VkRenderPassCreateInfo renderPassParams =
904 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
906 (VkRenderPassCreateFlags)0,
911 DE_LENGTH_OF_ARRAY(dependencies),
915 return vk::createRenderPass(vkd, device, &renderPassParams);
918 Move<VkPipelineLayout> TriangleRenderer::createPipelineLayout (const DeviceInterface& vkd,
919 const VkDevice device)
921 const VkPushConstantRange pushConstantRange =
923 VK_SHADER_STAGE_VERTEX_BIT,
925 (deUint32)sizeof(deUint32), // size
927 const VkPipelineLayoutCreateInfo pipelineLayoutParams =
929 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
931 (vk::VkPipelineLayoutCreateFlags)0,
932 0u, // setLayoutCount
933 DE_NULL, // pSetLayouts
938 return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
941 Move<VkPipeline> TriangleRenderer::createPipeline (const DeviceInterface& vkd,
942 const VkDevice device,
943 const VkRenderPass renderPass,
944 const VkPipelineLayout pipelineLayout,
945 const BinaryCollection& binaryCollection,
946 const UVec2& renderSize)
948 // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
949 // and can be deleted immediately following that call.
950 const Unique<VkShaderModule> vertShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
951 const Unique<VkShaderModule> fragShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
952 const std::vector<VkViewport> viewports (1, makeViewport(renderSize));
953 const std::vector<VkRect2D> scissors (1, makeRect2D(renderSize));
955 return vk::makeGraphicsPipeline(vkd, // const DeviceInterface& vk
956 device, // const VkDevice device
957 pipelineLayout, // const VkPipelineLayout pipelineLayout
958 *vertShaderModule, // const VkShaderModule vertexShaderModule
959 DE_NULL, // const VkShaderModule tessellationControlShaderModule
960 DE_NULL, // const VkShaderModule tessellationEvalShaderModule
961 DE_NULL, // const VkShaderModule geometryShaderModule
962 *fragShaderModule, // const VkShaderModule fragmentShaderModule
963 renderPass, // const VkRenderPass renderPass
964 viewports, // const std::vector<VkViewport>& viewports
965 scissors); // const std::vector<VkRect2D>& scissors
968 Move<VkImageView> TriangleRenderer::createAttachmentView (const DeviceInterface& vkd,
969 const VkDevice device,
971 const VkFormat format)
973 const VkImageViewCreateInfo viewParams =
975 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
977 (VkImageViewCreateFlags)0,
979 VK_IMAGE_VIEW_TYPE_2D,
981 vk::makeComponentMappingRGBA(),
983 VK_IMAGE_ASPECT_COLOR_BIT,
986 0u, // baseArrayLayer
991 return vk::createImageView(vkd, device, &viewParams);
994 Move<VkFramebuffer> TriangleRenderer::createFramebuffer (const DeviceInterface& vkd,
995 const VkDevice device,
996 const VkRenderPass renderPass,
997 const VkImageView colorAttachment,
998 const UVec2& renderSize)
1000 const VkFramebufferCreateInfo framebufferParams =
1002 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1004 (VkFramebufferCreateFlags)0,
1013 return vk::createFramebuffer(vkd, device, &framebufferParams);
1016 Move<VkBuffer> TriangleRenderer::createBuffer (const DeviceInterface& vkd,
1019 VkBufferUsageFlags usage)
1021 const VkBufferCreateInfo bufferParams =
1023 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1025 (VkBufferCreateFlags)0,
1028 VK_SHARING_MODE_EXCLUSIVE,
1033 return vk::createBuffer(vkd, device, &bufferParams);
1036 TriangleRenderer::TriangleRenderer (const DeviceInterface& vkd,
1037 const VkDevice device,
1038 Allocator& allocator,
1039 const BinaryCollection& binaryRegistry,
1040 const vector<VkImage> swapchainImages,
1041 const VkFormat framebufferFormat,
1042 const UVec2& renderSize)
1044 , m_swapchainImages (swapchainImages)
1045 , m_renderSize (renderSize)
1046 , m_renderPass (createRenderPass(vkd, device, framebufferFormat))
1047 , m_pipelineLayout (createPipelineLayout(vkd, device))
1048 , m_pipeline (createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
1049 , m_vertexBuffer (createBuffer(vkd, device, (VkDeviceSize)(sizeof(float)*4*3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
1050 , m_vertexBufferMemory (allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer),
1051 MemoryRequirement::HostVisible))
1053 m_attachmentViews.resize(swapchainImages.size());
1054 m_framebuffers.resize(swapchainImages.size());
1056 for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
1058 m_attachmentViews[imageNdx] = ImageViewSp(new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
1059 m_framebuffers[imageNdx] = FramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
1062 VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset()));
1065 const VkMappedMemoryRange memRange =
1067 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
1069 m_vertexBufferMemory->getMemory(),
1070 m_vertexBufferMemory->getOffset(),
1073 const tcu::Vec4 vertices[] =
1075 tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
1076 tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
1077 tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
1079 DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
1081 deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
1082 VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
1086 TriangleRenderer::~TriangleRenderer (void)
1090 void TriangleRenderer::recordFrame (VkCommandBuffer cmdBuffer,
1092 deUint32 frameNdx) const
1094 const VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
1096 beginCommandBuffer(m_vkd, cmdBuffer, 0u);
1098 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));
1100 m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1103 const VkDeviceSize bindingOffset = 0;
1104 m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
1107 m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
1108 m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1109 endRenderPass(m_vkd, cmdBuffer);
1111 endCommandBuffer(m_vkd, cmdBuffer);
1114 void TriangleRenderer::getPrograms (SourceCollections& dst)
1116 dst.glslSources.add("tri-vert") << glu::VertexSource(
1118 "layout(location = 0) in highp vec4 a_position;\n"
1119 "layout(push_constant) uniform FrameData\n"
1121 " highp uint frameNdx;\n"
1123 "void main (void)\n"
1125 " highp float angle = float(frameData.frameNdx) / 100.0;\n"
1126 " highp float c = cos(angle);\n"
1127 " highp float s = sin(angle);\n"
1128 " highp mat4 t = mat4( c, -s, 0, 0,\n"
1132 " gl_Position = t * a_position;\n"
1134 dst.glslSources.add("tri-frag") << glu::FragmentSource(
1136 "layout(location = 0) out lowp vec4 o_color;\n"
1137 "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1140 typedef de::SharedPtr<Unique<VkCommandBuffer> > CommandBufferSp;
1141 typedef de::SharedPtr<Unique<VkFence> > FenceSp;
1142 typedef de::SharedPtr<Unique<VkSemaphore> > SemaphoreSp;
1144 vector<FenceSp> createFences (const DeviceInterface& vkd,
1145 const VkDevice device,
1148 vector<FenceSp> fences(numFences);
1150 for (size_t ndx = 0; ndx < numFences; ++ndx)
1151 fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
1156 vector<SemaphoreSp> createSemaphores (const DeviceInterface& vkd,
1157 const VkDevice device,
1158 size_t numSemaphores)
1160 vector<SemaphoreSp> semaphores(numSemaphores);
1162 for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1163 semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
1168 vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface& vkd,
1169 const VkDevice device,
1170 const VkCommandPool commandPool,
1171 const VkCommandBufferLevel level,
1172 const size_t numCommandBuffers)
1174 vector<CommandBufferSp> buffers (numCommandBuffers);
1176 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1177 buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1182 tcu::TestStatus basicRenderTest (Context& context, Type wsiType)
1184 const tcu::UVec2 desiredSize (256, 256);
1185 const InstanceHelper instHelper (context, wsiType);
1186 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1187 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1188 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
1189 const DeviceInterface& vkd = devHelper.vkd;
1190 const VkDevice device = *devHelper.device;
1191 SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1192 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1193 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
1194 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
1196 const TriangleRenderer renderer (vkd,
1199 context.getBinaryCollection(),
1201 swapchainInfo.imageFormat,
1202 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1204 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1206 const size_t maxQueuedFrames = swapchainImages.size()*2;
1208 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1209 // limit number of frames we allow to be queued.
1210 const vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
1212 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1213 // the semaphore in same time as the fence we use to meter rendering.
1214 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
1216 // For rest we simply need maxQueuedFrames as we will wait for image
1217 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1218 // previous uses must have completed.
1219 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
1220 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1224 const deUint32 numFramesToRender = 60*10;
1226 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1228 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
1229 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1230 deUint32 imageNdx = ~0u;
1232 if (frameNdx >= maxQueuedFrames)
1233 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1235 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1238 const VkResult acquireResult = vkd.acquireNextImageKHR(device,
1240 std::numeric_limits<deUint64>::max(),
1241 imageReadySemaphore,
1245 if (acquireResult == VK_SUBOPTIMAL_KHR)
1246 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1248 VK_CHECK(acquireResult);
1251 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1254 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1255 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
1256 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1257 const VkSubmitInfo submitInfo =
1259 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1262 &imageReadySemaphore,
1267 &renderingCompleteSemaphore
1269 const VkPresentInfoKHR presentInfo =
1271 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1274 &renderingCompleteSemaphore,
1281 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1282 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
1283 VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1287 VK_CHECK(vkd.deviceWaitIdle(device));
1291 // Make sure device is idle before destroying resources
1292 vkd.deviceWaitIdle(device);
1296 return tcu::TestStatus::pass("Rendering tests succeeded");
1299 vector<tcu::UVec2> getSwapchainSizeSequence (const VkSurfaceCapabilitiesKHR& capabilities, const tcu::UVec2& defaultSize)
1301 vector<tcu::UVec2> sizes(3);
1302 sizes[0] = defaultSize / 2u;
1303 sizes[1] = defaultSize;
1304 sizes[2] = defaultSize * 2u;
1306 for (deUint32 i = 0; i < sizes.size(); ++i)
1308 sizes[i].x() = de::clamp(sizes[i].x(), capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
1309 sizes[i].y() = de::clamp(sizes[i].y(), capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
1315 tcu::TestStatus resizeSwapchainTest (Context& context, Type wsiType)
1317 const tcu::UVec2 desiredSize (256, 256);
1318 const InstanceHelper instHelper (context, wsiType);
1319 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1320 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1321 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
1322 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
1323 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
1324 const DeviceInterface& vkd = devHelper.vkd;
1325 const VkDevice device = *devHelper.device;
1326 SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1327 vector<tcu::UVec2> sizes = getSwapchainSizeSequence(capabilities, desiredSize);
1328 Move<VkSwapchainKHR> prevSwapchain;
1330 DE_ASSERT(platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE);
1331 DE_UNREF(platformProperties);
1333 for (deUint32 sizeNdx = 0; sizeNdx < sizes.size(); ++sizeNdx)
1335 // \todo [2016-05-30 jesse] This test currently waits for idle and
1336 // recreates way more than necessary when recreating the swapchain. Make
1337 // it match expected real app behavior better by smoothly switching from
1338 // old to new swapchain. Once that is done, it will also be possible to
1339 // test creating a new swapchain while images from the previous one are
1342 VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, sizes[sizeNdx], 2);
1343 swapchainInfo.oldSwapchain = *prevSwapchain;
1345 Move<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
1346 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
1347 const TriangleRenderer renderer (vkd,
1350 context.getBinaryCollection(),
1352 swapchainInfo.imageFormat,
1353 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1354 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1355 const size_t maxQueuedFrames = swapchainImages.size()*2;
1357 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1358 // limit number of frames we allow to be queued.
1359 const vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
1361 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1362 // the semaphore in same time as the fence we use to meter rendering.
1363 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
1365 // For rest we simply need maxQueuedFrames as we will wait for image
1366 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1367 // previous uses must have completed.
1368 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
1369 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1373 const deUint32 numFramesToRender = 60;
1375 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1377 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
1378 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1379 deUint32 imageNdx = ~0u;
1381 if (frameNdx >= maxQueuedFrames)
1382 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1384 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1387 const VkResult acquireResult = vkd.acquireNextImageKHR(device,
1389 std::numeric_limits<deUint64>::max(),
1390 imageReadySemaphore,
1394 if (acquireResult == VK_SUBOPTIMAL_KHR)
1395 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1397 VK_CHECK(acquireResult);
1400 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1403 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1404 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
1405 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1406 const VkSubmitInfo submitInfo =
1408 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1411 &imageReadySemaphore,
1416 &renderingCompleteSemaphore
1418 const VkPresentInfoKHR presentInfo =
1420 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1423 &renderingCompleteSemaphore,
1430 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1431 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, (VkFence)0));
1432 VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1436 VK_CHECK(vkd.deviceWaitIdle(device));
1438 prevSwapchain = swapchain;
1442 // Make sure device is idle before destroying resources
1443 vkd.deviceWaitIdle(device);
1448 return tcu::TestStatus::pass("Resizing tests succeeded");
1451 tcu::TestStatus getImagesIncompleteResultTest (Context& context, Type wsiType)
1453 const tcu::UVec2 desiredSize (256, 256);
1454 const InstanceHelper instHelper (context, wsiType);
1455 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1456 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1457 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
1458 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1459 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
1461 vector<VkImage> swapchainImages = getSwapchainImages(devHelper.vkd, *devHelper.device, *swapchain);
1463 ValidateQueryBits::fillBits(swapchainImages.begin(), swapchainImages.end());
1465 const deUint32 usedCount = static_cast<deUint32>(swapchainImages.size() / 2);
1466 deUint32 count = usedCount;
1467 const VkResult result = devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &count, &swapchainImages[0]);
1469 if (count != usedCount || result != VK_INCOMPLETE || !ValidateQueryBits::checkBits(swapchainImages.begin() + count, swapchainImages.end()))
1470 return tcu::TestStatus::fail("Get swapchain images didn't return VK_INCOMPLETE");
1472 return tcu::TestStatus::pass("Get swapchain images tests succeeded");
1475 tcu::TestStatus destroyNullHandleSwapchainTest (Context& context, Type wsiType)
1477 const InstanceHelper instHelper (context, wsiType);
1478 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
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 VkSwapchainKHR nullHandle = DE_NULL;
1483 // Default allocator
1484 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, DE_NULL);
1488 AllocationCallbackRecorder recordingAllocator (getSystemAllocator(), 1u);
1490 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, recordingAllocator.getCallbacks());
1492 if (recordingAllocator.getNumRecords() != 0u)
1493 return tcu::TestStatus::fail("Implementation allocated/freed the memory");
1496 return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
1499 void getBasicRenderPrograms (SourceCollections& dst, Type)
1501 TriangleRenderer::getPrograms(dst);
1504 void populateRenderGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1506 addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
1509 void populateGetImagesGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1511 addFunctionCase(testGroup, "incomplete", "Test VK_INCOMPLETE return code", getImagesIncompleteResultTest, wsiType);
1514 void populateModifyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1516 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
1518 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
1520 addFunctionCaseWithPrograms(testGroup, "resize", "Resize Swapchain Test", getBasicRenderPrograms, resizeSwapchainTest, wsiType);
1523 // \todo [2016-05-30 jesse] Add tests for modifying preTransform, compositeAlpha, presentMode
1526 void populateDestroyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1528 addFunctionCase(testGroup, "null_handle", "Destroying a VK_NULL_HANDLE swapchain", destroyNullHandleSwapchainTest, wsiType);
1533 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1535 addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
1536 addTestGroup(testGroup, "simulate_oom", "Simulate OOM using callbacks during swapchain construction", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainSimulateOOMTest));
1537 addTestGroup(testGroup, "render", "Rendering Tests", populateRenderGroup, wsiType);
1538 addTestGroup(testGroup, "modify", "Modify VkSwapchain", populateModifyGroup, wsiType);
1539 addTestGroup(testGroup, "destroy", "Destroy VkSwapchain", populateDestroyGroup, wsiType);
1540 addTestGroup(testGroup, "get_images", "Get swapchain images", populateGetImagesGroup, wsiType);