Merge changes I87bf1147,I1bfc5656 into nyc-dev

* changes:
  Enable blending for floating point formats
  Always disable blending for 32bit float formats
diff --git a/android/cts/master/com.drawelements.deqp.vk.xml b/android/cts/master/com.drawelements.deqp.vk.xml
index 6a6cef9..3b93b5d 100644
--- a/android/cts/master/com.drawelements.deqp.vk.xml
+++ b/android/cts/master/com.drawelements.deqp.vk.xml
@@ -258753,6 +258753,12 @@
 					<Test name="create">
 						<TestInstance/>
 					</Test>
+					<Test name="create_custom_allocator">
+						<TestInstance/>
+					</Test>
+					<Test name="create_simulate_oom">
+						<TestInstance/>
+					</Test>
 					<Test name="query_support">
 						<TestInstance/>
 					</Test>
@@ -258802,6 +258808,38 @@
 							<TestInstance/>
 						</Test>
 					</TestCase>
+					<TestCase name="simulate_oom">
+						<Test name="min_image_count">
+							<TestInstance/>
+						</Test>
+						<Test name="image_format">
+							<TestInstance/>
+						</Test>
+						<Test name="image_extent">
+							<TestInstance/>
+						</Test>
+						<Test name="image_array_layers">
+							<TestInstance/>
+						</Test>
+						<Test name="image_usage">
+							<TestInstance/>
+						</Test>
+						<Test name="image_sharing_mode">
+							<TestInstance/>
+						</Test>
+						<Test name="pre_transform">
+							<TestInstance/>
+						</Test>
+						<Test name="composite_alpha">
+							<TestInstance/>
+						</Test>
+						<Test name="present_mode">
+							<TestInstance/>
+						</Test>
+						<Test name="clipped">
+							<TestInstance/>
+						</Test>
+					</TestCase>
 				</TestSuite>
 			</TestSuite>
 		</TestSuite>
diff --git a/android/cts/master/vk-master.txt b/android/cts/master/vk-master.txt
index 67729e3..fdb1556 100644
--- a/android/cts/master/vk-master.txt
+++ b/android/cts/master/vk-master.txt
@@ -80289,6 +80289,8 @@
 dEQP-VK.image.image_size.buffer.readonly_writeonly_1
 dEQP-VK.image.image_size.buffer.readonly_writeonly_7
 dEQP-VK.wsi.android.surface.create
+dEQP-VK.wsi.android.surface.create_custom_allocator
+dEQP-VK.wsi.android.surface.create_simulate_oom
 dEQP-VK.wsi.android.surface.query_support
 dEQP-VK.wsi.android.surface.query_capabilities
 dEQP-VK.wsi.android.surface.query_formats
@@ -80304,6 +80306,16 @@
 dEQP-VK.wsi.android.swapchain.create.composite_alpha
 dEQP-VK.wsi.android.swapchain.create.present_mode
 dEQP-VK.wsi.android.swapchain.create.clipped
+dEQP-VK.wsi.android.swapchain.simulate_oom.min_image_count
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_format
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_extent
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_array_layers
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_usage
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_sharing_mode
+dEQP-VK.wsi.android.swapchain.simulate_oom.pre_transform
+dEQP-VK.wsi.android.swapchain.simulate_oom.composite_alpha
+dEQP-VK.wsi.android.swapchain.simulate_oom.present_mode
+dEQP-VK.wsi.android.swapchain.simulate_oom.clipped
 dEQP-VK.synchronization.fences
 dEQP-VK.synchronization.semaphores
 dEQP-VK.synchronization.events
diff --git a/external/vulkancts/README.md b/external/vulkancts/README.md
index 65561e9..7985148 100644
--- a/external/vulkancts/README.md
+++ b/external/vulkancts/README.md
@@ -134,6 +134,11 @@
 
 	--deqp-vk-device-id=<value>
 
+To speed up the conformance run on some platforms the following command line
+option may be used to disable frequent fflush() calls to the output logs:
+
+	--deqp-log-flush=disable
+
 No other command line options are allowed.
 
 ### Win32
diff --git a/external/vulkancts/framework/vulkan/vkDeviceUtil.cpp b/external/vulkancts/framework/vulkan/vkDeviceUtil.cpp
index a551680..3e146f6 100644
--- a/external/vulkancts/framework/vulkan/vkDeviceUtil.cpp
+++ b/external/vulkancts/framework/vulkan/vkDeviceUtil.cpp
@@ -43,9 +43,10 @@
 using std::vector;
 using std::string;
 
-Move<VkInstance> createDefaultInstance (const PlatformInterface&	vkPlatform,
-										const vector<string>&		enabledLayers,
-										const vector<string>&		enabledExtensions)
+Move<VkInstance> createDefaultInstance (const PlatformInterface&		vkPlatform,
+										const vector<string>&			enabledLayers,
+										const vector<string>&			enabledExtensions,
+										const VkAllocationCallbacks*	pAllocator)
 {
 	vector<const char*>		layerNamePtrs		(enabledLayers.size());
 	vector<const char*>		extensionNamePtrs	(enabledExtensions.size());
@@ -79,12 +80,12 @@
 	for (size_t ndx = 0; ndx < enabledExtensions.size(); ++ndx)
 		extensionNamePtrs[ndx] = enabledExtensions[ndx].c_str();
 
-	return createInstance(vkPlatform, &instanceInfo);
+	return createInstance(vkPlatform, &instanceInfo, pAllocator);
 }
 
 Move<VkInstance> createDefaultInstance (const PlatformInterface& vkPlatform)
 {
-	return createDefaultInstance(vkPlatform, vector<string>(), vector<string>());
+	return createDefaultInstance(vkPlatform, vector<string>(), vector<string>(), DE_NULL);
 }
 
 VkPhysicalDevice chooseDevice (const InstanceInterface& vkInstance, VkInstance instance, const tcu::CommandLine& cmdLine)
diff --git a/external/vulkancts/framework/vulkan/vkDeviceUtil.hpp b/external/vulkancts/framework/vulkan/vkDeviceUtil.hpp
index 3b59e8b..123a815 100644
--- a/external/vulkancts/framework/vulkan/vkDeviceUtil.hpp
+++ b/external/vulkancts/framework/vulkan/vkDeviceUtil.hpp
@@ -47,7 +47,8 @@
 Move<VkInstance>	createDefaultInstance	(const PlatformInterface&			vkPlatform);
 Move<VkInstance>	createDefaultInstance	(const PlatformInterface&			vkPlatform,
 											 const std::vector<std::string>&	enabledLayers,
-											 const std::vector<std::string>&	enabledExtensions);
+											 const std::vector<std::string>&	enabledExtensions,
+											 const VkAllocationCallbacks*		pAllocator	= DE_NULL);
 
 VkPhysicalDevice	chooseDevice			(const InstanceInterface&			vkInstance,
 											 VkInstance							instance,
diff --git a/external/vulkancts/modules/vulkan/api/vktApiBufferTests.cpp b/external/vulkancts/modules/vulkan/api/vktApiBufferTests.cpp
index 6b36cce..f4dc86e 100644
--- a/external/vulkancts/modules/vulkan/api/vktApiBufferTests.cpp
+++ b/external/vulkancts/modules/vulkan/api/vktApiBufferTests.cpp
@@ -50,6 +50,8 @@
 namespace
 {
 
+static const deUint32	MAX_BUFFER_SIZE_DIVISOR	= 16;
+
 struct BufferCaseParameters
 {
 	VkBufferUsageFlags	usage;
@@ -97,16 +99,19 @@
 
  tcu::TestStatus BufferTestInstance::bufferCreateAndAllocTest (VkDeviceSize size)
 {
-	const VkDevice			vkDevice			= m_context.getDevice();
-	const DeviceInterface&	vk					= m_context.getDeviceInterface();
-	Move<VkBuffer>			testBuffer;
-	VkMemoryRequirements	memReqs;
-	Move<VkDeviceMemory>	memory;
-	const deUint32			queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
+	const VkPhysicalDevice		vkPhysicalDevice	= m_context.getPhysicalDevice();
+	const InstanceInterface&	vkInstance			= m_context.getInstanceInterface();
+	const VkDevice				vkDevice			= m_context.getDevice();
+	const DeviceInterface&		vk					= m_context.getDeviceInterface();
+	Move<VkBuffer>				testBuffer;
+	VkMemoryRequirements		memReqs;
+	Move<VkDeviceMemory>		memory;
+	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
+	const VkPhysicalDeviceMemoryProperties	memoryProperties = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
 
 	// Create buffer
 	{
-		const VkBufferCreateInfo		bufferParams		=
+		VkBufferCreateInfo		bufferParams		=
 		{
 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
 			DE_NULL,
@@ -120,7 +125,7 @@
 
 		try
 		{
-			testBuffer = createBuffer(vk, vkDevice, &bufferParams, (const VkAllocationCallbacks*)DE_NULL);
+			testBuffer = createBuffer(vk, vkDevice, &bufferParams);
 		}
 		catch (const vk::Error& error)
 		{
@@ -129,6 +134,27 @@
 
 		vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
 
+		const deUint32		heapTypeIndex	= (deUint32)deCtz32(memReqs.memoryTypeBits);
+		const VkMemoryType	memoryType		= memoryProperties.memoryTypes[heapTypeIndex];
+		const VkMemoryHeap	memoryHeap		= memoryProperties.memoryHeaps[memoryType.heapIndex];
+		const VkDeviceSize	maxBufferSize	= memoryHeap.size / MAX_BUFFER_SIZE_DIVISOR;
+		// If the requested size is too large, clamp it based on the selected heap size
+		if (size > maxBufferSize)
+		{
+			size = maxBufferSize;
+			bufferParams.size = size;
+			try
+			{
+				// allocate a new buffer with the adjusted size, the old one will be destroyed by the smart pointer
+				testBuffer = createBuffer(vk, vkDevice, &bufferParams);
+			}
+			catch (const vk::Error& error)
+			{
+				return tcu::TestStatus::fail("Buffer creation failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
+			}
+			vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
+		}
+
 		if (size > memReqs.size)
 		{
 			std::ostringstream errorMsg;
@@ -250,14 +276,10 @@
 	{
 		const VkPhysicalDevice					vkPhysicalDevice	= m_context.getPhysicalDevice();
 		const InstanceInterface&				vkInstance			= m_context.getInstanceInterface();
-		const VkPhysicalDeviceMemoryProperties	memoryProperties	= getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
 		VkPhysicalDeviceProperties	props;
 
 		vkInstance.getPhysicalDeviceProperties(vkPhysicalDevice, &props);
-
-		const VkDeviceSize maxTestBufferSize = de::min((VkDeviceSize) props.limits.maxTexelBufferElements, memoryProperties.memoryHeaps[memoryProperties.memoryTypes[0].heapIndex].size / 16);
-
-		testStatus = bufferCreateAndAllocTest(maxTestBufferSize);
+		testStatus = bufferCreateAndAllocTest((VkDeviceSize) props.limits.maxTexelBufferElements);
 	}
 
 	return testStatus;
diff --git a/external/vulkancts/modules/vulkan/memory/vktMemoryPipelineBarrierTests.cpp b/external/vulkancts/modules/vulkan/memory/vktMemoryPipelineBarrierTests.cpp
index 68f9396..61cb205 100644
--- a/external/vulkancts/modules/vulkan/memory/vktMemoryPipelineBarrierTests.cpp
+++ b/external/vulkancts/modules/vulkan/memory/vktMemoryPipelineBarrierTests.cpp
@@ -60,7 +60,7 @@
 #include <string>
 #include <vector>
 
-// \todo Check bufferImageGranularity
+// \todo [2016-03-09 mika] Check bufferImageGranularity
 
 using tcu::TestLog;
 using tcu::Maybe;
@@ -145,7 +145,7 @@
 	USAGE_UNIFORM_TEXEL_BUFFER = (0x1u<<8),
 	USAGE_STORAGE_TEXEL_BUFFER = (0x1u<<9),
 
-	// \todo This is probably almost impossible to do
+	// \todo [2016-03-09 mika] This is probably almost impossible to do
 	USAGE_INDIRECT_BUFFER = (0x1u<<10),
 
 	// Texture usage flags
@@ -753,7 +753,7 @@
 {
 	const deUint8* data = (const deUint8*)data_;
 
-	// \todo Optimize
+	// \todo [2016-03-09 mika] Optimize
 	for (size_t pos = 0; pos < size; pos++)
 	{
 		m_data[offset + pos] = data[pos];
@@ -763,7 +763,7 @@
 
 void ReferenceMemory::setUndefined	(size_t offset, size_t size)
 {
-	// \todo Optimize
+	// \todo [2016-03-09 mika] Optimize
 	for (size_t pos = 0; pos < size; pos++)
 		m_defined[(offset + pos) / 64] |= 0x1ull << ((offset + pos) % 64);
 }
@@ -874,7 +874,7 @@
 	vk::VkDeviceSize		bestW			= de::max(maxTexelCount, maxTextureSize);
 	vk::VkDeviceSize		bestH			= maxTexelCount / bestW;
 
-	// \todo Could probably be faster?
+	// \todo [2016-03-09 mika] Could probably be faster?
 	for (vk::VkDeviceSize w = 1; w * w < maxTexelCount && w < maxTextureSize && bestW * bestH * 4 < size; w++)
 	{
 		const vk::VkDeviceSize h = maxTexelCount / w;
@@ -898,7 +898,7 @@
 
 	DE_ASSERT((size % 4) == 0);
 
-	// \todo Could probably be faster?
+	// \todo [2016-03-09 mika] Could probably be faster?
 	for (vk::VkDeviceSize w = 1; w < maxTextureSize && w < texelCount; w++)
 	{
 		const vk::VkDeviceSize	h	= texelCount / w;
@@ -2077,7 +2077,15 @@
 class ImageTransition : public CmdCommand
 {
 public:
-						ImageTransition		(void) {}
+						ImageTransition		(vk::VkPipelineStageFlags	srcStages,
+											 vk::VkAccessFlags			srcAccesses,
+
+											 vk::VkPipelineStageFlags	dstStages,
+											 vk::VkAccessFlags			dstAccesses,
+
+											 vk::VkImageLayout			srcLayout,
+											 vk::VkImageLayout			dstLayout);
+
 						~ImageTransition	(void) {}
 	const char*			getName				(void) const { return "ImageTransition"; }
 
@@ -2087,17 +2095,47 @@
 	void				verify				(VerifyContext& context, size_t);
 
 private:
-	vk::VkDeviceSize	m_imageMemorySize;
+	const vk::VkPipelineStageFlags	m_srcStages;
+	const vk::VkAccessFlags			m_srcAccesses;
+	const vk::VkPipelineStageFlags	m_dstStages;
+	const vk::VkAccessFlags			m_dstAccesses;
+	const vk::VkImageLayout			m_srcLayout;
+	const vk::VkImageLayout			m_dstLayout;
+
+	vk::VkDeviceSize				m_imageMemorySize;
 };
 
+ImageTransition::ImageTransition (vk::VkPipelineStageFlags	srcStages,
+								  vk::VkAccessFlags			srcAccesses,
+
+								  vk::VkPipelineStageFlags	dstStages,
+								  vk::VkAccessFlags			dstAccesses,
+
+								  vk::VkImageLayout			srcLayout,
+								  vk::VkImageLayout			dstLayout)
+	: m_srcStages		(srcStages)
+	, m_srcAccesses		(srcAccesses)
+	, m_dstStages		(dstStages)
+	, m_dstAccesses		(dstAccesses)
+	, m_srcLayout		(srcLayout)
+	, m_dstLayout		(dstLayout)
+{
+}
+
 void ImageTransition::logSubmit (TestLog& log, size_t commandIndex) const
 {
-	log << TestLog::Message << commandIndex << ":" << getName() << " Use pipeline barrier to transition to VK_IMAGE_LAYOUT_GENERAL." << TestLog::EndMessage;
+	log << TestLog::Message << commandIndex << ":" << getName()
+		<< " Image transition pipeline barrier"
+		<< ", srcStages: " << vk::getPipelineStageFlagsStr(m_srcStages) << ", srcAccesses: " << vk::getAccessFlagsStr(m_srcAccesses)
+		<< ", dstStages: " << vk::getPipelineStageFlagsStr(m_dstStages) << ", dstAccesses: " << vk::getAccessFlagsStr(m_dstAccesses)
+		<< ", srcLayout: " << m_srcLayout << ", dstLayout: " << m_dstLayout << TestLog::EndMessage;
 }
 
 void ImageTransition::prepare (PrepareContext& context)
 {
-	context.setImageLayout(vk::VK_IMAGE_LAYOUT_GENERAL);
+	DE_ASSERT(context.getImageLayout() == vk::VK_IMAGE_LAYOUT_UNDEFINED || m_srcLayout == vk::VK_IMAGE_LAYOUT_UNDEFINED || context.getImageLayout() == m_srcLayout);
+
+	context.setImageLayout(m_dstLayout);
 	m_imageMemorySize = context.getImageMemorySize();
 }
 
@@ -2110,11 +2148,11 @@
 		vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
 		DE_NULL,
 
-		ALL_ACCESSES,
-		ALL_ACCESSES,
+		m_srcAccesses,
+		m_dstAccesses,
 
-		context.getImageLayout(),
-		vk::VK_IMAGE_LAYOUT_GENERAL,
+		m_srcLayout,
+		m_dstLayout,
 
 		vk::VK_QUEUE_FAMILY_IGNORED,
 		vk::VK_QUEUE_FAMILY_IGNORED,
@@ -2127,7 +2165,7 @@
 		}
 	};
 
-	vkd.cmdPipelineBarrier(cmd, ALL_PIPELINE_STAGES, ALL_PIPELINE_STAGES, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 1, &barrier);
+	vkd.cmdPipelineBarrier(cmd, m_srcStages, m_dstStages, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 1, &barrier);
 }
 
 void ImageTransition::verify (VerifyContext& context, size_t)
@@ -4920,7 +4958,7 @@
 	OP_IMAGE_DESTROY,
 	OP_IMAGE_BINDMEMORY,
 
-	OP_IMAGE_TRANSITION_TO_GENERAL,
+	OP_IMAGE_TRANSITION_LAYOUT,
 
 	OP_IMAGE_COPY_TO_BUFFER,
 	OP_IMAGE_COPY_FROM_BUFFER,
@@ -4954,63 +4992,60 @@
 	STAGE_RENDER_PASS
 };
 
+vk::VkAccessFlags getWriteAccessFlags (void)
+{
+	return vk::VK_ACCESS_SHADER_WRITE_BIT
+		| vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
+		| vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
+		| vk::VK_ACCESS_TRANSFER_WRITE_BIT
+		| vk::VK_ACCESS_HOST_WRITE_BIT
+		| vk::VK_ACCESS_MEMORY_WRITE_BIT;
+}
+
 bool isWriteAccess (vk::VkAccessFlagBits access)
 {
-	switch (access)
-	{
-
-		case vk::VK_ACCESS_INDIRECT_COMMAND_READ_BIT:			return false;
-		case vk::VK_ACCESS_INDEX_READ_BIT:						return false;
-		case vk::VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT:			return false;
-		case vk::VK_ACCESS_UNIFORM_READ_BIT:					return false;
-		case vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT:			return false;
-		case vk::VK_ACCESS_SHADER_READ_BIT:						return false;
-		case vk::VK_ACCESS_SHADER_WRITE_BIT:					return true;
-		case vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT:			return false;
-		case vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT:			return true;
-		case vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT:	return false;
-		case vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT:	return true;
-		case vk::VK_ACCESS_TRANSFER_READ_BIT:					return false;
-		case vk::VK_ACCESS_TRANSFER_WRITE_BIT:					return true;
-		case vk::VK_ACCESS_HOST_READ_BIT:						return false;
-		case vk::VK_ACCESS_HOST_WRITE_BIT:						return true;
-		case vk::VK_ACCESS_MEMORY_READ_BIT:						return false;
-		case vk::VK_ACCESS_MEMORY_WRITE_BIT:					return true;
-
-		default:
-			DE_FATAL("Unknown access");
-			return true;
-	}
+	return getWriteAccessFlags() & access;
 }
 
 class CacheState
 {
 public:
-			CacheState			(vk::VkPipelineStageFlags allowedStages, vk::VkAccessFlags allowedAccesses);
+									CacheState				(vk::VkPipelineStageFlags allowedStages, vk::VkAccessFlags allowedAccesses);
 
-	bool	isValid				(vk::VkPipelineStageFlagBits	stage,
-								 vk::VkAccessFlagBits			access) const;
+	bool							isValid					(vk::VkPipelineStageFlagBits	stage,
+															 vk::VkAccessFlagBits			access) const;
 
-	void	perform				(vk::VkPipelineStageFlagBits	stage,
-								 vk::VkAccessFlagBits			access);
+	void							perform					(vk::VkPipelineStageFlagBits	stage,
+															 vk::VkAccessFlagBits			access);
 
-	void	submitCommandBuffer	(void);
+	void							submitCommandBuffer		(void);
+	void							waitForIdle				(void);
 
-	void	getFullBarrier		(vk::VkPipelineStageFlags&	srcStages,
-								 vk::VkAccessFlags&			srcAccesses,
-								 vk::VkPipelineStageFlags&	dstStages,
-								 vk::VkAccessFlags&			dstAccesses) const;
+	void							getFullBarrier			(vk::VkPipelineStageFlags&	srcStages,
+															 vk::VkAccessFlags&			srcAccesses,
+															 vk::VkPipelineStageFlags&	dstStages,
+															 vk::VkAccessFlags&			dstAccesses) const;
 
-	void	barrier				(vk::VkPipelineStageFlags	srcStages,
-								 vk::VkAccessFlags			srcAccesses,
-								 vk::VkPipelineStageFlags	dstStages,
-								 vk::VkAccessFlags			dstAccesses);
+	void							barrier					(vk::VkPipelineStageFlags	srcStages,
+															 vk::VkAccessFlags			srcAccesses,
+															 vk::VkPipelineStageFlags	dstStages,
+															 vk::VkAccessFlags			dstAccesses);
 
-	void	fullBarrier			(void);
+	void							imageLayoutBarrier		(vk::VkPipelineStageFlags	srcStages,
+															 vk::VkAccessFlags			srcAccesses,
+															 vk::VkPipelineStageFlags	dstStages,
+															 vk::VkAccessFlags			dstAccesses);
+
+	void							checkImageLayoutBarrier	(vk::VkPipelineStageFlags	srcStages,
+															 vk::VkAccessFlags			srcAccesses,
+															 vk::VkPipelineStageFlags	dstStages,
+															 vk::VkAccessFlags			dstAccesses);
 
 	// Everything is clean and there is no need for barriers
-	bool	isClean				(void) const;
+	bool							isClean					(void) const;
 
+	vk::VkPipelineStageFlags		getAllowedStages		(void) const { return m_allowedStages; }
+	vk::VkAccessFlags				getAllowedAcceses		(void) const { return m_allowedAccesses; }
 private:
 	// Limit which stages and accesses are used by the CacheState tracker
 	const vk::VkPipelineStageFlags	m_allowedStages;
@@ -5019,6 +5054,8 @@
 	// [dstStage][srcStage] = srcAccesses
 	// In stage dstStage write srcAccesses from srcStage are not yet available
 	vk::VkAccessFlags				m_unavailableWriteOperations[PIPELINESTAGE_LAST][PIPELINESTAGE_LAST];
+	// Latest pipeline transition is not available in stage
+	bool							m_unavailableLayoutTransition[PIPELINESTAGE_LAST];
 	// [dstStage] = dstAccesses
 	// In stage dstStage ops with dstAccesses are not yet visible
 	vk::VkAccessFlags				m_invisibleOperations[PIPELINESTAGE_LAST];
@@ -5045,6 +5082,9 @@
 		// There are no incomplete read operations initially
 		m_incompleteOperations[dstStage] = 0;
 
+		// There are no incomplete layout transitions
+		m_unavailableLayoutTransition[dstStage] = false;
+
 		for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
 		{
 			const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
@@ -5068,7 +5108,7 @@
 	const PipelineStage	dstStage	= pipelineStageFlagToPipelineStage(stage);
 
 	// Previous operations are not visible to access on stage
-	if ((m_invisibleOperations[dstStage] & access) != 0)
+	if (m_unavailableLayoutTransition[dstStage] || (m_invisibleOperations[dstStage] & access) != 0)
 		return false;
 
 	if (isWriteAccess(access))
@@ -5120,6 +5160,21 @@
 			m_allowedAccesses);
 }
 
+void CacheState::waitForIdle (void)
+{
+	// Make all writes available
+	barrier(m_allowedStages,
+			m_allowedAccesses & getWriteAccessFlags(),
+			m_allowedStages,
+			0);
+
+	// Make all writes visible on device side
+	barrier(m_allowedStages,
+			0,
+			m_allowedStages & (~vk::VK_PIPELINE_STAGE_HOST_BIT),
+			m_allowedAccesses);
+}
+
 void CacheState::getFullBarrier (vk::VkPipelineStageFlags&	srcStages,
 								 vk::VkAccessFlags&			srcAccesses,
 								 vk::VkPipelineStageFlags&	dstStages,
@@ -5165,6 +5220,14 @@
 				srcStages |= dstStage_;
 				srcAccesses |= m_unavailableWriteOperations[dstStage][srcStage];
 			}
+
+			if (m_unavailableLayoutTransition[dstStage] && !m_unavailableLayoutTransition[srcStage])
+			{
+				// Add dependency between srcStage and dstStage if layout transition has not completed in dstStage,
+				// but has completed in srcStage.
+				dstStages |= dstStage_;
+				srcStages |= dstStage_;
+			}
 		}
 	}
 
@@ -5174,6 +5237,108 @@
 	DE_ASSERT((dstAccesses & (~m_allowedAccesses)) == 0);
 }
 
+void CacheState::checkImageLayoutBarrier (vk::VkPipelineStageFlags	srcStages,
+										 vk::VkAccessFlags			srcAccesses,
+										 vk::VkPipelineStageFlags	dstStages,
+										 vk::VkAccessFlags			dstAccesses)
+{
+	DE_ASSERT((srcStages & (~m_allowedStages)) == 0);
+	DE_ASSERT((srcAccesses & (~m_allowedAccesses)) == 0);
+	DE_ASSERT((dstStages & (~m_allowedStages)) == 0);
+	DE_ASSERT((dstAccesses & (~m_allowedAccesses)) == 0);
+
+	DE_UNREF(srcStages);
+	DE_UNREF(srcAccesses);
+
+	DE_UNREF(dstStages);
+	DE_UNREF(dstAccesses);
+
+#if defined(DE_DEBUG)
+	// Check that all stages have completed before srcStages or are in srcStages.
+	{
+		vk::VkPipelineStageFlags completedStages = srcStages;
+
+		for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= srcStages; srcStage_ <<= 1)
+		{
+			const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
+
+			if ((srcStage_ & srcStages) == 0)
+				continue;
+
+			completedStages |= (~m_incompleteOperations[srcStage]);
+		}
+
+		DE_ASSERT((completedStages & m_allowedStages) == m_allowedStages);
+	}
+
+	// Check that any write is available at least in one stage. Since all stages are complete even single flush is enough.
+	if ((getWriteAccessFlags() & m_allowedAccesses) != 0 && (srcAccesses & getWriteAccessFlags()) == 0)
+	{
+		bool anyWriteAvailable = false;
+
+		for (vk::VkPipelineStageFlags dstStage_ = 1; dstStage_ <= m_allowedStages; dstStage_ <<= 1)
+		{
+			const PipelineStage dstStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)dstStage_);
+
+			if ((dstStage_ & m_allowedStages) == 0)
+				continue;
+
+			for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
+			{
+				const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
+
+				if ((srcStage_ & m_allowedStages) == 0)
+					continue;
+
+				if (m_unavailableWriteOperations[dstStage][srcStage] != (getWriteAccessFlags() & m_allowedAccesses))
+				{
+					anyWriteAvailable = true;
+					break;
+				}
+			}
+		}
+
+		DE_ASSERT(anyWriteAvailable);
+	}
+#endif
+}
+
+void CacheState::imageLayoutBarrier (vk::VkPipelineStageFlags	srcStages,
+									 vk::VkAccessFlags			srcAccesses,
+									 vk::VkPipelineStageFlags	dstStages,
+									 vk::VkAccessFlags			dstAccesses)
+{
+	checkImageLayoutBarrier(srcStages, srcAccesses, dstStages, dstAccesses);
+
+	for (vk::VkPipelineStageFlags dstStage_ = 1; dstStage_ <= m_allowedStages; dstStage_ <<= 1)
+	{
+		const PipelineStage dstStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)dstStage_);
+
+		if ((dstStage_ & m_allowedStages) == 0)
+			continue;
+
+		// All stages are incomplete after the barrier except each dstStage in it self.
+		m_incompleteOperations[dstStage] = m_allowedStages & (~dstStage_);
+
+		// All memory operations are invisible unless they are listed in dstAccess
+		m_invisibleOperations[dstStage] = m_allowedAccesses & (~dstAccesses);
+
+		// Layout transition is unavailable in stage unless it was listed in dstStages
+		m_unavailableLayoutTransition[dstStage]= (dstStage_ & dstStages) == 0;
+
+		for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
+		{
+			const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
+
+			if ((srcStage_ & m_allowedStages) == 0)
+				continue;
+
+			// All write operations are available after layout transition
+			m_unavailableWriteOperations[dstStage][srcStage] = 0;
+		}
+	}
+}
+
 void CacheState::barrier (vk::VkPipelineStageFlags	srcStages,
 						  vk::VkAccessFlags			srcAccesses,
 						  vk::VkPipelineStageFlags	dstStages,
@@ -5188,9 +5353,11 @@
 	{
 		vk::VkPipelineStageFlags		oldIncompleteOperations[PIPELINESTAGE_LAST];
 		vk::VkAccessFlags				oldUnavailableWriteOperations[PIPELINESTAGE_LAST][PIPELINESTAGE_LAST];
+		bool							oldUnavailableLayoutTransition[PIPELINESTAGE_LAST];
 
 		deMemcpy(oldIncompleteOperations, m_incompleteOperations, sizeof(oldIncompleteOperations));
 		deMemcpy(oldUnavailableWriteOperations, m_unavailableWriteOperations, sizeof(oldUnavailableWriteOperations));
+		deMemcpy(oldUnavailableLayoutTransition, m_unavailableLayoutTransition, sizeof(oldUnavailableLayoutTransition));
 
 		for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= srcStages; srcStage_ <<= 1)
 		{
@@ -5209,6 +5376,9 @@
 				// Stages that have completed before srcStage have also completed before dstStage
 				m_incompleteOperations[dstStage] &= oldIncompleteOperations[srcStage];
 
+				// Image layout transition in srcStage are now available in dstStage
+				m_unavailableLayoutTransition[dstStage] &= oldUnavailableLayoutTransition[srcStage];
+
 				for (vk::VkPipelineStageFlags sharedStage_ = 1; sharedStage_ <= m_allowedStages; sharedStage_ <<= 1)
 				{
 					const PipelineStage	sharedStage			= pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)sharedStage_);
@@ -5273,6 +5443,10 @@
 		if (m_incompleteOperations[dstStage] != 0)
 			return false;
 
+		// Layout transition has not completed yet
+		if (m_unavailableLayoutTransition[dstStage])
+			return false;
+
 		for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
 		{
 			const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
@@ -5289,34 +5463,6 @@
 	return true;
 }
 
-void CacheState::fullBarrier (void)
-{
-	for (vk::VkPipelineStageFlags dstStage_ = 1; dstStage_ <= m_allowedStages; dstStage_ <<= 1)
-	{
-		const PipelineStage dstStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)dstStage_);
-
-		if ((dstStage_ & m_allowedStages) == 0)
-			continue;
-
-		// All stages have completed
-		m_incompleteOperations[dstStage] = 0;
-
-		// All operations are visible
-		m_invisibleOperations[dstStage] = 0;
-
-		for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
-		{
-			const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
-
-			if ((srcStage_ & m_allowedStages) == 0)
-				continue;
-
-			// All writes are available
-			m_unavailableWriteOperations[dstStage][srcStage] = 0;
-		}
-	}
-}
-
 struct State
 {
 	State (Usage usage, deUint32 seed)
@@ -5331,7 +5477,7 @@
 		, hasBoundBufferMemory	(false)
 		, hasImage				(false)
 		, hasBoundImageMemory	(false)
-		, imageHasGeneralLayout	(false)
+		, imageLayout			(vk::VK_IMAGE_LAYOUT_UNDEFINED)
 		, imageDefined			(false)
 		, queueIdle				(true)
 		, deviceIdle			(true)
@@ -5339,27 +5485,27 @@
 	{
 	}
 
-	Stage		stage;
-	CacheState	cache;
-	de::Random	rng;
+	Stage				stage;
+	CacheState			cache;
+	de::Random			rng;
 
-	bool		mapped;
-	bool		hostInvalidated;
-	bool		hostFlushed;
-	bool		memoryDefined;
+	bool				mapped;
+	bool				hostInvalidated;
+	bool				hostFlushed;
+	bool				memoryDefined;
 
-	bool		hasBuffer;
-	bool		hasBoundBufferMemory;
+	bool				hasBuffer;
+	bool				hasBoundBufferMemory;
 
-	bool		hasImage;
-	bool		hasBoundImageMemory;
-	bool		imageHasGeneralLayout;
-	bool		imageDefined;
+	bool				hasImage;
+	bool				hasBoundImageMemory;
+	vk::VkImageLayout	imageLayout;
+	bool				imageDefined;
 
-	bool		queueIdle;
-	bool		deviceIdle;
+	bool				queueIdle;
+	bool				deviceIdle;
 
-	bool		commandBufferIsEmpty;
+	bool				commandBufferIsEmpty;
 };
 
 void getAvailableOps (const State& state, bool supportsBuffers, bool supportsImages, Usage usage, vector<Op>& ops)
@@ -5502,14 +5648,12 @@
 
 		if (state.hasBoundImageMemory)
 		{
-			if (!state.imageHasGeneralLayout)
-			{
-				ops.push_back(OP_IMAGE_TRANSITION_TO_GENERAL);
-			}
-			else
+			ops.push_back(OP_IMAGE_TRANSITION_LAYOUT);
+
 			{
 				if (usage & USAGE_TRANSFER_DST
-					&& state.imageHasGeneralLayout
+					&& (state.imageLayout == vk::VK_IMAGE_LAYOUT_GENERAL
+						|| state.imageLayout == vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
 					&& state.cache.isValid(vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_ACCESS_TRANSFER_WRITE_BIT))
 				{
 					ops.push_back(OP_IMAGE_COPY_FROM_BUFFER);
@@ -5518,7 +5662,8 @@
 				}
 
 				if (usage & USAGE_TRANSFER_SRC
-					&& state.imageHasGeneralLayout
+					&& (state.imageLayout == vk::VK_IMAGE_LAYOUT_GENERAL
+						|| state.imageLayout == vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
 					&& state.imageDefined
 					&& state.cache.isValid(vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT))
 				{
@@ -5529,7 +5674,7 @@
 			}
 		}
 
-		// \todo Add other usages?
+		// \todo [2016-03-09 mika] Add other usages?
 		if (((usage & USAGE_VERTEX_BUFFER) && state.cache.isValid(vk::VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, vk::VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT))
 			|| ((usage & USAGE_INDEX_BUFFER) && state.cache.isValid(vk::VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, vk::VK_ACCESS_INDEX_READ_BIT)))
 			ops.push_back(OP_RENDERPASS_BEGIN);
@@ -5563,7 +5708,85 @@
 		DE_FATAL("Unknown stage");
 }
 
-void applyOp (State& state, const Memory& memory, Op op)
+bool layoutSupportedByUsage (Usage usage, vk::VkImageLayout layout)
+{
+	switch (layout)
+	{
+		case vk::VK_IMAGE_LAYOUT_GENERAL:
+			return true;
+
+		case vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
+			return (usage & USAGE_COLOR_ATTACHMENT) != 0;
+
+		case vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
+			return (usage & USAGE_DEPTH_STENCIL_ATTACHMENT) != 0;
+
+		case vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
+			return (usage & USAGE_DEPTH_STENCIL_ATTACHMENT) != 0;
+
+		case vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
+			// \todo [2016-03-09 mika] Should include input attachment
+			return (usage & USAGE_TEXTURE_SAMPLED) != 0;
+
+		case vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
+			return (usage & USAGE_TRANSFER_SRC) != 0;
+
+		case vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
+			return (usage & USAGE_TRANSFER_DST) != 0;
+
+		case vk::VK_IMAGE_LAYOUT_PREINITIALIZED:
+			return true;
+
+		default:
+			DE_FATAL("Unknown layout");
+			return false;
+	}
+}
+
+vk::VkImageLayout getRandomNextLayout (de::Random&			rng,
+									   Usage				usage,
+									   vk::VkImageLayout	previousLayout)
+{
+	const vk::VkImageLayout layouts[] =
+	{
+		vk::VK_IMAGE_LAYOUT_GENERAL,
+		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+		vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+		vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
+		vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+		vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+		vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+	};
+	size_t possibleLayoutCount = 0;
+
+	for (size_t layoutNdx = 0; layoutNdx < DE_LENGTH_OF_ARRAY(layouts); layoutNdx++)
+	{
+		const vk::VkImageLayout layout = layouts[layoutNdx];
+
+		if (layoutSupportedByUsage(usage, layout) && layout != previousLayout)
+			possibleLayoutCount++;
+	}
+
+	size_t nextLayoutNdx = ((size_t)rng.getUint64()) % possibleLayoutCount;
+
+	for (size_t layoutNdx = 0; layoutNdx < DE_LENGTH_OF_ARRAY(layouts); layoutNdx++)
+	{
+		const vk::VkImageLayout layout = layouts[layoutNdx];
+
+		if (layoutSupportedByUsage(usage, layout) && layout != previousLayout)
+		{
+			if (nextLayoutNdx == 0)
+				return layout;
+			else
+				nextLayoutNdx--;
+		}
+	}
+
+	DE_FATAL("Unreachable");
+	return vk::VK_IMAGE_LAYOUT_UNDEFINED;
+}
+
+void applyOp (State& state, const Memory& memory, Op op, Usage usage)
 {
 	switch (op)
 	{
@@ -5604,7 +5827,7 @@
 
 			state.memoryDefined = true;
 			state.imageDefined = false;
-			state.imageHasGeneralLayout = false;
+			state.imageLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
 			state.rng.getUint32();
 			break;
 
@@ -5657,7 +5880,7 @@
 
 			state.hasImage = false;
 			state.hasBoundImageMemory = false;
-			state.imageHasGeneralLayout = false;
+			state.imageLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
 			state.imageDefined = false;
 			break;
 
@@ -5669,20 +5892,58 @@
 			state.hasBoundImageMemory = true;
 			break;
 
-		case OP_IMAGE_TRANSITION_TO_GENERAL:
+		case OP_IMAGE_TRANSITION_LAYOUT:
+		{
 			DE_ASSERT(state.stage == STAGE_COMMAND_BUFFER);
 			DE_ASSERT(state.hasImage);
 			DE_ASSERT(state.hasBoundImageMemory);
 
-			state.imageHasGeneralLayout = true;
+			// \todo [2016-03-09 mika] Support linear tiling and predefined data
+			const vk::VkImageLayout		srcLayout	= state.rng.getFloat() < 0.9f ? state.imageLayout : vk::VK_IMAGE_LAYOUT_UNDEFINED;
+			const vk::VkImageLayout		dstLayout	= getRandomNextLayout(state.rng, usage, srcLayout);
+
+			vk::VkPipelineStageFlags	dirtySrcStages;
+			vk::VkAccessFlags			dirtySrcAccesses;
+			vk::VkPipelineStageFlags	dirtyDstStages;
+			vk::VkAccessFlags			dirtyDstAccesses;
+
+			vk::VkPipelineStageFlags	srcStages;
+			vk::VkAccessFlags			srcAccesses;
+			vk::VkPipelineStageFlags	dstStages;
+			vk::VkAccessFlags			dstAccesses;
+
+			state.cache.getFullBarrier(dirtySrcStages, dirtySrcAccesses, dirtyDstStages, dirtyDstAccesses);
+
+			// Try masking some random bits
+			srcStages	= dirtySrcStages;
+			srcAccesses	= dirtySrcAccesses;
+
+			dstStages	= state.cache.getAllowedStages() & state.rng.getUint32();
+			dstAccesses	= state.cache.getAllowedAcceses() & state.rng.getUint32();
+
+			// If there are no bits in dst stage mask use all stages
+			dstStages	= dstStages ? dstStages : state.cache.getAllowedStages();
+
+			if (!srcStages)
+				srcStages = dstStages;
+
+			if (srcLayout == vk::VK_IMAGE_LAYOUT_UNDEFINED)
+				state.imageDefined = false;
+
+			state.commandBufferIsEmpty = false;
+			state.imageLayout = dstLayout;
 			state.memoryDefined = false;
+			state.cache.imageLayoutBarrier(srcStages, srcAccesses, dstStages, dstAccesses);
 			break;
+		}
 
 		case OP_QUEUE_WAIT_FOR_IDLE:
 			DE_ASSERT(state.stage == STAGE_HOST);
 			DE_ASSERT(!state.queueIdle);
 
 			state.queueIdle = true;
+
+			state.cache.waitForIdle();
 			break;
 
 		case OP_DEVICE_WAIT_FOR_IDLE:
@@ -5691,6 +5952,8 @@
 
 			state.queueIdle = true;
 			state.deviceIdle = true;
+
+			state.cache.waitForIdle();
 			break;
 
 		case OP_COMMAND_BUFFER_BEGIN:
@@ -5706,7 +5969,6 @@
 			state.stage = STAGE_HOST;
 			state.queueIdle = false;
 			state.deviceIdle = false;
-			// \todo Should this set all device reads ready?
 			break;
 
 		case OP_BUFFER_COPY_FROM_BUFFER:
@@ -5722,7 +5984,7 @@
 			state.commandBufferIsEmpty = false;
 			state.memoryDefined = true;
 			state.imageDefined = false;
-			state.imageHasGeneralLayout = false;
+			state.imageLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
 			state.cache.perform(vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_ACCESS_TRANSFER_WRITE_BIT);
 			break;
 
@@ -5872,7 +6134,8 @@
 
 de::MovePtr<CmdCommand> createCmdCommand (de::Random&	rng,
 										  const State&	state,
-										  Op			op)
+										  Op			op,
+										  Usage			usage)
 {
 	switch (op)
 	{
@@ -5884,7 +6147,42 @@
 		case OP_BUFFER_COPY_TO_IMAGE:			return de::MovePtr<CmdCommand>(new BufferCopyToImage());
 		case OP_BUFFER_COPY_FROM_IMAGE:			return de::MovePtr<CmdCommand>(new BufferCopyFromImage(rng.getUint32()));
 
-		case OP_IMAGE_TRANSITION_TO_GENERAL:	return de::MovePtr<CmdCommand>(new ImageTransition());
+		case OP_IMAGE_TRANSITION_LAYOUT:
+		{
+			DE_ASSERT(state.stage == STAGE_COMMAND_BUFFER);
+			DE_ASSERT(state.hasImage);
+			DE_ASSERT(state.hasBoundImageMemory);
+
+			const vk::VkImageLayout		srcLayout	= rng.getFloat() < 0.9f ? state.imageLayout : vk::VK_IMAGE_LAYOUT_UNDEFINED;
+			const vk::VkImageLayout		dstLayout	= getRandomNextLayout(rng, usage, srcLayout);
+
+			vk::VkPipelineStageFlags	dirtySrcStages;
+			vk::VkAccessFlags			dirtySrcAccesses;
+			vk::VkPipelineStageFlags	dirtyDstStages;
+			vk::VkAccessFlags			dirtyDstAccesses;
+
+			vk::VkPipelineStageFlags	srcStages;
+			vk::VkAccessFlags			srcAccesses;
+			vk::VkPipelineStageFlags	dstStages;
+			vk::VkAccessFlags			dstAccesses;
+
+			state.cache.getFullBarrier(dirtySrcStages, dirtySrcAccesses, dirtyDstStages, dirtyDstAccesses);
+
+			// Try masking some random bits
+			srcStages	= dirtySrcStages;
+			srcAccesses	= dirtySrcAccesses;
+
+			dstStages	= state.cache.getAllowedStages() & rng.getUint32();
+			dstAccesses	= state.cache.getAllowedAcceses() & rng.getUint32();
+
+			// If there are no bits in dst stage mask use all stages
+			dstStages	= dstStages ? dstStages : state.cache.getAllowedStages();
+
+			if (!srcStages)
+				srcStages = dstStages;
+
+			return de::MovePtr<CmdCommand>(new ImageTransition(srcStages, srcAccesses, dstStages, dstAccesses, srcLayout, dstLayout));
+		}
 
 		case OP_IMAGE_COPY_TO_BUFFER:			return de::MovePtr<CmdCommand>(new ImageCopyToBuffer());
 		case OP_IMAGE_COPY_FROM_BUFFER:			return de::MovePtr<CmdCommand>(new ImageCopyFromBuffer(rng.getUint32()));
@@ -5977,38 +6275,47 @@
 												  size_t&		opNdx,
 												  size_t		opCount)
 {
-	// \todo Exception safety
 	vector<RenderPassCommand*>	commands;
 
-	for (; opNdx < opCount; opNdx++)
+	try
 	{
-		vector<Op>	ops;
-
-		getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
-
-		DE_ASSERT(!ops.empty());
-
+		for (; opNdx < opCount; opNdx++)
 		{
-			const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
+			vector<Op>	ops;
 
-			if (op == OP_RENDERPASS_END)
+			getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
+
+			DE_ASSERT(!ops.empty());
+
 			{
-				break;
-			}
-			else
-			{
-				de::Random	rng	(state.rng);
+				const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
 
-				commands.push_back(createRenderPassCommand(rng, state, op).release());
-				applyOp(state, memory, op);
+				if (op == OP_RENDERPASS_END)
+				{
+					break;
+				}
+				else
+				{
+					de::Random	rng	(state.rng);
 
-				DE_ASSERT(state.rng == rng);
+					commands.push_back(createRenderPassCommand(rng, state, op).release());
+					applyOp(state, memory, op, usage);
+
+					DE_ASSERT(state.rng == rng);
+				}
 			}
 		}
-	}
 
-	applyOp(state, memory, OP_RENDERPASS_END);
-	return de::MovePtr<CmdCommand>(new SubmitRenderPass(commands));
+		applyOp(state, memory, OP_RENDERPASS_END, usage);
+		return de::MovePtr<CmdCommand>(new SubmitRenderPass(commands));
+	}
+	catch (...)
+	{
+		for (size_t commandNdx = 0; commandNdx < commands.size(); commandNdx++)
+			delete commands[commandNdx];
+
+		throw;
+	}
 }
 
 de::MovePtr<Command> createCmdCommands (const Memory&	memory,
@@ -6018,48 +6325,57 @@
 										size_t&			opNdx,
 										size_t			opCount)
 {
-	// \todo Exception safety
 	vector<CmdCommand*>	commands;
 
-	for (; opNdx < opCount; opNdx++)
+	try
 	{
-		vector<Op>	ops;
-
-		getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
-
-		DE_ASSERT(!ops.empty());
-
+		for (; opNdx < opCount; opNdx++)
 		{
-			const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
+			vector<Op>	ops;
 
-			if (op == OP_COMMAND_BUFFER_END)
+			getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
+
+			DE_ASSERT(!ops.empty());
+
 			{
-				break;
-			}
-			else
-			{
-				// \note Command needs to known the state before the operation
-				if (op == OP_RENDERPASS_BEGIN)
+				const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
+
+				if (op == OP_COMMAND_BUFFER_END)
 				{
-					applyOp(state, memory, op);
-					commands.push_back(createRenderPassCommands(memory, nextOpRng, state, usage, opNdx, opCount).release());
+					break;
 				}
 				else
 				{
-					de::Random	rng	(state.rng);
+					// \note Command needs to known the state before the operation
+					if (op == OP_RENDERPASS_BEGIN)
+					{
+						applyOp(state, memory, op, usage);
+						commands.push_back(createRenderPassCommands(memory, nextOpRng, state, usage, opNdx, opCount).release());
+					}
+					else
+					{
+						de::Random	rng	(state.rng);
 
-					commands.push_back(createCmdCommand(rng, state, op).release());
-					applyOp(state, memory, op);
+						commands.push_back(createCmdCommand(rng, state, op, usage).release());
+						applyOp(state, memory, op, usage);
 
-					DE_ASSERT(state.rng == rng);
+						DE_ASSERT(state.rng == rng);
+					}
+
 				}
-
 			}
 		}
-	}
 
-	applyOp(state, memory, OP_COMMAND_BUFFER_END);
-	return de::MovePtr<Command>(new SubmitCommandBuffer(commands));
+		applyOp(state, memory, OP_COMMAND_BUFFER_END, usage);
+		return de::MovePtr<Command>(new SubmitCommandBuffer(commands));
+	}
+	catch (...)
+	{
+		for (size_t commandNdx = 0; commandNdx < commands.size(); commandNdx++)
+			delete commands[commandNdx];
+
+		throw;
+	}
 }
 
 void createCommands (vector<Command*>&			commands,
@@ -6088,7 +6404,7 @@
 
 			if (op == OP_COMMAND_BUFFER_BEGIN)
 			{
-				applyOp(state, memory, op);
+				applyOp(state, memory, op, usage);
 				commands.push_back(createCmdCommands(memory, nextOpRng, state, usage, opNdx, opCount).release());
 			}
 			else
@@ -6096,7 +6412,7 @@
 				de::Random	rng	(state.rng);
 
 				commands.push_back(createHostCommand(op, rng, usage, sharingMode).release());
-				applyOp(state, memory, op);
+				applyOp(state, memory, op, usage);
 
 				// Make sure that random generator is in sync
 				DE_ASSERT(state.rng == rng);
@@ -6319,7 +6635,7 @@
 
 tcu::TestStatus MemoryTestInstance::iterate (void)
 {
-	// \todo Split different stages over multiple iterations
+	// \todo [2016-03-09 mika] Split different stages over multiple iterations
 	if (m_memoryTypeNdx < m_memoryProperties.memoryTypeCount)
 	{
 		TestLog&									log					= m_context.getTestContext().getLog();
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp
index 6e6426c..0e731a2 100644
--- a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp
+++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp
@@ -101,6 +101,18 @@
 		typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
 }
 
+static void floorAll (vector<float>& values)
+{
+	for (size_t i = 0; i < values.size(); i++)
+		values[i] = deFloatFloor(values[i]);
+}
+
+static void floorAll (vector<Vec4>& values)
+{
+	for (size_t i = 0; i < values.size(); i++)
+		values[i] = floor(values[i]);
+}
+
 struct CaseParameter
 {
 	const char*		name;
@@ -571,6 +583,9 @@
 
 	fillRandomScalars(rnd, -200.f, 200.f, &inputFloats1[0], numElements * 4);
 
+	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+	floorAll(inputFloats1);
+
 	for (size_t ndx = 0; ndx < numElements; ++ndx)
 		outputFloats1[ndx] = inputFloats1[ndx] + Vec4(0.f, 0.5f, 1.5f, 2.5f);
 
@@ -777,6 +792,9 @@
 
 	fillRandomScalars(rnd, -200.f, 200.f, &inputFloats[0], numElements);
 
+	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+	floorAll(inputFloats);
+
 	for (size_t ndx = 0; ndx < numElements; ++ndx)
 		outputFloats[ndx] = inputFloats[ndx] + 7.5f;
 
@@ -1037,15 +1055,12 @@
 	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats3[0], numElements);
 	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats4[0], numElements);
 
-
-	for (size_t ndx = 0; ndx < numElements; ++ndx)
-	{
-		inputFloats0[ndx] = deFloatFloor(inputFloats0[ndx]);
-		inputFloats1[ndx] = deFloatFloor(inputFloats1[ndx]);
-		inputFloats2[ndx] = deFloatFloor(inputFloats2[ndx]);
-		inputFloats3[ndx] = deFloatFloor(inputFloats3[ndx]);
-		inputFloats4[ndx] = deFloatFloor(inputFloats4[ndx]);
-	}
+	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+	floorAll(inputFloats0);
+	floorAll(inputFloats1);
+	floorAll(inputFloats2);
+	floorAll(inputFloats3);
+	floorAll(inputFloats4);
 
 	for (size_t ndx = 0; ndx < numElements; ++ndx)
 		outputFloats[ndx] = inputFloats0[ndx] + inputFloats1[ndx] + inputFloats2[ndx] + inputFloats3[ndx] + inputFloats4[ndx];
@@ -1396,6 +1411,9 @@
 
 	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats[0], numElements);
 
+	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+	floorAll(inputFloats);
+
 	for (size_t ndx = 0; ndx < numElements; ++ndx)
 	{
 		switch (ndx % 3)
@@ -1598,8 +1616,8 @@
 
 	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
 
-	for (size_t ndx = 0; ndx < numElements; ++ndx)
-		inputFloats[ndx] = deFloatFloor(inputFloats[ndx]);
+	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+	floorAll(inputFloats);
 
 	for (size_t ndx = 0; ndx <= 50; ++ndx)
 		outputFloats[ndx] = -inputFloats[ndx];
@@ -2928,6 +2946,9 @@
 
 	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
 
+	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+	floorAll(inputFloats);
+
 	for (size_t ndx = 0; ndx < numElements; ++ndx)
 		outputFloats[ndx] = inputFloats[ndx] + (inputFloats[ndx] > 10.f ? 1.f : -1.f);
 
@@ -3020,6 +3041,9 @@
 
 	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
 
+	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+	floorAll(inputFloats);
+
 	for (size_t ndx = 0; ndx < numElements; ++ndx)
 		outputFloats[ndx] = inputFloats[ndx] + 10.f;
 
diff --git a/external/vulkancts/modules/vulkan/vktSynchronization.cpp b/external/vulkancts/modules/vulkan/vktSynchronization.cpp
index e6cdbc2..695d17b 100644
--- a/external/vulkancts/modules/vulkan/vktSynchronization.cpp
+++ b/external/vulkancts/modules/vulkan/vktSynchronization.cpp
@@ -209,7 +209,7 @@
 			range.offset	= newMemory->getOffset();
 			range.size		= bufferParameters.size;
 
-			deMemcpy(newMemory->getHostPtr(), bufferParameters.memory, bufferParameters.size);
+			deMemcpy(newMemory->getHostPtr(), bufferParameters.memory, (size_t)bufferParameters.size);
 			VK_CHECK(deviceInterface.flushMappedMemoryRanges(device, 1, &range));
 
 			barrier.sType			= VK_STRUCTURE_TYPE_MEMORY_BARRIER;
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp
index 29b8973..42c0553 100644
--- a/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp
@@ -45,6 +45,7 @@
 #include "vkTypeUtil.hpp"
 #include "vkWsiPlatform.hpp"
 #include "vkWsiUtil.hpp"
+#include "vkAllocationCallbackUtil.hpp"
 
 #include "tcuTestLog.hpp"
 #include "tcuFormatUtil.hpp"
@@ -108,9 +109,10 @@
 	}
 }
 
-Move<VkInstance> createInstanceWithWsi (const PlatformInterface&	vkp,
-										const Extensions&			supportedExtensions,
-										Type						wsiType)
+Move<VkInstance> createInstanceWithWsi (const PlatformInterface&		vkp,
+										const Extensions&				supportedExtensions,
+										Type							wsiType,
+										const VkAllocationCallbacks*	pAllocator	= DE_NULL)
 {
 	vector<string>	extensions;
 
@@ -119,7 +121,7 @@
 
 	checkAllSupported(supportedExtensions, extensions);
 
-	return createDefaultInstance(vkp, vector<string>(), extensions);
+	return createDefaultInstance(vkp, vector<string>(), extensions, pAllocator);
 }
 
 struct InstanceHelper
@@ -128,12 +130,13 @@
 	Unique<VkInstance>					instance;
 	const InstanceDriver				vki;
 
-	InstanceHelper (Context& context, Type wsiType)
+	InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
 		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(),
 																	  DE_NULL))
 		, instance				(createInstanceWithWsi(context.getPlatformInterface(),
 													   supportedExtensions,
-													   wsiType))
+													   wsiType,
+													   pAllocator))
 		, vki					(context.getPlatformInterface(), *instance)
 	{}
 };
@@ -196,6 +199,89 @@
 	return tcu::TestStatus::pass("Creating surface succeeded");
 }
 
+tcu::TestStatus createSurfaceCustomAllocatorTest (Context& context, Type wsiType)
+{
+	AllocationCallbackRecorder	allocationRecorder	(getSystemAllocator());
+	tcu::TestLog&				log					= context.getTestContext().getLog();
+
+	{
+		const InstanceHelper		instHelper	(context, wsiType, allocationRecorder.getCallbacks());
+		const NativeObjects			native		(context, instHelper.supportedExtensions, wsiType);
+		const Unique<VkSurfaceKHR>	surface		(createSurface(instHelper.vki,
+															   *instHelper.instance,
+															   wsiType,
+															   *native.display,
+															   *native.window,
+															   allocationRecorder.getCallbacks()));
+
+		if (!validateAndLog(log,
+							allocationRecorder,
+							(1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)		|
+							(1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
+			return tcu::TestStatus::fail("Detected invalid system allocation callback");
+	}
+
+	if (!validateAndLog(log, allocationRecorder, 0u))
+		return tcu::TestStatus::fail("Detected invalid system allocation callback");
+
+	if (allocationRecorder.getRecordsBegin() == allocationRecorder.getRecordsEnd())
+		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
+	else
+		return tcu::TestStatus::pass("Creating surface succeeded using custom allocator");
+}
+
+tcu::TestStatus createSurfaceSimulateOOMTest (Context& context, Type wsiType)
+{
+	tcu::TestLog&	log	= context.getTestContext().getLog();
+
+	for (deUint32 numPassingAllocs = 0; numPassingAllocs <= 1024u; ++numPassingAllocs)
+	{
+		AllocationCallbackRecorder	allocationRecorder	(getSystemAllocator());
+		DeterministicFailAllocator	failingAllocator	(allocationRecorder.getCallbacks(), numPassingAllocs);
+		bool						gotOOM				= false;
+
+		log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
+
+		try
+		{
+			const InstanceHelper		instHelper	(context, wsiType, failingAllocator.getCallbacks());
+			const NativeObjects			native		(context, instHelper.supportedExtensions, wsiType);
+			const Unique<VkSurfaceKHR>	surface		(createSurface(instHelper.vki,
+																   *instHelper.instance,
+																   wsiType,
+																   *native.display,
+																   *native.window,
+																   failingAllocator.getCallbacks()));
+
+			if (!validateAndLog(log,
+								allocationRecorder,
+								(1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)		|
+								(1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
+				return tcu::TestStatus::fail("Detected invalid system allocation callback");
+		}
+		catch (const OutOfMemoryError& e)
+		{
+			log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
+			gotOOM = true;
+		}
+
+		if (!validateAndLog(log, allocationRecorder, 0u))
+			return tcu::TestStatus::fail("Detected invalid system allocation callback");
+
+		if (!gotOOM)
+		{
+			log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
+
+			if (numPassingAllocs == 0)
+				return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
+			else
+				return tcu::TestStatus::pass("OOM simulation completed");
+		}
+	}
+
+	return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating surface did not succeed, callback limit exceeded");
+}
+
 deUint32 getNumQueueFamilies (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
 {
 	deUint32	numFamilies		= 0;
@@ -524,11 +610,13 @@
 {
 	const PlatformProperties&	platformProperties	= getPlatformProperties(wsiType);
 
-	addFunctionCase(testGroup, "create",				"Create surface",				createSurfaceTest,				wsiType);
-	addFunctionCase(testGroup, "query_support",			"Query surface support",		querySurfaceSupportTest,		wsiType);
-	addFunctionCase(testGroup, "query_capabilities",	"Query surface capabilities",	querySurfaceCapabilitiesTest,	wsiType);
-	addFunctionCase(testGroup, "query_formats",			"Query surface formats",		querySurfaceFormatsTest,		wsiType);
-	addFunctionCase(testGroup, "query_present_modes",	"Query surface present modes",	querySurfacePresentModesTest,	wsiType);
+	addFunctionCase(testGroup, "create",					"Create surface",						createSurfaceTest,					wsiType);
+	addFunctionCase(testGroup, "create_custom_allocator",	"Create surface with custom allocator",	createSurfaceCustomAllocatorTest,	wsiType);
+	addFunctionCase(testGroup, "create_simulate_oom",		"Create surface with simulating OOM",	createSurfaceSimulateOOMTest,		wsiType);
+	addFunctionCase(testGroup, "query_support",				"Query surface support",				querySurfaceSupportTest,			wsiType);
+	addFunctionCase(testGroup, "query_capabilities",		"Query surface capabilities",			querySurfaceCapabilitiesTest,		wsiType);
+	addFunctionCase(testGroup, "query_formats",				"Query surface formats",				querySurfaceFormatsTest,			wsiType);
+	addFunctionCase(testGroup, "query_present_modes",		"Query surface present modes",			querySurfacePresentModesTest,		wsiType);
 
 	if ((platformProperties.features & PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE) != 0)
 		addFunctionCase(testGroup, "initial_size",	"Create surface with initial window size set",	createSurfaceInitialSizeTest,	wsiType);
diff --git a/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp b/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
index 5f977b8..1342955 100644
--- a/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
+++ b/external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
@@ -45,6 +45,7 @@
 #include "vkTypeUtil.hpp"
 #include "vkWsiPlatform.hpp"
 #include "vkWsiUtil.hpp"
+#include "vkAllocationCallbackUtil.hpp"
 
 #include "tcuTestLog.hpp"
 #include "tcuFormatUtil.hpp"
@@ -89,9 +90,10 @@
 	}
 }
 
-Move<VkInstance> createInstanceWithWsi (const PlatformInterface&	vkp,
-										const Extensions&			supportedExtensions,
-										Type						wsiType)
+Move<VkInstance> createInstanceWithWsi (const PlatformInterface&		vkp,
+										const Extensions&				supportedExtensions,
+										Type							wsiType,
+										const VkAllocationCallbacks*	pAllocator	= DE_NULL)
 {
 	vector<string>	extensions;
 
@@ -100,7 +102,7 @@
 
 	checkAllSupported(supportedExtensions, extensions);
 
-	return createDefaultInstance(vkp, vector<string>(), extensions);
+	return createDefaultInstance(vkp, vector<string>(), extensions, pAllocator);
 }
 
 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
@@ -110,10 +112,11 @@
 	return features;
 }
 
-Move<VkDevice> createDeviceWithWsi (const InstanceInterface&	vki,
-									VkPhysicalDevice			physicalDevice,
-									const Extensions&			supportedExtensions,
-									const deUint32				queueFamilyIndex)
+Move<VkDevice> createDeviceWithWsi (const InstanceInterface&		vki,
+									VkPhysicalDevice				physicalDevice,
+									const Extensions&				supportedExtensions,
+									const deUint32					queueFamilyIndex,
+									const VkAllocationCallbacks*	pAllocator = DE_NULL)
 {
 	const float						queuePriorities[]	= { 1.0f };
 	const VkDeviceQueueCreateInfo	queueInfos[]		=
@@ -149,7 +152,7 @@
 			TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
 	}
 
-	return createDevice(vki, physicalDevice, &deviceParams, (const VkAllocationCallbacks*)DE_NULL);
+	return createDevice(vki, physicalDevice, &deviceParams, pAllocator);
 }
 
 deUint32 getNumQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
@@ -191,12 +194,13 @@
 	const Unique<VkInstance>			instance;
 	const InstanceDriver				vki;
 
-	InstanceHelper (Context& context, Type wsiType)
+	InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
 		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(),
 																	  DE_NULL))
 		, instance				(createInstanceWithWsi(context.getPlatformInterface(),
 													   supportedExtensions,
-													   wsiType))
+													   wsiType,
+													   pAllocator))
 		, vki					(context.getPlatformInterface(), *instance)
 	{}
 };
@@ -216,13 +220,18 @@
 	const DeviceDriver		vkd;
 	const VkQueue			queue;
 
-	DeviceHelper (Context& context, const InstanceInterface& vki, VkInstance instance, VkSurfaceKHR surface)
+	DeviceHelper (Context&						context,
+				  const InstanceInterface&		vki,
+				  VkInstance					instance,
+				  VkSurfaceKHR					surface,
+				  const VkAllocationCallbacks*	pAllocator = DE_NULL)
 		: physicalDevice	(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
 		, queueFamilyIndex	(chooseQueueFamilyIndex(vki, physicalDevice, surface))
 		, device			(createDeviceWithWsi(vki,
 												 physicalDevice,
 												 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
-												 queueFamilyIndex))
+												 queueFamilyIndex,
+												 pAllocator))
 		, vkd				(vki, *device)
 		, queue				(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
 	{
@@ -572,6 +581,75 @@
 	return tcu::TestStatus::pass("Creating swapchain succeeded");
 }
 
+tcu::TestStatus createSwapchainSimulateOOMTest (Context& context, TestParameters params)
+{
+	tcu::TestLog&	log	= context.getTestContext().getLog();
+
+	// \note This is a little counter-intuitive order (iterating on callback count until all cases pass)
+	//		 but since cases depend on what device reports, it is the only easy way. In practice
+	//		 we should see same number of total callbacks (and executed code) regardless of the
+	//		 loop order.
+
+	for (deUint32 numPassingAllocs = 0; numPassingAllocs <= 16*1024u; ++numPassingAllocs)
+	{
+		AllocationCallbackRecorder	allocationRecorder	(getSystemAllocator());
+		DeterministicFailAllocator	failingAllocator	(allocationRecorder.getCallbacks(), numPassingAllocs);
+		bool						gotOOM				= false;
+
+		log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
+
+		try
+		{
+			const InstanceHelper					instHelper	(context, params.wsiType, failingAllocator.getCallbacks());
+			const NativeObjects						native		(context, instHelper.supportedExtensions, params.wsiType);
+			const Unique<VkSurfaceKHR>				surface		(createSurface(instHelper.vki,
+																			   *instHelper.instance,
+																			   params.wsiType,
+																			   *native.display,
+																			   *native.window,
+																			   failingAllocator.getCallbacks()));
+			const DeviceHelper						devHelper	(context, instHelper.vki, *instHelper.instance, *surface, failingAllocator.getCallbacks());
+			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() << TestLog::EndMessage;
+
+				{
+					const Unique<VkSwapchainKHR>	swapchain	(createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
+				}
+			}
+		}
+		catch (const OutOfMemoryError& e)
+		{
+			log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
+			gotOOM = true;
+		}
+
+		if (!validateAndLog(log, allocationRecorder, 0u))
+			return tcu::TestStatus::fail("Detected invalid system allocation callback");
+
+		if (!gotOOM)
+		{
+			log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
+
+			if (numPassingAllocs == 0)
+				return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
+			else
+				return tcu::TestStatus::pass("OOM simulation completed");
+		}
+	}
+
+	return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
+}
+
 struct GroupParameters
 {
 	typedef FunctionInstance1<TestParameters>::Function	Function;
@@ -604,7 +682,8 @@
 
 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
 {
-	addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
+	addTestGroup(testGroup, "create",			"Create VkSwapchain with various parameters",					populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
+	addTestGroup(testGroup, "simulate_oom",		"Simulate OOM using callbacks during swapchain construction",	populateSwapchainGroup, GroupParameters(wsiType, createSwapchainSimulateOOMTest));
 }
 
 } // wsi
diff --git a/framework/common/tcuCommandLine.cpp b/framework/common/tcuCommandLine.cpp
index b41ef7b..ba267d5 100644
--- a/framework/common/tcuCommandLine.cpp
+++ b/framework/common/tcuCommandLine.cpp
@@ -84,6 +84,7 @@
 DE_DECLARE_COMMAND_LINE_OPT(LogShaderSources,			bool);
 DE_DECLARE_COMMAND_LINE_OPT(TestOOM,					bool);
 DE_DECLARE_COMMAND_LINE_OPT(VKDeviceID,					int);
+DE_DECLARE_COMMAND_LINE_OPT(LogFlush,					bool);
 
 static void parseIntList (const char* src, std::vector<int>* dst)
 {
@@ -168,7 +169,8 @@
 		<< Option<VKDeviceID>			(DE_NULL,	"deqp-vk-device-id",			"Vulkan device ID (IDs start from 1)",									"1")
 		<< Option<LogImages>			(DE_NULL,	"deqp-log-images",				"Enable or disable logging of result images",		s_enableNames,		"enable")
 		<< Option<LogShaderSources>		(DE_NULL,	"deqp-log-shader-sources",		"Enable or disable logging of shader sources",		s_enableNames,		"enable")
-		<< Option<TestOOM>				(DE_NULL,	"deqp-test-oom",				"Run tests that exhaust memory on purpose",			s_enableNames,		TEST_OOM_DEFAULT);
+		<< Option<TestOOM>				(DE_NULL,	"deqp-test-oom",				"Run tests that exhaust memory on purpose",			s_enableNames,		TEST_OOM_DEFAULT)
+		<< Option<LogFlush>             (DE_NULL,   "deqp-log-flush",               "Enable or disable log file fflush",                s_enableNames,      "enable");
 }
 
 void registerLegacyOptions (de::cmdline::Parser& parser)
@@ -725,6 +727,9 @@
 	if (!m_cmdLine.getOption<opt::LogShaderSources>())
 		m_logFlags |= QP_TEST_LOG_EXCLUDE_SHADER_SOURCES;
 
+	if (!m_cmdLine.getOption<opt::LogFlush>())
+		m_logFlags |= QP_TEST_LOG_NO_FLUSH;
+
 	if ((m_cmdLine.hasOption<opt::CasePath>()?1:0) +
 		(m_cmdLine.hasOption<opt::CaseList>()?1:0) +
 		(m_cmdLine.hasOption<opt::CaseListFile>()?1:0) +
diff --git a/framework/common/tcuTestHierarchyUtil.cpp b/framework/common/tcuTestHierarchyUtil.cpp
index dc21619..34882eb 100644
--- a/framework/common/tcuTestHierarchyUtil.cpp
+++ b/framework/common/tcuTestHierarchyUtil.cpp
@@ -146,7 +146,7 @@
 			if (!file)
 				throw Exception("Failed to open " + filename);
 
-			writer = qpXmlWriter_createFileWriter(file, DE_FALSE);
+			writer = qpXmlWriter_createFileWriter(file, DE_FALSE, DE_FALSE);
 			if (!writer)
 				throw Exception("XML writer creation failed");
 
diff --git a/framework/qphelper/qpTestLog.c b/framework/qphelper/qpTestLog.c
index 26c7923..327e232 100644
--- a/framework/qphelper/qpTestLog.c
+++ b/framework/qphelper/qpTestLog.c
@@ -350,7 +350,7 @@
 	}
 
 	log->flags			= flags;
-	log->writer			= qpXmlWriter_createFileWriter(log->outputFile, 0);
+	log->writer			= qpXmlWriter_createFileWriter(log->outputFile, 0, !(flags & QP_TEST_LOG_NO_FLUSH));
 	log->lock			= deMutex_create(DE_NULL);
 	log->isSessionOpen	= DE_FALSE;
 	log->isCaseOpen		= DE_FALSE;
@@ -419,7 +419,8 @@
 	/* Flush XML and write out #beginTestCaseResult. */
 	qpXmlWriter_flush(log->writer);
 	fprintf(log->outputFile, "\n#beginTestCaseResult %s\n", testCasePath);
-	qpTestLog_flushFile(log);
+	if (!(log->flags & QP_TEST_LOG_NO_FLUSH))
+		qpTestLog_flushFile(log);
 
 	log->isCaseOpen = DE_TRUE;
 
@@ -473,7 +474,8 @@
 	/* Flush XML and write #endTestCaseResult. */
 	qpXmlWriter_flush(log->writer);
 	fprintf(log->outputFile, "\n#endTestCaseResult\n");
-	qpTestLog_flushFile(log);
+	if (!(log->flags & QP_TEST_LOG_NO_FLUSH))
+		qpTestLog_flushFile(log);
 
 	log->isCaseOpen = DE_FALSE;
 
diff --git a/framework/qphelper/qpTestLog.h b/framework/qphelper/qpTestLog.h
index aa74fa7..f12454f 100644
--- a/framework/qphelper/qpTestLog.h
+++ b/framework/qphelper/qpTestLog.h
@@ -133,7 +133,8 @@
 typedef enum qpTestLogFlag_e
 {
 	QP_TEST_LOG_EXCLUDE_IMAGES			= (1<<0),		/*!< Do not log images. This reduces log size considerably.			*/
-	QP_TEST_LOG_EXCLUDE_SHADER_SOURCES	= (1<<1)		/*!< Do not log shader sources. Helps to reduce log size further.	*/
+	QP_TEST_LOG_EXCLUDE_SHADER_SOURCES	= (1<<1),		/*!< Do not log shader sources. Helps to reduce log size further.	*/
+	QP_TEST_LOG_NO_FLUSH				= (1<<2)		/*!< Do not do a fflush after writing the log.						*/
 } qpTestLogFlag;
 
 /* Shader type. */
diff --git a/framework/qphelper/qpXmlWriter.c b/framework/qphelper/qpXmlWriter.c
index 6921dab..97ee987 100644
--- a/framework/qphelper/qpXmlWriter.c
+++ b/framework/qphelper/qpXmlWriter.c
@@ -36,6 +36,7 @@
 struct qpXmlWriter_s
 {
 	FILE*				outputFile;
+	deBool				flushAfterWrite;
 
 	deBool				xmlPrevIsStartElement;
 	deBool				xmlIsWriting;
@@ -114,12 +115,13 @@
 		}
 	} while (!isEOS);
 
-	fflush(writer->outputFile);
+	if (writer->flushAfterWrite)
+		fflush(writer->outputFile);
 	DE_ASSERT(d == &buf[0]); /* buffer must be empty */
 	return DE_TRUE;
 }
 
-qpXmlWriter* qpXmlWriter_createFileWriter (FILE* outputFile, deBool useCompression)
+qpXmlWriter* qpXmlWriter_createFileWriter (FILE* outputFile, deBool useCompression, deBool flushAfterWrite)
 {
 	qpXmlWriter* writer = (qpXmlWriter*)deCalloc(sizeof(qpXmlWriter));
 	if (!writer)
@@ -128,6 +130,7 @@
 	DE_UNREF(useCompression); /* no compression supported. */
 
 	writer->outputFile = outputFile;
+	writer->flushAfterWrite = flushAfterWrite;
 
 	return writer;
 }
diff --git a/framework/qphelper/qpXmlWriter.h b/framework/qphelper/qpXmlWriter.h
index ebba428..bb63bde 100644
--- a/framework/qphelper/qpXmlWriter.h
+++ b/framework/qphelper/qpXmlWriter.h
@@ -85,9 +85,10 @@
  * \brief Create a file based XML Writer instance
  * \param fileName Name of the file
  * \param useCompression Set to DE_TRUE to use compression, if supported by implementation
+ * \param flushAfterWrite Set to DE_TRUE to call fflush after writing each XML token
  * \return qpXmlWriter instance, or DE_NULL if cannot create file
  *//*--------------------------------------------------------------------*/
-qpXmlWriter*	qpXmlWriter_createFileWriter (FILE* outFile, deBool useCompression);
+qpXmlWriter*	qpXmlWriter_createFileWriter (FILE* outFile, deBool useCompression, deBool flushAfterWrite);
 
 /*--------------------------------------------------------------------*//*!
  * \brief XML Writer instance