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"
28 #include "vktCustomInstancesDevices.hpp"
29 #include "vktNativeObjectsUtil.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkStrUtil.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkMemUtil.hpp"
38 #include "vkDeviceUtil.hpp"
39 #include "vkPrograms.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkWsiPlatform.hpp"
42 #include "vkWsiUtil.hpp"
43 #include "vkAllocationCallbackUtil.hpp"
44 #include "vkCmdUtil.hpp"
45 #include "vkObjTypeImpl.inl"
46 #include "vkObjUtil.hpp"
48 #include "tcuCommandLine.hpp"
49 #include "tcuTestLog.hpp"
50 #include "tcuFormatUtil.hpp"
51 #include "tcuPlatform.hpp"
52 #include "tcuResultCollector.hpp"
54 #include "deUniquePtr.hpp"
55 #include "deStringUtil.hpp"
56 #include "deArrayUtil.hpp"
57 #include "deSharedPtr.hpp"
72 using namespace vk::wsi;
85 typedef vector<VkExtensionProperties> Extensions;
87 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
89 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
90 requiredExtName != requiredExtensions.end();
93 if (!isExtensionSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
94 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
98 CustomInstance createInstanceWithWsi (Context& context,
99 const Extensions& supportedExtensions,
101 const vector<string> extraExtensions,
102 const VkAllocationCallbacks* pAllocator = DE_NULL)
104 vector<string> extensions = extraExtensions;
106 extensions.push_back("VK_KHR_surface");
107 extensions.push_back(getExtensionName(wsiType));
109 // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
110 // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
111 // but using them without enabling the extension is not allowed. Thus we have
114 // 1) Filter out non-core formats to stay within valid usage.
116 // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
118 // We opt for (2) as it provides basic coverage for the extension as a bonus.
119 if (isExtensionSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
120 extensions.push_back("VK_EXT_swapchain_colorspace");
122 checkAllSupported(supportedExtensions, extensions);
124 return vkt::createCustomInstanceWithExtensions(context, extensions, pAllocator);
127 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
129 VkPhysicalDeviceFeatures features;
130 deMemset(&features, 0, sizeof(features));
134 Move<VkDevice> createDeviceWithWsi (const PlatformInterface& vkp,
137 const InstanceInterface& vki,
138 VkPhysicalDevice physicalDevice,
139 const Extensions& supportedExtensions,
140 const vector<string>& additionalExtensions,
141 const vector<deUint32>& queueFamilyIndices,
142 bool validationEnabled,
143 const VkAllocationCallbacks* pAllocator = DE_NULL)
145 const float queuePriorities[] = { 1.0f };
146 vector<VkDeviceQueueCreateInfo> queueInfos;
148 for (const auto familyIndex : queueFamilyIndices)
150 const VkDeviceQueueCreateInfo info =
152 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
154 (VkDeviceQueueCreateFlags)0,
156 DE_LENGTH_OF_ARRAY(queuePriorities),
160 queueInfos.push_back(info);
163 vector<string> extensions;
164 extensions.push_back("VK_KHR_swapchain");
165 extensions.insert(end(extensions), begin(additionalExtensions), end(additionalExtensions));
167 for (const auto& extName : extensions)
169 if (!isCoreDeviceExtension(apiVersion, extName) && !isExtensionSupported(supportedExtensions, RequiredExtension(extName)))
170 TCU_THROW(NotSupportedError, extName + " is not supported");
173 const void * pNext = nullptr;
174 const VkPhysicalDeviceFeatures features = getDeviceFeaturesForWsi();
176 VkDevicePrivateDataCreateInfoEXT pdci = initVulkanStructure();
177 pdci.privateDataSlotRequestCount = 4u;
179 VkPhysicalDevicePrivateDataFeaturesEXT privateDataFeatures = initVulkanStructure(&pdci);
180 privateDataFeatures.privateData = VK_TRUE;
182 if (de::contains(begin(extensions), end(extensions), "VK_EXT_private_data"))
184 pNext = &privateDataFeatures;
187 // Convert from std::vector<std::string> to std::vector<const char*>.
188 std::vector<const char*> extensionsChar;
189 extensionsChar.reserve(extensions.size());
190 std::transform(begin(extensions), end(extensions), std::back_inserter(extensionsChar), [](const std::string& s) { return s.c_str(); });
192 const VkDeviceCreateInfo deviceParams =
194 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
196 (VkDeviceCreateFlags)0,
197 static_cast<deUint32>(queueInfos.size()),
199 0u, // enabledLayerCount
200 nullptr, // ppEnabledLayerNames
201 static_cast<deUint32>(extensionsChar.size()), // enabledExtensionCount
202 extensionsChar.data(), // ppEnabledExtensionNames
206 return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
209 Move<VkDevice> createDeviceWithWsi (const PlatformInterface& vkp,
212 const InstanceInterface& vki,
213 VkPhysicalDevice physicalDevice,
214 const Extensions& supportedExtensions,
215 const vector<string>& additionalExtensions,
216 const deUint32 queueFamilyIndex,
217 bool validationEnabled,
218 const VkAllocationCallbacks* pAllocator = DE_NULL)
220 return createDeviceWithWsi(vkp, apiVersion, instance, vki, physicalDevice, supportedExtensions, additionalExtensions, vector<deUint32>(1u, queueFamilyIndex), validationEnabled, pAllocator);
223 struct InstanceHelper
225 const vector<VkExtensionProperties> supportedExtensions;
226 const CustomInstance instance;
227 const InstanceDriver& vki;
229 InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
230 : supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
232 , instance (createInstanceWithWsi(context,
237 , vki (instance.getDriver())
240 InstanceHelper (Context& context, Type wsiType, const vector<string>& extensions, const VkAllocationCallbacks* pAllocator = DE_NULL)
241 : supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
243 , instance (createInstanceWithWsi(context,
248 , vki (instance.getDriver())
254 const VkPhysicalDevice physicalDevice;
255 const deUint32 queueFamilyIndex;
256 const Unique<VkDevice> device;
257 const DeviceDriver vkd;
260 DeviceHelper (Context& context,
261 const InstanceInterface& vki,
263 const vector<VkSurfaceKHR>& surface,
264 const vector<string>& additionalExtensions = vector<string>(),
265 const VkAllocationCallbacks* pAllocator = DE_NULL)
266 : physicalDevice (chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
267 , queueFamilyIndex (chooseQueueFamilyIndex(vki, physicalDevice, surface))
268 , device (createDeviceWithWsi(context.getPlatformInterface(),
269 context.getUsedApiVersion(),
273 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
274 additionalExtensions,
276 context.getTestContext().getCommandLine().isValidationEnabled(),
278 , vkd (context.getPlatformInterface(), instance, *device)
279 , queue (getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
283 // Single-surface shortcut.
284 DeviceHelper (Context& context,
285 const InstanceInterface& vki,
287 VkSurfaceKHR surface,
288 const vector<string>& additionalExtensions = vector<string>(),
289 const VkAllocationCallbacks* pAllocator = DE_NULL)
290 : DeviceHelper(context, vki, instance, vector<VkSurfaceKHR>(1u, surface), additionalExtensions, pAllocator)
295 // Similar to the one above with no queues and multiple queue families.
296 struct MultiQueueDeviceHelper
298 const VkPhysicalDevice physicalDevice;
299 const vector<deUint32> queueFamilyIndices;
300 const Unique<VkDevice> device;
301 const DeviceDriver vkd;
303 MultiQueueDeviceHelper (Context& context,
304 const InstanceInterface& vki,
306 const vector<VkSurfaceKHR>& surface,
307 const vector<string>& additionalExtensions = vector<string>(),
308 const VkAllocationCallbacks* pAllocator = DE_NULL)
309 : physicalDevice (chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
310 , queueFamilyIndices(getCompatibleQueueFamilyIndices(vki, physicalDevice, surface))
311 , device (createDeviceWithWsi(context.getPlatformInterface(),
312 context.getUsedApiVersion(),
316 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
317 additionalExtensions,
319 context.getTestContext().getCommandLine().isValidationEnabled(),
321 , vkd (context.getPlatformInterface(), instance, *device)
325 // Single-surface shortcut.
326 MultiQueueDeviceHelper (Context& context,
327 const InstanceInterface& vki,
329 VkSurfaceKHR surface,
330 const vector<string> additionalExtensions = vector<string>(),
331 const VkAllocationCallbacks* pAllocator = DE_NULL)
332 : MultiQueueDeviceHelper(context, vki, instance, vector<VkSurfaceKHR>(1u, surface), additionalExtensions, pAllocator)
339 TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
340 TEST_DIMENSION_IMAGE_FORMAT, //!< Test all supported formats
341 TEST_DIMENSION_IMAGE_EXTENT, //!< Test various (supported) extents
342 TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
343 TEST_DIMENSION_IMAGE_USAGE,
344 TEST_DIMENSION_IMAGE_SHARING_MODE,
345 TEST_DIMENSION_PRE_TRANSFORM,
346 TEST_DIMENSION_COMPOSITE_ALPHA,
347 TEST_DIMENSION_PRESENT_MODE,
348 TEST_DIMENSION_CLIPPED,
353 const char* getTestDimensionName (TestDimension dimension)
355 static const char* const s_names[] =
360 "image_array_layers",
362 "image_sharing_mode",
368 return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
371 struct TestParameters
374 TestDimension dimension;
376 TestParameters (Type wsiType_, TestDimension dimension_)
378 , dimension (dimension_)
381 TestParameters (void)
382 : wsiType (TYPE_LAST)
383 , dimension (TEST_DIMENSION_LAST)
387 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (const InstanceInterface& vki,
388 VkPhysicalDevice physicalDevice,
390 TestDimension dimension,
391 const VkSurfaceCapabilitiesKHR& capabilities,
392 const vector<VkSurfaceFormatKHR>& formats,
393 const vector<VkPresentModeKHR>& presentModes)
395 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
396 vector<VkSwapchainCreateInfoKHR> cases;
397 const VkSurfaceTransformFlagBitsKHR defaultTransform = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
398 const VkSwapchainCreateInfoKHR baseParameters =
400 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
402 (VkSwapchainCreateFlagsKHR)0,
404 capabilities.minImageCount,
406 formats[0].colorSpace,
407 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
408 ? capabilities.minImageExtent : capabilities.currentExtent),
409 1u, // imageArrayLayers
410 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
411 VK_SHARING_MODE_EXCLUSIVE,
413 (const deUint32*)DE_NULL,
415 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
416 VK_PRESENT_MODE_FIFO_KHR,
418 (VkSwapchainKHR)0 // oldSwapchain
423 case TEST_DIMENSION_MIN_IMAGE_COUNT:
425 const deUint32 maxImageCountToTest = de::clamp(16u, capabilities.minImageCount, (capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u);
427 for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
429 cases.push_back(baseParameters);
430 cases.back().minImageCount = imageCount;
436 case TEST_DIMENSION_IMAGE_FORMAT:
438 for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
440 cases.push_back(baseParameters);
441 cases.back().imageFormat = curFmt->format;
442 cases.back().imageColorSpace = curFmt->colorSpace;
448 case TEST_DIMENSION_IMAGE_EXTENT:
450 static const VkExtent2D s_testSizes[] =
459 if (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
460 platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
462 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
464 cases.push_back(baseParameters);
465 cases.back().imageExtent.width = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
466 cases.back().imageExtent.height = de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
470 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
472 cases.push_back(baseParameters);
473 cases.back().imageExtent = capabilities.currentExtent;
476 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
478 cases.push_back(baseParameters);
479 cases.back().imageExtent = capabilities.minImageExtent;
481 cases.push_back(baseParameters);
482 cases.back().imageExtent = capabilities.maxImageExtent;
488 case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
490 const deUint32 maxLayers = de::min(capabilities.maxImageArrayLayers, 16u);
492 for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
494 cases.push_back(baseParameters);
495 cases.back().imageArrayLayers = numLayers;
501 case TEST_DIMENSION_IMAGE_USAGE:
503 for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
505 VkImageFormatProperties imageProps;
507 if (vki.getPhysicalDeviceImageFormatProperties(physicalDevice,
508 baseParameters.imageFormat,
510 VK_IMAGE_TILING_OPTIMAL,
512 (VkImageCreateFlags)0u,
513 &imageProps) != VK_SUCCESS)
516 if ((flags & ~capabilities.supportedUsageFlags) == 0)
518 cases.push_back(baseParameters);
519 cases.back().imageUsage = flags;
526 case TEST_DIMENSION_IMAGE_SHARING_MODE:
529 // Skipping since this matches the base parameters.
530 cases.push_back(baseParameters);
531 cases.back().imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
534 cases.push_back(baseParameters);
535 cases.back().imageSharingMode = VK_SHARING_MODE_CONCURRENT;
540 case TEST_DIMENSION_PRE_TRANSFORM:
542 for (deUint32 transform = 1u;
543 transform <= capabilities.supportedTransforms;
544 transform = transform<<1u)
546 if ((transform & capabilities.supportedTransforms) != 0)
548 cases.push_back(baseParameters);
549 cases.back().preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
556 case TEST_DIMENSION_COMPOSITE_ALPHA:
558 for (deUint32 alphaMode = 1u;
559 alphaMode <= capabilities.supportedCompositeAlpha;
560 alphaMode = alphaMode<<1u)
562 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
564 cases.push_back(baseParameters);
565 cases.back().compositeAlpha = (VkCompositeAlphaFlagBitsKHR)alphaMode;
572 case TEST_DIMENSION_PRESENT_MODE:
574 for (vector<VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
576 cases.push_back(baseParameters);
577 cases.back().presentMode = *curMode;
583 case TEST_DIMENSION_CLIPPED:
585 cases.push_back(baseParameters);
586 cases.back().clipped = VK_FALSE;
588 cases.push_back(baseParameters);
589 cases.back().clipped = VK_TRUE;
595 DE_FATAL("Impossible");
598 DE_ASSERT(!cases.empty());
602 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type wsiType,
603 TestDimension dimension,
604 const InstanceInterface& vki,
605 VkPhysicalDevice physicalDevice,
606 VkSurfaceKHR surface)
608 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki,
611 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(vki,
614 const vector<VkPresentModeKHR> presentModes = getPhysicalDeviceSurfacePresentModes(vki,
618 return generateSwapchainParameterCases(vki, physicalDevice, wsiType, dimension, capabilities, formats, presentModes);
621 tcu::TestStatus createSwapchainTest (Context& context, TestParameters params)
623 tcu::TestLog& log = context.getTestContext().getLog();
624 const InstanceHelper instHelper (context, params.wsiType);
625 const NativeObjects native (context, instHelper.supportedExtensions, params.wsiType);
626 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, params.wsiType, native.getDisplay(), native.getWindow()));
627 const MultiQueueDeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
628 const vector<VkSwapchainCreateInfoKHR> cases (generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
629 const VkSurfaceCapabilitiesKHR capabilities(getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface));
631 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
633 std::ostringstream subcase;
634 subcase << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": ";
636 VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
638 if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
640 const deUint32 numFamilies = static_cast<deUint32>(devHelper.queueFamilyIndices.size());
641 if (numFamilies < 2u)
642 TCU_THROW(NotSupportedError, "Only " + de::toString(numFamilies) + " queue families available for VK_SHARING_MODE_CONCURRENT");
643 curParams.queueFamilyIndexCount = numFamilies;
647 // Take only the first queue.
648 if (devHelper.queueFamilyIndices.empty())
649 TCU_THROW(NotSupportedError, "No queue families compatible with the given surface");
650 curParams.queueFamilyIndexCount = 1u;
652 curParams.pQueueFamilyIndices = devHelper.queueFamilyIndices.data();
653 curParams.surface = *surface;
655 log << TestLog::Message << subcase.str() << curParams << TestLog::EndMessage;
657 // The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
659 // * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
660 // VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
661 VkImageFormatProperties properties;
662 const VkResult propertiesResult = instHelper.vki.getPhysicalDeviceImageFormatProperties(devHelper.physicalDevice,
663 curParams.imageFormat,
665 VK_IMAGE_TILING_OPTIMAL,
666 curParams.imageUsage,
670 log << TestLog::Message << subcase.str()
671 << "vkGetPhysicalDeviceImageFormatProperties => "
672 << getResultStr(propertiesResult) << TestLog::EndMessage;
674 switch (propertiesResult) {
677 // The maxExtents case might not be able to create the requested surface due to insufficient
678 // memory, so in this case *only* we handle the OOM exception.
679 if (params.dimension == TEST_DIMENSION_IMAGE_EXTENT &&
680 capabilities.maxImageExtent.width == curParams.imageExtent.width &&
681 capabilities.maxImageExtent.height == curParams.imageExtent.height)
685 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
687 log << TestLog::Message << subcase.str()
688 << "Creating swapchain succeeded" << TestLog::EndMessage;
690 catch (const OutOfMemoryError& e)
692 log << TestLog::Message << subcase.str() << "vkCreateSwapchainKHR with maxImageExtent encountered " << e.getError() << TestLog::EndMessage;
697 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
699 log << TestLog::Message << subcase.str()
700 << "Creating swapchain succeeded" << TestLog::EndMessage;
704 case VK_ERROR_FORMAT_NOT_SUPPORTED:
705 log << TestLog::Message << subcase.str()
706 << "Skip because vkGetPhysicalDeviceImageFormatProperties returned VK_ERROR_FORMAT_NOT_SUPPORTED" << TestLog::EndMessage;
709 log << TestLog::Message << subcase.str()
710 << "Fail because vkGetPhysicalDeviceImageFormatProperties returned "
711 << getResultStr(propertiesResult) << TestLog::EndMessage;
712 return tcu::TestStatus::fail("Unexpected result from vkGetPhysicalDeviceImageFormatProperties");
716 return tcu::TestStatus::pass("No sub-case failed");
719 template<typename T> static deUint64 HandleToInt(T t) { return t.getInternal(); }
721 tcu::TestStatus createSwapchainPrivateDataTest (Context& context, TestParameters params)
723 if (!context.getPrivateDataFeaturesEXT().privateData)
724 TCU_THROW(NotSupportedError, "privateData not supported");
726 tcu::TestLog& log = context.getTestContext().getLog();
727 const InstanceHelper instHelper (context, params.wsiType);
728 const NativeObjects native (context, instHelper.supportedExtensions, params.wsiType);
729 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, params.wsiType, native.getDisplay(), native.getWindow()));
730 const vector<string> extraExts (1u, "VK_EXT_private_data");
731 const MultiQueueDeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface, extraExts);
732 const vector<VkSwapchainCreateInfoKHR> cases (generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
734 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
736 std::ostringstream subcase;
737 subcase << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": ";
739 VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
741 if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
743 const deUint32 numFamilies = static_cast<deUint32>(devHelper.queueFamilyIndices.size());
744 if (numFamilies < 2u)
745 TCU_THROW(NotSupportedError, "Only " + de::toString(numFamilies) + " queue families available for VK_SHARING_MODE_CONCURRENT");
746 curParams.queueFamilyIndexCount = numFamilies;
750 // Take only the first queue.
751 if (devHelper.queueFamilyIndices.empty())
752 TCU_THROW(NotSupportedError, "No queue families compatible with the given surface");
753 curParams.queueFamilyIndexCount = 1u;
755 curParams.pQueueFamilyIndices = devHelper.queueFamilyIndices.data();
756 curParams.surface = *surface;
758 log << TestLog::Message << subcase.str() << curParams << TestLog::EndMessage;
760 // The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
762 // * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
763 // VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
764 VkImageFormatProperties properties;
765 const VkResult propertiesResult = instHelper.vki.getPhysicalDeviceImageFormatProperties(devHelper.physicalDevice,
766 curParams.imageFormat,
768 VK_IMAGE_TILING_OPTIMAL,
769 curParams.imageUsage,
773 log << TestLog::Message << subcase.str()
774 << "vkGetPhysicalDeviceImageFormatProperties => "
775 << getResultStr(propertiesResult) << TestLog::EndMessage;
777 switch (propertiesResult) {
780 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
782 const int numSlots = 100;
783 typedef Unique<VkPrivateDataSlotEXT> PrivateDataSlotUp;
784 typedef SharedPtr<PrivateDataSlotUp> PrivateDataSlotSp;
785 vector<PrivateDataSlotSp> slots;
787 const VkPrivateDataSlotCreateInfoEXT createInfo =
789 VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT, // VkStructureType sType;
790 DE_NULL, // const void* pNext;
791 0u, // VkPrivateDataSlotCreateFlagsEXT flags;
794 for (int i = 0; i < numSlots; ++i)
796 Move<VkPrivateDataSlotEXT> s = createPrivateDataSlotEXT(devHelper.vkd, *devHelper.device, &createInfo, DE_NULL);
797 slots.push_back(PrivateDataSlotSp(new PrivateDataSlotUp(s)));
800 // Based on code in vktApiObjectManagementTests.cpp
801 for (int r = 0; r < 3; ++r)
805 for (int i = 0; i < numSlots; ++i)
808 devHelper.vkd.getPrivateDataEXT(*devHelper.device, getObjectType<VkSwapchainKHR>(), HandleToInt(swapchain.get()), **slots[i], &data);
809 // Don't test default value of zero on Android, due to spec erratum
810 if (params.wsiType != TYPE_ANDROID)
813 return tcu::TestStatus::fail("Expected initial value of zero");
817 for (int i = 0; i < numSlots; ++i)
818 VK_CHECK(devHelper.vkd.setPrivateDataEXT(*devHelper.device, getObjectType<VkSwapchainKHR>(), HandleToInt(swapchain.get()), **slots[i], i*i*i + 1));
820 for (int i = 0; i < numSlots; ++i)
823 devHelper.vkd.getPrivateDataEXT(*devHelper.device, getObjectType<VkSwapchainKHR>(), HandleToInt(swapchain.get()), **slots[i], &data);
824 if (data != (deUint64)(i*i*i + 1))
825 return tcu::TestStatus::fail("Didn't read back set value");
828 // Destroy and realloc slots for the next iteration
830 for (int i = 0; i < numSlots; ++i)
832 Move<VkPrivateDataSlotEXT> s = createPrivateDataSlotEXT(devHelper.vkd, *devHelper.device, &createInfo, DE_NULL);
833 slots.push_back(PrivateDataSlotSp(new PrivateDataSlotUp(s)));
840 case VK_ERROR_FORMAT_NOT_SUPPORTED:
841 log << TestLog::Message << subcase.str()
842 << "Skip because vkGetPhysicalDeviceImageFormatProperties returned VK_ERROR_FORMAT_NOT_SUPPORTED" << TestLog::EndMessage;
845 log << TestLog::Message << subcase.str()
846 << "Fail because vkGetPhysicalDeviceImageFormatProperties returned "
847 << getResultStr(propertiesResult) << TestLog::EndMessage;
848 return tcu::TestStatus::fail("Unexpected result from vkGetPhysicalDeviceImageFormatProperties");
852 return tcu::TestStatus::pass("No sub-case failed");
855 tcu::TestStatus createSwapchainSimulateOOMTest (Context& context, TestParameters params)
857 const size_t maxCases = 300u;
858 const deUint32 maxAllocs = 1024u;
860 tcu::TestLog& log = context.getTestContext().getLog();
861 tcu::ResultCollector results (log);
863 AllocationCallbackRecorder allocationRecorder (getSystemAllocator());
864 DeterministicFailAllocator failingAllocator (allocationRecorder.getCallbacks(),
865 DeterministicFailAllocator::MODE_DO_NOT_COUNT,
868 const InstanceHelper instHelper (context, params.wsiType, failingAllocator.getCallbacks());
869 const NativeObjects native (context, instHelper.supportedExtensions, params.wsiType);
870 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
875 failingAllocator.getCallbacks()));
876 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface, vector<string>(), failingAllocator.getCallbacks());
877 const vector<VkSwapchainCreateInfoKHR> allCases (generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
878 const VkSurfaceCapabilitiesKHR capabilities(getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface));
880 if (maxCases < allCases.size())
881 log << TestLog::Message << "Note: Will only test first " << maxCases << " cases out of total of " << allCases.size() << " parameter combinations" << TestLog::EndMessage;
883 for (size_t caseNdx = 0; caseNdx < de::min(maxCases, allCases.size()); ++caseNdx)
885 log << TestLog::Message << "Testing parameter case " << caseNdx << ": " << allCases[caseNdx] << TestLog::EndMessage;
887 for (deUint32 numPassingAllocs = 0; numPassingAllocs <= maxAllocs; ++numPassingAllocs)
890 VkSwapchainCreateInfoKHR curParams = allCases[caseNdx];
891 curParams.surface = *surface;
892 curParams.queueFamilyIndexCount = 1u;
893 curParams.pQueueFamilyIndices = &devHelper.queueFamilyIndex;
895 failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
897 log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
901 // With concurrent sharing mode, at least two queues are needed.
902 if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
905 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
907 catch (const OutOfMemoryError& e)
909 log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
915 log << TestLog::Message << "Creating swapchain succeeded!" << TestLog::EndMessage;
917 if (numPassingAllocs == 0)
918 results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
922 else if (numPassingAllocs == maxAllocs)
924 // The maxExtents case might not be able to create the requested surface due to insufficient
925 // memory, so in this case *only* we allow the OOM exception upto maxAllocs.
926 if (params.dimension == TEST_DIMENSION_IMAGE_EXTENT &&
927 capabilities.maxImageExtent.width == curParams.imageExtent.width &&
928 capabilities.maxImageExtent.height == curParams.imageExtent.height)
931 results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
935 context.getTestContext().touchWatchdog();
939 if (!validateAndLog(log, allocationRecorder, 0u))
940 results.fail("Detected invalid system allocation callback");
942 return tcu::TestStatus(results.getResult(), results.getMessage());
945 tcu::TestStatus testImageSwapchainCreateInfo (Context& context, Type wsiType)
947 const tcu::UVec2 desiredSize (256, 256);
948 const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
949 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
950 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
954 native.getWindow()));
955 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface, vector<string>(1u, "VK_KHR_bind_memory2"));
956 const Extensions& deviceExtensions = enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL);
958 // structures this tests checks were added in revision 69
959 if (!isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_swapchain", 69)))
960 TCU_THROW(NotSupportedError, "Required extension revision is not supported");
962 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki,
963 devHelper.physicalDevice,
965 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
966 devHelper.physicalDevice,
968 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
969 const VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
970 const deUint32 desiredImageCount = 2;
971 const VkSwapchainCreateInfoKHR swapchainInfo =
973 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
975 (VkSwapchainCreateFlagsKHR)0,
977 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
979 formats[0].colorSpace,
980 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
981 ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
983 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
984 VK_SHARING_MODE_EXCLUSIVE,
986 (const deUint32*)DE_NULL,
988 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
989 VK_PRESENT_MODE_FIFO_KHR,
991 (VkSwapchainKHR)0 // oldSwapchain
994 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
995 deUint32 numImages = 0;
996 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
998 return tcu::TestStatus::pass("Pass");
1000 VkImageSwapchainCreateInfoKHR imageSwapchainCreateInfo =
1002 VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
1007 VkImageCreateInfo imageCreateInfo =
1009 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1010 &imageSwapchainCreateInfo,
1011 (VkImageCreateFlags)0u, // flags
1012 VK_IMAGE_TYPE_2D, // imageType
1013 formats[0].format, // format
1015 desiredSize.x(), // width
1016 desiredSize.y(), // height
1021 VK_SAMPLE_COUNT_1_BIT, // samples
1022 VK_IMAGE_TILING_OPTIMAL, // tiling
1023 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // usage
1024 VK_SHARING_MODE_EXCLUSIVE, // sharingMode
1025 0u, // queueFamilyIndexCount
1026 DE_NULL, // pQueueFamilyIndices
1027 VK_IMAGE_LAYOUT_UNDEFINED // initialLayout
1030 typedef vk::Unique<VkImage> UniqueImage;
1031 typedef de::SharedPtr<UniqueImage> ImageSp;
1033 std::vector<ImageSp> images (numImages);
1034 std::vector<VkBindImageMemorySwapchainInfoKHR> bindImageMemorySwapchainInfo(numImages);
1035 std::vector<VkBindImageMemoryInfo> bindImageMemoryInfos (numImages);
1037 for (deUint32 idx = 0; idx < numImages; ++idx)
1040 images[idx] = ImageSp(new UniqueImage(createImage(devHelper.vkd, *devHelper.device, &imageCreateInfo)));
1042 VkBindImageMemorySwapchainInfoKHR bimsInfo =
1044 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR,
1049 bindImageMemorySwapchainInfo[idx] = bimsInfo;
1051 VkBindImageMemoryInfo bimInfo =
1053 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
1054 &bindImageMemorySwapchainInfo[idx],
1056 DE_NULL, // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
1057 0u // If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
1060 bindImageMemoryInfos[idx] = bimInfo;
1063 VK_CHECK(devHelper.vkd.bindImageMemory2(*devHelper.device, numImages, &bindImageMemoryInfos[0]));
1065 return tcu::TestStatus::pass("Pass");
1068 struct GroupParameters
1070 typedef FunctionInstance1<TestParameters>::Function Function;
1075 GroupParameters (Type wsiType_, Function function_)
1076 : wsiType (wsiType_)
1077 , function (function_)
1080 GroupParameters (void)
1081 : wsiType (TYPE_LAST)
1082 , function ((Function)DE_NULL)
1086 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
1088 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
1090 const TestDimension testDimension = (TestDimension)dimensionNdx;
1092 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
1095 addFunctionCase(testGroup, "image_swapchain_create_info", "Test VkImageSwapchainCreateInfoKHR", testImageSwapchainCreateInfo, params.wsiType);
1098 void populateSwapchainPrivateDataGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
1100 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
1102 const TestDimension testDimension = (TestDimension)dimensionNdx;
1103 if (testDimension == TEST_DIMENSION_IMAGE_EXTENT)
1106 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
1110 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type wsiType,
1111 const InstanceInterface& vki,
1112 VkPhysicalDevice physicalDevice,
1113 VkSurfaceKHR surface,
1114 const tcu::UVec2& desiredSize,
1115 deUint32 desiredImageCount)
1117 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki,
1120 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(vki,
1123 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
1124 const VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
1125 const VkSwapchainCreateInfoKHR parameters =
1127 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
1129 (VkSwapchainCreateFlagsKHR)0,
1131 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
1133 formats[0].colorSpace,
1134 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
1135 ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
1136 1u, // imageArrayLayers
1137 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1138 VK_SHARING_MODE_EXCLUSIVE,
1140 (const deUint32*)DE_NULL,
1142 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1143 VK_PRESENT_MODE_FIFO_KHR,
1144 VK_FALSE, // clipped
1145 (VkSwapchainKHR)0 // oldSwapchain
1151 typedef de::SharedPtr<Unique<VkCommandBuffer> > CommandBufferSp;
1152 typedef de::SharedPtr<Unique<VkFence> > FenceSp;
1153 typedef de::SharedPtr<Unique<VkSemaphore> > SemaphoreSp;
1155 vector<FenceSp> createFences (const DeviceInterface& vkd,
1156 const VkDevice device,
1158 bool isSignaled = true)
1160 vector<FenceSp> fences(numFences);
1162 for (size_t ndx = 0; ndx < numFences; ++ndx)
1163 fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device, (isSignaled) ? vk::VK_FENCE_CREATE_SIGNALED_BIT : 0)));
1168 vector<SemaphoreSp> createSemaphores (const DeviceInterface& vkd,
1169 const VkDevice device,
1170 size_t numSemaphores)
1172 vector<SemaphoreSp> semaphores(numSemaphores);
1174 for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1175 semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
1180 vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface& vkd,
1181 const VkDevice device,
1182 const VkCommandPool commandPool,
1183 const VkCommandBufferLevel level,
1184 const size_t numCommandBuffers)
1186 vector<CommandBufferSp> buffers (numCommandBuffers);
1188 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1189 buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1194 class AcquireNextImageWrapper
1198 AcquireNextImageWrapper(const DeviceInterface& vkd,
1200 deUint32 deviceMask,
1201 VkSwapchainKHR swapchain,
1205 , m_swapchain (swapchain)
1206 , m_timeout (timeout)
1208 DE_UNREF(deviceMask); // needed for compatibility with acquireNextImage2KHR
1211 bool featureAvailable(Context&)
1213 return true; // needed for compatibility with acquireNextImage2KHR
1216 VkResult call(VkSemaphore semaphore, VkFence fence, deUint32* imageIndex)
1218 return m_vkd.acquireNextImageKHR(m_device,
1228 const DeviceInterface& m_vkd;
1230 VkSwapchainKHR m_swapchain;
1234 class AcquireNextImage2Wrapper
1238 AcquireNextImage2Wrapper(const DeviceInterface& vkd,
1240 deUint32 deviceMask,
1241 VkSwapchainKHR swapchain,
1246 m_info.sType = VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR;
1247 m_info.pNext = DE_NULL;
1248 m_info.swapchain = swapchain;
1249 m_info.timeout = timeout;
1250 m_info.semaphore = DE_NULL;
1251 m_info.fence = DE_NULL;
1252 m_info.deviceMask = deviceMask;
1255 bool featureAvailable(Context& context)
1257 return context.isDeviceFunctionalitySupported("VK_KHR_device_group");
1260 VkResult call(VkSemaphore semaphore, VkFence fence, deUint32* imageIndex)
1262 m_info.semaphore = semaphore;
1263 m_info.fence = fence;
1264 return m_vkd.acquireNextImage2KHR(m_device,
1271 const DeviceInterface& m_vkd;
1273 VkAcquireNextImageInfoKHR m_info;
1277 template <typename AcquireWrapperType>
1278 tcu::TestStatus basicRenderTest (Context& context, Type wsiType)
1280 const tcu::UVec2 desiredSize (256, 256);
1281 const InstanceHelper instHelper (context, wsiType);
1282 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1283 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
1284 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
1285 const DeviceInterface& vkd = devHelper.vkd;
1286 const VkDevice device = *devHelper.device;
1287 SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1288 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1289 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
1290 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
1292 AcquireWrapperType acquireImageWrapper(vkd, device, 1u, *swapchain, std::numeric_limits<deUint64>::max());
1293 if (!acquireImageWrapper.featureAvailable(context))
1294 TCU_THROW(NotSupportedError, "Required extension is not supported");
1296 const WsiTriangleRenderer renderer (vkd,
1299 context.getBinaryCollection(),
1303 swapchainInfo.imageFormat,
1304 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1306 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1308 const size_t maxQueuedFrames = swapchainImages.size()*2;
1310 // We need to keep hold of fences from vkAcquireNextImage(2)KHR to actually
1311 // limit number of frames we allow to be queued.
1312 const vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
1314 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1315 // the semaphore in same time as the fence we use to meter rendering.
1316 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
1318 // For rest we simply need maxQueuedFrames as we will wait for image
1319 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1320 // previous uses must have completed.
1321 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
1322 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1326 const deUint32 numFramesToRender = 60*10;
1328 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1330 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
1331 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1332 deUint32 imageNdx = ~0u;
1334 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1335 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1338 const VkResult acquireResult = acquireImageWrapper.call(imageReadySemaphore, (VkFence)0, &imageNdx);
1340 if (acquireResult == VK_SUBOPTIMAL_KHR)
1341 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1343 VK_CHECK(acquireResult);
1346 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1349 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1350 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
1351 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1352 const VkSubmitInfo submitInfo =
1354 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1357 &imageReadySemaphore,
1362 &renderingCompleteSemaphore
1364 const VkPresentInfoKHR presentInfo =
1366 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1369 &renderingCompleteSemaphore,
1376 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1377 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
1378 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1382 VK_CHECK(vkd.deviceWaitIdle(device));
1386 // Make sure device is idle before destroying resources
1387 vkd.deviceWaitIdle(device);
1391 return tcu::TestStatus::pass("Rendering tests succeeded");
1394 class FrameStreamObjects
1399 const vk::VkFence& renderCompleteFence;
1400 const vk::VkSemaphore& renderCompleteSemaphore;
1401 const vk::VkSemaphore& imageAvailableSemaphore;
1402 const vk::VkCommandBuffer& commandBuffer;
1405 FrameStreamObjects (const vk::DeviceInterface& vkd, vk::VkDevice device, vk::VkCommandPool cmdPool, size_t maxQueuedFrames)
1406 : renderingCompleteFences(createFences(vkd, device, maxQueuedFrames))
1407 , renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
1408 , imageAvailableSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
1409 , commandBuffers(allocateCommandBuffers(vkd, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames))
1410 , m_maxQueuedFrames(maxQueuedFrames)
1414 size_t frameNumber (void) const { DE_ASSERT(m_nextFrame > 0u); return m_nextFrame - 1u; }
1416 FrameObjects newFrame ()
1418 const size_t mod = m_nextFrame % m_maxQueuedFrames;
1421 **renderingCompleteFences[mod],
1422 **renderingCompleteSemaphores[mod],
1423 **imageAvailableSemaphores[mod],
1424 **commandBuffers[mod],
1431 const vector<FenceSp> renderingCompleteFences;
1432 const vector<SemaphoreSp> renderingCompleteSemaphores;
1433 const vector<SemaphoreSp> imageAvailableSemaphores;
1434 const vector<CommandBufferSp> commandBuffers;
1436 const size_t m_maxQueuedFrames;
1440 struct MultiSwapchainParams
1443 size_t swapchainCount;
1446 struct AccumulatedPresentInfo
1448 vector<VkSemaphore> semaphores;
1449 vector<VkSwapchainKHR> swapchains;
1450 vector<deUint32> imageIndices;
1452 AccumulatedPresentInfo ()
1453 : semaphores(), swapchains(), imageIndices()
1457 void push_back (VkSemaphore sem, VkSwapchainKHR sc, deUint32 index)
1459 semaphores.push_back(sem);
1460 swapchains.push_back(sc);
1461 imageIndices.push_back(index);
1466 semaphores.resize(0);
1467 swapchains.resize(0);
1468 imageIndices.resize(0);
1471 size_t size () const
1473 // Any of the vectors would do.
1474 return semaphores.size();
1478 template <typename AcquireWrapperType>
1479 tcu::TestStatus multiSwapchainRenderTest (Context& context, MultiSwapchainParams params)
1481 DE_ASSERT(params.swapchainCount > 0);
1483 const tcu::UVec2 desiredSize (256, 256);
1484 const InstanceHelper instHelper (context, params.wsiType);
1486 // Create native window system objects, surfaces and helper surface vector.
1487 std::unique_ptr<NativeObjects> native;
1490 native.reset(new NativeObjects(context, instHelper.supportedExtensions, params.wsiType, params.swapchainCount, tcu::just(desiredSize)));
1492 catch(tcu::ResourceError&)
1494 std::ostringstream msg;
1495 msg << "Unable to create " << params.swapchainCount << " windows";
1496 TCU_THROW(NotSupportedError, msg.str());
1499 vector<Move<VkSurfaceKHR>> surface;
1500 vector<VkSurfaceKHR> surfaceKHR; // The plain Vulkan objects from the vector above.
1502 for (size_t i = 0; i < params.swapchainCount; ++i)
1504 surface.emplace_back(createSurface(instHelper.vki, instHelper.instance, params.wsiType, native->getDisplay(), native->getWindow(i)));
1505 surfaceKHR.push_back(surface.back().get());
1508 // Create a device compatible with all surfaces.
1509 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, surfaceKHR);
1510 const DeviceInterface& vkd = devHelper.vkd;
1511 const VkDevice device = *devHelper.device;
1512 SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1514 // Create several swapchains and images.
1515 vector<VkSwapchainCreateInfoKHR> swapchainInfo;
1516 vector<Move<VkSwapchainKHR>> swapchain;
1517 vector<vector<VkImage>> swapchainImages;
1518 vector<AcquireWrapperType> acquireImageWrapper;
1519 for (size_t i = 0; i < params.swapchainCount; ++i)
1521 swapchainInfo.emplace_back(getBasicSwapchainParameters(params.wsiType, instHelper.vki, devHelper.physicalDevice, *surface[i], desiredSize, 2));
1522 swapchain.emplace_back(createSwapchainKHR(vkd, device, &swapchainInfo.back()));
1523 swapchainImages.emplace_back(getSwapchainImages(vkd, device, swapchain.back().get()));
1524 acquireImageWrapper.emplace_back(vkd, device, 1u, swapchain.back().get(), std::numeric_limits<deUint64>::max());
1527 // Every acquire wrapper requires the same features, so we only check the first one.
1528 if (!acquireImageWrapper.front().featureAvailable(context))
1529 TCU_THROW(NotSupportedError, "Required extension is not supported");
1531 // Renderer per swapchain.
1532 vector<WsiTriangleRenderer> renderer;
1533 for (size_t i = 0; i < params.swapchainCount; ++i)
1535 renderer.emplace_back(vkd,
1538 context.getBinaryCollection(),
1542 swapchainInfo[i].imageFormat,
1543 tcu::UVec2(swapchainInfo[i].imageExtent.width, swapchainInfo[i].imageExtent.height));
1546 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1547 const size_t maxQueuedFrames = swapchainImages.front().size()*2; // Limit in-flight frames.
1549 vector<FrameStreamObjects> frameStreamObjects;
1550 for (size_t i = 0; i < params.swapchainCount; ++i)
1551 frameStreamObjects.emplace_back(vkd, device, commandPool.get(), maxQueuedFrames);
1555 // 3 seconds for 60 Hz screens.
1556 const deUint32 kNumFramesToRender = 60*3*static_cast<deUint32>(params.swapchainCount);
1557 AccumulatedPresentInfo accumulatedPresentInfo;
1559 for (size_t frameNdx = 0; frameNdx < kNumFramesToRender; ++frameNdx)
1561 size_t swapchainIndex = frameNdx % params.swapchainCount;
1562 auto& fsObjects = frameStreamObjects[swapchainIndex];
1563 auto frameObjects = fsObjects.newFrame();
1564 deUint32 imageNdx = std::numeric_limits<deUint32>::max();
1566 VK_CHECK(vkd.waitForFences(device, 1u, &frameObjects.renderCompleteFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1567 VK_CHECK(vkd.resetFences(device, 1u, &frameObjects.renderCompleteFence));
1570 const VkResult acquireResult = acquireImageWrapper[swapchainIndex].call(frameObjects.imageAvailableSemaphore, (VkFence)DE_NULL, &imageNdx);
1571 if (acquireResult == VK_SUBOPTIMAL_KHR)
1572 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1574 VK_CHECK(acquireResult);
1577 TCU_CHECK(static_cast<size_t>(imageNdx) < swapchainImages[swapchainIndex].size());
1580 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1581 const VkSubmitInfo submitInfo =
1583 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1586 &frameObjects.imageAvailableSemaphore,
1589 &frameObjects.commandBuffer,
1591 &frameObjects.renderCompleteSemaphore,
1594 renderer[swapchainIndex].recordFrame(frameObjects.commandBuffer, imageNdx, static_cast<deUint32>(frameNdx));
1595 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, frameObjects.renderCompleteFence));
1597 // Save present information for the current frame.
1598 accumulatedPresentInfo.push_back(frameObjects.renderCompleteSemaphore, swapchain[swapchainIndex].get(), imageNdx);
1600 // Present frames when we have accumulated one frame per swapchain.
1601 if (accumulatedPresentInfo.size() == params.swapchainCount)
1603 DE_ASSERT( accumulatedPresentInfo.semaphores.size() == accumulatedPresentInfo.swapchains.size() &&
1604 accumulatedPresentInfo.semaphores.size() == accumulatedPresentInfo.imageIndices.size() );
1606 vector<VkResult> results(params.swapchainCount, VK_ERROR_DEVICE_LOST);
1608 const VkPresentInfoKHR presentInfo =
1610 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1612 static_cast<deUint32>(accumulatedPresentInfo.semaphores.size()),
1613 accumulatedPresentInfo.semaphores.data(),
1614 static_cast<deUint32>(accumulatedPresentInfo.swapchains.size()),
1615 accumulatedPresentInfo.swapchains.data(),
1616 accumulatedPresentInfo.imageIndices.data(),
1620 // Check both the global result and the individual results.
1621 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1622 for (const auto& result : results)
1623 VK_CHECK_WSI(result);
1625 accumulatedPresentInfo.reset();
1630 VK_CHECK(vkd.deviceWaitIdle(device));
1634 // Make sure device is idle before destroying resources
1635 vkd.deviceWaitIdle(device);
1639 return tcu::TestStatus::pass("Rendering tests succeeded");
1642 tcu::TestStatus deviceGroupRenderTest (Context& context, Type wsiType)
1644 const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
1645 const tcu::CommandLine& cmdLine = context.getTestContext().getCommandLine();
1646 VkPhysicalDevice physicalDevice = chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
1647 const Extensions& supportedExtensions = enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
1649 std::vector<const char*> deviceExtensions;
1650 deviceExtensions.push_back("VK_KHR_swapchain");
1651 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
1652 deviceExtensions.push_back("VK_KHR_device_group");
1654 for (std::size_t ndx = 0; ndx < deviceExtensions.size(); ++ndx)
1656 if (!isExtensionSupported(supportedExtensions, RequiredExtension(deviceExtensions[ndx])))
1657 TCU_THROW(NotSupportedError, (string(deviceExtensions[ndx]) + " is not supported").c_str());
1660 const tcu::UVec2 desiredSize (256, 256);
1661 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1662 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
1664 const deUint32 devGroupIdx = cmdLine.getVKDeviceGroupId() - 1;
1665 const deUint32 deviceIdx = context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
1666 const vector<VkPhysicalDeviceGroupProperties> deviceGroupProps = enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
1667 deUint32 physicalDevicesInGroupCount = deviceGroupProps[devGroupIdx].physicalDeviceCount;
1668 const VkPhysicalDevice* physicalDevicesInGroup = deviceGroupProps[devGroupIdx].physicalDevices;
1669 deUint32 queueFamilyIndex = chooseQueueFamilyIndex(instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface);
1670 const std::vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]);
1671 const float queuePriority = 1.0f;
1672 const deUint32 firstDeviceID = 0;
1673 const deUint32 secondDeviceID = 1;
1675 // create a device group
1676 const VkDeviceGroupDeviceCreateInfo groupDeviceInfo =
1678 VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR, // stype
1680 physicalDevicesInGroupCount, // physicalDeviceCount
1681 physicalDevicesInGroup // physicalDevices
1683 const VkDeviceQueueCreateInfo deviceQueueCreateInfo =
1685 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // type
1687 (VkDeviceQueueCreateFlags)0u, // flags
1688 queueFamilyIndex, // queueFamilyIndex
1690 &queuePriority, // pQueuePriorities
1693 const VkDeviceCreateInfo deviceCreateInfo =
1695 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
1696 &groupDeviceInfo, // pNext
1697 (VkDeviceCreateFlags)0u, // flags
1698 1, // queueRecordCount
1699 &deviceQueueCreateInfo, // pRequestedQueues
1701 DE_NULL, // ppEnabledLayerNames
1702 deUint32(deviceExtensions.size()), // enabledExtensionCount
1703 &deviceExtensions[0], // ppEnabledExtensionNames
1704 DE_NULL, // pEnabledFeatures
1707 Move<VkDevice> groupDevice = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), instHelper.instance, instHelper.vki, physicalDevicesInGroup[deviceIdx], &deviceCreateInfo);
1708 const DeviceDriver vkd (context.getPlatformInterface(), instHelper.instance, *groupDevice);
1709 VkQueue queue (getDeviceQueue(vkd, *groupDevice, queueFamilyIndex, 0));
1710 SimpleAllocator allocator (vkd, *groupDevice, getPhysicalDeviceMemoryProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]));
1712 // create swapchain for device group
1713 VkDeviceGroupSwapchainCreateInfoKHR deviceGroupSwapchainInfo = initVulkanStructure();
1714 deviceGroupSwapchainInfo.modes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
1716 VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType,
1718 physicalDevicesInGroup[deviceIdx],
1722 swapchainInfo.pNext = &deviceGroupSwapchainInfo;
1724 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, *groupDevice, &swapchainInfo));
1725 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, *groupDevice, *swapchain);
1727 const WsiTriangleRenderer renderer (vkd,
1730 context.getBinaryCollection(),
1734 swapchainInfo.imageFormat,
1735 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1737 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, *groupDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1739 const size_t maxQueuedFrames = swapchainImages.size()*2;
1741 // We need to keep hold of fences from vkAcquireNextImage2KHR
1742 // to actually limit number of frames we allow to be queued.
1743 const vector<FenceSp> imageReadyFences (createFences(vkd, *groupDevice, maxQueuedFrames));
1745 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to
1746 // pass the semaphore in same time as the fence we use to meter rendering.
1747 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, *groupDevice, maxQueuedFrames+1));
1749 // For rest we simply need maxQueuedFrames as we will wait for image from frameNdx-maxQueuedFrames
1750 // to become available to us, guaranteeing that previous uses must have completed.
1751 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, *groupDevice, maxQueuedFrames));
1752 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, *groupDevice, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1756 const deUint32 numFramesToRender = 60*10;
1758 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1760 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
1761 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1762 deUint32 imageNdx = ~0u;
1764 VK_CHECK(vkd.waitForFences(*groupDevice, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1765 VK_CHECK(vkd.resetFences(*groupDevice, 1, &imageReadyFence));
1768 VkAcquireNextImageInfoKHR acquireNextImageInfo =
1770 VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR,
1773 std::numeric_limits<deUint64>::max(),
1774 imageReadySemaphore,
1776 (1 << firstDeviceID)
1779 const VkResult acquireResult = vkd.acquireNextImage2KHR(*groupDevice, &acquireNextImageInfo, &imageNdx);
1781 if (acquireResult == VK_SUBOPTIMAL_KHR)
1782 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1784 VK_CHECK(acquireResult);
1787 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1790 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1791 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
1792 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1794 // render triangle using one or two subdevices when available
1795 renderer.recordDeviceGroupFrame(commandBuffer, firstDeviceID, secondDeviceID, physicalDevicesInGroupCount, imageNdx, frameNdx);
1798 deUint32 deviceMask = (1 << firstDeviceID);
1799 std::vector<deUint32> deviceIndices(1, firstDeviceID);
1800 if (physicalDevicesInGroupCount > 1)
1802 deviceMask |= (1 << secondDeviceID);
1803 deviceIndices.push_back(secondDeviceID);
1805 const VkDeviceGroupSubmitInfo deviceGroupSubmitInfo =
1807 VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR, // sType
1809 deUint32(deviceIndices.size()), // waitSemaphoreCount
1810 &deviceIndices[0], // pWaitSemaphoreDeviceIndices
1811 1u, // commandBufferCount
1812 &deviceMask, // pCommandBufferDeviceMasks
1813 deUint32(deviceIndices.size()), // signalSemaphoreCount
1814 &deviceIndices[0], // pSignalSemaphoreDeviceIndices
1816 const VkSubmitInfo submitInfo =
1818 VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
1819 &deviceGroupSubmitInfo, // pNext
1820 1u, // waitSemaphoreCount
1821 &imageReadySemaphore, // pWaitSemaphores
1822 &waitDstStage, // pWaitDstStageMask
1823 1u, // commandBufferCount
1824 &commandBuffer, // pCommandBuffers
1825 1u, // signalSemaphoreCount
1826 &renderingCompleteSemaphore, // pSignalSemaphores
1828 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, imageReadyFence));
1830 // present swapchain image
1831 deviceMask = (1 << firstDeviceID);
1832 const VkDeviceGroupPresentInfoKHR deviceGroupPresentInfo =
1834 VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR,
1838 VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR,
1840 const VkPresentInfoKHR presentInfo =
1842 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1843 &deviceGroupPresentInfo,
1845 &renderingCompleteSemaphore,
1851 VK_CHECK_WSI(vkd.queuePresentKHR(queue, &presentInfo));
1855 VK_CHECK(vkd.deviceWaitIdle(*groupDevice));
1859 // Make sure device is idle before destroying resources
1860 vkd.deviceWaitIdle(*groupDevice);
1864 return tcu::TestStatus::pass("Rendering tests succeeded");
1867 tcu::TestStatus deviceGroupRenderTest2 (Context& context, Type wsiType)
1869 const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
1870 const tcu::CommandLine& cmdLine = context.getTestContext().getCommandLine();
1871 VkPhysicalDevice physicalDevice = chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
1872 const Extensions& deviceExtensions = enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
1874 // structures this tests checks were added in revision 69
1875 if (!isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_swapchain", 69)))
1876 TCU_THROW(NotSupportedError, "Required extension revision is not supported");
1878 std::vector<const char*> requiredExtensions;
1879 requiredExtensions.push_back("VK_KHR_swapchain");
1880 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
1882 requiredExtensions.push_back("VK_KHR_device_group");
1883 if (!isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_device_group")))
1884 TCU_THROW(NotSupportedError, "VK_KHR_device_group is not supported");
1887 const tcu::UVec2 desiredSize (256, 256);
1888 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1889 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
1891 const deUint32 devGroupIdx = cmdLine.getVKDeviceGroupId() - 1;
1892 const deUint32 deviceIdx = context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
1893 const vector<VkPhysicalDeviceGroupProperties> deviceGroupProps = enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
1894 deUint32 physicalDevicesInGroupCount = deviceGroupProps[devGroupIdx].physicalDeviceCount;
1895 const VkPhysicalDevice* physicalDevicesInGroup = deviceGroupProps[devGroupIdx].physicalDevices;
1896 deUint32 queueFamilyIndex = chooseQueueFamilyIndex(instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface);
1897 const std::vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]);
1898 const float queuePriority = 1.0f;
1899 const deUint32 firstDeviceID = 0;
1900 const deUint32 secondDeviceID = 1;
1901 const deUint32 deviceIndices[] = { firstDeviceID, secondDeviceID };
1903 if (physicalDevicesInGroupCount < 2)
1904 TCU_THROW(NotSupportedError, "Test requires more than 1 device in device group");
1906 // create a device group
1907 const VkDeviceGroupDeviceCreateInfo groupDeviceInfo =
1909 VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR, // stype
1911 physicalDevicesInGroupCount, // physicalDeviceCount
1912 physicalDevicesInGroup // physicalDevices
1914 const VkDeviceQueueCreateInfo deviceQueueCreateInfo =
1916 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // type
1918 (VkDeviceQueueCreateFlags)0u, // flags
1919 queueFamilyIndex, // queueFamilyIndex
1921 &queuePriority, // pQueuePriorities
1924 const VkDeviceCreateInfo deviceCreateInfo =
1926 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
1927 &groupDeviceInfo, // pNext
1928 (VkDeviceCreateFlags)0u, // flags
1929 1, // queueRecordCount
1930 &deviceQueueCreateInfo, // pRequestedQueues
1932 DE_NULL, // ppEnabledLayerNames
1933 deUint32(requiredExtensions.size()), // enabledExtensionCount
1934 &requiredExtensions[0], // ppEnabledExtensionNames
1935 DE_NULL, // pEnabledFeatures
1938 Move<VkDevice> groupDevice = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), instHelper.instance, instHelper.vki, physicalDevicesInGroup[deviceIdx], &deviceCreateInfo);
1939 const DeviceDriver vkd (context.getPlatformInterface(), instHelper.instance, *groupDevice);
1940 VkQueue queue (getDeviceQueue(vkd, *groupDevice, queueFamilyIndex, 0));
1941 SimpleAllocator allocator (vkd, *groupDevice, getPhysicalDeviceMemoryProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]));
1943 // create swapchain for device group
1944 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevice, *surface);
1945 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(instHelper.vki, physicalDevice, *surface);
1946 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
1947 const VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
1948 const deUint32 desiredImageCount = 2;
1950 struct VkDeviceGroupSwapchainCreateInfoKHR deviceGroupSwapchainInfo =
1952 VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
1954 VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR
1956 const VkSwapchainCreateInfoKHR swapchainInfo =
1958 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
1959 &deviceGroupSwapchainInfo,
1960 VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR,
1962 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
1964 formats[0].colorSpace,
1965 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
1966 ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
1968 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1969 VK_SHARING_MODE_EXCLUSIVE,
1971 (const deUint32*)DE_NULL,
1973 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1974 VK_PRESENT_MODE_FIFO_KHR,
1979 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, *groupDevice, &swapchainInfo));
1980 deUint32 numImages = 0;
1981 VK_CHECK(vkd.getSwapchainImagesKHR(*groupDevice, *swapchain, &numImages, DE_NULL));
1983 return tcu::TestStatus::pass("Pass");
1985 VkImageSwapchainCreateInfoKHR imageSwapchainCreateInfo =
1987 VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
1992 VkImageCreateInfo imageCreateInfo =
1994 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1995 &imageSwapchainCreateInfo,
1996 VK_IMAGE_CREATE_ALIAS_BIT |
1997 VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR, // flags
1998 VK_IMAGE_TYPE_2D, // imageType
1999 formats[0].format, // format
2001 desiredSize.x(), // width
2002 desiredSize.y(), // height
2007 VK_SAMPLE_COUNT_1_BIT, // samples
2008 VK_IMAGE_TILING_OPTIMAL, // tiling
2009 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // usage
2010 VK_SHARING_MODE_EXCLUSIVE, // sharingMode
2011 0u, // queueFamilyIndexCount
2012 DE_NULL, // pQueueFamilyIndices
2013 VK_IMAGE_LAYOUT_UNDEFINED // initialLayout
2016 typedef vk::Unique<VkImage> UniqueImage;
2017 typedef de::SharedPtr<UniqueImage> ImageSp;
2019 vector<ImageSp> images (numImages);
2020 vector<VkImage> rawImages (numImages);
2021 vector<ImageSp> imagesSfr (numImages);
2022 vector<VkImage> rawImagesSfr (numImages);
2023 vector<VkBindImageMemorySwapchainInfoKHR> bindImageMemorySwapchainInfo (numImages);
2025 // Create non-SFR image aliases for image layout transition
2027 vector<VkBindImageMemoryInfo> bindImageMemoryInfos (numImages);
2029 for (deUint32 idx = 0; idx < numImages; ++idx)
2032 images[idx] = ImageSp(new UniqueImage(createImage(vkd, *groupDevice, &imageCreateInfo)));
2034 VkBindImageMemorySwapchainInfoKHR bimsInfo =
2036 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR,
2041 bindImageMemorySwapchainInfo[idx] = bimsInfo;
2043 VkBindImageMemoryInfo bimInfo =
2045 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
2046 &bindImageMemorySwapchainInfo[idx],
2048 DE_NULL, // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
2049 0u // If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
2051 bindImageMemoryInfos[idx] = bimInfo;
2052 rawImages[idx] = **images[idx];
2055 VK_CHECK(vkd.bindImageMemory2(*groupDevice, numImages, &bindImageMemoryInfos[0]));
2058 // Create the SFR images
2060 vector<VkBindImageMemoryDeviceGroupInfo > bindImageMemoryDeviceGroupInfo (numImages);
2061 vector<VkBindImageMemoryInfo> bindImageMemoryInfos (numImages);
2062 for (deUint32 idx = 0; idx < numImages; ++idx)
2065 imagesSfr[idx] = ImageSp(new UniqueImage(createImage(vkd, *groupDevice, &imageCreateInfo)));
2067 // Split into 2 vertical halves
2068 // NOTE: the same split has to be done also in WsiTriangleRenderer::recordDeviceGroupFrame
2069 const deUint32 halfWidth = desiredSize.x() / 2;
2070 const deUint32 height = desiredSize.y();
2071 const VkRect2D sfrRects[] =
2073 { { 0, 0 }, { halfWidth, height } }, // offset, extent
2074 { { (deInt32)halfWidth, 0 }, { halfWidth, height } }, // offset, extent
2075 { { 0, 0 }, { halfWidth, height } }, // offset, extent
2076 { { (deInt32)halfWidth, 0 }, { halfWidth, height } } // offset, extent
2079 VkBindImageMemoryDeviceGroupInfo bimdgInfo =
2081 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO,
2082 &bindImageMemorySwapchainInfo[idx],
2083 DE_LENGTH_OF_ARRAY(deviceIndices),
2085 DE_LENGTH_OF_ARRAY(sfrRects),
2088 bindImageMemoryDeviceGroupInfo[idx] = bimdgInfo;
2090 VkBindImageMemoryInfo bimInfo =
2092 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
2093 &bindImageMemoryDeviceGroupInfo[idx],
2095 DE_NULL, // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
2096 0u // If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
2098 bindImageMemoryInfos[idx] = bimInfo;
2099 rawImagesSfr[idx] = **imagesSfr[idx];
2102 VK_CHECK(vkd.bindImageMemory2(*groupDevice, numImages, &bindImageMemoryInfos[0]));
2105 VkPeerMemoryFeatureFlags peerMemoryFeatures = 0u;
2106 vkd.getDeviceGroupPeerMemoryFeatures(*groupDevice, 0, firstDeviceID, secondDeviceID, &peerMemoryFeatures);
2107 bool explicitLayoutTransitions = !(peerMemoryFeatures & VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT) ||
2108 !(peerMemoryFeatures & VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT);
2110 const WsiTriangleRenderer renderer (vkd,
2113 context.getBinaryCollection(),
2114 explicitLayoutTransitions,
2117 swapchainInfo.imageFormat,
2118 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
2120 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, *groupDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2122 const size_t maxQueuedFrames = rawImagesSfr.size()*2;
2124 // We need to keep hold of fences from vkAcquireNextImage2KHR
2125 // to actually limit number of frames we allow to be queued.
2126 const vector<FenceSp> imageReadyFences (createFences(vkd, *groupDevice, maxQueuedFrames));
2128 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to
2129 // pass the semaphore in same time as the fence we use to meter rendering.
2130 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, *groupDevice, maxQueuedFrames+1));
2132 // For rest we simply need maxQueuedFrames as we will wait for image from frameNdx-maxQueuedFrames
2133 // to become available to us, guaranteeing that previous uses must have completed.
2134 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, *groupDevice, maxQueuedFrames));
2135 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, *groupDevice, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
2139 const deUint32 numFramesToRender = 60*10;
2141 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
2143 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
2144 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
2145 deUint32 imageNdx = ~0u;
2147 VK_CHECK(vkd.waitForFences(*groupDevice, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
2148 VK_CHECK(vkd.resetFences(*groupDevice, 1, &imageReadyFence));
2151 VkAcquireNextImageInfoKHR acquireNextImageInfo =
2153 VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR,
2156 std::numeric_limits<deUint64>::max(),
2157 imageReadySemaphore,
2159 (1 << firstDeviceID)
2162 const VkResult acquireResult = vkd.acquireNextImage2KHR(*groupDevice, &acquireNextImageInfo, &imageNdx);
2164 if (acquireResult == VK_SUBOPTIMAL_KHR)
2165 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
2167 VK_CHECK(acquireResult);
2170 TCU_CHECK((size_t)imageNdx < rawImagesSfr.size());
2173 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
2174 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
2175 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2177 // render triangle using one or two subdevices when available
2178 renderer.recordDeviceGroupFrame(commandBuffer, firstDeviceID, secondDeviceID, physicalDevicesInGroupCount, imageNdx, frameNdx);
2181 deUint32 deviceMask = (1 << firstDeviceID) | (1 << secondDeviceID);
2182 const VkDeviceGroupSubmitInfo deviceGroupSubmitInfo =
2184 VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR, // sType
2186 DE_LENGTH_OF_ARRAY(deviceIndices), // waitSemaphoreCount
2187 deviceIndices, // pWaitSemaphoreDeviceIndices
2188 1u, // commandBufferCount
2189 &deviceMask, // pCommandBufferDeviceMasks
2190 DE_LENGTH_OF_ARRAY(deviceIndices), // signalSemaphoreCount
2191 deviceIndices, // pSignalSemaphoreDeviceIndices
2193 const VkSubmitInfo submitInfo =
2195 VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
2196 &deviceGroupSubmitInfo, // pNext
2197 1u, // waitSemaphoreCount
2198 &imageReadySemaphore, // pWaitSemaphores
2199 &waitDstStage, // pWaitDstStageMask
2200 1u, // commandBufferCount
2201 &commandBuffer, // pCommandBuffers
2202 1u, // signalSemaphoreCount
2203 &renderingCompleteSemaphore, // pSignalSemaphores
2205 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, imageReadyFence));
2207 // present swapchain image - asume that first device has a presentation engine
2208 deviceMask = (1 << firstDeviceID);
2209 const VkDeviceGroupPresentInfoKHR deviceGroupPresentInfo =
2211 VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR,
2215 VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR,
2217 const VkPresentInfoKHR presentInfo =
2219 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2220 &deviceGroupPresentInfo,
2222 &renderingCompleteSemaphore,
2228 VK_CHECK(vkd.queuePresentKHR(queue, &presentInfo));
2232 VK_CHECK(vkd.deviceWaitIdle(*groupDevice));
2236 // Make sure device is idle before destroying resources
2237 vkd.deviceWaitIdle(*groupDevice);
2241 return tcu::TestStatus::pass("Rendering tests succeeded");
2244 vector<tcu::UVec2> getSwapchainSizeSequence (const VkSurfaceCapabilitiesKHR& capabilities, const tcu::UVec2& defaultSize)
2246 vector<tcu::UVec2> sizes(3);
2247 sizes[0] = defaultSize / 2u;
2248 sizes[1] = defaultSize;
2249 sizes[2] = defaultSize * 2u;
2251 for (deUint32 i = 0; i < sizes.size(); ++i)
2253 sizes[i].x() = de::clamp(sizes[i].x(), capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
2254 sizes[i].y() = de::clamp(sizes[i].y(), capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
2260 tcu::TestStatus resizeSwapchainTest (Context& context, Type wsiType)
2262 const tcu::UVec2 desiredSize (256, 256);
2263 const InstanceHelper instHelper (context, wsiType);
2264 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2265 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2266 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
2267 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
2268 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
2269 const DeviceInterface& vkd = devHelper.vkd;
2270 const VkDevice device = *devHelper.device;
2271 SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
2272 vector<tcu::UVec2> sizes = getSwapchainSizeSequence(capabilities, desiredSize);
2273 Move<VkSwapchainKHR> prevSwapchain;
2275 DE_ASSERT(platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE);
2276 DE_UNREF(platformProperties);
2278 for (deUint32 sizeNdx = 0; sizeNdx < sizes.size(); ++sizeNdx)
2280 // \todo [2016-05-30 jesse] This test currently waits for idle and
2281 // recreates way more than necessary when recreating the swapchain. Make
2282 // it match expected real app behavior better by smoothly switching from
2283 // old to new swapchain. Once that is done, it will also be possible to
2284 // test creating a new swapchain while images from the previous one are
2287 VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, sizes[sizeNdx], 2);
2288 swapchainInfo.oldSwapchain = *prevSwapchain;
2290 Move<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
2291 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
2292 const WsiTriangleRenderer renderer (vkd,
2295 context.getBinaryCollection(),
2299 swapchainInfo.imageFormat,
2300 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
2301 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
2302 const size_t maxQueuedFrames = swapchainImages.size()*2;
2304 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
2305 // limit number of frames we allow to be queued.
2306 const vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
2308 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
2309 // the semaphore in same time as the fence we use to meter rendering.
2310 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
2312 // For rest we simply need maxQueuedFrames as we will wait for image
2313 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
2314 // previous uses must have completed.
2315 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
2316 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
2320 const deUint32 numFramesToRender = 60;
2322 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
2324 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
2325 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
2326 deUint32 imageNdx = ~0u;
2328 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
2329 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
2332 const VkResult acquireResult = vkd.acquireNextImageKHR(device,
2334 std::numeric_limits<deUint64>::max(),
2335 imageReadySemaphore,
2339 if (acquireResult == VK_SUBOPTIMAL_KHR)
2340 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
2342 VK_CHECK(acquireResult);
2345 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
2348 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
2349 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
2350 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2351 const VkSubmitInfo submitInfo =
2353 VK_STRUCTURE_TYPE_SUBMIT_INFO,
2356 &imageReadySemaphore,
2361 &renderingCompleteSemaphore
2363 const VkPresentInfoKHR presentInfo =
2365 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2368 &renderingCompleteSemaphore,
2375 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
2376 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
2377 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
2381 VK_CHECK(vkd.deviceWaitIdle(device));
2383 prevSwapchain = swapchain;
2387 // Make sure device is idle before destroying resources
2388 vkd.deviceWaitIdle(device);
2393 return tcu::TestStatus::pass("Resizing tests succeeded");
2396 tcu::TestStatus getImagesIncompleteResultTest (Context& context, Type wsiType)
2398 const tcu::UVec2 desiredSize (256, 256);
2399 const InstanceHelper instHelper (context, wsiType);
2400 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2401 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2402 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
2403 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2404 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2406 vector<VkImage> swapchainImages = getSwapchainImages(devHelper.vkd, *devHelper.device, *swapchain);
2408 ValidateQueryBits::fillBits(swapchainImages.begin(), swapchainImages.end());
2410 const deUint32 usedCount = static_cast<deUint32>(swapchainImages.size() / 2);
2411 deUint32 count = usedCount;
2412 const VkResult result = devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &count, &swapchainImages[0]);
2414 if (count != usedCount || result != VK_INCOMPLETE || !ValidateQueryBits::checkBits(swapchainImages.begin() + count, swapchainImages.end()))
2415 return tcu::TestStatus::fail("Get swapchain images didn't return VK_INCOMPLETE");
2417 return tcu::TestStatus::pass("Get swapchain images tests succeeded");
2420 tcu::TestStatus getImagesResultsCountTest (Context& context, Type wsiType)
2422 const tcu::UVec2 desiredSize(256, 256);
2423 const InstanceHelper instHelper(context, wsiType);
2424 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2425 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2426 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2427 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2428 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2430 deUint32 numImages = 0;
2432 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2436 std::vector<VkImage> images (numImages + 1);
2437 const deUint32 numImagesOrig = numImages;
2439 // check if below call properly overwrites formats count
2442 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, &images[0]));
2444 if ((size_t)numImages != numImagesOrig)
2445 TCU_FAIL("Image count changed between calls");
2447 return tcu::TestStatus::pass("Get swapchain images tests succeeded");
2450 tcu::TestStatus destroyNullHandleSwapchainTest (Context& context, Type wsiType)
2452 const InstanceHelper instHelper (context, wsiType);
2453 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
2454 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2455 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
2456 const VkSwapchainKHR nullHandle = DE_NULL;
2458 // Default allocator
2459 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, DE_NULL);
2463 AllocationCallbackRecorder recordingAllocator (getSystemAllocator(), 1u);
2465 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, recordingAllocator.getCallbacks());
2467 if (recordingAllocator.getNumRecords() != 0u)
2468 return tcu::TestStatus::fail("Implementation allocated/freed the memory");
2471 return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
2474 tcu::TestStatus acquireTooManyTest (Context& context, Type wsiType)
2476 const tcu::UVec2 desiredSize (256, 256);
2477 const InstanceHelper instHelper (context, wsiType);
2478 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
2479 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2480 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
2481 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2482 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2485 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2486 const deUint32 minImageCount = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface).minImageCount;
2487 if (numImages < minImageCount) return tcu::TestStatus::fail("Get swapchain images returned less than minImageCount images");
2488 const deUint32 numAcquirableImages = numImages - minImageCount + 1;
2490 const auto fences = createFences(devHelper.vkd, *devHelper.device, numAcquirableImages + 1, false);
2492 for (deUint32 i = 0; i < numAcquirableImages; ++i) {
2493 VK_CHECK_WSI(devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, std::numeric_limits<deUint64>::max(), (VkSemaphore)0, **fences[i], &dummy));
2496 const auto result = devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, 0, (VkSemaphore)0, **fences[numAcquirableImages], &dummy);
2498 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR && result != VK_NOT_READY ){
2499 return tcu::TestStatus::fail("Implementation failed to respond well acquiring too many images with 0 timeout");
2503 const deUint32 numFences = (result == VK_NOT_READY) ? static_cast<deUint32>(fences.size() - 1) : static_cast<deUint32>(fences.size());
2504 vector<vk::VkFence> fencesRaw(numFences);
2505 std::transform(fences.begin(), fences.begin() + numFences, fencesRaw.begin(), [](const FenceSp& f) -> vk::VkFence{ return **f; });
2506 VK_CHECK(devHelper.vkd.waitForFences(*devHelper.device, numFences, fencesRaw.data(), VK_TRUE, std::numeric_limits<deUint64>::max()));
2508 return tcu::TestStatus::pass("Acquire too many swapchain images test succeeded");
2511 tcu::TestStatus acquireTooManyTimeoutTest (Context& context, Type wsiType)
2513 const tcu::UVec2 desiredSize (256, 256);
2514 const InstanceHelper instHelper (context, wsiType);
2515 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
2516 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2517 const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
2518 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2519 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2522 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2523 const deUint32 minImageCount = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface).minImageCount;
2524 if (numImages < minImageCount) return tcu::TestStatus::fail("Get swapchain images returned less than minImageCount images");
2525 const deUint32 numAcquirableImages = numImages - minImageCount + 1;
2527 const auto fences = createFences(devHelper.vkd, *devHelper.device, numAcquirableImages + 1, false);
2529 for (deUint32 i = 0; i < numAcquirableImages; ++i) {
2530 VK_CHECK_WSI(devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, std::numeric_limits<deUint64>::max(), (VkSemaphore)0, **fences[i], &dummy));
2533 const deUint64 millisecond = 1000000;
2534 const deUint64 timeout = 50 * millisecond; // arbitrary realistic non-0 non-infinite timeout
2535 const auto result = devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, timeout, (VkSemaphore)0, **fences[numAcquirableImages], &dummy);
2537 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR && result != VK_TIMEOUT ){
2538 return tcu::TestStatus::fail("Implementation failed to respond well acquiring too many images with timeout");
2542 const deUint32 numFences = (result == VK_TIMEOUT) ? static_cast<deUint32>(fences.size() - 1) : static_cast<deUint32>(fences.size());
2543 vector<vk::VkFence> fencesRaw(numFences);
2544 std::transform(fences.begin(), fences.begin() + numFences, fencesRaw.begin(), [](const FenceSp& f) -> vk::VkFence{ return **f; });
2545 VK_CHECK(devHelper.vkd.waitForFences(*devHelper.device, numFences, fencesRaw.data(), VK_TRUE, std::numeric_limits<deUint64>::max()));
2547 return tcu::TestStatus::pass("Acquire too many swapchain images test succeeded");
2550 void getBasicRenderPrograms (SourceCollections& dst, Type)
2552 WsiTriangleRenderer::getPrograms(dst);
2555 void getBasicRenderPrograms (SourceCollections& dst, MultiSwapchainParams)
2557 WsiTriangleRenderer::getPrograms(dst);
2560 void populateRenderGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2562 addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest<AcquireNextImageWrapper>, wsiType);
2563 addFunctionCaseWithPrograms(testGroup, "basic2", "Basic Rendering Test using AcquireNextImage2", getBasicRenderPrograms, basicRenderTest<AcquireNextImage2Wrapper>, wsiType);
2564 addFunctionCaseWithPrograms(testGroup, "device_group", "Basic Rendering Test using device_group", getBasicRenderPrograms, deviceGroupRenderTest, wsiType);
2565 addFunctionCaseWithPrograms(testGroup, "device_group2", "Rendering Test using device_group and VkImageSwapchainCreateInfo", getBasicRenderPrograms, deviceGroupRenderTest2, wsiType);
2567 const MultiSwapchainParams kTwoSwapchains { wsiType, 2u };
2568 const MultiSwapchainParams kTenSwapchains { wsiType, 10u };
2570 addFunctionCaseWithPrograms(testGroup, "2swapchains", "2 Swapchains Rendering Test", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImageWrapper>, kTwoSwapchains);
2571 addFunctionCaseWithPrograms(testGroup, "2swapchains2", "2 Swapchains Rendering Test using AcquireNextImage2", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImage2Wrapper>, kTwoSwapchains);
2572 addFunctionCaseWithPrograms(testGroup, "10swapchains", "10 Swapchains Rendering Test", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImageWrapper>, kTenSwapchains);
2573 addFunctionCaseWithPrograms(testGroup, "10swapchains2", "10 Swapchains Rendering Test using AcquireNextImage2", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImage2Wrapper>, kTenSwapchains);
2576 void populateGetImagesGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2578 addFunctionCase(testGroup, "incomplete", "Test VK_INCOMPLETE return code", getImagesIncompleteResultTest, wsiType);
2579 addFunctionCase(testGroup, "count", "Test proper count of images", getImagesResultsCountTest, wsiType);
2582 void populateModifyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2584 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
2586 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
2588 addFunctionCaseWithPrograms(testGroup, "resize", "Resize Swapchain Test", getBasicRenderPrograms, resizeSwapchainTest, wsiType);
2591 // \todo [2016-05-30 jesse] Add tests for modifying preTransform, compositeAlpha, presentMode
2594 void populateDestroyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2596 addFunctionCase(testGroup, "null_handle", "Destroying a VK_NULL_HANDLE swapchain", destroyNullHandleSwapchainTest, wsiType);
2599 void populateAcquireGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2601 addFunctionCase(testGroup, "too_many", "Test acquiring too many images with 0 timeout", acquireTooManyTest, wsiType);
2602 addFunctionCase(testGroup, "too_many_timeout", "Test acquiring too many images with timeout", acquireTooManyTimeoutTest, wsiType);
2607 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
2609 addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
2610 addTestGroup(testGroup, "simulate_oom", "Simulate OOM using callbacks during swapchain construction", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainSimulateOOMTest));
2611 addTestGroup(testGroup, "render", "Rendering Tests", populateRenderGroup, wsiType);
2612 addTestGroup(testGroup, "modify", "Modify VkSwapchain", populateModifyGroup, wsiType);
2613 addTestGroup(testGroup, "destroy", "Destroy VkSwapchain", populateDestroyGroup, wsiType);
2614 addTestGroup(testGroup, "get_images", "Get swapchain images", populateGetImagesGroup, wsiType);
2615 addTestGroup(testGroup, "acquire", "Ancquire next swapchain image", populateAcquireGroup, wsiType);
2616 addTestGroup(testGroup, "private_data", "Create VkSwapchain and use VK_EXT_private_data", populateSwapchainPrivateDataGroup, GroupParameters(wsiType, createSwapchainPrivateDataTest));