Merge "Fix typo in negative buffer API tests" into nyc-dev
diff --git a/Android.mk b/Android.mk
index 3aff2a3..99e7a2c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -786,6 +786,7 @@
 	external/vulkancts/modules/vulkan/pipeline/vktPipelineStencilTests.cpp \
 	external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp \
 	external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp \
+	external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp \
 	external/vulkancts/modules/vulkan/wsi/vktWsiTests.cpp \
 	external/vulkancts/framework/vulkan/vkBuilderUtil.cpp \
 	external/vulkancts/framework/vulkan/vkSpirVProgram.cpp \
diff --git a/external/vulkancts/framework/vulkan/vkWsiUtil.cpp b/external/vulkancts/framework/vulkan/vkWsiUtil.cpp
index 3f599c9..dcd740c 100644
--- a/external/vulkancts/framework/vulkan/vkWsiUtil.cpp
+++ b/external/vulkancts/framework/vulkan/vkWsiUtil.cpp
@@ -111,7 +111,7 @@
 		// VK_KHR_android_surface
 		{
 			PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE,
-			PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
+			PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE,
 			1u,
 			1u, // Only one window available
 		},
diff --git a/external/vulkancts/modules/vulkan/wsi/CMakeLists.txt b/external/vulkancts/modules/vulkan/wsi/CMakeLists.txt
index 658dbd0..3a271dc 100644
--- a/external/vulkancts/modules/vulkan/wsi/CMakeLists.txt
+++ b/external/vulkancts/modules/vulkan/wsi/CMakeLists.txt
@@ -7,6 +7,8 @@
 	vktWsiTests.hpp
 	vktWsiSurfaceTests.cpp
 	vktWsiSurfaceTests.hpp
+	vktWsiSwapchainTests.cpp
+	vktWsiSwapchainTests.hpp
 	)
 
 set(DEQP_VK_WSI_LIBS
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
new file mode 100644
index 0000000..5f977b8
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
@@ -0,0 +1,611 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief VkSwapchain Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktWsiSwapchainTests.hpp"
+
+#include "vktTestCaseUtil.hpp"
+#include "vktTestGroupUtil.hpp"
+
+#include "vkDefs.hpp"
+#include "vkPlatform.hpp"
+#include "vkStrUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkDeviceUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkWsiPlatform.hpp"
+#include "vkWsiUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuFormatUtil.hpp"
+#include "tcuPlatform.hpp"
+#include "tcuResultCollector.hpp"
+
+#include "deUniquePtr.hpp"
+#include "deStringUtil.hpp"
+#include "deArrayUtil.hpp"
+
+namespace vkt
+{
+namespace wsi
+{
+
+namespace
+{
+
+using namespace vk;
+using namespace vk::wsi;
+
+using tcu::TestLog;
+using tcu::Maybe;
+using tcu::UVec2;
+
+using de::MovePtr;
+using de::UniquePtr;
+
+using std::string;
+using std::vector;
+
+typedef vector<VkExtensionProperties> Extensions;
+
+void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
+{
+	for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
+		 requiredExtName != requiredExtensions.end();
+		 ++requiredExtName)
+	{
+		if (!isExtensionSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
+			TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
+	}
+}
+
+Move<VkInstance> createInstanceWithWsi (const PlatformInterface&	vkp,
+										const Extensions&			supportedExtensions,
+										Type						wsiType)
+{
+	vector<string>	extensions;
+
+	extensions.push_back("VK_KHR_surface");
+	extensions.push_back(getExtensionName(wsiType));
+
+	checkAllSupported(supportedExtensions, extensions);
+
+	return createDefaultInstance(vkp, vector<string>(), extensions);
+}
+
+VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
+{
+	VkPhysicalDeviceFeatures features;
+	deMemset(&features, 0, sizeof(features));
+	return features;
+}
+
+Move<VkDevice> createDeviceWithWsi (const InstanceInterface&	vki,
+									VkPhysicalDevice			physicalDevice,
+									const Extensions&			supportedExtensions,
+									const deUint32				queueFamilyIndex)
+{
+	const float						queuePriorities[]	= { 1.0f };
+	const VkDeviceQueueCreateInfo	queueInfos[]		=
+	{
+		{
+			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+			DE_NULL,
+			(VkDeviceQueueCreateFlags)0,
+			queueFamilyIndex,
+			DE_LENGTH_OF_ARRAY(queuePriorities),
+			&queuePriorities[0]
+		}
+	};
+	const VkPhysicalDeviceFeatures	features		= getDeviceFeaturesForWsi();
+	const char* const				extensions[]	= { "VK_KHR_swapchain" };
+	const VkDeviceCreateInfo		deviceParams	=
+	{
+		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+		DE_NULL,
+		(VkDeviceCreateFlags)0,
+		DE_LENGTH_OF_ARRAY(queueInfos),
+		&queueInfos[0],
+		0u,									// enabledLayerCount
+		DE_NULL,							// ppEnabledLayerNames
+		0u,									// enabledExtensionCount
+		DE_NULL,							// ppEnabledExtensionNames
+		&features
+	};
+
+	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
+	{
+		if (!isExtensionSupported(supportedExtensions, RequiredExtension(extensions[ndx])))
+			TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
+	}
+
+	return createDevice(vki, physicalDevice, &deviceParams, (const VkAllocationCallbacks*)DE_NULL);
+}
+
+deUint32 getNumQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
+{
+	deUint32	numFamilies		= 0;
+
+	vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
+
+	return numFamilies;
+}
+
+vector<deUint32> getSupportedQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
+{
+	const deUint32		numTotalFamilyIndices	= getNumQueueFamilyIndices(vki, physicalDevice);
+	vector<deUint32>	supportedFamilyIndices;
+
+	for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
+	{
+		if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
+			supportedFamilyIndices.push_back(queueFamilyNdx);
+	}
+
+	return supportedFamilyIndices;
+}
+
+deUint32 chooseQueueFamilyIndex (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
+{
+	const vector<deUint32>	supportedFamilyIndices	= getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
+
+	if (supportedFamilyIndices.empty())
+		TCU_THROW(NotSupportedError, "Device doesn't support presentation");
+
+	return supportedFamilyIndices[0];
+}
+
+struct InstanceHelper
+{
+	const vector<VkExtensionProperties>	supportedExtensions;
+	const Unique<VkInstance>			instance;
+	const InstanceDriver				vki;
+
+	InstanceHelper (Context& context, Type wsiType)
+		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(),
+																	  DE_NULL))
+		, instance				(createInstanceWithWsi(context.getPlatformInterface(),
+													   supportedExtensions,
+													   wsiType))
+		, vki					(context.getPlatformInterface(), *instance)
+	{}
+};
+
+VkQueue getDeviceQueue (const DeviceInterface& vkd, VkDevice device, deUint32 queueFamilyIndex, deUint32 queueIndex)
+{
+	VkQueue queue = (VkQueue)0;
+	vkd.getDeviceQueue(device, queueFamilyIndex, queueIndex, &queue);
+	return queue;
+}
+
+struct DeviceHelper
+{
+	const VkPhysicalDevice	physicalDevice;
+	const deUint32			queueFamilyIndex;
+	const Unique<VkDevice>	device;
+	const DeviceDriver		vkd;
+	const VkQueue			queue;
+
+	DeviceHelper (Context& context, const InstanceInterface& vki, VkInstance instance, VkSurfaceKHR surface)
+		: physicalDevice	(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
+		, queueFamilyIndex	(chooseQueueFamilyIndex(vki, physicalDevice, surface))
+		, device			(createDeviceWithWsi(vki,
+												 physicalDevice,
+												 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
+												 queueFamilyIndex))
+		, vkd				(vki, *device)
+		, queue				(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
+	{
+	}
+};
+
+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))))
+		{
+			// 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
+	TEST_DIMENSION_IMAGE_FORMAT,		//!< Test all supported formats
+	TEST_DIMENSION_IMAGE_EXTENT,		//!< Test various (supported) extents
+	TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
+	TEST_DIMENSION_IMAGE_USAGE,
+	TEST_DIMENSION_IMAGE_SHARING_MODE,
+	TEST_DIMENSION_PRE_TRANSFORM,
+	TEST_DIMENSION_COMPOSITE_ALPHA,
+	TEST_DIMENSION_PRESENT_MODE,
+	TEST_DIMENSION_CLIPPED,
+
+	TEST_DIMENSION_LAST
+};
+
+const char* getTestDimensionName (TestDimension dimension)
+{
+	static const char* const s_names[] =
+	{
+		"min_image_count",
+		"image_format",
+		"image_extent",
+		"image_array_layers",
+		"image_usage",
+		"image_sharing_mode",
+		"pre_transform",
+		"composite_alpha",
+		"present_mode",
+		"clipped"
+	};
+	return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
+}
+
+struct TestParameters
+{
+	Type			wsiType;
+	TestDimension	dimension;
+
+	TestParameters (Type wsiType_, TestDimension dimension_)
+		: wsiType	(wsiType_)
+		, dimension	(dimension_)
+	{}
+
+	TestParameters (void)
+		: wsiType	(TYPE_LAST)
+		, dimension	(TEST_DIMENSION_LAST)
+	{}
+};
+
+vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type								wsiType,
+														 		  TestDimension						dimension,
+																  const VkSurfaceCapabilitiesKHR&	capabilities,
+																  const vector<VkSurfaceFormatKHR>&	formats,
+																  const vector<VkPresentModeKHR>&	presentModes)
+{
+	const PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
+	vector<VkSwapchainCreateInfoKHR>	cases;
+	const VkSwapchainCreateInfoKHR		baseParameters		=
+	{
+		VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+		DE_NULL,
+		(VkSwapchainCreateFlagsKHR)0,
+		(VkSurfaceKHR)0,
+		capabilities.minImageCount,
+		formats[0].format,
+		formats[0].colorSpace,
+		(platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
+			? capabilities.minImageExtent : capabilities.currentExtent),
+		1u,									// imageArrayLayers
+		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+		VK_SHARING_MODE_EXCLUSIVE,
+		0u,
+		(const deUint32*)DE_NULL,
+		VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
+		VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+		VK_PRESENT_MODE_FIFO_KHR,
+		VK_FALSE,							// clipped
+		(VkSwapchainKHR)0					// oldSwapchain
+	};
+
+	switch (dimension)
+	{
+		case TEST_DIMENSION_MIN_IMAGE_COUNT:
+		{
+			const deUint32	maxImageCountToTest	= de::clamp(16u, capabilities.minImageCount, capabilities.maxImageCount);
+
+			for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
+			{
+				cases.push_back(baseParameters);
+				cases.back().minImageCount = imageCount;
+			}
+
+			break;
+		}
+
+		case TEST_DIMENSION_IMAGE_FORMAT:
+		{
+			for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
+			{
+				cases.push_back(baseParameters);
+				cases.back().imageFormat		= curFmt->format;
+				cases.back().imageColorSpace	= curFmt->colorSpace;
+			}
+
+			break;
+		}
+
+		case TEST_DIMENSION_IMAGE_EXTENT:
+		{
+			static const VkExtent2D	s_testSizes[]	=
+			{
+				{ 1, 1 },
+				{ 16, 32 },
+				{ 32, 16 },
+				{ 632, 231 },
+				{ 117, 998 },
+			};
+
+			if (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
+				platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
+			{
+				for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
+				{
+					cases.push_back(baseParameters);
+					cases.back().imageExtent.width	= de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
+					cases.back().imageExtent.height	= de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
+				}
+			}
+
+			if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
+			{
+				cases.push_back(baseParameters);
+				cases.back().imageExtent = capabilities.currentExtent;
+			}
+
+			if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
+			{
+				cases.push_back(baseParameters);
+				cases.back().imageExtent = capabilities.minImageExtent;
+
+				cases.push_back(baseParameters);
+				cases.back().imageExtent = capabilities.maxImageExtent;
+			}
+
+			break;
+		}
+
+		case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
+		{
+			const deUint32	maxLayers	= de::min(capabilities.maxImageArrayLayers, 16u);
+
+			for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
+			{
+				cases.push_back(baseParameters);
+				cases.back().imageArrayLayers = numLayers;
+			}
+
+			break;
+		}
+
+		case TEST_DIMENSION_IMAGE_USAGE:
+		{
+			for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
+			{
+				if ((flags & ~capabilities.supportedUsageFlags) == 0)
+				{
+					cases.push_back(baseParameters);
+					cases.back().imageUsage = flags;
+				}
+			}
+
+			break;
+		}
+
+		case TEST_DIMENSION_IMAGE_SHARING_MODE:
+		{
+			cases.push_back(baseParameters);
+			cases.back().imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+			cases.push_back(baseParameters);
+			cases.back().imageSharingMode = VK_SHARING_MODE_CONCURRENT;
+
+			break;
+		}
+
+		case TEST_DIMENSION_PRE_TRANSFORM:
+		{
+			for (deUint32 transform = 1u;
+				 transform <= capabilities.supportedTransforms;
+				 transform = transform<<1u)
+			{
+				if ((transform & capabilities.supportedTransforms) != 0)
+				{
+					cases.push_back(baseParameters);
+					cases.back().preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
+				}
+			}
+
+			break;
+		}
+
+		case TEST_DIMENSION_COMPOSITE_ALPHA:
+		{
+			for (deUint32 alphaMode = 1u;
+				 alphaMode <= capabilities.supportedCompositeAlpha;
+				 alphaMode = alphaMode<<1u)
+			{
+				if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
+				{
+					cases.push_back(baseParameters);
+					cases.back().compositeAlpha = (VkCompositeAlphaFlagBitsKHR)alphaMode;
+				}
+			}
+
+			break;
+		}
+
+		case TEST_DIMENSION_PRESENT_MODE:
+		{
+			for (vector<VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
+			{
+				cases.push_back(baseParameters);
+				cases.back().presentMode = *curMode;
+			}
+
+			break;
+		}
+
+		case TEST_DIMENSION_CLIPPED:
+		{
+			cases.push_back(baseParameters);
+			cases.back().clipped = VK_FALSE;
+
+			cases.push_back(baseParameters);
+			cases.back().clipped = VK_TRUE;
+
+			break;
+		}
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	DE_ASSERT(!cases.empty());
+	return cases;
+}
+
+vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type								wsiType,
+																  TestDimension						dimension,
+																  const InstanceInterface&			vki,
+																  VkPhysicalDevice					physicalDevice,
+																  VkSurfaceKHR						surface)
+{
+	const VkSurfaceCapabilitiesKHR		capabilities	= getPhysicalDeviceSurfaceCapabilities(vki,
+																							   physicalDevice,
+																							   surface);
+	const vector<VkSurfaceFormatKHR>	formats			= getPhysicalDeviceSurfaceFormats(vki,
+																						  physicalDevice,
+																						  surface);
+	const vector<VkPresentModeKHR>		presentModes	= getPhysicalDeviceSurfacePresentModes(vki,
+																							   physicalDevice,
+																							   surface);
+
+	return generateSwapchainParameterCases(wsiType, dimension, capabilities, formats, presentModes);
+}
+
+tcu::TestStatus createSwapchainTest (Context& context, TestParameters params)
+{
+	const InstanceHelper					instHelper	(context, params.wsiType);
+	const NativeObjects						native		(context, instHelper.supportedExtensions, params.wsiType);
+	const Unique<VkSurfaceKHR>				surface		(createSurface(instHelper.vki, *instHelper.instance, params.wsiType, *native.display, *native.window));
+	const DeviceHelper						devHelper	(context, instHelper.vki, *instHelper.instance, *surface);
+	const vector<VkSwapchainCreateInfoKHR>	cases		(generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
+
+	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
+	{
+		VkSwapchainCreateInfoKHR	curParams	= cases[caseNdx];
+
+		curParams.surface				= *surface;
+		curParams.queueFamilyIndexCount	= 1u;
+		curParams.pQueueFamilyIndices	= &devHelper.queueFamilyIndex;
+
+		context.getTestContext().getLog()
+			<< TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": " << curParams << TestLog::EndMessage;
+
+		{
+			const Unique<VkSwapchainKHR>	swapchain	(createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
+		}
+	}
+
+	return tcu::TestStatus::pass("Creating swapchain succeeded");
+}
+
+struct GroupParameters
+{
+	typedef FunctionInstance1<TestParameters>::Function	Function;
+
+	Type		wsiType;
+	Function	function;
+
+	GroupParameters (Type wsiType_, Function function_)
+		: wsiType	(wsiType_)
+		, function	(function_)
+	{}
+
+	GroupParameters (void)
+		: wsiType	(TYPE_LAST)
+		, function	((Function)DE_NULL)
+	{}
+};
+
+void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
+{
+	for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
+	{
+		const TestDimension		testDimension	= (TestDimension)dimensionNdx;
+
+		addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
+	}
+}
+
+} // anonymous
+
+void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
+{
+	addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
+}
+
+} // wsi
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.hpp b/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.hpp
new file mode 100644
index 0000000..03403c9
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.hpp
@@ -0,0 +1,47 @@
+#ifndef _VKWSISWAPCHAINTESTS_HPP
+#define _VKWSISWAPCHAINTESTS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief VkSwapchain Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+#include "vkDefs.hpp"
+
+namespace vkt
+{
+namespace wsi
+{
+
+void	createSwapchainTests	(tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType);
+
+} // wsi
+} // vkt
+
+#endif // _VKWSISWAPCHAINTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiTests.cpp
index 517c634..6277c2a 100644
--- a/external/vulkancts/modules/vulkan/wsi/vktWsiTests.cpp
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiTests.cpp
@@ -29,10 +29,12 @@
  *//*--------------------------------------------------------------------*/
 
 #include "vktWsiTests.hpp"
-#include "vktWsiSurfaceTests.hpp"
 #include "vktTestGroupUtil.hpp"
 #include "vkWsiUtil.hpp"
 
+#include "vktWsiSurfaceTests.hpp"
+#include "vktWsiSwapchainTests.hpp"
+
 namespace vkt
 {
 namespace wsi
@@ -43,7 +45,8 @@
 
 void createTypeSpecificTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
 {
-	addTestGroup(testGroup, "surface", "VkSurface Tests", createSurfaceTests, wsiType);
+	addTestGroup(testGroup, "surface",		"VkSurface Tests",		createSurfaceTests,		wsiType);
+	addTestGroup(testGroup, "swapchain",	"VkSwapchain Tests",	createSwapchainTests,	wsiType);
 }
 
 void createWsiTests (tcu::TestCaseGroup* apiTests)