Tests for VK_KHR_present_id and VK_KHR_present_wait

Add tests for VK_KHR_present_id and VK_KHR_present_wait. This commit
also refactors some code so it can be reused in several places, hence
marking all WSI tests as affected.

Affected tests:
dEQP-VK.info.device_mandatory_features
dEQP-VK.wsi.*

New tests:
dEQP-VK.wsi.*.present_id_wait.*

Components: Vulkan
VK-GL-CTS issue: 2098
VK-GL-CTS issue: 2099

Change-Id: I1c95fbf031d651773a9fff1c10a23038d73f6e53
(cherry picked from commit 8bf210fd592883b3adebb57c3d6cc49188d1758e)
(cherry picked from commit b7a8721e2ffb9153283b434658463daac7ed1313)
diff --git a/AndroidGen.mk b/AndroidGen.mk
index 8c548ad..61f2663 100644
--- a/AndroidGen.mk
+++ b/AndroidGen.mk
@@ -515,12 +515,14 @@
 	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 \
diff --git a/android/cts/master/vk-master-2021-03-01/wsi.txt b/android/cts/master/vk-master-2021-03-01/wsi.txt
index a527ecc..cbc218b 100644
--- a/android/cts/master/vk-master-2021-03-01/wsi.txt
+++ b/android/cts/master/vk-master-2021-03-01/wsi.txt
@@ -19,6 +19,15 @@
 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
@@ -40,6 +49,15 @@
 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
@@ -481,3 +499,12 @@
 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
diff --git a/android/cts/master/vk-master/wsi.txt b/android/cts/master/vk-master/wsi.txt
index bb56709..8bf41c3 100644
--- a/android/cts/master/vk-master/wsi.txt
+++ b/android/cts/master/vk-master/wsi.txt
@@ -798,6 +798,15 @@
 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
@@ -1240,6 +1249,15 @@
 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
@@ -1681,6 +1699,15 @@
 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
diff --git a/external/vulkancts/framework/vulkan/vkDeviceExtensions.inl b/external/vulkancts/framework/vulkan/vkDeviceExtensions.inl
index 46d64d7..cfd915e 100644
--- a/external/vulkancts/framework/vulkan/vkDeviceExtensions.inl
+++ b/external/vulkancts/framework/vulkan/vkDeviceExtensions.inl
@@ -77,5 +77,7 @@
 	"VK_VALVE_mutable_descriptor_type",
 	"VK_EXT_multi_draw",
 	"VK_KHR_shader_subgroup_uniform_control_flow",
+	"VK_KHR_present_id",
+	"VK_KHR_present_wait",
 };
 
diff --git a/external/vulkancts/framework/vulkan/vkMandatoryFeatures.inl b/external/vulkancts/framework/vulkan/vkMandatoryFeatures.inl
index 91c3655..fe57bdb 100644
--- a/external/vulkancts/framework/vulkan/vkMandatoryFeatures.inl
+++ b/external/vulkancts/framework/vulkan/vkMandatoryFeatures.inl
@@ -266,6 +266,26 @@
 		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));
 
@@ -1838,6 +1858,24 @@
 		}
 	}
 
+	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;
 }
 
diff --git a/external/vulkancts/framework/vulkan/vkWsiUtil.cpp b/external/vulkancts/framework/vulkan/vkWsiUtil.cpp
index 0f3b966..b1023db 100644
--- a/external/vulkancts/framework/vulkan/vkWsiUtil.cpp
+++ b/external/vulkancts/framework/vulkan/vkWsiUtil.cpp
@@ -609,7 +609,7 @@
 		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			=
diff --git a/external/vulkancts/modules/vulkan/wsi/CMakeLists.txt b/external/vulkancts/modules/vulkan/wsi/CMakeLists.txt
index c884157..0e8f299 100644
--- a/external/vulkancts/modules/vulkan/wsi/CMakeLists.txt
+++ b/external/vulkancts/modules/vulkan/wsi/CMakeLists.txt
@@ -3,6 +3,8 @@
 include_directories(..)
 
 set(DEQP_VK_WSI_SRCS
+	vktNativeObjectsUtil.cpp
+	vktNativeObjectsUtil.hpp
 	vktWsiTests.cpp
 	vktWsiTests.hpp
 	vktWsiSurfaceTests.cpp
@@ -23,6 +25,8 @@
 	vktWsiColorSpaceTests.hpp
 	vktWsiFullScreenExclusiveTests.cpp
 	vktWsiFullScreenExclusiveTests.hpp
+	vktWsiPresentIdWaitTests.cpp
+	vktWsiPresentIdWaitTests.hpp
 	)
 
 set(DEQP_VK_WSI_LIBS
diff --git a/external/vulkancts/modules/vulkan/wsi/vktNativeObjectsUtil.cpp b/external/vulkancts/modules/vulkan/wsi/vktNativeObjectsUtil.cpp
new file mode 100644
index 0000000..d2bbaa4
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/wsi/vktNativeObjectsUtil.cpp
@@ -0,0 +1,105 @@
+/*-------------------------------------------------------------------------
+ * 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
diff --git a/external/vulkancts/modules/vulkan/wsi/vktNativeObjectsUtil.hpp b/external/vulkancts/modules/vulkan/wsi/vktNativeObjectsUtil.hpp
new file mode 100644
index 0000000..4f0479a
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/wsi/vktNativeObjectsUtil.hpp
@@ -0,0 +1,71 @@
+#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
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiColorSpaceTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiColorSpaceTests.cpp
index 69508fe..9ffd0f2 100644
--- a/external/vulkancts/modules/vulkan/wsi/vktWsiColorSpaceTests.cpp
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiColorSpaceTests.cpp
@@ -26,6 +26,7 @@
 #include "vktTestCaseUtil.hpp"
 #include "vktTestGroupUtil.hpp"
 #include "vktCustomInstancesDevices.hpp"
+#include "vktNativeObjectsUtil.hpp"
 
 #include "vkDefs.hpp"
 #include "vkPlatform.hpp"
@@ -222,56 +223,6 @@
 	}
 };
 
-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
@@ -465,8 +416,8 @@
 {
 	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"))
@@ -507,7 +458,7 @@
 	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,
@@ -815,8 +766,8 @@
 {
 	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"))
@@ -836,8 +787,8 @@
 {
 	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"))
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiFullScreenExclusiveTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiFullScreenExclusiveTests.cpp
index 7fd072e..bf67b8c 100644
--- a/external/vulkancts/modules/vulkan/wsi/vktWsiFullScreenExclusiveTests.cpp
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiFullScreenExclusiveTests.cpp
@@ -238,15 +238,15 @@
 	}
 }
 
-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))
@@ -341,7 +341,7 @@
 		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));
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiPresentIdWaitTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiPresentIdWaitTests.cpp
new file mode 100644
index 0000000..f32d7ee
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiPresentIdWaitTests.cpp
@@ -0,0 +1,1102 @@
+/*-------------------------------------------------------------------------
+ * 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
+
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiPresentIdWaitTests.hpp b/external/vulkancts/modules/vulkan/wsi/vktWsiPresentIdWaitTests.hpp
new file mode 100644
index 0000000..89b522a
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiPresentIdWaitTests.hpp
@@ -0,0 +1,41 @@
+#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
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp
index 861c26c..0cb5455 100644
--- a/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp
@@ -26,6 +26,7 @@
 #include "vktTestCaseUtil.hpp"
 #include "vktTestGroupUtil.hpp"
 #include "vktCustomInstancesDevices.hpp"
+#include "vktNativeObjectsUtil.hpp"
 
 #include "vkDefs.hpp"
 #include "vkPlatform.hpp"
@@ -221,61 +222,11 @@
 	{}
 };
 
-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");
 }
@@ -284,7 +235,7 @@
 {
 	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();
 
@@ -318,8 +269,8 @@
 		const Unique<VkSurfaceKHR>	surface		(createSurface(instHelper.vki,
 															   instHelper.instance,
 															   wsiType,
-															   *native.display,
-															   *native.window,
+															   native.getDisplay(),
+															   native.getWindow(),
 															   allocationRecorder.getCallbacks()));
 
 		if (!validateAndLog(log,
@@ -364,8 +315,8 @@
 			const Unique<VkSurfaceKHR>	surface		(createSurface(instHelper.vki,
 																   instHelper.instance,
 																   wsiType,
-																   *native.display,
-																   *native.window,
+																   native.getDisplay(),
+																   native.getWindow(),
 																   failingAllocator.getCallbacks()));
 
 			if (!validateAndLog(log,
@@ -413,7 +364,7 @@
 
 	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
@@ -447,9 +398,10 @@
 
 	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];
@@ -457,7 +409,7 @@
 
 		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 "
@@ -541,7 +493,7 @@
 
 	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)
@@ -569,7 +521,7 @@
 
 	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)
@@ -630,7 +582,7 @@
 	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)
@@ -723,7 +675,7 @@
 
 	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)
@@ -769,7 +721,7 @@
 
 	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)
@@ -879,7 +831,7 @@
 
 	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)
@@ -1027,7 +979,7 @@
 	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;
@@ -1180,9 +1132,9 @@
 
 	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[]			=
@@ -1197,7 +1149,7 @@
 	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)
@@ -1224,10 +1176,10 @@
 
 	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));
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
index bd19e55..8482828 100644
--- a/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
@@ -26,6 +26,7 @@
 #include "vktTestCaseUtil.hpp"
 #include "vktTestGroupUtil.hpp"
 #include "vktCustomInstancesDevices.hpp"
+#include "vktNativeObjectsUtil.hpp"
 
 #include "vkDefs.hpp"
 #include "vkPlatform.hpp"
@@ -333,80 +334,6 @@
 	}
 };
 
-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
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiTests.cpp
index aaa0942..02e5f5c 100644
--- a/external/vulkancts/modules/vulkan/wsi/vktWsiTests.cpp
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiTests.cpp
@@ -34,6 +34,7 @@
 #include "vktWsiSharedPresentableImageTests.hpp"
 #include "vktWsiColorSpaceTests.hpp"
 #include "vktWsiFullScreenExclusiveTests.hpp"
+#include "vktWsiPresentIdWaitTests.hpp"
 
 namespace vkt
 {
@@ -53,6 +54,7 @@
 	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)
diff --git a/external/vulkancts/mustpass/master/vk-default/wsi.txt b/external/vulkancts/mustpass/master/vk-default/wsi.txt
index bf4c7c3..c1f3660 100644
--- a/external/vulkancts/mustpass/master/vk-default/wsi.txt
+++ b/external/vulkancts/mustpass/master/vk-default/wsi.txt
@@ -440,6 +440,15 @@
 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
@@ -882,6 +891,15 @@
 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
@@ -1323,6 +1341,15 @@
 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
@@ -2485,6 +2512,15 @@
 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
@@ -2927,6 +2963,15 @@
 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
@@ -3369,6 +3414,15 @@
 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
@@ -3810,6 +3864,15 @@
 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
diff --git a/external/vulkancts/scripts/src/extensions_data.txt b/external/vulkancts/scripts/src/extensions_data.txt
index bd0c693..6526b2f 100644
--- a/external/vulkancts/scripts/src/extensions_data.txt
+++ b/external/vulkancts/scripts/src/extensions_data.txt
@@ -96,3 +96,5 @@
 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
diff --git a/external/vulkancts/scripts/src/mandatory_features.txt b/external/vulkancts/scripts/src/mandatory_features.txt
index 1f47b7d..f30c336 100644
--- a/external/vulkancts/scripts/src/mandatory_features.txt
+++ b/external/vulkancts/scripts/src/mandatory_features.txt
@@ -145,4 +145,6 @@
 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 )