external/vulkancts/modules/vulkan/vktTestGroupUtil.cpp \
external/vulkancts/modules/vulkan/vktTestPackage.cpp \
external/vulkancts/modules/vulkan/vktTestPackageEntry.cpp \
+ external/vulkancts/modules/vulkan/wsi/vktNativeObjectsUtil.cpp \
external/vulkancts/modules/vulkan/wsi/vktWsiColorSpaceTests.cpp \
external/vulkancts/modules/vulkan/wsi/vktWsiDisplayControlTests.cpp \
external/vulkancts/modules/vulkan/wsi/vktWsiDisplayTests.cpp \
external/vulkancts/modules/vulkan/wsi/vktWsiDisplayTimingTests.cpp \
external/vulkancts/modules/vulkan/wsi/vktWsiFullScreenExclusiveTests.cpp \
external/vulkancts/modules/vulkan/wsi/vktWsiIncrementalPresentTests.cpp \
+ external/vulkancts/modules/vulkan/wsi/vktWsiPresentIdWaitTests.cpp \
external/vulkancts/modules/vulkan/wsi/vktWsiSharedPresentableImageTests.cpp \
external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp \
external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp \
dEQP-VK.wsi.android.full_screen_exclusive.allowed
dEQP-VK.wsi.android.full_screen_exclusive.disallowed
dEQP-VK.wsi.android.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.android.present_id_wait.id.zero
+dEQP-VK.wsi.android.present_id_wait.id.increasing
+dEQP-VK.wsi.android.present_id_wait.id.interleaved
+dEQP-VK.wsi.android.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.android.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.android.present_id_wait.wait.no_frames
+dEQP-VK.wsi.android.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.android.present_id_wait.wait.future_frame
+dEQP-VK.wsi.android.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.macos.swapchain.acquire.too_many
dEQP-VK.wsi.macos.swapchain.acquire.too_many_timeout
dEQP-VK.wsi.macos.swapchain.private_data.min_image_count
dEQP-VK.wsi.macos.full_screen_exclusive.allowed
dEQP-VK.wsi.macos.full_screen_exclusive.disallowed
dEQP-VK.wsi.macos.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.macos.present_id_wait.id.zero
+dEQP-VK.wsi.macos.present_id_wait.id.increasing
+dEQP-VK.wsi.macos.present_id_wait.id.interleaved
+dEQP-VK.wsi.macos.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.macos.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.macos.present_id_wait.wait.no_frames
+dEQP-VK.wsi.macos.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.macos.present_id_wait.wait.future_frame
+dEQP-VK.wsi.macos.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.headless.surface.create
dEQP-VK.wsi.headless.surface.create_custom_allocator
dEQP-VK.wsi.headless.surface.create_simulate_oom
dEQP-VK.wsi.headless.full_screen_exclusive.allowed
dEQP-VK.wsi.headless.full_screen_exclusive.disallowed
dEQP-VK.wsi.headless.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.headless.present_id_wait.id.zero
+dEQP-VK.wsi.headless.present_id_wait.id.increasing
+dEQP-VK.wsi.headless.present_id_wait.id.interleaved
+dEQP-VK.wsi.headless.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.headless.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.headless.present_id_wait.wait.no_frames
+dEQP-VK.wsi.headless.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.headless.present_id_wait.wait.future_frame
+dEQP-VK.wsi.headless.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.android.full_screen_exclusive.allowed
dEQP-VK.wsi.android.full_screen_exclusive.disallowed
dEQP-VK.wsi.android.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.android.present_id_wait.id.zero
+dEQP-VK.wsi.android.present_id_wait.id.increasing
+dEQP-VK.wsi.android.present_id_wait.id.interleaved
+dEQP-VK.wsi.android.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.android.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.android.present_id_wait.wait.no_frames
+dEQP-VK.wsi.android.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.android.present_id_wait.wait.future_frame
+dEQP-VK.wsi.android.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.macos.surface.create
dEQP-VK.wsi.macos.surface.create_custom_allocator
dEQP-VK.wsi.macos.surface.create_simulate_oom
dEQP-VK.wsi.macos.full_screen_exclusive.allowed
dEQP-VK.wsi.macos.full_screen_exclusive.disallowed
dEQP-VK.wsi.macos.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.macos.present_id_wait.id.zero
+dEQP-VK.wsi.macos.present_id_wait.id.increasing
+dEQP-VK.wsi.macos.present_id_wait.id.interleaved
+dEQP-VK.wsi.macos.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.macos.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.macos.present_id_wait.wait.no_frames
+dEQP-VK.wsi.macos.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.macos.present_id_wait.wait.future_frame
+dEQP-VK.wsi.macos.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.headless.surface.create
dEQP-VK.wsi.headless.surface.create_custom_allocator
dEQP-VK.wsi.headless.surface.create_simulate_oom
dEQP-VK.wsi.headless.full_screen_exclusive.allowed
dEQP-VK.wsi.headless.full_screen_exclusive.disallowed
dEQP-VK.wsi.headless.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.headless.present_id_wait.id.zero
+dEQP-VK.wsi.headless.present_id_wait.id.increasing
+dEQP-VK.wsi.headless.present_id_wait.id.interleaved
+dEQP-VK.wsi.headless.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.headless.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.headless.present_id_wait.wait.no_frames
+dEQP-VK.wsi.headless.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.headless.present_id_wait.wait.future_frame
+dEQP-VK.wsi.headless.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.display.get_display_properties
dEQP-VK.wsi.display.get_display_plane_properties
dEQP-VK.wsi.display.get_display_plane_supported_displays
"VK_VALVE_mutable_descriptor_type",
"VK_EXT_multi_draw",
"VK_KHR_shader_subgroup_uniform_control_flow",
+ "VK_KHR_present_id",
+ "VK_KHR_present_wait",
};
nextPtr = &physicalDevicePipelineExecutablePropertiesFeaturesKHR.pNext;
}
+ vk::VkPhysicalDevicePresentIdFeaturesKHR physicalDevicePresentIdFeaturesKHR;
+ deMemset(&physicalDevicePresentIdFeaturesKHR, 0, sizeof(physicalDevicePresentIdFeaturesKHR));
+
+ if ( isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_present_id")) )
+ {
+ physicalDevicePresentIdFeaturesKHR.sType = getStructureType<VkPhysicalDevicePresentIdFeaturesKHR>();
+ *nextPtr = &physicalDevicePresentIdFeaturesKHR;
+ nextPtr = &physicalDevicePresentIdFeaturesKHR.pNext;
+ }
+
+ vk::VkPhysicalDevicePresentWaitFeaturesKHR physicalDevicePresentWaitFeaturesKHR;
+ deMemset(&physicalDevicePresentWaitFeaturesKHR, 0, sizeof(physicalDevicePresentWaitFeaturesKHR));
+
+ if ( isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_present_wait")) )
+ {
+ physicalDevicePresentWaitFeaturesKHR.sType = getStructureType<VkPhysicalDevicePresentWaitFeaturesKHR>();
+ *nextPtr = &physicalDevicePresentWaitFeaturesKHR;
+ nextPtr = &physicalDevicePresentWaitFeaturesKHR.pNext;
+ }
+
vk::VkPhysicalDeviceRayQueryFeaturesKHR physicalDeviceRayQueryFeaturesKHR;
deMemset(&physicalDeviceRayQueryFeaturesKHR, 0, sizeof(physicalDeviceRayQueryFeaturesKHR));
}
}
+ if ( isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_present_id")) )
+ {
+ if ( physicalDevicePresentIdFeaturesKHR.presentId == VK_FALSE )
+ {
+ log << tcu::TestLog::Message << "Mandatory feature presentId not supported" << tcu::TestLog::EndMessage;
+ result = false;
+ }
+ }
+
+ if ( isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_present_wait")) )
+ {
+ if ( physicalDevicePresentWaitFeaturesKHR.presentWait == VK_FALSE )
+ {
+ log << tcu::TestLog::Message << "Mandatory feature presentWait not supported" << tcu::TestLog::EndMessage;
+ result = false;
+ }
+ }
+
return result;
}
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
- (explicitLayoutTransitions) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ (explicitLayoutTransitions) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED,
(explicitLayoutTransitions) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
};
const VkAttachmentReference colorAttRef =
include_directories(..)
set(DEQP_VK_WSI_SRCS
+ vktNativeObjectsUtil.cpp
+ vktNativeObjectsUtil.hpp
vktWsiTests.cpp
vktWsiTests.hpp
vktWsiSurfaceTests.cpp
vktWsiColorSpaceTests.hpp
vktWsiFullScreenExclusiveTests.cpp
vktWsiFullScreenExclusiveTests.hpp
+ vktWsiPresentIdWaitTests.cpp
+ vktWsiPresentIdWaitTests.hpp
)
set(DEQP_VK_WSI_LIBS
--- /dev/null
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2019 The Khronos Group Inc.
+ * Copyright (c) 2019 Valve Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief WSI Native Objects utility class.
+ *//*--------------------------------------------------------------------*/
+#include "vktNativeObjectsUtil.hpp"
+
+#include "vkQueryUtil.hpp"
+#include "vkWsiUtil.hpp"
+
+#include "tcuPlatform.hpp"
+
+#include "deDefs.hpp"
+
+namespace vkt
+{
+namespace wsi
+{
+
+de::MovePtr<vk::wsi::Display> NativeObjects::createDisplay (const vk::Platform& platform,
+ const NativeObjects::Extensions& supportedExtensions,
+ vk::wsi::Type wsiType)
+{
+ try
+ {
+ return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
+ }
+ catch (const tcu::NotSupportedError& e)
+ {
+ if (vk::isExtensionSupported(supportedExtensions, vk::RequiredExtension(vk::wsi::getExtensionName(wsiType))) &&
+ platform.hasDisplay(wsiType))
+ {
+ // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
+ // must support creating native display & window for that WSI type.
+ throw tcu::TestError(e.getMessage());
+ }
+ else
+ throw;
+ }
+}
+
+de::MovePtr<vk::wsi::Window> NativeObjects::createWindow (const vk::wsi::Display& display, const tcu::Maybe<tcu::UVec2>& initialSize)
+{
+ try
+ {
+ return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
+ }
+ catch (const tcu::NotSupportedError& e)
+ {
+ // See createDisplay - assuming that wsi::Display was supported platform port
+ // should also support creating a window.
+ throw tcu::TestError(e.getMessage());
+ }
+}
+
+NativeObjects::NativeObjects (Context& context,
+ const Extensions& supportedExtensions,
+ vk::wsi::Type wsiType,
+ size_t windowCount,
+ const tcu::Maybe<tcu::UVec2>& initialWindowSize)
+ : display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
+{
+ DE_ASSERT(windowCount > 0u);
+ for (size_t i = 0; i < windowCount; ++i)
+ windows.emplace_back(createWindow(*display, initialWindowSize));
+}
+
+NativeObjects::NativeObjects (NativeObjects&& other)
+ : display (other.display.move())
+ , windows ()
+{
+ windows.swap(other.windows);
+}
+
+vk::wsi::Display& NativeObjects::getDisplay () const
+{
+ return *display;
+}
+
+vk::wsi::Window& NativeObjects::getWindow (size_t index) const
+{
+ DE_ASSERT(index < windows.size());
+ return *windows[index];
+}
+
+} // wsi
+} // vkt
--- /dev/null
+#ifndef _VKTNATIVEOBJECTSUTIL_HPP
+#define _VKTNATIVEOBJECTSUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2019 The Khronos Group Inc.
+ * Copyright (c) 2019 Valve Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief WSI Native Objects utility class.
+ *//*--------------------------------------------------------------------*/
+#include "vktTestCase.hpp"
+
+#include "vkDefs.hpp"
+#include "vkWsiPlatform.hpp"
+
+#include "tcuMaybe.hpp"
+#include "tcuVectorType.hpp"
+
+
+namespace vkt
+{
+namespace wsi
+{
+
+class NativeObjects
+{
+public:
+ using Extensions = std::vector<vk::VkExtensionProperties>;
+
+ NativeObjects (Context& context,
+ const Extensions& supportedExtensions,
+ vk::wsi::Type wsiType,
+ size_t windowCount = 1u,
+ const tcu::Maybe<tcu::UVec2>& initialWindowSize = tcu::nothing<tcu::UVec2>());
+
+ NativeObjects (NativeObjects&& other);
+
+ vk::wsi::Display& getDisplay () const;
+
+ vk::wsi::Window& getWindow (size_t index = 0u) const;
+
+ static de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const tcu::Maybe<tcu::UVec2>& initialSize);
+
+ static de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform& platform,
+ const Extensions& supportedExtensions,
+ vk::wsi::Type wsiType);
+private:
+ de::UniquePtr<vk::wsi::Display> display;
+ std::vector<de::MovePtr<vk::wsi::Window>> windows;
+
+};
+
+} // wsi
+} // vkt
+
+#endif // _VKTNATIVEOBJECTSUTIL_HPP
#include "vktTestCaseUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktCustomInstancesDevices.hpp"
+#include "vktNativeObjectsUtil.hpp"
#include "vkDefs.hpp"
#include "vkPlatform.hpp"
}
};
-MovePtr<Display> createDisplay (const vk::Platform& platform,
- const Extensions& supportedExtensions,
- Type wsiType)
-{
- try
- {
- return MovePtr<Display>(platform.createWsiDisplay(wsiType));
- }
- catch (const tcu::NotSupportedError& e)
- {
- if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))) &&
- platform.hasDisplay(wsiType))
- {
- // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
- // must support creating native display & window for that WSI type.
- throw tcu::TestError(e.getMessage());
- }
- else
- throw;
- }
-}
-
-MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
-{
- try
- {
- return MovePtr<Window>(display.createWindow(initialSize));
- }
- catch (const tcu::NotSupportedError& e)
- {
- // See createDisplay - assuming that wsi::Display was supported platform port
- // should also support creating a window.
- throw tcu::TestError(e.getMessage());
- }
-}
-
-struct NativeObjects
-{
- const UniquePtr<Display> display;
- const UniquePtr<Window> window;
-
- NativeObjects (Context& context,
- const Extensions& supportedExtensions,
- Type wsiType,
- const Maybe<UVec2>& initialWindowSize = tcu::nothing<UVec2>())
- : display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
- , window (createWindow(*display, initialWindowSize))
- {}
-};
-
enum TestDimension
{
TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
{
const tcu::UVec2 desiredSize (256, 256);
const InstanceHelper instHelper (context, wsiType);
- const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
const tcu::UVec2 desiredSize (256, 256);
const InstanceHelper instHelper (context, params.wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, params.wsiType, tcu::just(desiredSize));
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, params.wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, params.wsiType, native.getDisplay(), native.getWindow()));
const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
const vector<VkSurfaceFormatKHR> queriedFormats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
{
const tcu::UVec2 desiredSize (256, 256);
const InstanceHelper instHelper (context, wsiType);
- const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
{
const tcu::UVec2 desiredSize (256, 256);
const InstanceHelper instHelper (context, wsiType);
- const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const NativeObjects native (context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const DeviceHelper devHelper (context, instHelper.vki, instHelper.instance, *surface);
if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
}
}
-struct NativeObjects
+struct NativeObjectsFS
{
const de::UniquePtr<Display> display;
tcu::UVec2 windowSize;
const de::UniquePtr<Window> window;
- NativeObjects (Context& context,
- const Extensions& supportedExtensions,
- Type wsiType)
+ NativeObjectsFS (Context& context,
+ const Extensions& supportedExtensions,
+ Type wsiType)
: display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
, windowSize (getFullScreenSize(wsiType, *display.get(), tcu::UVec2(256U, 256U)))
, window (createWindow(*display, windowSize))
TCU_THROW(NotSupportedError, "Extension VK_EXT_full_screen_exclusive not supported");
const InstanceHelper instHelper(context, testParams.wsiType);
- const NativeObjects native(context, instHelper.supportedExtensions, testParams.wsiType);
+ const NativeObjectsFS native(context, instHelper.supportedExtensions, testParams.wsiType);
const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, testParams.wsiType, *native.display, *native.window));
const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
const std::vector<VkExtensionProperties> deviceExtensions(enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL));
--- /dev/null
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2019 The Khronos Group Inc.
+ * Copyright (c) 2019 Valve Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Tests for the present id and present wait extensions.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktWsiPresentIdWaitTests.hpp"
+#include "vktTestCase.hpp"
+#include "vktCustomInstancesDevices.hpp"
+#include "vktNativeObjectsUtil.hpp"
+
+#include "vkQueryUtil.hpp"
+#include "vkDeviceUtil.hpp"
+#include "vkWsiUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkRefUtil.hpp"
+
+#include "tcuTestContext.hpp"
+#include "tcuPlatform.hpp"
+#include "tcuCommandLine.hpp"
+#include "tcuTestLog.hpp"
+
+#include "deDefs.hpp"
+
+#include <vector>
+#include <string>
+#include <set>
+#include <sstream>
+#include <chrono>
+#include <algorithm>
+#include <utility>
+#include <limits>
+
+using std::vector;
+using std::string;
+using std::set;
+
+namespace vkt
+{
+namespace wsi
+{
+
+namespace
+{
+
+// Handy time constants in nanoseconds.
+constexpr deUint64 k10sec = 10000000000ull;
+constexpr deUint64 k1sec = 1000000000ull;
+
+// 100 milliseconds, way above 1/50 seconds for systems with 50Hz ticks.
+// This should also take into account possible measure deviations due to the machine being loaded.
+constexpr deUint64 kMargin = 100000000ull;
+
+using TimeoutRange = std::pair<deInt64, deInt64>;
+
+// Calculate acceptable timeout range based on indicated timeout and taking into account kMargin.
+TimeoutRange calcTimeoutRange (deUint64 timeout)
+{
+ constexpr auto kUnsignedMax = std::numeric_limits<deUint64>::max();
+ constexpr auto kSignedMax = static_cast<deUint64>(std::numeric_limits<deInt64>::max());
+
+ // Watch for over- and under-flows.
+ deUint64 timeoutMin = ((timeout < kMargin) ? 0ull : (timeout - kMargin));
+ deUint64 timeoutMax = ((kUnsignedMax - timeout < kMargin) ? kUnsignedMax : timeout + kMargin);
+
+ // Make sure casting is safe.
+ timeoutMin = de::min(kSignedMax, timeoutMin);
+ timeoutMax = de::min(kSignedMax, timeoutMax);
+
+ return TimeoutRange(static_cast<deInt64>(timeoutMin), static_cast<deInt64>(timeoutMax));
+}
+
+class PresentIdWaitInstance : public TestInstance
+{
+public:
+ PresentIdWaitInstance (Context& context, vk::wsi::Type wsiType) : TestInstance(context), m_wsiType(wsiType) {}
+ virtual ~PresentIdWaitInstance (void) {}
+
+ virtual tcu::TestStatus iterate (void);
+
+ virtual tcu::TestStatus run (const vk::DeviceInterface& vkd,
+ vk::VkDevice device,
+ vk::VkQueue queue,
+ vk::VkCommandPool commandPool,
+ vk::VkSwapchainKHR swapchain,
+ size_t swapchainSize,
+ const vk::wsi::WsiTriangleRenderer& renderer) = 0;
+
+ // Subclasses will need to implement a static method like this one indicating which extensions they need.
+ static vector<const char*> requiredDeviceExts (void) { return vector<const char*>(); }
+
+ // Subclasses will also need to implement this nonstatic method returning the same information as above.
+ virtual vector<const char*> getRequiredDeviceExts (void) = 0;
+
+protected:
+ vk::wsi::Type m_wsiType;
+};
+
+vector<const char*> getRequiredInstanceExtensions (vk::wsi::Type wsiType)
+{
+ vector<const char*> extensions;
+ extensions.push_back("VK_KHR_surface");
+ extensions.push_back(getExtensionName(wsiType));
+ return extensions;
+}
+
+CustomInstance createInstanceWithWsi (Context& context,
+ vk::wsi::Type wsiType,
+ const vk::VkAllocationCallbacks* pAllocator = nullptr)
+{
+ const auto version = context.getUsedApiVersion();
+ const auto requiredExtensions = getRequiredInstanceExtensions(wsiType);
+
+ vector<string> requestedExtensions;
+ for (const auto& extensionName : requiredExtensions)
+ {
+ if (!vk::isCoreInstanceExtension(version, extensionName))
+ requestedExtensions.push_back(extensionName);
+ }
+
+ return vkt::createCustomInstanceWithExtensions(context, requestedExtensions, pAllocator);
+}
+
+struct InstanceHelper
+{
+ const vector<vk::VkExtensionProperties> supportedExtensions;
+ CustomInstance instance;
+ const vk::InstanceDriver& vki;
+
+ InstanceHelper (Context& context, vk::wsi::Type wsiType, const vk::VkAllocationCallbacks* pAllocator = nullptr)
+ : supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(), nullptr))
+ , instance (createInstanceWithWsi(context, wsiType, pAllocator))
+ , vki (instance.getDriver())
+ {}
+};
+
+vector<const char*> getMandatoryDeviceExtensions ()
+{
+ vector<const char*> mandatoryExtensions;
+ mandatoryExtensions.push_back("VK_KHR_swapchain");
+ return mandatoryExtensions;
+}
+
+vk::Move<vk::VkDevice> createDeviceWithWsi (const vk::PlatformInterface& vkp,
+ vk::VkInstance instance,
+ const vk::InstanceInterface& vki,
+ vk::VkPhysicalDevice physicalDevice,
+ const vector<const char*>& extraExtensions,
+ const deUint32 queueFamilyIndex,
+ bool validationEnabled,
+ const vk::VkAllocationCallbacks* pAllocator = nullptr)
+{
+ const float queuePriorities[] = { 1.0f };
+ const vk::VkDeviceQueueCreateInfo queueInfos[] =
+ {
+ {
+ vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ nullptr,
+ (vk::VkDeviceQueueCreateFlags)0,
+ queueFamilyIndex,
+ DE_LENGTH_OF_ARRAY(queuePriorities),
+ &queuePriorities[0]
+ }
+ };
+ vk::VkPhysicalDeviceFeatures features;
+ std::vector<const char*> extensions = extraExtensions;
+ const auto mandatoryExtensions = getMandatoryDeviceExtensions();
+
+ for (const auto& ext : mandatoryExtensions)
+ extensions.push_back(ext);
+
+ deMemset(&features, 0, sizeof(features));
+ const vk::VkDeviceCreateInfo deviceParams =
+ {
+ vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ nullptr,
+ (vk::VkDeviceCreateFlags)0,
+ DE_LENGTH_OF_ARRAY(queueInfos),
+ &queueInfos[0],
+ 0u, // enabledLayerCount
+ nullptr, // ppEnabledLayerNames
+ static_cast<deUint32>(extensions.size()), // enabledExtensionCount
+ extensions.data(), // ppEnabledExtensionNames
+ &features
+ };
+
+ return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
+}
+
+struct DeviceHelper
+{
+ const vk::VkPhysicalDevice physicalDevice;
+ const deUint32 queueFamilyIndex;
+ const vk::Unique<vk::VkDevice> device;
+ const vk::DeviceDriver vkd;
+ const vk::VkQueue queue;
+
+ DeviceHelper (Context& context,
+ const vk::InstanceInterface& vki,
+ vk::VkInstance instance,
+ const vector<vk::VkSurfaceKHR>& surfaces,
+ const vector<const char*>& extraExtensions,
+ const vk::VkAllocationCallbacks* pAllocator = nullptr)
+ : physicalDevice (chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
+ , queueFamilyIndex (vk::wsi::chooseQueueFamilyIndex(vki, physicalDevice, surfaces))
+ , device (createDeviceWithWsi(context.getPlatformInterface(),
+ instance,
+ vki,
+ physicalDevice,
+ extraExtensions,
+ queueFamilyIndex,
+ context.getTestContext().getCommandLine().isValidationEnabled(),
+ pAllocator))
+ , vkd (context.getPlatformInterface(), instance, *device)
+ , queue (getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
+ {
+ }
+};
+
+vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters (vk::wsi::Type wsiType,
+ const vk::InstanceInterface& vki,
+ vk::VkPhysicalDevice physicalDevice,
+ vk::VkSurfaceKHR surface,
+ const tcu::UVec2& desiredSize,
+ deUint32 desiredImageCount)
+{
+ const vk::VkSurfaceCapabilitiesKHR capabilities = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
+ physicalDevice,
+ surface);
+ const vector<vk::VkSurfaceFormatKHR> formats = vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
+ physicalDevice,
+ surface);
+ const vk::wsi::PlatformProperties& platformProperties = vk::wsi::getPlatformProperties(wsiType);
+ const vk::VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
+ const vk::VkSwapchainCreateInfoKHR parameters =
+ {
+ vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+ nullptr,
+ (vk::VkSwapchainCreateFlagsKHR)0,
+ surface,
+ de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
+ formats[0].format,
+ formats[0].colorSpace,
+ (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
+ ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
+ 1u, // imageArrayLayers
+ vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ vk::VK_SHARING_MODE_EXCLUSIVE,
+ 0u,
+ nullptr,
+ transform,
+ vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ vk::VK_PRESENT_MODE_FIFO_KHR,
+ VK_FALSE, // clipped
+ (vk::VkSwapchainKHR)0 // oldSwapchain
+ };
+
+ return parameters;
+}
+
+using CommandBufferSp = de::SharedPtr<vk::Unique<vk::VkCommandBuffer>>;
+using FenceSp = de::SharedPtr<vk::Unique<vk::VkFence>>;
+using SemaphoreSp = de::SharedPtr<vk::Unique<vk::VkSemaphore>>;
+
+vector<FenceSp> createFences (const vk::DeviceInterface& vkd,
+ const vk::VkDevice device,
+ size_t numFences)
+{
+ vector<FenceSp> fences(numFences);
+
+ for (size_t ndx = 0; ndx < numFences; ++ndx)
+ fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device, vk::VK_FENCE_CREATE_SIGNALED_BIT)));
+
+ return fences;
+}
+
+vector<SemaphoreSp> createSemaphores (const vk::DeviceInterface& vkd,
+ const vk::VkDevice device,
+ size_t numSemaphores)
+{
+ vector<SemaphoreSp> semaphores(numSemaphores);
+
+ for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
+ semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
+
+ return semaphores;
+}
+
+vector<CommandBufferSp> allocateCommandBuffers (const vk::DeviceInterface& vkd,
+ const vk::VkDevice device,
+ const vk::VkCommandPool commandPool,
+ const vk::VkCommandBufferLevel level,
+ const size_t numCommandBuffers)
+{
+ vector<CommandBufferSp> buffers (numCommandBuffers);
+
+ for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
+ buffers[ndx] = CommandBufferSp(new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
+
+ return buffers;
+}
+
+class FrameStreamObjects
+{
+public:
+ struct FrameObjects
+ {
+ const vk::VkFence& renderCompleteFence;
+ const vk::VkSemaphore& renderCompleteSemaphore;
+ const vk::VkSemaphore& imageAvailableSemaphore;
+ const vk::VkCommandBuffer& commandBuffer;
+ };
+
+ FrameStreamObjects (const vk::DeviceInterface& vkd, vk::VkDevice device, vk::VkCommandPool cmdPool, size_t maxQueuedFrames)
+ : renderingCompleteFences (createFences(vkd, device, maxQueuedFrames))
+ , renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames))
+ , imageAvailableSemaphores (createSemaphores(vkd, device, maxQueuedFrames))
+ , commandBuffers (allocateCommandBuffers(vkd, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames))
+ , m_maxQueuedFrames (maxQueuedFrames)
+ , m_nextFrame (0u)
+ {}
+
+ size_t frameNumber (void) const { DE_ASSERT(m_nextFrame > 0u); return m_nextFrame - 1u; }
+
+ FrameObjects newFrame ()
+ {
+ const size_t mod = m_nextFrame % m_maxQueuedFrames;
+ FrameObjects ret =
+ {
+ **renderingCompleteFences[mod],
+ **renderingCompleteSemaphores[mod],
+ **imageAvailableSemaphores[mod],
+ **commandBuffers[mod],
+ };
+ ++m_nextFrame;
+ return ret;
+ }
+
+private:
+ const vector<FenceSp> renderingCompleteFences;
+ const vector<SemaphoreSp> renderingCompleteSemaphores;
+ const vector<SemaphoreSp> imageAvailableSemaphores;
+ const vector<CommandBufferSp> commandBuffers;
+
+ const size_t m_maxQueuedFrames;
+ size_t m_nextFrame;
+};
+
+tcu::TestStatus PresentIdWaitInstance::iterate (void)
+{
+ const tcu::UVec2 desiredSize (256, 256);
+ const InstanceHelper instHelper (m_context, m_wsiType);
+ const NativeObjects native (m_context, instHelper.supportedExtensions, m_wsiType, 1u, tcu::just(desiredSize));
+ const vk::Unique<vk::VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, m_wsiType, native.getDisplay(), native.getWindow()));
+ const DeviceHelper devHelper (m_context, instHelper.vki, instHelper.instance, vector<vk::VkSurfaceKHR>(1u, surface.get()), getRequiredDeviceExts());
+ const vk::DeviceInterface& vkd = devHelper.vkd;
+ const vk::VkDevice device = *devHelper.device;
+ vk::SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
+ const vk::VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(m_wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
+ const vk::Unique<vk::VkSwapchainKHR> swapchain (vk::createSwapchainKHR(vkd, device, &swapchainInfo));
+ const vector<vk::VkImage> swapchainImages = vk::wsi::getSwapchainImages(vkd, device, *swapchain);
+ const vk::Unique<vk::VkCommandPool> commandPool (createCommandPool(vkd, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
+ const vk::wsi::WsiTriangleRenderer renderer (vkd,
+ device,
+ allocator,
+ m_context.getBinaryCollection(),
+ false,
+ swapchainImages,
+ swapchainImages,
+ swapchainInfo.imageFormat,
+ tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
+
+ try
+ {
+ return run(vkd, device, devHelper.queue, commandPool.get(), swapchain.get(), swapchainImages.size(), renderer);
+ }
+ catch (...)
+ {
+ // Make sure device is idle before destroying resources
+ vkd.deviceWaitIdle(device);
+ throw;
+ }
+
+ return tcu::TestStatus(QP_TEST_RESULT_INTERNAL_ERROR, "Reached unreachable code");
+}
+
+struct PresentParameters
+{
+ tcu::Maybe<deUint64> presentId;
+ tcu::Maybe<vk::VkResult> expectedResult;
+};
+
+struct WaitParameters
+{
+ deUint64 presentId;
+ deUint64 timeout; // Nanoseconds.
+ bool timeoutExpected;
+};
+
+// This structure represents a set of present operations to be run followed by a set of wait operations to be run after them.
+// When running the present operations, the present id can be provided, together with an optional expected result to be checked.
+// When runing the wait operations, the present id must be provided together with a timeout and an indication of whether the operation is expected to time out or not.
+struct PresentAndWaitOps
+{
+ vector<PresentParameters> presentOps;
+ vector<WaitParameters> waitOps;
+};
+
+// Parent class for VK_KHR_present_id and VK_KHR_present_wait simple tests.
+class PresentIdWaitSimpleInstance : public PresentIdWaitInstance
+{
+public:
+ PresentIdWaitSimpleInstance(Context& context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps>& sequence)
+ : PresentIdWaitInstance(context, wsiType), m_sequence(sequence)
+ {}
+
+ virtual ~PresentIdWaitSimpleInstance() {}
+
+ virtual tcu::TestStatus run (const vk::DeviceInterface& vkd,
+ vk::VkDevice device,
+ vk::VkQueue queue,
+ vk::VkCommandPool commandPool,
+ vk::VkSwapchainKHR swapchain,
+ size_t swapchainSize,
+ const vk::wsi::WsiTriangleRenderer& renderer);
+protected:
+ const vector<PresentAndWaitOps> m_sequence;
+};
+
+// Waits for the appropriate fences, acquires swapchain image, records frame and submits it to the given queue, signaling the appropriate frame semaphores.
+// Returns the image index from the swapchain.
+deUint32 recordAndSubmitFrame (FrameStreamObjects::FrameObjects& frameObjects, const vk::wsi::WsiTriangleRenderer& triangleRenderer, const vk::DeviceInterface& vkd, vk::VkDevice device, vk::VkSwapchainKHR swapchain, size_t swapchainSize, vk::VkQueue queue, size_t frameNumber, tcu::TestLog& testLog)
+{
+ // Wait and reset the render complete fence to avoid having too many submitted frames.
+ VK_CHECK(vkd.waitForFences(device, 1u, &frameObjects.renderCompleteFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
+ VK_CHECK(vkd.resetFences(device, 1, &frameObjects.renderCompleteFence));
+
+ // Acquire swapchain image.
+ deUint32 imageNdx = std::numeric_limits<deUint32>::max();
+ const vk::VkResult acquireResult = vkd.acquireNextImageKHR(device,
+ swapchain,
+ std::numeric_limits<deUint64>::max(),
+ frameObjects.imageAvailableSemaphore,
+ (vk::VkFence)0,
+ &imageNdx);
+
+ if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
+ testLog << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNumber << tcu::TestLog::EndMessage;
+ else
+ VK_CHECK(acquireResult);
+ TCU_CHECK(static_cast<size_t>(imageNdx) < swapchainSize);
+
+ // Submit frame to the queue.
+ const vk::VkPipelineStageFlags waitDstStage = vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ const vk::VkSubmitInfo submitInfo =
+ {
+ vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ nullptr,
+ 1u,
+ &frameObjects.imageAvailableSemaphore,
+ &waitDstStage,
+ 1u,
+ &frameObjects.commandBuffer,
+ 1u,
+ &frameObjects.renderCompleteSemaphore,
+ };
+
+ triangleRenderer.recordFrame(frameObjects.commandBuffer, imageNdx, static_cast<deUint32>(frameNumber));
+ VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, frameObjects.renderCompleteFence));
+
+ return imageNdx;
+}
+
+tcu::TestStatus PresentIdWaitSimpleInstance::run (const vk::DeviceInterface& vkd, vk::VkDevice device, vk::VkQueue queue, vk::VkCommandPool commandPool, vk::VkSwapchainKHR swapchain, size_t swapchainSize, const vk::wsi::WsiTriangleRenderer& renderer)
+{
+ const size_t maxQueuedFrames = swapchainSize*2;
+ FrameStreamObjects frameStreamObjects (vkd, device, commandPool, maxQueuedFrames);
+
+ for (const auto& step : m_sequence)
+ {
+ for (const auto& presentOp : step.presentOps)
+ {
+ // Get objects for the next frame.
+ FrameStreamObjects::FrameObjects frameObjects = frameStreamObjects.newFrame();
+
+ // Record and submit new frame.
+ deUint32 imageNdx = recordAndSubmitFrame(frameObjects, renderer, vkd, device, swapchain, swapchainSize, queue, frameStreamObjects.frameNumber(), m_context.getTestContext().getLog());
+
+ // Present rendered frame.
+ const vk::VkPresentIdKHR presentId =
+ {
+ vk::VK_STRUCTURE_TYPE_PRESENT_ID_KHR, // VkStructureType sType;
+ nullptr, // const void* pNext;
+ (presentOp.presentId ? 1u : 0u), // deUint32 swapchainCount;
+ (presentOp.presentId ? &presentOp.presentId.get() : nullptr ), // const deUint64* pPresentIds;
+ };
+
+ const vk::VkPresentInfoKHR presentInfo =
+ {
+ vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+ (presentOp.presentId ? &presentId : nullptr),
+ 1u,
+ &frameObjects.renderCompleteSemaphore,
+ 1u,
+ &swapchain,
+ &imageNdx,
+ nullptr,
+ };
+
+ vk::VkResult result = vkd.queuePresentKHR(queue, &presentInfo);
+
+ if (presentOp.expectedResult)
+ {
+ const vk::VkResult expected = presentOp.expectedResult.get();
+ if ((expected == vk::VK_SUCCESS && result != vk::VK_SUCCESS && result != vk::VK_SUBOPTIMAL_KHR) ||
+ (expected != vk::VK_SUCCESS && result != expected))
+ {
+ std::ostringstream msg;
+ msg << "Got " << result << " while expecting " << expected << " after presenting with ";
+ if (presentOp.presentId)
+ msg << "id " << presentOp.presentId.get();
+ else
+ msg << "no id";
+ TCU_FAIL(msg.str());
+ }
+ }
+ }
+
+ // Wait operations.
+ for (const auto& waitOp : step.waitOps)
+ {
+ auto before = std::chrono::high_resolution_clock::now();
+ vk::VkResult waitResult = vkd.waitForPresentKHR(device, swapchain, waitOp.presentId, waitOp.timeout);
+ auto after = std::chrono::high_resolution_clock::now();
+ auto diff = std::chrono::nanoseconds(after - before).count();
+
+ if (waitOp.timeoutExpected)
+ {
+ if (waitResult != vk::VK_TIMEOUT)
+ {
+ std::ostringstream msg;
+ msg << "Got " << waitResult << " while expecting a timeout in vkWaitForPresentKHR call";
+ TCU_FAIL(msg.str());
+ }
+
+ const auto timeoutRange = calcTimeoutRange(waitOp.timeout);
+
+ if (diff < timeoutRange.first || diff > timeoutRange.second)
+ {
+ std::ostringstream msg;
+ msg << "vkWaitForPresentKHR waited for " << diff << " nanoseconds with a timeout of " << waitOp.timeout << " nanoseconds";
+ TCU_FAIL(msg.str());
+ }
+ }
+ else if (waitResult != vk::VK_SUCCESS)
+ {
+ std::ostringstream msg;
+ msg << "Got " << waitResult << " while expecting success in vkWaitForPresentKHR call";
+ TCU_FAIL(msg.str());
+ }
+ }
+ }
+
+ // Wait until device is idle.
+ VK_CHECK(vkd.deviceWaitIdle(device));
+
+ return tcu::TestStatus::pass("Pass");
+}
+
+// Parent class for VK_KHR_present_id simple tests.
+class PresentIdInstance : public PresentIdWaitSimpleInstance
+{
+public:
+ PresentIdInstance(Context& context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps>& sequence)
+ : PresentIdWaitSimpleInstance(context, wsiType, sequence)
+ {}
+
+ virtual ~PresentIdInstance() {}
+
+ static vector<const char*> requiredDeviceExts (void)
+ {
+ vector<const char*> extensions;
+ extensions.push_back("VK_KHR_present_id");
+ return extensions;
+ }
+
+ virtual vector<const char*> getRequiredDeviceExts (void)
+ {
+ return requiredDeviceExts();
+ }
+};
+
+// Parent class for VK_KHR_present_wait simple tests.
+class PresentWaitInstance : public PresentIdWaitSimpleInstance
+{
+public:
+ PresentWaitInstance(Context& context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps>& sequence)
+ : PresentIdWaitSimpleInstance(context, wsiType, sequence)
+ {}
+
+ virtual ~PresentWaitInstance() {}
+
+ static vector<const char*> requiredDeviceExts (void)
+ {
+ vector<const char*> extensions;
+ extensions.push_back("VK_KHR_present_id");
+ extensions.push_back("VK_KHR_present_wait");
+ return extensions;
+ }
+
+ virtual vector<const char*> getRequiredDeviceExts (void)
+ {
+ return requiredDeviceExts();
+ }
+};
+
+class PresentIdZeroInstance : public PresentIdInstance
+{
+public:
+ static const vector<PresentAndWaitOps> sequence;
+
+ PresentIdZeroInstance (Context& context, vk::wsi::Type wsiType)
+ : PresentIdInstance(context, wsiType, sequence)
+ {}
+};
+
+const vector<PresentAndWaitOps> PresentIdZeroInstance::sequence =
+{
+ { // PresentAndWaitOps
+ { // presentOps vector
+ { tcu::just<deUint64>(0), tcu::just(vk::VK_SUCCESS) },
+ },
+ { // waitOps vector
+ },
+ },
+};
+
+class PresentIdIncreasingInstance : public PresentIdInstance
+{
+public:
+ static const vector<PresentAndWaitOps> sequence;
+
+ PresentIdIncreasingInstance (Context& context, vk::wsi::Type wsiType)
+ : PresentIdInstance(context, wsiType, sequence)
+ {}
+};
+
+const vector<PresentAndWaitOps> PresentIdIncreasingInstance::sequence =
+{
+ { // PresentAndWaitOps
+ { // presentOps vector
+ { tcu::just<deUint64>(1), tcu::just(vk::VK_SUCCESS) },
+ { tcu::just(std::numeric_limits<deUint64>::max()), tcu::just(vk::VK_SUCCESS) },
+ },
+ { // waitOps vector
+ },
+ },
+};
+
+class PresentIdInterleavedInstance : public PresentIdInstance
+{
+public:
+ static const vector<PresentAndWaitOps> sequence;
+
+ PresentIdInterleavedInstance (Context& context, vk::wsi::Type wsiType)
+ : PresentIdInstance(context, wsiType, sequence)
+ {}
+};
+
+const vector<PresentAndWaitOps> PresentIdInterleavedInstance::sequence =
+{
+ { // PresentAndWaitOps
+ { // presentOps vector
+ { tcu::just<deUint64>(0), tcu::just(vk::VK_SUCCESS) },
+ { tcu::just<deUint64>(1), tcu::just(vk::VK_SUCCESS) },
+ { tcu::nothing<deUint64>(), tcu::just(vk::VK_SUCCESS) },
+ { tcu::just(std::numeric_limits<deUint64>::max()), tcu::just(vk::VK_SUCCESS) },
+ },
+ { // waitOps vector
+ },
+ },
+};
+
+class PresentWaitSingleFrameInstance : public PresentWaitInstance
+{
+public:
+ static const vector<PresentAndWaitOps> sequence;
+
+ PresentWaitSingleFrameInstance (Context& context, vk::wsi::Type wsiType)
+ : PresentWaitInstance(context, wsiType, sequence)
+ {}
+};
+
+const vector<PresentAndWaitOps> PresentWaitSingleFrameInstance::sequence =
+{
+ { // PresentAndWaitOps
+ { // presentOps vector
+ { tcu::just<deUint64>(1), tcu::just(vk::VK_SUCCESS) },
+ },
+ { // waitOps vector
+ { 1ull, k10sec, false },
+ },
+ },
+};
+
+class PresentWaitPastFrameInstance : public PresentWaitInstance
+{
+public:
+ static const vector<PresentAndWaitOps> sequence;
+
+ PresentWaitPastFrameInstance (Context& context, vk::wsi::Type wsiType)
+ : PresentWaitInstance(context, wsiType, sequence)
+ {}
+};
+
+const vector<PresentAndWaitOps> PresentWaitPastFrameInstance::sequence =
+{
+ // Start with present id 1.
+ { // PresentAndWaitOps
+ { // presentOps vector
+ { tcu::just<deUint64>(1), tcu::just(vk::VK_SUCCESS) },
+ },
+ { // waitOps vector
+ { 1ull, k10sec, false },
+ { 1ull, 0ull, false },
+ },
+ },
+ // Then the maximum value. Both waiting for id 1 and the max id should work.
+ { // PresentAndWaitOps
+ { // presentOps vector
+ { tcu::just(std::numeric_limits<deUint64>::max()), tcu::just(vk::VK_SUCCESS) },
+ },
+ { // waitOps vector
+ { 1ull, 0ull, false },
+ { 1ull, k10sec, false },
+ { std::numeric_limits<deUint64>::max(), k10sec, false },
+ { std::numeric_limits<deUint64>::max(), 0ull, false },
+ },
+ },
+ // Submit some frames without id after having used the maximum value. This should also work.
+ { // PresentAndWaitOps
+ { // presentOps vector
+ { tcu::nothing<deUint64>(), tcu::just(vk::VK_SUCCESS) },
+ { tcu::just<deUint64>(0), tcu::just(vk::VK_SUCCESS) },
+ },
+ { // waitOps vector
+ },
+ },
+};
+
+class PresentWaitNoFramesInstance : public PresentWaitInstance
+{
+public:
+ static const vector<PresentAndWaitOps> sequence;
+
+ PresentWaitNoFramesInstance (Context& context, vk::wsi::Type wsiType)
+ : PresentWaitInstance(context, wsiType, sequence)
+ {}
+};
+
+const vector<PresentAndWaitOps> PresentWaitNoFramesInstance::sequence =
+{
+ { // PresentAndWaitOps
+ { // presentOps vector
+ },
+ { // waitOps vector
+ { 1ull, 0ull, true },
+ { 1ull, k1sec, true },
+ },
+ },
+};
+
+class PresentWaitNoFrameIdInstance : public PresentWaitInstance
+{
+public:
+ static const vector<PresentAndWaitOps> sequence;
+
+ PresentWaitNoFrameIdInstance (Context& context, vk::wsi::Type wsiType)
+ : PresentWaitInstance(context, wsiType, sequence)
+ {}
+};
+
+const vector<PresentAndWaitOps> PresentWaitNoFrameIdInstance::sequence =
+{
+ { // PresentAndWaitOps
+ { // presentOps vector
+ { tcu::just<deUint64>(0), tcu::just(vk::VK_SUCCESS) },
+ },
+ { // waitOps vector
+ { 1ull, 0ull, true },
+ { 1ull, k1sec, true },
+ },
+ },
+ { // PresentAndWaitOps
+ { // presentOps vector
+ { tcu::nothing<deUint64>(), tcu::just(vk::VK_SUCCESS) },
+ },
+ { // waitOps vector
+ { 1ull, 0ull, true },
+ { 1ull, k1sec, true },
+ },
+ },
+};
+
+class PresentWaitFutureFrameInstance : public PresentWaitInstance
+{
+public:
+ static const vector<PresentAndWaitOps> sequence;
+
+ PresentWaitFutureFrameInstance (Context& context, vk::wsi::Type wsiType)
+ : PresentWaitInstance(context, wsiType, sequence)
+ {}
+};
+
+const vector<PresentAndWaitOps> PresentWaitFutureFrameInstance::sequence =
+{
+ { // PresentAndWaitOps
+ { // presentOps vector
+ { tcu::just<deUint64>(1), tcu::just(vk::VK_SUCCESS) },
+ },
+ { // waitOps vector
+ { std::numeric_limits<deUint64>::max(), k1sec, true },
+ { std::numeric_limits<deUint64>::max(), 0ull, true },
+ { 2ull, 0ull, true },
+ { 2ull, k1sec, true },
+ },
+ },
+};
+
+// Instance with two windows and surfaces to check present ids are not mixed up.
+class PresentWaitDualInstance : public TestInstance
+{
+public:
+ PresentWaitDualInstance (Context& context, vk::wsi::Type wsiType) : TestInstance(context), m_wsiType(wsiType) {}
+ virtual ~PresentWaitDualInstance (void) {}
+
+ virtual tcu::TestStatus iterate (void);
+
+ static vector<const char*> requiredDeviceExts (void)
+ {
+ vector<const char*> extensions;
+ extensions.push_back("VK_KHR_present_id");
+ extensions.push_back("VK_KHR_present_wait");
+ return extensions;
+ }
+
+ virtual vector<const char*> getRequiredDeviceExts (void)
+ {
+ return requiredDeviceExts();
+ }
+
+protected:
+ vk::wsi::Type m_wsiType;
+};
+
+struct IdAndWait
+{
+ deUint64 presentId;
+ bool wait;
+};
+
+struct DualIdAndWait
+{
+ IdAndWait idWait1;
+ IdAndWait idWait2;
+};
+
+tcu::TestStatus PresentWaitDualInstance::iterate (void)
+{
+ const tcu::UVec2 desiredSize (256, 256);
+ const InstanceHelper instHelper (m_context, m_wsiType);
+ const NativeObjects native (m_context, instHelper.supportedExtensions, m_wsiType, 2u, tcu::just(desiredSize));
+ const vk::Unique<vk::VkSurfaceKHR> surface1 (createSurface(instHelper.vki, instHelper.instance, m_wsiType, native.getDisplay(), native.getWindow(0)));
+ const vk::Unique<vk::VkSurfaceKHR> surface2 (createSurface(instHelper.vki, instHelper.instance, m_wsiType, native.getDisplay(), native.getWindow(1)));
+ const DeviceHelper devHelper (m_context, instHelper.vki, instHelper.instance, vector<vk::VkSurfaceKHR>{surface1.get(), surface2.get()}, getRequiredDeviceExts());
+ const vk::DeviceInterface& vkd = devHelper.vkd;
+ const vk::VkDevice device = *devHelper.device;
+ vk::SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
+ const vk::VkSwapchainCreateInfoKHR swapchainInfo1 = getBasicSwapchainParameters(m_wsiType, instHelper.vki, devHelper.physicalDevice, surface1.get(), desiredSize, 2);
+ const vk::VkSwapchainCreateInfoKHR swapchainInfo2 = getBasicSwapchainParameters(m_wsiType, instHelper.vki, devHelper.physicalDevice, surface2.get(), desiredSize, 2);
+ const vk::Unique<vk::VkSwapchainKHR> swapchain1 (vk::createSwapchainKHR(vkd, device, &swapchainInfo1));
+ const vk::Unique<vk::VkSwapchainKHR> swapchain2 (vk::createSwapchainKHR(vkd, device, &swapchainInfo2));
+ const vector<vk::VkImage> swapchainImages1 = vk::wsi::getSwapchainImages(vkd, device, swapchain1.get());
+ const vector<vk::VkImage> swapchainImages2 = vk::wsi::getSwapchainImages(vkd, device, swapchain2.get());
+ const vk::Unique<vk::VkCommandPool> commandPool (createCommandPool(vkd, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
+ const vk::wsi::WsiTriangleRenderer renderer1 (vkd,
+ device,
+ allocator,
+ m_context.getBinaryCollection(),
+ false,
+ swapchainImages1,
+ swapchainImages1,
+ swapchainInfo1.imageFormat,
+ tcu::UVec2(swapchainInfo1.imageExtent.width, swapchainInfo1.imageExtent.height));
+ const vk::wsi::WsiTriangleRenderer renderer2 (vkd,
+ device,
+ allocator,
+ m_context.getBinaryCollection(),
+ false,
+ swapchainImages2,
+ swapchainImages2,
+ swapchainInfo2.imageFormat,
+ tcu::UVec2(swapchainInfo2.imageExtent.width, swapchainInfo2.imageExtent.height));
+ tcu::TestLog& testLog = m_context.getTestContext().getLog();
+
+ try
+ {
+ const size_t maxQueuedFrames = swapchainImages1.size()*2;
+ FrameStreamObjects frameStreamObjects1 (vkd, device, commandPool.get(), maxQueuedFrames);
+ FrameStreamObjects frameStreamObjects2 (vkd, device, commandPool.get(), maxQueuedFrames);
+
+ // Increasing ids for both swapchains, waiting on some to make sure we do not time out unexpectedly.
+ const vector<DualIdAndWait> sequence =
+ {
+ {
+ { 1ull, false },
+ { 2ull, true },
+ },
+ {
+ { 4ull, true },
+ { 3ull, false },
+ },
+ {
+ { 5ull, true },
+ { 6ull, true },
+ },
+ };
+
+ for (const auto& step : sequence)
+ {
+ // Get objects for the next frames.
+ FrameStreamObjects::FrameObjects frameObjects1 = frameStreamObjects1.newFrame();
+ FrameStreamObjects::FrameObjects frameObjects2 = frameStreamObjects2.newFrame();
+
+ // Record and submit frame.
+ deUint32 imageNdx1 = recordAndSubmitFrame(frameObjects1, renderer1, vkd, device, swapchain1.get(), swapchainImages1.size(), devHelper.queue, frameStreamObjects1.frameNumber(), testLog);
+ deUint32 imageNdx2 = recordAndSubmitFrame(frameObjects2, renderer2, vkd, device, swapchain2.get(), swapchainImages2.size(), devHelper.queue, frameStreamObjects2.frameNumber(), testLog);
+
+ // Present both images at the same time with their corresponding ids.
+ const deUint64 presentIdsArr[] = { step.idWait1.presentId, step.idWait2.presentId };
+ const vk::VkPresentIdKHR presentId =
+ {
+ vk::VK_STRUCTURE_TYPE_PRESENT_ID_KHR, // VkStructureType sType;
+ nullptr, // const void* pNext;
+ static_cast<deUint32>(DE_LENGTH_OF_ARRAY(presentIdsArr)), // deUint32 swapchainCount;
+ presentIdsArr, // const deUint64* pPresentIds;
+ };
+
+ const vk::VkSemaphore semaphoreArr[] = { frameObjects1.renderCompleteSemaphore, frameObjects2.renderCompleteSemaphore };
+ const vk::VkSwapchainKHR swapchainArr[] = { swapchain1.get(), swapchain2.get() };
+ const deUint32 imgIndexArr[] = { imageNdx1, imageNdx2 };
+ const vk::VkPresentInfoKHR presentInfo =
+ {
+ vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+ &presentId,
+ static_cast<deUint32>(DE_LENGTH_OF_ARRAY(semaphoreArr)),
+ semaphoreArr,
+ static_cast<deUint32>(DE_LENGTH_OF_ARRAY(swapchainArr)),
+ swapchainArr,
+ imgIndexArr,
+ nullptr,
+ };
+
+ VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
+
+ const IdAndWait* idWaitArr[] = { &step.idWait1, &step.idWait2 };
+ for (int i = 0; i < DE_LENGTH_OF_ARRAY(idWaitArr); ++i)
+ {
+ if (idWaitArr[i]->wait)
+ VK_CHECK(vkd.waitForPresentKHR(device, swapchainArr[i], idWaitArr[i]->presentId, k10sec));
+ }
+ }
+
+ // Wait until device is idle.
+ VK_CHECK(vkd.deviceWaitIdle(device));
+
+ return tcu::TestStatus::pass("Pass");
+ }
+ catch (...)
+ {
+ // Make sure device is idle before destroying resources
+ vkd.deviceWaitIdle(device);
+ throw;
+ }
+
+ return tcu::TestStatus(QP_TEST_RESULT_INTERNAL_ERROR, "Reached unreachable code");
+}
+
+// Templated class for every instance type.
+template <class T> // T is the test instance class.
+class PresentIdWaitCase : public TestCase
+{
+public:
+ PresentIdWaitCase (vk::wsi::Type wsiType, tcu::TestContext& ctx, const std::string& name, const std::string& description);
+ virtual ~PresentIdWaitCase (void) {}
+ virtual void initPrograms (vk::SourceCollections& programCollection) const;
+ virtual TestInstance* createInstance (Context& context) const;
+ virtual void checkSupport (Context& context) const;
+
+protected:
+ vk::wsi::Type m_wsiType;
+};
+
+template <class T>
+PresentIdWaitCase<T>::PresentIdWaitCase (vk::wsi::Type wsiType, tcu::TestContext& ctx, const std::string& name, const std::string& description)
+ : TestCase(ctx, name, description), m_wsiType(wsiType)
+{
+}
+
+template <class T>
+void PresentIdWaitCase<T>::initPrograms (vk::SourceCollections& programCollection) const
+{
+ vk::wsi::WsiTriangleRenderer::getPrograms(programCollection);
+}
+
+template <class T>
+TestInstance* PresentIdWaitCase<T>::createInstance (Context& context) const
+{
+ return new T(context, m_wsiType);
+}
+
+template <class T>
+void PresentIdWaitCase<T>::checkSupport (Context& context) const
+{
+ // Check instance extension support.
+ const auto instanceExtensions = getRequiredInstanceExtensions(m_wsiType);
+ for (const auto& ext : instanceExtensions)
+ {
+ if (!context.isInstanceFunctionalitySupported(ext))
+ TCU_THROW(NotSupportedError, ext + string(" is not supported"));
+ }
+
+ // Check device extension support.
+ const auto& vki = context.getInstanceInterface();
+ const auto physDev = context.getPhysicalDevice();
+ const auto supportedDeviceExts = vk::enumerateDeviceExtensionProperties(vki, physDev, nullptr);
+ const auto mandatoryDeviceExts = getMandatoryDeviceExtensions();
+
+ auto checkedDeviceExts = T::requiredDeviceExts();
+ for (const auto& ext : mandatoryDeviceExts)
+ checkedDeviceExts.push_back(ext);
+
+ for (const auto& ext : checkedDeviceExts)
+ {
+ if (!vk::isExtensionSupported(supportedDeviceExts, vk::RequiredExtension(ext)))
+ TCU_THROW(NotSupportedError, ext + string(" is not supported"));
+ }
+}
+
+void createPresentIdTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
+{
+ testGroup->addChild(new PresentIdWaitCase<PresentIdZeroInstance> (wsiType, testGroup->getTestContext(), "zero", "Use present id zero"));
+ testGroup->addChild(new PresentIdWaitCase<PresentIdIncreasingInstance> (wsiType, testGroup->getTestContext(), "increasing", "Use increasing present ids"));
+ testGroup->addChild(new PresentIdWaitCase<PresentIdInterleavedInstance> (wsiType, testGroup->getTestContext(), "interleaved", "Use increasing present ids interleaved with no ids"));
+}
+
+void createPresentWaitTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
+{
+ testGroup->addChild(new PresentIdWaitCase<PresentWaitSingleFrameInstance> (wsiType, testGroup->getTestContext(), "single_no_timeout", "Present single frame with no expected timeout"));
+ testGroup->addChild(new PresentIdWaitCase<PresentWaitPastFrameInstance> (wsiType, testGroup->getTestContext(), "past_no_timeout", "Wait for past frame with no expected timeout"));
+ testGroup->addChild(new PresentIdWaitCase<PresentWaitNoFramesInstance> (wsiType, testGroup->getTestContext(), "no_frames", "Expect timeout before submitting any frame"));
+ testGroup->addChild(new PresentIdWaitCase<PresentWaitNoFrameIdInstance> (wsiType, testGroup->getTestContext(), "no_frame_id", "Expect timeout after submitting frames with no id"));
+ testGroup->addChild(new PresentIdWaitCase<PresentWaitFutureFrameInstance> (wsiType, testGroup->getTestContext(), "future_frame", "Expect timeout when waiting for a future frame"));
+ testGroup->addChild(new PresentIdWaitCase<PresentWaitDualInstance> (wsiType, testGroup->getTestContext(), "two_swapchains", "Smoke test using two windows, surfaces and swapchains"));
+}
+
+} // anonymous
+
+void createPresentIdWaitTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
+{
+ de::MovePtr<tcu::TestCaseGroup> idGroup (new tcu::TestCaseGroup(testGroup->getTestContext(), "id", "VK_KHR_present_id tests"));
+ de::MovePtr<tcu::TestCaseGroup> waitGroup (new tcu::TestCaseGroup(testGroup->getTestContext(), "wait", "VK_KHR_present_wait tests"));
+
+ createPresentIdTests (idGroup.get(), wsiType);
+ createPresentWaitTests (waitGroup.get(), wsiType);
+
+ testGroup->addChild(idGroup.release());
+ testGroup->addChild(waitGroup.release());
+}
+
+} // wsi
+} // vkt
+
--- /dev/null
+#ifndef _VKTWSIPRESENTIDWAITTESTS_HPP
+#define _VKTWSIPRESENTIDWAITTESTS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2019 The Khronos Group Inc.
+ * Copyright (c) 2019 Valve Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Tests for the present id and present wait extensions.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+#include "vkDefs.hpp"
+
+namespace vkt
+{
+namespace wsi
+{
+
+void createPresentIdWaitTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType);
+
+} // wsi
+} // vkt
+
+#endif // _VKTWSIPRESENTIDWAITTESTS_HPP
#include "vktTestCaseUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktCustomInstancesDevices.hpp"
+#include "vktNativeObjectsUtil.hpp"
#include "vkDefs.hpp"
#include "vkPlatform.hpp"
{}
};
-MovePtr<Display> createDisplay (const vk::Platform& platform,
- const Extensions& supportedExtensions,
- Type wsiType)
-{
- try
- {
- return MovePtr<Display>(platform.createWsiDisplay(wsiType));
- }
- catch (const tcu::NotSupportedError& e)
- {
- if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))) &&
- platform.hasDisplay(wsiType))
- {
- // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
- // must support creating native display & window for that WSI type.
- throw tcu::TestError(e.getMessage());
- }
- else
- throw;
- }
-}
-
-MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
-{
- try
- {
- return MovePtr<Window>(display.createWindow(initialSize));
- }
- catch (const tcu::NotSupportedError& e)
- {
- // See createDisplay - assuming that wsi::Display was supported platform port
- // should also support creating a window.
- throw tcu::TestError(e.getMessage());
- }
-}
-
-struct NativeObjects
-{
- const UniquePtr<Display> display;
- const UniquePtr<Window> window;
-
- NativeObjects (Context& context,
- const Extensions& supportedExtensions,
- Type wsiType,
- const Maybe<UVec2>& initialWindowSize = tcu::nothing<UVec2>())
- : display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
- , window (createWindow(*display, initialWindowSize))
- {}
-};
-
tcu::TestStatus createSurfaceTest (Context& context, Type wsiType)
{
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
return tcu::TestStatus::pass("Creating surface succeeded");
}
{
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const vk::InstanceInterface& vki = context.getInstanceInterface();
const vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
instHelper.instance,
wsiType,
- *native.display,
- *native.window,
+ native.getDisplay(),
+ native.getWindow(),
allocationRecorder.getCallbacks()));
if (!validateAndLog(log,
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
instHelper.instance,
wsiType,
- *native.display,
- *native.window,
+ native.getDisplay(),
+ native.getWindow(),
failingAllocator.getCallbacks()));
if (!validateAndLog(log,
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
// On Android surface must be supported by all devices and queue families
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
+ native.getDisplay();
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
{
const VkPhysicalDevice physicalDevice = physicalDevices[deviceNdx];
for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numQueueFamilies; ++queueFamilyNdx)
{
- VkBool32 isPresentationSupported = getPhysicalDevicePresentationSupport(instHelper.vki, physicalDevice, queueFamilyNdx, wsiType, *native.display);
+ VkBool32 isPresentationSupported = getPhysicalDevicePresentationSupport(instHelper.vki, physicalDevice, queueFamilyNdx, wsiType, native.getDisplay());
VkBool32 isSurfaceSupported = getPhysicalDeviceSurfaceSupport(instHelper.vki, physicalDevice, queueFamilyNdx, *surface);
log << TestLog::Message << "Device " << deviceNdx << ", queue family " << queueFamilyNdx << ": presentation "
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_get_surface_capabilities2")));
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
requiredExtensions.push_back("VK_KHR_surface_protected_capabilities");
const InstanceHelper instHelper (context, wsiType, requiredExtensions);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_get_surface_capabilities2")));
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
tcu::ResultCollector results (log);
const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
- const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
+ const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
const float queuePriority = 1.0f;
const tcu::CommandLine& cmdLine = context.getTestContext().getCommandLine();
const deUint32 devGroupIdx = cmdLine.getVKDeviceGroupId() - 1;
const InstanceHelper instHelper (context, wsiType);
- const UniquePtr<Display> nativeDisplay (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
- instHelper.supportedExtensions,
- wsiType));
+ const UniquePtr<Display> nativeDisplay (NativeObjects::createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
+ instHelper.supportedExtensions,
+ wsiType));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
const UVec2 sizes[] =
for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
{
const UVec2& testSize = sizes[sizeNdx];
- const UniquePtr<Window> nativeWindow (createWindow(*nativeDisplay, tcu::just(testSize)));
+ const UniquePtr<Window> nativeWindow (NativeObjects::createWindow(*nativeDisplay, tcu::just(testSize)));
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *nativeDisplay, *nativeWindow));
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
const InstanceHelper instHelper (context, wsiType);
- const UniquePtr<Display> nativeDisplay (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
- instHelper.supportedExtensions,
- wsiType));
- UniquePtr<Window> nativeWindow (createWindow(*nativeDisplay, tcu::nothing<UVec2>()));
+ const UniquePtr<Display> nativeDisplay (NativeObjects::createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
+ instHelper.supportedExtensions,
+ wsiType));
+ UniquePtr<Window> nativeWindow (NativeObjects::createWindow(*nativeDisplay, tcu::nothing<UVec2>()));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *nativeDisplay, *nativeWindow));
#include "vktTestCaseUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktCustomInstancesDevices.hpp"
+#include "vktNativeObjectsUtil.hpp"
#include "vkDefs.hpp"
#include "vkPlatform.hpp"
}
};
-MovePtr<Display> createDisplay (const vk::Platform& platform,
- const Extensions& supportedExtensions,
- Type wsiType)
-{
- try
- {
- return MovePtr<Display>(platform.createWsiDisplay(wsiType));
- }
- catch (const tcu::NotSupportedError& e)
- {
- if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))) &&
- platform.hasDisplay(wsiType))
- {
- // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
- // must support creating native display & window for that WSI type.
- throw tcu::TestError(e.getMessage());
- }
- else
- throw;
- }
-}
-
-MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
-{
- try
- {
- return MovePtr<Window>(display.createWindow(initialSize));
- }
- catch (const tcu::NotSupportedError& e)
- {
- // See createDisplay - assuming that wsi::Display was supported platform port
- // should also support creating a window.
- throw tcu::TestError(e.getMessage());
- }
-}
-
-class NativeObjects
-{
-private:
- UniquePtr<Display> display;
- vector<MovePtr<Window>> windows;
-
-public:
- NativeObjects (Context& context,
- const Extensions& supportedExtensions,
- Type wsiType,
- size_t windowCount = 1u,
- const Maybe<UVec2>& initialWindowSize = tcu::nothing<UVec2>())
- : display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
- {
- DE_ASSERT(windowCount > 0u);
- for (size_t i = 0; i < windowCount; ++i)
- windows.emplace_back(createWindow(*display, initialWindowSize));
- }
-
- NativeObjects (NativeObjects&& other)
- : display (other.display.move())
- , windows ()
- {
- windows.swap(other.windows);
- }
-
- Display& getDisplay () const
- {
- return *display;
- }
-
- Window& getWindow (size_t index = 0u) const
- {
- DE_ASSERT(index < windows.size());
- return *windows[index];
- }
-};
-
enum TestDimension
{
TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
#include "vktWsiSharedPresentableImageTests.hpp"
#include "vktWsiColorSpaceTests.hpp"
#include "vktWsiFullScreenExclusiveTests.hpp"
+#include "vktWsiPresentIdWaitTests.hpp"
namespace vkt
{
addTestGroup(testGroup, "colorspace", "ColorSpace tests", createColorSpaceTests, wsiType);
addTestGroup(testGroup, "colorspace_compare", "ColorSpace compare tests", createColorspaceCompareTests, wsiType);
addTestGroup(testGroup, "full_screen_exclusive", "VK_EXT_full_screen_exclusive tests", createFullScreenExclusiveTests, wsiType);
+ addTestGroup(testGroup, "present_id_wait", "VK_KHR_present_(id|wait) tests", createPresentIdWaitTests, wsiType);
}
void createWsiTests (tcu::TestCaseGroup* apiTests)
dEQP-VK.wsi.xlib.full_screen_exclusive.allowed
dEQP-VK.wsi.xlib.full_screen_exclusive.disallowed
dEQP-VK.wsi.xlib.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.xlib.present_id_wait.id.zero
+dEQP-VK.wsi.xlib.present_id_wait.id.increasing
+dEQP-VK.wsi.xlib.present_id_wait.id.interleaved
+dEQP-VK.wsi.xlib.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.xlib.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.xlib.present_id_wait.wait.no_frames
+dEQP-VK.wsi.xlib.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.xlib.present_id_wait.wait.future_frame
+dEQP-VK.wsi.xlib.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.xcb.surface.create
dEQP-VK.wsi.xcb.surface.create_custom_allocator
dEQP-VK.wsi.xcb.surface.create_simulate_oom
dEQP-VK.wsi.xcb.full_screen_exclusive.allowed
dEQP-VK.wsi.xcb.full_screen_exclusive.disallowed
dEQP-VK.wsi.xcb.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.xcb.present_id_wait.id.zero
+dEQP-VK.wsi.xcb.present_id_wait.id.increasing
+dEQP-VK.wsi.xcb.present_id_wait.id.interleaved
+dEQP-VK.wsi.xcb.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.xcb.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.xcb.present_id_wait.wait.no_frames
+dEQP-VK.wsi.xcb.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.xcb.present_id_wait.wait.future_frame
+dEQP-VK.wsi.xcb.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.wayland.surface.create
dEQP-VK.wsi.wayland.surface.create_custom_allocator
dEQP-VK.wsi.wayland.surface.create_simulate_oom
dEQP-VK.wsi.wayland.full_screen_exclusive.allowed
dEQP-VK.wsi.wayland.full_screen_exclusive.disallowed
dEQP-VK.wsi.wayland.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.wayland.present_id_wait.id.zero
+dEQP-VK.wsi.wayland.present_id_wait.id.increasing
+dEQP-VK.wsi.wayland.present_id_wait.id.interleaved
+dEQP-VK.wsi.wayland.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.wayland.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.wayland.present_id_wait.wait.no_frames
+dEQP-VK.wsi.wayland.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.wayland.present_id_wait.wait.future_frame
+dEQP-VK.wsi.wayland.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.android.surface.create
dEQP-VK.wsi.android.surface.create_custom_allocator
dEQP-VK.wsi.android.surface.create_simulate_oom
dEQP-VK.wsi.android.full_screen_exclusive.allowed
dEQP-VK.wsi.android.full_screen_exclusive.disallowed
dEQP-VK.wsi.android.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.android.present_id_wait.id.zero
+dEQP-VK.wsi.android.present_id_wait.id.increasing
+dEQP-VK.wsi.android.present_id_wait.id.interleaved
+dEQP-VK.wsi.android.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.android.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.android.present_id_wait.wait.no_frames
+dEQP-VK.wsi.android.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.android.present_id_wait.wait.future_frame
+dEQP-VK.wsi.android.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.win32.surface.create
dEQP-VK.wsi.win32.surface.create_custom_allocator
dEQP-VK.wsi.win32.surface.create_simulate_oom
dEQP-VK.wsi.win32.full_screen_exclusive.allowed
dEQP-VK.wsi.win32.full_screen_exclusive.disallowed
dEQP-VK.wsi.win32.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.win32.present_id_wait.id.zero
+dEQP-VK.wsi.win32.present_id_wait.id.increasing
+dEQP-VK.wsi.win32.present_id_wait.id.interleaved
+dEQP-VK.wsi.win32.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.win32.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.win32.present_id_wait.wait.no_frames
+dEQP-VK.wsi.win32.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.win32.present_id_wait.wait.future_frame
+dEQP-VK.wsi.win32.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.macos.surface.create
dEQP-VK.wsi.macos.surface.create_custom_allocator
dEQP-VK.wsi.macos.surface.create_simulate_oom
dEQP-VK.wsi.macos.full_screen_exclusive.allowed
dEQP-VK.wsi.macos.full_screen_exclusive.disallowed
dEQP-VK.wsi.macos.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.macos.present_id_wait.id.zero
+dEQP-VK.wsi.macos.present_id_wait.id.increasing
+dEQP-VK.wsi.macos.present_id_wait.id.interleaved
+dEQP-VK.wsi.macos.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.macos.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.macos.present_id_wait.wait.no_frames
+dEQP-VK.wsi.macos.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.macos.present_id_wait.wait.future_frame
+dEQP-VK.wsi.macos.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.headless.surface.create
dEQP-VK.wsi.headless.surface.create_custom_allocator
dEQP-VK.wsi.headless.surface.create_simulate_oom
dEQP-VK.wsi.headless.full_screen_exclusive.allowed
dEQP-VK.wsi.headless.full_screen_exclusive.disallowed
dEQP-VK.wsi.headless.full_screen_exclusive.application_controlled
+dEQP-VK.wsi.headless.present_id_wait.id.zero
+dEQP-VK.wsi.headless.present_id_wait.id.increasing
+dEQP-VK.wsi.headless.present_id_wait.id.interleaved
+dEQP-VK.wsi.headless.present_id_wait.wait.single_no_timeout
+dEQP-VK.wsi.headless.present_id_wait.wait.past_no_timeout
+dEQP-VK.wsi.headless.present_id_wait.wait.no_frames
+dEQP-VK.wsi.headless.present_id_wait.wait.no_frame_id
+dEQP-VK.wsi.headless.present_id_wait.wait.future_frame
+dEQP-VK.wsi.headless.present_id_wait.wait.two_swapchains
dEQP-VK.wsi.display.get_display_properties
dEQP-VK.wsi.display.get_display_plane_properties
dEQP-VK.wsi.display.get_display_plane_supported_displays
VK_VALVE_mutable_descriptor_type DEVICE
VK_EXT_multi_draw DEVICE
VK_KHR_shader_subgroup_uniform_control_flow DEVICE
+VK_KHR_present_id DEVICE
+VK_KHR_present_wait DEVICE
VkPhysicalDeviceShaderAtomicFloatFeaturesEXT FEATURES ( shaderImageFloat32Atomics ) REQUIREMENTS ( VK_EXT_shader_atomic_float physicalDeviceShaderAtomicFloatFeaturesEXT.sparseImageFloat32Atomics )
VkPhysicalDeviceShaderAtomicFloatFeaturesEXT FEATURES ( shaderImageFloat32AtomicAdd ) REQUIREMENTS ( VK_EXT_shader_atomic_float physicalDeviceShaderAtomicFloatFeaturesEXT.sparseImageFloat32AtomicAdd )
VkPhysicalDeviceMultiDrawFeaturesEXT FEATURES ( multiDraw ) REQUIREMENTS ( VK_EXT_multi_draw )
-VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR FEATURES ( shaderSubgroupUniformControlFlow ) REQUIREMENTS ( VK_KHR_shader_subgroup_uniform_control_flow )
\ No newline at end of file
+VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR FEATURES ( shaderSubgroupUniformControlFlow ) REQUIREMENTS ( VK_KHR_shader_subgroup_uniform_control_flow )
+VkPhysicalDevicePresentIdFeaturesKHR FEATURES ( presentId ) REQUIREMENTS ( VK_KHR_present_id )
+VkPhysicalDevicePresentWaitFeaturesKHR FEATURES ( presentWait ) REQUIREMENTS ( VK_KHR_present_wait )