text: /*-------------------------------------------------------------------------
   * Vulkan Conformance Tests
   * ------------------------
   *
   * Copyright (c) 2015 Google Inc.
   *
   * 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 RenderPass tests
   *//*--------------------------------------------------------------------*/
  
  #include "vktRenderPassTests.hpp"
  
  #include "vktTestCaseUtil.hpp"
  #include "vktTestGroupUtil.hpp"
  
  #include "vkDefs.hpp"
  #include "vkDeviceUtil.hpp"
  #include "vkImageUtil.hpp"
  #include "vkMemUtil.hpp"
  #include "vkPlatform.hpp"
  #include "vkPrograms.hpp"
  #include "vkQueryUtil.hpp"
  #include "vkRef.hpp"
  #include "vkRefUtil.hpp"
  #include "vkStrUtil.hpp"
  #include "vkTypeUtil.hpp"
  
  #include "tcuFloat.hpp"
  #include "tcuFormatUtil.hpp"
  #include "tcuMaybe.hpp"
  #include "tcuResultCollector.hpp"
  #include "tcuTestLog.hpp"
  #include "tcuTextureUtil.hpp"
  #include "tcuVectorUtil.hpp"
  
  #include "deRandom.hpp"
  #include "deSTLUtil.hpp"
  #include "deSharedPtr.hpp"
  #include "deStringUtil.hpp"
  #include "deUniquePtr.hpp"
  
  #include <limits>
  #include <set>
  #include <string>
  #include <vector>
  
  using namespace vk;
  
  using tcu::BVec4;
  using tcu::IVec2;
  using tcu::IVec4;
  using tcu::UVec2;
  using tcu::UVec4;
  using tcu::Vec2;
  using tcu::Vec4;
  
  using tcu::Maybe;
  using tcu::just;
  using tcu::nothing;
  
  using tcu::ConstPixelBufferAccess;
  using tcu::PixelBufferAccess;
  
  using tcu::TestLog;
  
  using de::UniquePtr;
  
  using std::pair;
  using std::set;
  using std::string;
  using std::vector;
  
  namespace vkt
  {
  namespace
  {
  enum BoolOp
  {
  	BOOLOP_AND,
  	BOOLOP_OR,
  	BOOLOP_EQ,
  	BOOLOP_NEQ
  };
  
  const char* boolOpToString (BoolOp op)
  {
  	switch (op)
  	{
  		case BOOLOP_OR:
  			return "||";
  
  		case BOOLOP_AND:
  			return "&&";
  
  		case BOOLOP_EQ:
  			return "==";
  
  		case BOOLOP_NEQ:
  			return "!=";
  
  		default:
  			DE_FATAL("Unknown boolean operation.");
  			return DE_NULL;
  	}
  }
  
  bool performBoolOp (BoolOp op, bool a, bool b)
  {
  	switch (op)
  	{
  		case BOOLOP_OR:
  			return a || b;
  
  		case BOOLOP_AND:
  			return a && b;
  
  		case BOOLOP_EQ:
  			return a == b;
  
  		case BOOLOP_NEQ:
  			return a != b;
  
  		default:
  			DE_FATAL("Unknown boolean operation.");
  			return false;
  	}
  }
  
  BoolOp boolOpFromIndex (size_t index)
  {
  	const BoolOp ops[] =
  	{
  		BOOLOP_OR,
  		BOOLOP_AND,
  		BOOLOP_EQ,
  		BOOLOP_NEQ
  	};
  
  	return ops[index % DE_LENGTH_OF_ARRAY(ops)];
  }
  
  // Utility functions using flattened structs
  Move<VkFence> createFence (const DeviceInterface& vk, VkDevice device, VkFenceCreateFlags flags)
  {
  	const VkFenceCreateInfo pCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
  		DE_NULL,
  
  		flags
  	};
  	return createFence(vk, device, &pCreateInfo);
  }
  
  Move<VkFramebuffer> createFramebuffer (const DeviceInterface&	vk,
  									   VkDevice					device,
  									   VkFramebufferCreateFlags	pCreateInfo_flags,
  									   VkRenderPass				pCreateInfo_renderPass,
  									   deUint32					pCreateInfo_attachmentCount,
  									   const VkImageView*		pCreateInfo_pAttachments,
  									   deUint32					pCreateInfo_width,
  									   deUint32					pCreateInfo_height,
  									   deUint32					pCreateInfo_layers)
  {
  	const VkFramebufferCreateInfo pCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
  		DE_NULL,
  		pCreateInfo_flags,
  		pCreateInfo_renderPass,
  		pCreateInfo_attachmentCount,
  		pCreateInfo_pAttachments,
  		pCreateInfo_width,
  		pCreateInfo_height,
  		pCreateInfo_layers,
  	};
  	return createFramebuffer(vk, device, &pCreateInfo);
  }
  
  Move<VkImage> createImage (const DeviceInterface&	vk,
  						   VkDevice					device,
  						   VkImageCreateFlags		pCreateInfo_flags,
  						   VkImageType				pCreateInfo_imageType,
  						   VkFormat					pCreateInfo_format,
  						   VkExtent3D				pCreateInfo_extent,
  						   deUint32					pCreateInfo_mipLevels,
  						   deUint32					pCreateInfo_arrayLayers,
  						   VkSampleCountFlagBits	pCreateInfo_samples,
  						   VkImageTiling			pCreateInfo_tiling,
  						   VkImageUsageFlags		pCreateInfo_usage,
  						   VkSharingMode			pCreateInfo_sharingMode,
  						   deUint32					pCreateInfo_queueFamilyCount,
  						   const deUint32*			pCreateInfo_pQueueFamilyIndices,
  						   VkImageLayout			pCreateInfo_initialLayout)
  {
  	const VkImageCreateInfo pCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
  		DE_NULL,
  		pCreateInfo_flags,
  		pCreateInfo_imageType,
  		pCreateInfo_format,
  		pCreateInfo_extent,
  		pCreateInfo_mipLevels,
  		pCreateInfo_arrayLayers,
  		pCreateInfo_samples,
  		pCreateInfo_tiling,
  		pCreateInfo_usage,
  		pCreateInfo_sharingMode,
  		pCreateInfo_queueFamilyCount,
  		pCreateInfo_pQueueFamilyIndices,
  		pCreateInfo_initialLayout
  	};
  	return createImage(vk, device, &pCreateInfo);
  }
  
  void bindBufferMemory (const DeviceInterface& vk, VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset)
  {
  	VK_CHECK(vk.bindBufferMemory(device, buffer, mem, memOffset));
  }
  
  void bindImageMemory (const DeviceInterface& vk, VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset)
  {
  	VK_CHECK(vk.bindImageMemory(device, image, mem, memOffset));
  }
  
  Move<VkImageView> createImageView (const DeviceInterface&	vk,
  									VkDevice				device,
  									VkImageViewCreateFlags	pCreateInfo_flags,
  									VkImage					pCreateInfo_image,
  									VkImageViewType			pCreateInfo_viewType,
  									VkFormat				pCreateInfo_format,
  									VkComponentMapping		pCreateInfo_components,
  									VkImageSubresourceRange	pCreateInfo_subresourceRange)
  {
  	const VkImageViewCreateInfo pCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
  		DE_NULL,
  		pCreateInfo_flags,
  		pCreateInfo_image,
  		pCreateInfo_viewType,
  		pCreateInfo_format,
  		pCreateInfo_components,
  		pCreateInfo_subresourceRange,
  	};
  	return createImageView(vk, device, &pCreateInfo);
  }
  
  Move<VkBuffer> createBuffer (const DeviceInterface&	vk,
  							 VkDevice				device,
  							 VkBufferCreateFlags	pCreateInfo_flags,
  							 VkDeviceSize			pCreateInfo_size,
  							 VkBufferUsageFlags		pCreateInfo_usage,
  							 VkSharingMode			pCreateInfo_sharingMode,
  							 deUint32				pCreateInfo_queueFamilyCount,
  							 const deUint32*		pCreateInfo_pQueueFamilyIndices)
  {
  	const VkBufferCreateInfo pCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
  		DE_NULL,
  		pCreateInfo_flags,
  		pCreateInfo_size,
  		pCreateInfo_usage,
  		pCreateInfo_sharingMode,
  		pCreateInfo_queueFamilyCount,
  		pCreateInfo_pQueueFamilyIndices,
  	};
  	return createBuffer(vk, device, &pCreateInfo);
  }
  
  Move<VkCommandPool> createCommandPool (const DeviceInterface&	vk,
  									   VkDevice					device,
  									   VkCommandPoolCreateFlags	pCreateInfo_flags,
  									   deUint32					pCreateInfo_queueFamilyIndex)
  {
  	const VkCommandPoolCreateInfo pCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
  		DE_NULL,
  		pCreateInfo_flags,
  		pCreateInfo_queueFamilyIndex,
  	};
  	return createCommandPool(vk, device, &pCreateInfo);
  }
  
  void cmdBeginRenderPass (const DeviceInterface&	vk,
  						 VkCommandBuffer		cmdBuffer,
  						 VkRenderPass			pRenderPassBegin_renderPass,
  						 VkFramebuffer			pRenderPassBegin_framebuffer,
  						 VkRect2D				pRenderPassBegin_renderArea,
  						 deUint32				pRenderPassBegin_clearValueCount,
  						 const VkClearValue*	pRenderPassBegin_pAttachmentClearValues,
  						 VkSubpassContents		contents)
  {
  	const VkRenderPassBeginInfo pRenderPassBegin =
  	{
  		VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
  		DE_NULL,
  		pRenderPassBegin_renderPass,
  		pRenderPassBegin_framebuffer,
  		pRenderPassBegin_renderArea,
  		pRenderPassBegin_clearValueCount,
  		pRenderPassBegin_pAttachmentClearValues,
  	};
  	vk.cmdBeginRenderPass(cmdBuffer, &pRenderPassBegin, contents);
  }
  
  Move<VkCommandBuffer> allocateCommandBuffer (const DeviceInterface&	vk,
  											 VkDevice				device,
  											 VkCommandPool			pCreateInfo_commandPool,
  											 VkCommandBufferLevel	pCreateInfo_level)
  {
  	const VkCommandBufferAllocateInfo pAllocateInfo =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
  		DE_NULL,
  		pCreateInfo_commandPool,
  		pCreateInfo_level,
  		1u,												// bufferCount
  	};
  	return allocateCommandBuffer(vk, device, &pAllocateInfo);
  }
  
  void beginCommandBuffer (const DeviceInterface&			vk,
  						 VkCommandBuffer				cmdBuffer,
  						 VkCommandBufferUsageFlags		pBeginInfo_flags,
  						 VkRenderPass					pInheritanceInfo_renderPass,
  						 deUint32						pInheritanceInfo_subpass,
  						 VkFramebuffer					pInheritanceInfo_framebuffer,
  						 VkBool32						pInheritanceInfo_occlusionQueryEnable,
  						 VkQueryControlFlags			pInheritanceInfo_queryFlags,
  						 VkQueryPipelineStatisticFlags	pInheritanceInfo_pipelineStatistics)
  {
  	const VkCommandBufferInheritanceInfo pInheritanceInfo =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		pInheritanceInfo_renderPass,
  		pInheritanceInfo_subpass,
  		pInheritanceInfo_framebuffer,
  		pInheritanceInfo_occlusionQueryEnable,
  		pInheritanceInfo_queryFlags,
  		pInheritanceInfo_pipelineStatistics,
  	};
  	const VkCommandBufferBeginInfo pBeginInfo =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  		DE_NULL,
  		pBeginInfo_flags,
  		&pInheritanceInfo,
  	};
  	VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &pBeginInfo));
  }
  
  void endCommandBuffer (const DeviceInterface& vk, VkCommandBuffer cmdBuffer)
  {
  	VK_CHECK(vk.endCommandBuffer(cmdBuffer));
  }
  
  void queueSubmit (const DeviceInterface& vk, VkQueue queue, deUint32 cmdBufferCount, const VkCommandBuffer* pCmdBuffers, VkFence fence)
  {
  	const VkSubmitInfo submitInfo =
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,
  		DE_NULL,
  		0u,								// waitSemaphoreCount
  		(const VkSemaphore*)DE_NULL,	// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,
  		cmdBufferCount,					// commandBufferCount
  		pCmdBuffers,
  		0u,								// signalSemaphoreCount
  		(const VkSemaphore*)DE_NULL,	// pSignalSemaphores
  	};
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, fence));
  }
  
  void waitForFences (const DeviceInterface& vk, VkDevice device, deUint32 fenceCount, const VkFence* pFences, VkBool32 waitAll, deUint64 timeout)
  {
  	VK_CHECK(vk.waitForFences(device, fenceCount, pFences, waitAll, timeout));
  }
  
  VkImageAspectFlags getImageAspectFlags (VkFormat vkFormat)
  {
  	const tcu::TextureFormat format = mapVkFormat(vkFormat);
  
  	DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST == 21);
  
  	switch (format.order)
  	{
  		case tcu::TextureFormat::DS:
  			return VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
  
  		case tcu::TextureFormat::D:
  			return VK_IMAGE_ASPECT_DEPTH_BIT;
  
  		case tcu::TextureFormat::S:
  			return VK_IMAGE_ASPECT_STENCIL_BIT;
  
  		default:
  			return VK_IMAGE_ASPECT_COLOR_BIT;
  	}
  }
  
  VkAccessFlags getAllMemoryReadFlags (void)
  {
  	return VK_ACCESS_TRANSFER_READ_BIT
  		   | VK_ACCESS_UNIFORM_READ_BIT
  		   | VK_ACCESS_HOST_READ_BIT
  		   | VK_ACCESS_INDEX_READ_BIT
  		   | VK_ACCESS_SHADER_READ_BIT
  		   | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
  		   | VK_ACCESS_INDIRECT_COMMAND_READ_BIT
  		   | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
  		   | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
  		   | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
  }
  
  VkAccessFlags getAllMemoryWriteFlags (void)
  {
  	return VK_ACCESS_TRANSFER_WRITE_BIT
  		   | VK_ACCESS_HOST_WRITE_BIT
  		   | VK_ACCESS_SHADER_WRITE_BIT
  		   | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
  		   | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  }
  
  VkAccessFlags getMemoryFlagsForLayout (const VkImageLayout layout)
  {
  	switch (layout)
  	{
  		case VK_IMAGE_LAYOUT_GENERAL:							return getAllMemoryReadFlags() | getAllMemoryWriteFlags();
  		case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:			return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  		case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:	return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
  		case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:	return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
  		case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:			return VK_ACCESS_SHADER_READ_BIT;
  		case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:				return VK_ACCESS_TRANSFER_READ_BIT;
  		case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:				return VK_ACCESS_TRANSFER_WRITE_BIT;
  
  		default:
  			return (VkAccessFlags)0;
  	}
  }
  
  VkPipelineStageFlags getAllPipelineStageFlags (void)
  {
  	return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT
  		   | VK_PIPELINE_STAGE_TRANSFER_BIT
  		   | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT
  		   | VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
  		   | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
  		   | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT
  		   | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT
  		   | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  		   | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT
  		   | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  		   | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
  		   | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  		   | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
  }
  
  class AttachmentReference
  {
  public:
  					AttachmentReference		(deUint32		attachment,
  											 VkImageLayout	layout)
  		: m_attachment	(attachment)
  		, m_layout		(layout)
  	{
  	}
  
  	deUint32		getAttachment			(void) const { return m_attachment;	}
  	VkImageLayout	getImageLayout			(void) const { return m_layout;		}
  
  private:
  	deUint32		m_attachment;
  	VkImageLayout	m_layout;
  };
  
  class Subpass
  {
  public:
  										Subpass						(VkPipelineBindPoint				pipelineBindPoint,
  																	 VkSubpassDescriptionFlags			flags,
  																	 const vector<AttachmentReference>&	inputAttachments,
  																	 const vector<AttachmentReference>&	colorAttachments,
  																	 const vector<AttachmentReference>&	resolveAttachments,
  																	 AttachmentReference				depthStencilAttachment,
  																	 const vector<deUint32>&			preserveAttachments)
  		: m_pipelineBindPoint		(pipelineBindPoint)
  		, m_flags					(flags)
  		, m_inputAttachments		(inputAttachments)
  		, m_colorAttachments		(colorAttachments)
  		, m_resolveAttachments		(resolveAttachments)
  		, m_depthStencilAttachment	(depthStencilAttachment)
  		, m_preserveAttachments		(preserveAttachments)
  	{
  	}
  
  	VkPipelineBindPoint					getPipelineBindPoint		(void) const { return m_pipelineBindPoint;		}
  	VkSubpassDescriptionFlags			getFlags					(void) const { return m_flags;					}
  	const vector<AttachmentReference>&	getInputAttachments			(void) const { return m_inputAttachments;		}
  	const vector<AttachmentReference>&	getColorAttachments			(void) const { return m_colorAttachments;		}
  	const vector<AttachmentReference>&	getResolveAttachments		(void) const { return m_resolveAttachments;		}
  	const AttachmentReference&			getDepthStencilAttachment	(void) const { return m_depthStencilAttachment;	}
  	const vector<deUint32>&				getPreserveAttachments		(void) const { return m_preserveAttachments;	}
  
  private:
  	VkPipelineBindPoint					m_pipelineBindPoint;
  	VkSubpassDescriptionFlags			m_flags;
  
  	vector<AttachmentReference>			m_inputAttachments;
  	vector<AttachmentReference>			m_colorAttachments;
  	vector<AttachmentReference>			m_resolveAttachments;
  	AttachmentReference					m_depthStencilAttachment;
  
  	vector<deUint32>					m_preserveAttachments;
  };
  
  class SubpassDependency
  {
  public:
  							SubpassDependency	(deUint32				srcPass,
  												 deUint32				dstPass,
  
  												 VkPipelineStageFlags	srcStageMask,
  												 VkPipelineStageFlags	dstStageMask,
  
  												 VkAccessFlags			outputMask,
  												 VkAccessFlags			inputMask,
  
  												 VkDependencyFlags		flags)
  		: m_srcPass			(srcPass)
  		, m_dstPass			(dstPass)
  
  		, m_srcStageMask	(srcStageMask)
  		, m_dstStageMask	(dstStageMask)
  
  		, m_outputMask		(outputMask)
  		, m_inputMask		(inputMask)
  		, m_flags			(flags)
  	{
  	}
  
  	deUint32				getSrcPass			(void) const { return m_srcPass;		}
  	deUint32				getDstPass			(void) const { return m_dstPass;		}
  
  	VkPipelineStageFlags	getSrcStageMask		(void) const { return m_srcStageMask;	}
  	VkPipelineStageFlags	getDstStageMask		(void) const { return m_dstStageMask;	}
  
  	VkAccessFlags			getOutputMask		(void) const { return m_outputMask;		}
  	VkAccessFlags			getInputMask		(void) const { return m_inputMask;		}
  
  	VkDependencyFlags		getFlags			(void) const { return m_flags;		}
  
  private:
  	deUint32				m_srcPass;
  	deUint32				m_dstPass;
  
  	VkPipelineStageFlags	m_srcStageMask;
  	VkPipelineStageFlags	m_dstStageMask;
  
  	VkAccessFlags			m_outputMask;
  	VkAccessFlags			m_inputMask;
  	VkDependencyFlags		m_flags;
  };
  
  class Attachment
  {
  public:
  							Attachment			(VkFormat				format,
  												 VkSampleCountFlagBits	samples,
  
  												 VkAttachmentLoadOp		loadOp,
  												 VkAttachmentStoreOp	storeOp,
  
  												 VkAttachmentLoadOp		stencilLoadOp,
  												 VkAttachmentStoreOp	stencilStoreOp,
  
  												 VkImageLayout			initialLayout,
  												 VkImageLayout			finalLayout)
  		: m_format			(format)
  		, m_samples			(samples)
  
  		, m_loadOp			(loadOp)
  		, m_storeOp			(storeOp)
  
  		, m_stencilLoadOp	(stencilLoadOp)
  		, m_stencilStoreOp	(stencilStoreOp)
  
  		, m_initialLayout	(initialLayout)
  		, m_finalLayout		(finalLayout)
  	{
  	}
  
  	VkFormat				getFormat			(void) const { return m_format;			}
  	VkSampleCountFlagBits	getSamples			(void) const { return m_samples;		}
  
  	VkAttachmentLoadOp		getLoadOp			(void) const { return m_loadOp;			}
  	VkAttachmentStoreOp		getStoreOp			(void) const { return m_storeOp;		}
  
  
  	VkAttachmentLoadOp		getStencilLoadOp	(void) const { return m_stencilLoadOp;	}
  	VkAttachmentStoreOp		getStencilStoreOp	(void) const { return m_stencilStoreOp;	}
  
  	VkImageLayout			getInitialLayout	(void) const { return m_initialLayout;	}
  	VkImageLayout			getFinalLayout		(void) const { return m_finalLayout;	}
  
  private:
  	VkFormat				m_format;
  	VkSampleCountFlagBits	m_samples;
  
  	VkAttachmentLoadOp		m_loadOp;
  	VkAttachmentStoreOp		m_storeOp;
  
  	VkAttachmentLoadOp		m_stencilLoadOp;
  	VkAttachmentStoreOp		m_stencilStoreOp;
  
  	VkImageLayout			m_initialLayout;
  	VkImageLayout			m_finalLayout;
  };
  
  class RenderPass
  {
  public:
  										RenderPass		(const vector<Attachment>&			attachments,
  														 const vector<Subpass>&				subpasses,
  														 const vector<SubpassDependency>&	dependencies)
  		: m_attachments		(attachments)
  		, m_subpasses		(subpasses)
  		, m_dependencies	(dependencies)
  	{
  	}
  
  	const vector<Attachment>&			getAttachments	(void) const { return m_attachments;	}
  	const vector<Subpass>&				getSubpasses	(void) const { return m_subpasses;		}
  	const vector<SubpassDependency>&	getDependencies	(void) const { return m_dependencies;	}
  
  private:
  	const vector<Attachment>			m_attachments;
  	const vector<Subpass>				m_subpasses;
  	const vector<SubpassDependency>		m_dependencies;
  };
  
  struct TestConfig
  {
  	enum RenderTypes
  	{
  		RENDERTYPES_NONE	= 0,
  		RENDERTYPES_CLEAR	= (1<<1),
  		RENDERTYPES_DRAW	= (1<<2)
  	};
  
  	enum CommandBufferTypes
  	{
  		COMMANDBUFFERTYPES_INLINE		= (1<<0),
  		COMMANDBUFFERTYPES_SECONDARY	= (1<<1)
  	};
  
  	enum ImageMemory
  	{
  		IMAGEMEMORY_STRICT		= (1<<0),
  		IMAGEMEMORY_LAZY		= (1<<1)
  	};
  
  						TestConfig (const RenderPass&	renderPass_,
  									RenderTypes			renderTypes_,
  									CommandBufferTypes	commandBufferTypes_,
  									ImageMemory			imageMemory_,
  									const UVec2&		targetSize_,
  									const UVec2&		renderPos_,
  									const UVec2&		renderSize_,
  									deUint32			seed_)
  		: renderPass			(renderPass_)
  		, renderTypes			(renderTypes_)
  		, commandBufferTypes	(commandBufferTypes_)
  		, imageMemory			(imageMemory_)
  		, targetSize			(targetSize_)
  		, renderPos				(renderPos_)
  		, renderSize			(renderSize_)
  		, seed					(seed_)
  	{
  	}
  
  	RenderPass			renderPass;
  	RenderTypes			renderTypes;
  	CommandBufferTypes	commandBufferTypes;
  	ImageMemory			imageMemory;
  	UVec2				targetSize;
  	UVec2				renderPos;
  	UVec2				renderSize;
  	deUint32			seed;
  };
  
  TestConfig::RenderTypes operator| (TestConfig::RenderTypes a, TestConfig::RenderTypes b)
  {
  	return (TestConfig::RenderTypes)(((deUint32)a) | ((deUint32)b));
  }
  
  TestConfig::CommandBufferTypes operator| (TestConfig::CommandBufferTypes a, TestConfig::CommandBufferTypes b)
  {
  	return (TestConfig::CommandBufferTypes)(((deUint32)a) | ((deUint32)b));
  }
  
  TestConfig::ImageMemory operator| (TestConfig::ImageMemory a, TestConfig::ImageMemory b)
  {
  	return (TestConfig::ImageMemory)(((deUint32)a) | ((deUint32)b));
  }
  
  void logRenderPassInfo (TestLog&			log,
  						const RenderPass&	renderPass)
  {
  	const tcu::ScopedLogSection section (log, "RenderPass", "RenderPass");
  
  	{
  		const tcu::ScopedLogSection	attachmentsSection	(log, "Attachments", "Attachments");
  		const vector<Attachment>&	attachments			= renderPass.getAttachments();
  
  		for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
  		{
  			const tcu::ScopedLogSection	attachmentSection	(log, "Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx));
  			const Attachment&			attachment			= attachments[attachmentNdx];
  
  			log << TestLog::Message << "Format: " << attachment.getFormat() << TestLog::EndMessage;
  			log << TestLog::Message << "Samples: " << attachment.getSamples() << TestLog::EndMessage;
  
  			log << TestLog::Message << "LoadOp: " << attachment.getLoadOp() << TestLog::EndMessage;
  			log << TestLog::Message << "StoreOp: " << attachment.getStoreOp() << TestLog::EndMessage;
  
  			log << TestLog::Message << "StencilLoadOp: " << attachment.getStencilLoadOp() << TestLog::EndMessage;
  			log << TestLog::Message << "StencilStoreOp: " << attachment.getStencilStoreOp() << TestLog::EndMessage;
  
  			log << TestLog::Message << "InitialLayout: " << attachment.getInitialLayout() << TestLog::EndMessage;
  			log << TestLog::Message << "FinalLayout: " << attachment.getFinalLayout() << TestLog::EndMessage;
  		}
  	}
  
  	{
  		const tcu::ScopedLogSection	subpassesSection	(log, "Subpasses", "Subpasses");
  		const vector<Subpass>&		subpasses			= renderPass.getSubpasses();
  
  		for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
  		{
  			const tcu::ScopedLogSection			subpassSection		(log, "Subpass" + de::toString(subpassNdx), "Subpass " + de::toString(subpassNdx));
  			const Subpass&						subpass				= subpasses[subpassNdx];
  
  			const vector<AttachmentReference>&	inputAttachments	= subpass.getInputAttachments();
  			const vector<AttachmentReference>&	colorAttachments	= subpass.getColorAttachments();
  			const vector<AttachmentReference>&	resolveAttachments	= subpass.getResolveAttachments();
  			const vector<deUint32>&				preserveAttachments	= subpass.getPreserveAttachments();
  
  			if (!inputAttachments.empty())
  			{
  				const tcu::ScopedLogSection	inputAttachmentsSection	(log, "Inputs", "Inputs");
  
  				for (size_t inputNdx = 0; inputNdx < inputAttachments.size(); inputNdx++)
  				{
  					const tcu::ScopedLogSection	inputAttachmentSection	(log, "Input" + de::toString(inputNdx), "Input " + de::toString(inputNdx));
  					const AttachmentReference&	inputAttachment			= inputAttachments[inputNdx];
  
  					log << TestLog::Message << "Attachment: " << inputAttachment.getAttachment() << TestLog::EndMessage;
  					log << TestLog::Message << "Layout: " << inputAttachment.getImageLayout() << TestLog::EndMessage;
  				}
  			}
  
  			if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
  			{
  				const tcu::ScopedLogSection	depthStencilAttachmentSection	(log, "DepthStencil", "DepthStencil");
  				const AttachmentReference&	depthStencilAttachment			= subpass.getDepthStencilAttachment();
  
  				log << TestLog::Message << "Attachment: " << depthStencilAttachment.getAttachment() << TestLog::EndMessage;
  				log << TestLog::Message << "Layout: " << depthStencilAttachment.getImageLayout() << TestLog::EndMessage;
  			}
  
  			if (!colorAttachments.empty())
  			{
  				const tcu::ScopedLogSection	colorAttachmentsSection	(log, "Colors", "Colors");
  
  				for (size_t colorNdx = 0; colorNdx < colorAttachments.size(); colorNdx++)
  				{
  					const tcu::ScopedLogSection	colorAttachmentSection	(log, "Color" + de::toString(colorNdx), "Color " + de::toString(colorNdx));
  					const AttachmentReference&	colorAttachment			= colorAttachments[colorNdx];
  
  					log << TestLog::Message << "Attachment: " << colorAttachment.getAttachment() << TestLog::EndMessage;
  					log << TestLog::Message << "Layout: " << colorAttachment.getImageLayout() << TestLog::EndMessage;
  				}
  			}
  
  			if (!resolveAttachments.empty())
  			{
  				const tcu::ScopedLogSection	resolveAttachmentsSection	(log, "Resolves", "Resolves");
  
  				for (size_t resolveNdx = 0; resolveNdx < resolveAttachments.size(); resolveNdx++)
  				{
  					const tcu::ScopedLogSection	resolveAttachmentSection	(log, "Resolve" + de::toString(resolveNdx), "Resolve " + de::toString(resolveNdx));
  					const AttachmentReference&	resolveAttachment			= resolveAttachments[resolveNdx];
  
  					log << TestLog::Message << "Attachment: " << resolveAttachment.getAttachment() << TestLog::EndMessage;
  					log << TestLog::Message << "Layout: " << resolveAttachment.getImageLayout() << TestLog::EndMessage;
  				}
  			}
  
  			if (!preserveAttachments.empty())
  			{
  				const tcu::ScopedLogSection	preserveAttachmentsSection	(log, "Preserves", "Preserves");
  
  				for (size_t preserveNdx = 0; preserveNdx < preserveAttachments.size(); preserveNdx++)
  				{
  					const tcu::ScopedLogSection	preserveAttachmentSection	(log, "Preserve" + de::toString(preserveNdx), "Preserve " + de::toString(preserveNdx));
  					const deUint32				preserveAttachment			= preserveAttachments[preserveNdx];
  
  					log << TestLog::Message << "Attachment: " << preserveAttachment << TestLog::EndMessage;
  				}
  			}
  		}
  
  	}
  
  	if (!renderPass.getDependencies().empty())
  	{
  		const tcu::ScopedLogSection	dependenciesSection	(log, "Dependencies", "Dependencies");
  
  		for (size_t depNdx = 0; depNdx < renderPass.getDependencies().size(); depNdx++)
  		{
  			const tcu::ScopedLogSection	dependencySection	(log, "Dependency" + de::toString(depNdx), "Dependency " + de::toString(depNdx));
  			const SubpassDependency&	dep					= renderPass.getDependencies()[depNdx];
  
  			log << TestLog::Message << "Source: " << dep.getSrcPass() << TestLog::EndMessage;
  			log << TestLog::Message << "Destination: " << dep.getDstPass() << TestLog::EndMessage;
  
  			log << TestLog::Message << "Source Stage Mask: " << dep.getSrcStageMask() << TestLog::EndMessage;
  			log << TestLog::Message << "Destination Stage Mask: " << dep.getDstStageMask() << TestLog::EndMessage;
  
  			log << TestLog::Message << "Input Mask: " << dep.getInputMask() << TestLog::EndMessage;
  			log << TestLog::Message << "Output Mask: " << dep.getOutputMask() << TestLog::EndMessage;
  			log << TestLog::Message << "Dependency Flags: " << getDependencyFlagsStr(dep.getFlags()) << TestLog::EndMessage;
  		}
  	}
  }
  
  std::string clearColorToString (VkFormat vkFormat, VkClearColorValue value)
  {
  	const tcu::TextureFormat		format			= mapVkFormat(vkFormat);
  	const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(format.type);
  	const tcu::BVec4				channelMask		= tcu::getTextureFormatChannelMask(format);
  
  	std::ostringstream				stream;
  
  	stream << "(";
  
  	switch (channelClass)
  	{
  		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
  			for (int i = 0; i < 4; i++)
  			{
  				if (i > 0)
  					stream << ", ";
  
  				if (channelMask[i])
  					stream << value.int32[i];
  				else
  					stream << "Undef";
  			}
  			break;
  
  		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
  			for (int i = 0; i < 4; i++)
  			{
  				if (i > 0)
  					stream << ", ";
  
  				if (channelMask[i])
  					stream << value.uint32[i];
  				else
  					stream << "Undef";
  			}
  			break;
  
  		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
  		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
  		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
  			for (int i = 0; i < 4; i++)
  			{
  				if (i > 0)
  					stream << ", ";
  
  				if (channelMask[i])
  					stream << value.float32[i];
  				else
  					stream << "Undef";
  			}
  			break;
  
  		default:
  			DE_FATAL("Unknown channel class");
  	}
  
  	stream << ")";
  
  	return stream.str();
  }
  
  std::string clearValueToString (VkFormat vkFormat, VkClearValue value)
  {
  	const tcu::TextureFormat	format	= mapVkFormat(vkFormat);
  
  	if (tcu::hasStencilComponent(format.order) || tcu::hasDepthComponent(format.order))
  	{
  		std::ostringstream stream;
  
  		stream << "(";
  
  		if (tcu::hasStencilComponent(format.order))
  			stream << "stencil: " << value.depthStencil.stencil;
  
  		if (tcu::hasStencilComponent(format.order) && tcu::hasDepthComponent(format.order))
  			stream << ", ";
  
  		if (tcu::hasDepthComponent(format.order))
  			stream << "depth: " << value.depthStencil.depth;
  
  		stream << ")";
  
  		return stream.str();
  	}
  	else
  		return clearColorToString(vkFormat, value.color);
  }
  
  VkClearColorValue randomColorClearValue (const Attachment& attachment, de::Random& rng)
  {
  	const float						clearNan		= tcu::Float32::nan().asFloat();
  	const tcu::TextureFormat		format			= mapVkFormat(attachment.getFormat());
  	const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(format.type);
  	const tcu::BVec4				channelMask		= tcu::getTextureFormatChannelMask(format);
  	VkClearColorValue				clearColor;
  
  	switch (channelClass)
  	{
  		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
  		{
  			for (int ndx = 0; ndx < 4; ndx++)
  			{
  				if (!channelMask[ndx])
  					clearColor.int32[ndx] = std::numeric_limits<deInt32>::min();
  				else
  					clearColor.uint32[ndx] = rng.getBool() ? 1u : 0u;
  			}
  			break;
  		}
  
  		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
  		{
  			for (int ndx = 0; ndx < 4; ndx++)
  			{
  				if (!channelMask[ndx])
  					clearColor.uint32[ndx] = std::numeric_limits<deUint32>::max();
  				else
  					clearColor.uint32[ndx] = rng.getBool() ? 1u : 0u;
  			}
  			break;
  		}
  
  		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
  		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
  		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
  		{
  			for (int ndx = 0; ndx < 4; ndx++)
  			{
  				if (!channelMask[ndx])
  					clearColor.float32[ndx] = clearNan;
  				else
  					clearColor.float32[ndx] = rng.getBool() ? 1.0f : 0.0f;
  			}
  			break;
  		}
  
  		default:
  			DE_FATAL("Unknown channel class");
  	}
  
  	return clearColor;
  }
  
  VkAttachmentDescription createAttachmentDescription (const Attachment& attachment)
  {
  	const VkAttachmentDescription attachmentDescription =
  	{
  		0,								// flags
  
  		attachment.getFormat(),			// format
  		attachment.getSamples(),		// samples
  
  		attachment.getLoadOp(),			// loadOp
  		attachment.getStoreOp(),		// storeOp
  
  		attachment.getStencilLoadOp(),	// stencilLoadOp
  		attachment.getStencilStoreOp(),	// stencilStoreOp
  
  		attachment.getInitialLayout(),	// initialLayout
  		attachment.getFinalLayout(),	// finalLayout
  	};
  
  	return attachmentDescription;
  }
  
  VkAttachmentReference createAttachmentReference (const AttachmentReference& referenceInfo)
  {
  	const VkAttachmentReference reference =
  	{
  		referenceInfo.getAttachment(),	// attachment;
  		referenceInfo.getImageLayout()	// layout;
  	};
  
  	return reference;
  }
  
  VkSubpassDescription createSubpassDescription (const Subpass&					subpass,
  											   vector<VkAttachmentReference>*	attachmentReferenceLists,
  											   vector<deUint32>*				preserveAttachmentReferences)
  {
  	vector<VkAttachmentReference>&	inputAttachmentReferences			= attachmentReferenceLists[0];
  	vector<VkAttachmentReference>&	colorAttachmentReferences			= attachmentReferenceLists[1];
  	vector<VkAttachmentReference>&	resolveAttachmentReferences			= attachmentReferenceLists[2];
  	vector<VkAttachmentReference>&	depthStencilAttachmentReferences	= attachmentReferenceLists[3];
  
  	for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++)
  		colorAttachmentReferences.push_back(createAttachmentReference(subpass.getColorAttachments()[attachmentNdx]));
  
  	for (size_t attachmentNdx = 0; attachmentNdx < subpass.getInputAttachments().size(); attachmentNdx++)
  		inputAttachmentReferences.push_back(createAttachmentReference(subpass.getInputAttachments()[attachmentNdx]));
  
  	for (size_t attachmentNdx = 0; attachmentNdx < subpass.getResolveAttachments().size(); attachmentNdx++)
  		resolveAttachmentReferences.push_back(createAttachmentReference(subpass.getResolveAttachments()[attachmentNdx]));
  
  	depthStencilAttachmentReferences.push_back(createAttachmentReference(subpass.getDepthStencilAttachment()));
  
  	for (size_t attachmentNdx = 0; attachmentNdx < subpass.getPreserveAttachments().size(); attachmentNdx++)
  		preserveAttachmentReferences->push_back(subpass.getPreserveAttachments()[attachmentNdx]);
  
  	DE_ASSERT(resolveAttachmentReferences.empty() || colorAttachmentReferences.size() == resolveAttachmentReferences.size());
  
  	{
  		const VkSubpassDescription subpassDescription =
  		{
  			subpass.getFlags(),																		// flags;
  			subpass.getPipelineBindPoint(),															// pipelineBindPoint;
  
  			(deUint32)inputAttachmentReferences.size(),												// inputCount;
  			inputAttachmentReferences.empty() ? DE_NULL : &inputAttachmentReferences[0],			// inputAttachments;
  
  			(deUint32)colorAttachmentReferences.size(),												// colorCount;
  			colorAttachmentReferences.empty() ? DE_NULL :  &colorAttachmentReferences[0],			// colorAttachments;
  			resolveAttachmentReferences.empty() ? DE_NULL : &resolveAttachmentReferences[0],		// resolveAttachments;
  
  			&depthStencilAttachmentReferences[0],													// pDepthStencilAttachment;
  			(deUint32)preserveAttachmentReferences->size(),											// preserveCount;
  			preserveAttachmentReferences->empty() ? DE_NULL : &(*preserveAttachmentReferences)[0]	// preserveAttachments;
  		};
  
  		return subpassDescription;
  	}
  }
  
  VkSubpassDependency createSubpassDependency	(const SubpassDependency& dependencyInfo)
  {
  	const VkSubpassDependency dependency =
  	{
  		dependencyInfo.getSrcPass(),		// srcSubpass;
  		dependencyInfo.getDstPass(),		// destSubpass;
  
  		dependencyInfo.getSrcStageMask(),	// srcStageMask;
  		dependencyInfo.getDstStageMask(),	// destStageMask;
  
  		dependencyInfo.getOutputMask(),		// outputMask;
  		dependencyInfo.getInputMask(),		// inputMask;
  
  		dependencyInfo.getFlags()			// dependencyFlags;
  	};
  
  	return dependency;
  }
  
  Move<VkRenderPass> createRenderPass (const DeviceInterface&	vk,
  									 VkDevice				device,
  									 const RenderPass&		renderPassInfo)
  {
  	const size_t							perSubpassAttachmentReferenceLists = 4;
  	vector<VkAttachmentDescription>			attachments;
  	vector<VkSubpassDescription>			subpasses;
  	vector<VkSubpassDependency>				dependencies;
  	vector<vector<VkAttachmentReference> >	attachmentReferenceLists(renderPassInfo.getSubpasses().size() * perSubpassAttachmentReferenceLists);
  	vector<vector<deUint32> >				preserveAttachments(renderPassInfo.getSubpasses().size());
  
  	for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
  		attachments.push_back(createAttachmentDescription(renderPassInfo.getAttachments()[attachmentNdx]));
  
  	for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++)
  		subpasses.push_back(createSubpassDescription(renderPassInfo.getSubpasses()[subpassNdx], &(attachmentReferenceLists[subpassNdx * perSubpassAttachmentReferenceLists]), &preserveAttachments[subpassNdx]));
  
  	for (size_t depNdx = 0; depNdx < renderPassInfo.getDependencies().size(); depNdx++)
  		dependencies.push_back(createSubpassDependency(renderPassInfo.getDependencies()[depNdx]));
  
  	{
  		const VkRenderPassCreateInfo	createInfo	=
  		{
  			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
  			DE_NULL,
  			(VkRenderPassCreateFlags)0u,
  			(deUint32)attachments.size(),
  			(attachments.empty() ? DE_NULL : &attachments[0]),
  			(deUint32)subpasses.size(),
  			(subpasses.empty() ? DE_NULL : &subpasses[0]),
  			(deUint32)dependencies.size(),
  			(dependencies.empty() ? DE_NULL : &dependencies[0])
  		};
  
  		return createRenderPass(vk, device, &createInfo);
  	}
  }
  
  Move<VkFramebuffer> createFramebuffer (const DeviceInterface&		vk,
  									   VkDevice						device,
  									   VkRenderPass					renderPass,
  									   const UVec2&					size,
  									   const vector<VkImageView>&	attachments)
  {
  	return createFramebuffer(vk, device, 0u, renderPass, (deUint32)attachments.size(), attachments.empty() ? DE_NULL : &attachments[0], size.x(), size.y(), 1u);
  }
  
  Move<VkImage> createAttachmentImage (const DeviceInterface&	vk,
  									 VkDevice				device,
  									 deUint32				queueIndex,
  									 const UVec2&			size,
  									 VkFormat				format,
  									 VkSampleCountFlagBits	samples,
  									 VkImageUsageFlags		usageFlags,
  									 VkImageLayout			layout)
  {
  	VkImageUsageFlags			targetUsageFlags	= 0;
  	const tcu::TextureFormat	textureFormat		= mapVkFormat(format);
  
  	DE_ASSERT(!(tcu::hasDepthComponent(vk::mapVkFormat(format).order) || tcu::hasStencilComponent(vk::mapVkFormat(format).order))
  					|| ((usageFlags & vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0));
  
  	DE_ASSERT((tcu::hasDepthComponent(vk::mapVkFormat(format).order) || tcu::hasStencilComponent(vk::mapVkFormat(format).order))
  					|| ((usageFlags & vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0));
  
  	if (tcu::hasDepthComponent(textureFormat.order) || tcu::hasStencilComponent(textureFormat.order))
  		targetUsageFlags |= vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
  	else
  		targetUsageFlags |= vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  
  	return createImage(vk, device,
  					   (VkImageCreateFlags)0,
  					   VK_IMAGE_TYPE_2D,
  					   format,
  					   vk::makeExtent3D(size.x(), size.y(), 1u),
  					   1u /* mipLevels */,
  					   1u /* arraySize */,
  					   samples,
  					   VK_IMAGE_TILING_OPTIMAL,
  					   usageFlags | targetUsageFlags,
  					   VK_SHARING_MODE_EXCLUSIVE,
  					   1,
  					   &queueIndex,
  					   layout);
  }
  
  de::MovePtr<Allocation> createImageMemory (const DeviceInterface&	vk,
  										   VkDevice					device,
  										   Allocator&				allocator,
  										   VkImage					image,
  										   bool						lazy)
  {
  	de::MovePtr<Allocation> allocation (allocator.allocate(getImageMemoryRequirements(vk, device, image), lazy ? MemoryRequirement::LazilyAllocated : MemoryRequirement::Any));
  	bindImageMemory(vk, device, image, allocation->getMemory(), allocation->getOffset());
  	return allocation;
  }
  
  Move<VkImageView> createImageAttachmentView (const DeviceInterface&	vk,
  											 VkDevice				device,
  											 VkImage				image,
  											 VkFormat				format,
  											 VkImageAspectFlags		aspect)
  {
  	const VkImageSubresourceRange range =
  	{
  		aspect,
  		0,
  		1,
  		0,
  		1
  	};
  
  	return createImageView(vk, device, 0u, image, VK_IMAGE_VIEW_TYPE_2D, format, makeComponentMappingRGBA(), range);
  }
  
  VkClearValue randomClearValue (const Attachment& attachment, de::Random& rng)
  {
  	const float					clearNan	= tcu::Float32::nan().asFloat();
  	const tcu::TextureFormat	format		= mapVkFormat(attachment.getFormat());
  
  	if (tcu::hasStencilComponent(format.order) || tcu::hasDepthComponent(format.order))
  	{
  		VkClearValue clearValue;
  
  		clearValue.depthStencil.depth	= clearNan;
  		clearValue.depthStencil.stencil	= 0xCDu;
  
  		if (tcu::hasStencilComponent(format.order))
  			clearValue.depthStencil.stencil	= rng.getBool()
  											? 0xFFu
  											: 0x0u;
  
  		if (tcu::hasDepthComponent(format.order))
  			clearValue.depthStencil.depth	= rng.getBool()
  											? 1.0f
  											: 0.0f;
  
  		return clearValue;
  	}
  	else
  	{
  		VkClearValue clearValue;
  
  		clearValue.color = randomColorClearValue(attachment, rng);
  
  		return clearValue;
  	}
  }
  
  class AttachmentResources
  {
  public:
  	AttachmentResources (const DeviceInterface&	vk,
  						 VkDevice				device,
  						 Allocator&				allocator,
  						 deUint32				queueIndex,
  						 const UVec2&			size,
  						 const Attachment&		attachmentInfo,
  						 VkImageUsageFlags		usageFlags)
  		: m_image			(createAttachmentImage(vk, device, queueIndex, size, attachmentInfo.getFormat(), attachmentInfo.getSamples(), usageFlags, VK_IMAGE_LAYOUT_UNDEFINED))
  		, m_imageMemory		(createImageMemory(vk, device, allocator, *m_image, ((usageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0)))
  		, m_attachmentView	(createImageAttachmentView(vk, device, *m_image, attachmentInfo.getFormat(), getImageAspectFlags(attachmentInfo.getFormat())))
  	{
  		const tcu::TextureFormat	format			= mapVkFormat(attachmentInfo.getFormat());
  		const bool					isDepthFormat	= tcu::hasDepthComponent(format.order);
  		const bool					isStencilFormat	= tcu::hasStencilComponent(format.order);
  
  		if (isDepthFormat && isStencilFormat)
  		{
  			m_depthInputAttachmentView		= createImageAttachmentView(vk, device, *m_image, attachmentInfo.getFormat(), VK_IMAGE_ASPECT_DEPTH_BIT);
  			m_stencilInputAttachmentView	= createImageAttachmentView(vk, device, *m_image, attachmentInfo.getFormat(), VK_IMAGE_ASPECT_STENCIL_BIT);
  
  			m_inputAttachmentViews = std::make_pair(*m_depthInputAttachmentView, *m_stencilInputAttachmentView);
  		}
  		else
  			m_inputAttachmentViews = std::make_pair(*m_attachmentView, (vk::VkImageView)0u);
  
  		if ((usageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) == 0)
  		{
  			if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order))
  			{
  				const tcu::TextureFormat	depthFormat		= getDepthCopyFormat(attachmentInfo.getFormat());
  				const tcu::TextureFormat	stencilFormat	= getStencilCopyFormat(attachmentInfo.getFormat());
  
  				m_bufferSize			= size.x() * size.y() * depthFormat.getPixelSize();
  				m_secondaryBufferSize	= size.x() * size.y() * stencilFormat.getPixelSize();
  
  				m_buffer				= createBuffer(vk, device, 0, m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex);
  				m_bufferMemory			= allocator.allocate(getBufferMemoryRequirements(vk, device, *m_buffer), MemoryRequirement::HostVisible);
  
  				bindBufferMemory(vk, device, *m_buffer, m_bufferMemory->getMemory(), m_bufferMemory->getOffset());
  
  				m_secondaryBuffer		= createBuffer(vk, device, 0, m_secondaryBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex);
  				m_secondaryBufferMemory	= allocator.allocate(getBufferMemoryRequirements(vk, device, *m_secondaryBuffer), MemoryRequirement::HostVisible);
  
  				bindBufferMemory(vk, device, *m_secondaryBuffer, m_secondaryBufferMemory->getMemory(), m_secondaryBufferMemory->getOffset());
  			}
  			else
  			{
  				m_bufferSize	= size.x() * size.y() * format.getPixelSize();
  
  				m_buffer		= createBuffer(vk, device, 0, m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex);
  				m_bufferMemory	= allocator.allocate(getBufferMemoryRequirements(vk, device, *m_buffer), MemoryRequirement::HostVisible);
  
  				bindBufferMemory(vk, device, *m_buffer, m_bufferMemory->getMemory(), m_bufferMemory->getOffset());
  			}
  		}
  	}
  
  	const pair<VkImageView, VkImageView>& getInputAttachmentViews (void) const
  	{
  		return m_inputAttachmentViews;
  	}
  
  	~AttachmentResources (void)
  	{
  	}
  
  	VkImageView getAttachmentView (void) const
  	{
  		return *m_attachmentView;
  	}
  
  	VkImage getImage (void) const
  	{
  		return *m_image;
  	}
  
  	VkBuffer getBuffer (void) const
  	{
  		DE_ASSERT(*m_buffer != DE_NULL);
  		return *m_buffer;
  	}
  
  	VkDeviceSize getBufferSize (void) const
  	{
  		DE_ASSERT(*m_buffer != DE_NULL);
  		return m_bufferSize;
  	}
  
  	const Allocation& getResultMemory (void) const
  	{
  		DE_ASSERT(m_bufferMemory);
  		return *m_bufferMemory;
  	}
  
  	VkBuffer getSecondaryBuffer (void) const
  	{
  		DE_ASSERT(*m_secondaryBuffer != DE_NULL);
  		return *m_secondaryBuffer;
  	}
  
  	VkDeviceSize getSecondaryBufferSize (void) const
  	{
  		DE_ASSERT(*m_secondaryBuffer != DE_NULL);
  		return m_secondaryBufferSize;
  	}
  
  	const Allocation& getSecondaryResultMemory (void) const
  	{
  		DE_ASSERT(m_secondaryBufferMemory);
  		return *m_secondaryBufferMemory;
  	}
  
  private:
  	const Unique<VkImage>			m_image;
  	const UniquePtr<Allocation>		m_imageMemory;
  	const Unique<VkImageView>		m_attachmentView;
  
  	Move<VkImageView>				m_depthInputAttachmentView;
  	Move<VkImageView>				m_stencilInputAttachmentView;
  	pair<VkImageView, VkImageView>	m_inputAttachmentViews;
  
  	Move<VkBuffer>					m_buffer;
  	VkDeviceSize					m_bufferSize;
  	de::MovePtr<Allocation>			m_bufferMemory;
  
  	Move<VkBuffer>					m_secondaryBuffer;
  	VkDeviceSize					m_secondaryBufferSize;
  	de::MovePtr<Allocation>			m_secondaryBufferMemory;
  };
  
  void uploadBufferData (const DeviceInterface&	vk,
  					   VkDevice					device,
  					   const Allocation&		memory,
  					   size_t					size,
  					   const void*				data)
  {
  	const VkMappedMemoryRange range =
  	{
  		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	// sType;
  		DE_NULL,								// pNext;
  		memory.getMemory(),						// mem;
  		memory.getOffset(),						// offset;
  		(VkDeviceSize)size						// size;
  	};
  	void* const ptr = memory.getHostPtr();
  
  	deMemcpy(ptr, data, size);
  	VK_CHECK(vk.flushMappedMemoryRanges(device, 1, &range));
  }
  
  VkImageAspectFlagBits getPrimaryImageAspect (tcu::TextureFormat::ChannelOrder order)
  {
  	DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST == 21);
  
  	switch (order)
  	{
  		case tcu::TextureFormat::D:
  		case tcu::TextureFormat::DS:
  			return VK_IMAGE_ASPECT_DEPTH_BIT;
  
  		case tcu::TextureFormat::S:
  			return VK_IMAGE_ASPECT_STENCIL_BIT;
  
  		default:
  			return VK_IMAGE_ASPECT_COLOR_BIT;
  	}
  }
  
  class RenderQuad
  {
  public:
  					RenderQuad			(const Vec2& posA, const Vec2& posB)
  		: m_vertices(6)
  	{
  		m_vertices[0] = posA;
  		m_vertices[1] = Vec2(posA[0], posB[1]);
  		m_vertices[2] = posB;
  
  		m_vertices[3] = posB;
  		m_vertices[4] = Vec2(posB[0], posA[1]);
  		m_vertices[5] = posA;
  	}
  
  	const Vec2&		getCornerA			(void) const
  	{
  		return m_vertices[0];
  	}
  
  	const Vec2&		getCornerB			(void) const
  	{
  		return m_vertices[2];
  	}
  
  	const void*		getVertexPointer	(void) const
  	{
  		return &m_vertices[0];
  	}
  
  	size_t			getVertexDataSize	(void) const
  	{
  		return sizeof(Vec2) * m_vertices.size();
  	}
  
  private:
  	vector<Vec2>	m_vertices;
  };
  
  class ColorClear
  {
  public:
  								ColorClear	(const UVec2&				offset,
  											 const UVec2&				size,
  											 const VkClearColorValue&	color)
  		: m_offset	(offset)
  		, m_size	(size)
  		, m_color	(color)
  	{
  	}
  
  	const UVec2&				getOffset	(void) const { return m_offset;	}
  	const UVec2&				getSize		(void) const { return m_size;	}
  	const VkClearColorValue&	getColor	(void) const { return m_color;	}
  
  private:
  	UVec2						m_offset;
  	UVec2						m_size;
  	VkClearColorValue			m_color;
  };
  
  class DepthStencilClear
  {
  public:
  					DepthStencilClear	(const UVec2&	offset,
  										 const UVec2&	size,
  										 float			depth,
  										 deUint32		stencil)
  		: m_offset	(offset)
  		, m_size	(size)
  		, m_depth	(depth)
  		, m_stencil	(stencil)
  	{
  	}
  
  	const UVec2&	getOffset			(void) const { return m_offset;		}
  	const UVec2&	getSize				(void) const { return m_size;		}
  	float			getDepth			(void) const { return m_depth;		}
  	deUint32		getStencil			(void) const { return m_stencil;	}
  
  private:
  	const UVec2		m_offset;
  	const UVec2		m_size;
  
  	const float		m_depth;
  	const deUint32	m_stencil;
  };
  
  class SubpassRenderInfo
  {
  public:
  									SubpassRenderInfo				(const RenderPass&					renderPass,
  																	 deUint32							subpassIndex,
  
  																	 bool								isSecondary_,
  
  																	 const UVec2&						viewportOffset,
  																	 const UVec2&						viewportSize,
  
  																	 const Maybe<RenderQuad>&			renderQuad,
  																	 const vector<ColorClear>&			colorClears,
  																	 const Maybe<DepthStencilClear>&	depthStencilClear)
  		: m_viewportOffset		(viewportOffset)
  		, m_viewportSize		(viewportSize)
  		, m_subpassIndex		(subpassIndex)
  		, m_isSecondary			(isSecondary_)
  		, m_flags				(renderPass.getSubpasses()[subpassIndex].getFlags())
  		, m_renderQuad			(renderQuad)
  		, m_colorClears			(colorClears)
  		, m_depthStencilClear	(depthStencilClear)
  		, m_colorAttachments	(renderPass.getSubpasses()[subpassIndex].getColorAttachments())
  		, m_inputAttachments	(renderPass.getSubpasses()[subpassIndex].getInputAttachments())
  	{
  		for (deUint32 attachmentNdx = 0; attachmentNdx < (deUint32)m_colorAttachments.size(); attachmentNdx++)
  			m_colorAttachmentInfo.push_back(renderPass.getAttachments()[m_colorAttachments[attachmentNdx].getAttachment()]);
  
  		if (renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
  		{
  			m_depthStencilAttachment		= tcu::just(renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment());
  			m_depthStencilAttachmentInfo	= tcu::just(renderPass.getAttachments()[renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment().getAttachment()]);
  		}
  	}
  
  	const UVec2&					getViewportOffset				(void) const { return m_viewportOffset;		}
  	const UVec2&					getViewportSize					(void) const { return m_viewportSize;		}
  
  	deUint32						getSubpassIndex					(void) const { return m_subpassIndex;		}
  	bool							isSecondary						(void) const { return m_isSecondary;		}
  
  	const Maybe<RenderQuad>&		getRenderQuad					(void) const { return m_renderQuad;			}
  	const vector<ColorClear>&		getColorClears					(void) const { return m_colorClears;		}
  	const Maybe<DepthStencilClear>&	getDepthStencilClear			(void) const { return m_depthStencilClear;	}
  
  	deUint32						getInputAttachmentCount			(void) const { return (deUint32)m_inputAttachments.size(); }
  	deUint32						getInputAttachmentIndex			(deUint32 attachmentNdx) const { return m_inputAttachments[attachmentNdx].getAttachment(); }
  	VkImageLayout					getInputAttachmentLayout		(deUint32 attachmentNdx) const { return m_inputAttachments[attachmentNdx].getImageLayout(); }
  
  	deUint32						getColorAttachmentCount			(void) const { return (deUint32)m_colorAttachments.size(); }
  	VkImageLayout					getColorAttachmentLayout		(deUint32 attachmentNdx) const { return m_colorAttachments[attachmentNdx].getImageLayout(); }
  	deUint32						getColorAttachmentIndex			(deUint32 attachmentNdx) const { return m_colorAttachments[attachmentNdx].getAttachment(); }
  	const Attachment&				getColorAttachment				(deUint32 attachmentNdx) const { return m_colorAttachmentInfo[attachmentNdx]; }
  	Maybe<VkImageLayout>			getDepthStencilAttachmentLayout	(void) const { return m_depthStencilAttachment ? tcu::just(m_depthStencilAttachment->getImageLayout()) : tcu::nothing<VkImageLayout>(); }
  	Maybe<deUint32>					getDepthStencilAttachmentIndex	(void) const { return m_depthStencilAttachment ? tcu::just(m_depthStencilAttachment->getAttachment()) : tcu::nothing<deUint32>(); };
  	const Maybe<Attachment>&		getDepthStencilAttachment		(void) const { return m_depthStencilAttachmentInfo; }
  	VkSubpassDescriptionFlags		getSubpassFlags					(void) const { return m_flags; }
  
  private:
  	UVec2							m_viewportOffset;
  	UVec2							m_viewportSize;
  
  	deUint32						m_subpassIndex;
  	bool							m_isSecondary;
  	VkSubpassDescriptionFlags		m_flags;
  
  	Maybe<RenderQuad>				m_renderQuad;
  	vector<ColorClear>				m_colorClears;
  	Maybe<DepthStencilClear>		m_depthStencilClear;
  
  	vector<AttachmentReference>		m_colorAttachments;
  	vector<Attachment>				m_colorAttachmentInfo;
  
  	Maybe<AttachmentReference>		m_depthStencilAttachment;
  	Maybe<Attachment>				m_depthStencilAttachmentInfo;
  
  	vector<AttachmentReference>		m_inputAttachments;
  };
  
  Move<VkPipeline> createSubpassPipeline (const DeviceInterface&		vk,
  										VkDevice					device,
  										VkRenderPass				renderPass,
  										VkShaderModule				vertexShaderModule,
  										VkShaderModule				fragmentShaderModule,
  										VkPipelineLayout			pipelineLayout,
  										const SubpassRenderInfo&	renderInfo)
  {
  	const VkSpecializationInfo emptyShaderSpecializations =
  	{
  		0u,			// mapEntryCount
  		DE_NULL,	// pMap
  		0u,			// dataSize
  		DE_NULL,	// pData
  	};
  
  	Maybe<VkSampleCountFlagBits>				rasterSamples;
  	vector<VkPipelineColorBlendAttachmentState>	attachmentBlendStates;
  
  	for (deUint32 attachmentNdx = 0; attachmentNdx < renderInfo.getColorAttachmentCount(); attachmentNdx++)
  	{
  		const Attachment&	attachment	= renderInfo.getColorAttachment(attachmentNdx);
  
  		DE_ASSERT(!rasterSamples || *rasterSamples == attachment.getSamples());
  
  		rasterSamples = attachment.getSamples();
  
  		{
  			const VkPipelineColorBlendAttachmentState	attachmentBlendState =
  			{
  				VK_FALSE,																								// blendEnable
  				VK_BLEND_FACTOR_SRC_ALPHA,																				// srcBlendColor
  				VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,																	// destBlendColor
  				VK_BLEND_OP_ADD,																						// blendOpColor
  				VK_BLEND_FACTOR_ONE,																					// srcBlendAlpha
  				VK_BLEND_FACTOR_ONE,																					// destBlendAlpha
  				VK_BLEND_OP_ADD,																						// blendOpAlpha
  				VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT,	// channelWriteMask
  			};
  
  			attachmentBlendStates.push_back(attachmentBlendState);
  		}
  	}
  
  	if (renderInfo.getDepthStencilAttachment())
  	{
  		const Attachment& attachment = *renderInfo.getDepthStencilAttachment();
  
  		DE_ASSERT(!rasterSamples || *rasterSamples == attachment.getSamples());
  		rasterSamples = attachment.getSamples();
  	}
  
  	// If there are no attachment use single sample
  	if (!rasterSamples)
  		rasterSamples = VK_SAMPLE_COUNT_1_BIT;
  
  	const VkPipelineShaderStageCreateInfo shaderStages[2] =
  	{
  		{
  			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// sType
  			DE_NULL,												// pNext
  			(VkPipelineShaderStageCreateFlags)0u,
  			VK_SHADER_STAGE_VERTEX_BIT,								// stage
  			vertexShaderModule,										// shader
  			"main",
  			&emptyShaderSpecializations
  		},
  		{
  			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// sType
  			DE_NULL,												// pNext
  			(VkPipelineShaderStageCreateFlags)0u,
  			VK_SHADER_STAGE_FRAGMENT_BIT,							// stage
  			fragmentShaderModule,									// shader
  			"main",
  			&emptyShaderSpecializations
  		}
  	};
  	const VkVertexInputBindingDescription vertexBinding =
  	{
  		0u,															// binding
  		(deUint32)sizeof(tcu::Vec2),								// strideInBytes
  		VK_VERTEX_INPUT_RATE_VERTEX,								// stepRate
  	};
  	const VkVertexInputAttributeDescription vertexAttrib =
  	{
  		0u,															// location
  		0u,															// binding
  		VK_FORMAT_R32G32_SFLOAT,									// format
  		0u,															// offsetInBytes
  	};
  	const VkPipelineVertexInputStateCreateInfo vertexInputState =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	sType
  		DE_NULL,													//	pNext
  		(VkPipelineVertexInputStateCreateFlags)0u,
  		1u,															//	bindingCount
  		&vertexBinding,												//	pVertexBindingDescriptions
  		1u,															//	attributeCount
  		&vertexAttrib,												//	pVertexAttributeDescriptions
  	};
  	const VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// sType
  		DE_NULL,														// pNext
  		(VkPipelineInputAssemblyStateCreateFlags)0u,
  		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							// topology
  		VK_FALSE,														// primitiveRestartEnable
  	};
  	const VkViewport viewport =
  	{
  		(float)renderInfo.getViewportOffset().x(),	(float)renderInfo.getViewportOffset().y(),
  		(float)renderInfo.getViewportSize().x(),	(float)renderInfo.getViewportSize().y(),
  		0.0f, 1.0f
  	};
  	const VkRect2D scissor =
  	{
  		{ (deInt32)renderInfo.getViewportOffset().x(),	(deInt32)renderInfo.getViewportOffset().y() },
  		{ renderInfo.getViewportSize().x(),				renderInfo.getViewportSize().y() }
  	};
  	const VkPipelineViewportStateCreateInfo viewportState =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  		DE_NULL,
  		(VkPipelineViewportStateCreateFlags)0u,
  		1u,
  		&viewport,
  		1u,
  		&scissor
  	};
  	const VkPipelineRasterizationStateCreateInfo rasterState =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// sType
  		DE_NULL,														// pNext
  		(VkPipelineRasterizationStateCreateFlags)0u,
  		VK_TRUE,														// depthClipEnable
  		VK_FALSE,														// rasterizerDiscardEnable
  		VK_POLYGON_MODE_FILL,											// fillMode
  		VK_CULL_MODE_NONE,												// cullMode
  		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// frontFace
  		VK_FALSE,														// depthBiasEnable
  		0.0f,															// depthBias
  		0.0f,															// depthBiasClamp
  		0.0f,															// slopeScaledDepthBias
  		1.0f															// lineWidth
  	};
  	const VkPipelineMultisampleStateCreateInfo multisampleState =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// sType
  		DE_NULL,														// pNext
  		(VkPipelineMultisampleStateCreateFlags)0u,
  		*rasterSamples,													// rasterSamples
  		VK_FALSE,														// sampleShadingEnable
  		0.0f,															// minSampleShading
  		DE_NULL,														// pSampleMask
  		VK_FALSE,														// alphaToCoverageEnable
  		VK_FALSE,														// alphaToOneEnable
  	};
  	const size_t stencilIndex = renderInfo.getSubpassIndex();
  	const VkPipelineDepthStencilStateCreateInfo depthStencilState =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// sType
  		DE_NULL,													// pNext
  		(VkPipelineDepthStencilStateCreateFlags)0u,
  		VK_TRUE,													// depthTestEnable
  		VK_TRUE,													// depthWriteEnable
  		VK_COMPARE_OP_ALWAYS,										// depthCompareOp
  		VK_FALSE,													// depthBoundsEnable
  		VK_TRUE,													// stencilTestEnable
  		{
  			VK_STENCIL_OP_REPLACE,									// stencilFailOp
  			VK_STENCIL_OP_REPLACE,									// stencilPassOp
  			VK_STENCIL_OP_REPLACE,									// stencilDepthFailOp
  			VK_COMPARE_OP_ALWAYS,									// stencilCompareOp
  			~0u,													// stencilCompareMask
  			~0u,													// stencilWriteMask
  			((stencilIndex % 2) == 0) ? ~0x0u : 0x0u				// stencilReference
  		},															// front
  		{
  			VK_STENCIL_OP_REPLACE,									// stencilFailOp
  			VK_STENCIL_OP_REPLACE,									// stencilPassOp
  			VK_STENCIL_OP_REPLACE,									// stencilDepthFailOp
  			VK_COMPARE_OP_ALWAYS,									// stencilCompareOp
  			~0u,													// stencilCompareMask
  			~0u,													// stencilWriteMask
  			((stencilIndex % 2) == 0) ? ~0x0u : 0x0u				// stencilReference
  		},															// back
  
  		0.0f,														// minDepthBounds;
  		1.0f														// maxDepthBounds;
  	};
  	const VkPipelineColorBlendStateCreateInfo blendState =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,			// sType
  		DE_NULL,															// pNext
  		(VkPipelineColorBlendStateCreateFlags)0u,
  		VK_FALSE,															// logicOpEnable
  		VK_LOGIC_OP_COPY,													// logicOp
  		(deUint32)attachmentBlendStates.size(),								// attachmentCount
  		attachmentBlendStates.empty() ? DE_NULL : &attachmentBlendStates[0],// pAttachments
  		{ 0.0f, 0.0f, 0.0f, 0.0f }											// blendConst
  	};
  	const VkGraphicsPipelineCreateInfo createInfo =
  	{
  		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// sType
  		DE_NULL,											// pNext
  		(VkPipelineCreateFlags)0u,
  
  		2,													// stageCount
  		shaderStages,										// pStages
  
  		&vertexInputState,									// pVertexInputState
  		&inputAssemblyState,								// pInputAssemblyState
  		DE_NULL,											// pTessellationState
  		&viewportState,										// pViewportState
  		&rasterState,										// pRasterState
  		&multisampleState,									// pMultisampleState
  		&depthStencilState,									// pDepthStencilState
  		&blendState,										// pColorBlendState
  		(const VkPipelineDynamicStateCreateInfo*)DE_NULL,	// pDynamicState
  		pipelineLayout,										// layout
  
  		renderPass,											// renderPass
  		renderInfo.getSubpassIndex(),						// subpass
  		DE_NULL,											// basePipelineHandle
  		0u													// basePipelineIndex
  	};
  
  	return createGraphicsPipeline(vk, device, DE_NULL, &createInfo);
  }
  
  class SubpassRenderer
  {
  public:
  	SubpassRenderer (Context&										context,
  					 const DeviceInterface&							vk,
  					 VkDevice										device,
  					 Allocator&										allocator,
  					 VkRenderPass									renderPass,
  					 VkFramebuffer									framebuffer,
  					 VkCommandPool									commandBufferPool,
  					 deUint32										queueFamilyIndex,
  					 const vector<VkImage>&							attachmentImages,
  					 const vector<pair<VkImageView, VkImageView> >&	attachmentViews,
  					 const SubpassRenderInfo&						renderInfo,
  					 const vector<Attachment>&						attachmentInfos)
  		: m_renderInfo	(renderInfo)
  	{
  		const deUint32							subpassIndex	= renderInfo.getSubpassIndex();
  		vector<VkDescriptorSetLayoutBinding>	bindings;
  
  		for (deUint32 colorAttachmentNdx = 0; colorAttachmentNdx < renderInfo.getColorAttachmentCount();  colorAttachmentNdx++)
  			m_colorAttachmentImages.push_back(attachmentImages[renderInfo.getColorAttachmentIndex(colorAttachmentNdx)]);
  
  		if (renderInfo.getDepthStencilAttachmentIndex())
  			m_depthStencilAttachmentImage = attachmentImages[*renderInfo.getDepthStencilAttachmentIndex()];
  
  		if (renderInfo.getRenderQuad())
  		{
  			const RenderQuad&	renderQuad	= *renderInfo.getRenderQuad();
  
  			if (renderInfo.getInputAttachmentCount() > 0)
  			{
  				deUint32								bindingIndex	= 0;
  
  				for (deUint32 inputAttachmentNdx = 0; inputAttachmentNdx < renderInfo.getInputAttachmentCount(); inputAttachmentNdx++)
  				{
  					const Attachment			attachmentInfo	= attachmentInfos[renderInfo.getInputAttachmentIndex(inputAttachmentNdx)];
  					const tcu::TextureFormat	format			= mapVkFormat(attachmentInfo.getFormat());
  					const bool					isDepthFormat	= tcu::hasDepthComponent(format.order);
  					const bool					isStencilFormat	= tcu::hasStencilComponent(format.order);
  					const deUint32				bindingCount	= isDepthFormat && isStencilFormat ? 2u : 1u;
  
  					for (deUint32 bindingNdx = 0; bindingNdx < bindingCount; bindingNdx++)
  					{
  						const VkDescriptorSetLayoutBinding binding =
  						{
  							bindingIndex,
  							vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
  							1u,
  							vk::VK_SHADER_STAGE_FRAGMENT_BIT,
  							DE_NULL
  						};
  
  						bindings.push_back(binding);
  						bindingIndex++;
  					}
  				}
  
  				const VkDescriptorSetLayoutCreateInfo createInfo =
  				{
  					vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
  					DE_NULL,
  
  					0u,
  					(deUint32)bindings.size(),
  					&bindings[0]
  				};
  
  				m_descriptorSetLayout = vk::createDescriptorSetLayout(vk, device, &createInfo);
  			}
  
  			const VkDescriptorSetLayout			descriptorSetLayout		= *m_descriptorSetLayout;
  			const VkPipelineLayoutCreateInfo	pipelineLayoutParams	=
  			{
  				VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,			// sType;
  				DE_NULL,												// pNext;
  				(vk::VkPipelineLayoutCreateFlags)0,
  				m_descriptorSetLayout ? 1u :0u ,						// setLayoutCount;
  				m_descriptorSetLayout ? &descriptorSetLayout : DE_NULL,	// pSetLayouts;
  				0u,														// pushConstantRangeCount;
  				DE_NULL,												// pPushConstantRanges;
  			};
  
  			m_vertexShaderModule	= createShaderModule(vk, device, context.getBinaryCollection().get(de::toString(subpassIndex) + "-vert"), 0u);
  			m_fragmentShaderModule	= createShaderModule(vk, device, context.getBinaryCollection().get(de::toString(subpassIndex) + "-frag"), 0u);
  			m_pipelineLayout		= createPipelineLayout(vk, device, &pipelineLayoutParams);
  			m_pipeline				= createSubpassPipeline(vk, device, renderPass, *m_vertexShaderModule, *m_fragmentShaderModule, *m_pipelineLayout, m_renderInfo);
  
  			m_vertexBuffer			= createBuffer(vk, device, 0u, (VkDeviceSize)renderQuad.getVertexDataSize(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE, 1u, &queueFamilyIndex);
  			m_vertexBufferMemory	= allocator.allocate(getBufferMemoryRequirements(vk, device, *m_vertexBuffer), MemoryRequirement::HostVisible);
  
  			bindBufferMemory(vk, device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset());
  			uploadBufferData(vk, device, *m_vertexBufferMemory, renderQuad.getVertexDataSize(), renderQuad.getVertexPointer());
  
  			if (renderInfo.getInputAttachmentCount() > 0)
  			{
  				{
  					const VkDescriptorPoolSize poolSize =
  					{
  						vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
  						// \note Reserve 2 per input attachment since depthStencil attachments require 2.
  						renderInfo.getInputAttachmentCount() * 2u
  					};
  					const VkDescriptorPoolCreateInfo createInfo =
  					{
  						vk::VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
  						DE_NULL,
  						VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
  
  						// \note Reserve 2 per input attachment since depthStencil attachments require 2.
  						renderInfo.getInputAttachmentCount() * 2u,
  						1u,
  						&poolSize
  					};
  
  					m_descriptorPool = vk::createDescriptorPool(vk, device, &createInfo);
  				}
  				{
  					const VkDescriptorSetAllocateInfo	allocateInfo =
  					{
  						vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
  						DE_NULL,
  
  						*m_descriptorPool,
  						1u,
  						&descriptorSetLayout
  					};
  
  					m_descriptorSet = vk::allocateDescriptorSet(vk, device, &allocateInfo);
  				}
  				{
  					vector<VkWriteDescriptorSet>	writes			(bindings.size());
  					vector<VkDescriptorImageInfo>	imageInfos		(bindings.size());
  					deUint32						bindingIndex	= 0;
  
  					for (deUint32 inputAttachmentNdx = 0; inputAttachmentNdx < renderInfo.getInputAttachmentCount(); inputAttachmentNdx++)
  					{
  						const Attachment			attachmentInfo			= attachmentInfos[renderInfo.getInputAttachmentIndex(inputAttachmentNdx)];
  						const tcu::TextureFormat	format					= mapVkFormat(attachmentInfo.getFormat());
  						const bool					isDepthFormat			= tcu::hasDepthComponent(format.order);
  						const bool					isStencilFormat			= tcu::hasStencilComponent(format.order);
  						const VkImageLayout			inputAttachmentLayout	= renderInfo.getInputAttachmentLayout(inputAttachmentNdx);
  
  						if (isDepthFormat && isStencilFormat)
  						{
  							{
  								const VkDescriptorImageInfo	imageInfo =
  								{
  									(VkSampler)0,
  									attachmentViews[renderInfo.getInputAttachmentIndex(inputAttachmentNdx)].first,
  									inputAttachmentLayout
  								};
  								imageInfos[bindingIndex] = imageInfo;
  
  								{
  									const VkWriteDescriptorSet	write =
  									{
  										VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
  										DE_NULL,
  
  										*m_descriptorSet,
  										bindingIndex,
  										0u,
  										1u,
  										VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
  										&imageInfos[bindingIndex],
  										DE_NULL,
  										DE_NULL
  									};
  									writes[bindingIndex] = write;
  
  									bindingIndex++;
  								}
  							}
  							{
  								const VkDescriptorImageInfo	imageInfo =
  								{
  									(VkSampler)0,
  									attachmentViews[renderInfo.getInputAttachmentIndex(inputAttachmentNdx)].second,
  									inputAttachmentLayout
  								};
  								imageInfos[bindingIndex] = imageInfo;
  
  								{
  									const VkWriteDescriptorSet	write =
  									{
  										VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
  										DE_NULL,
  
  										*m_descriptorSet,
  										bindingIndex,
  										0u,
  										1u,
  										VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
  										&imageInfos[bindingIndex],
  										DE_NULL,
  										DE_NULL
  									};
  									writes[bindingIndex] = write;
  
  									bindingIndex++;
  								}
  							}
  						}
  						else
  						{
  							const VkDescriptorImageInfo	imageInfo =
  							{
  								(VkSampler)0,
  								attachmentViews[renderInfo.getInputAttachmentIndex(inputAttachmentNdx)].first,
  								inputAttachmentLayout
  							};
  							imageInfos[bindingIndex] = imageInfo;
  
  							{
  								const VkWriteDescriptorSet	write =
  								{
  									VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
  									DE_NULL,
  
  									*m_descriptorSet,
  									bindingIndex,
  									0u,
  									1u,
  									VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
  									&imageInfos[bindingIndex],
  									DE_NULL,
  									DE_NULL
  								};
  								writes[bindingIndex] = write;
  
  								bindingIndex++;
  							}
  						}
  					}
  
  					vk.updateDescriptorSets(device, (deUint32)writes.size(), &writes[0], 0u, DE_NULL);
  				}
  			}
  		}
  
  		if (renderInfo.isSecondary())
  		{
  			m_commandBuffer = allocateCommandBuffer(vk, device, commandBufferPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
  
  			beginCommandBuffer(vk, *m_commandBuffer, vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, renderPass, subpassIndex, framebuffer, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0);
  			pushRenderCommands(vk, *m_commandBuffer);
  			endCommandBuffer(vk, *m_commandBuffer);
  		}
  	}
  
  	bool isSecondary (void) const
  	{
  		return m_commandBuffer;
  	}
  
  	VkCommandBuffer getCommandBuffer (void) const
  	{
  		DE_ASSERT(isSecondary());
  		return *m_commandBuffer;
  	}
  
  	void pushRenderCommands (const DeviceInterface&		vk,
  							 VkCommandBuffer			commandBuffer)
  	{
  		if (!m_renderInfo.getColorClears().empty())
  		{
  			const vector<ColorClear>&	colorClears	(m_renderInfo.getColorClears());
  
  			for (deUint32 attachmentNdx = 0; attachmentNdx < m_renderInfo.getColorAttachmentCount(); attachmentNdx++)
  			{
  				const ColorClear&		colorClear	= colorClears[attachmentNdx];
  				const VkClearAttachment	attachment	=
  				{
  					VK_IMAGE_ASPECT_COLOR_BIT,
  					attachmentNdx,
  					makeClearValue(colorClear.getColor()),
  				};
  				const VkClearRect		rect		=
  				{
  					{
  						{ (deInt32)colorClear.getOffset().x(),	(deInt32)colorClear.getOffset().y()	},
  						{ colorClear.getSize().x(),				colorClear.getSize().y()			}
  					},					// rect
  					0u,					// baseArrayLayer
  					1u,					// layerCount
  				};
  
  				vk.cmdClearAttachments(commandBuffer, 1u, &attachment, 1u, &rect);
  			}
  		}
  
  		if (m_renderInfo.getDepthStencilClear())
  		{
  			const DepthStencilClear&	depthStencilClear	= *m_renderInfo.getDepthStencilClear();
  			const deUint32				attachmentNdx		= m_renderInfo.getColorAttachmentCount();
  			tcu::TextureFormat			format				= mapVkFormat(m_renderInfo.getDepthStencilAttachment()->getFormat());
  			const VkClearAttachment		attachment			=
  			{
  				(VkImageAspectFlags)((hasDepthComponent(format.order) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0)
  					| (hasStencilComponent(format.order) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0)),
  				attachmentNdx,
  				makeClearValueDepthStencil(depthStencilClear.getDepth(), depthStencilClear.getStencil())
  			};
  			const VkClearRect				rect				=
  			{
  				{
  					{ (deInt32)depthStencilClear.getOffset().x(),	(deInt32)depthStencilClear.getOffset().y()	},
  					{ depthStencilClear.getSize().x(),				depthStencilClear.getSize().y()				}
  				},							// rect
  				0u,							// baseArrayLayer
  				1u,							// layerCount
  			};
  
  			vk.cmdClearAttachments(commandBuffer, 1u, &attachment, 1u, &rect);
  		}
  
  		vector<VkImageMemoryBarrier>	selfDeps;
  		VkPipelineStageFlags			srcStages = 0;
  		VkPipelineStageFlags			dstStages = 0;
  
  		for (deUint32 inputAttachmentNdx = 0; inputAttachmentNdx < m_renderInfo.getInputAttachmentCount(); inputAttachmentNdx++)
  		{
  			for (deUint32 colorAttachmentNdx = 0; colorAttachmentNdx < m_renderInfo.getColorAttachmentCount(); colorAttachmentNdx++)
  			{
  				if (m_renderInfo.getInputAttachmentIndex(inputAttachmentNdx) == m_renderInfo.getColorAttachmentIndex(colorAttachmentNdx))
  				{
  					const VkImageMemoryBarrier	barrier   =
  					{
  						VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// sType
  						DE_NULL,										// pNext
  
  						VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// srcAccessMask
  						VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,			// dstAccessMask
  
  						VK_IMAGE_LAYOUT_GENERAL,						// oldLayout
  						VK_IMAGE_LAYOUT_GENERAL,						// newLayout
  
  						VK_QUEUE_FAMILY_IGNORED,						// srcQueueFamilyIndex
  						VK_QUEUE_FAMILY_IGNORED,						// destQueueFamilyIndex
  
  						m_colorAttachmentImages[colorAttachmentNdx],	// image
  						{												// subresourceRange
  							VK_IMAGE_ASPECT_COLOR_BIT,						// aspect
  							0,												// baseMipLevel
  							1,												// mipLevels
  							0,												// baseArraySlice
  							1												// arraySize
  						}
  					};
  
  					srcStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  					dstStages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
  
  					selfDeps.push_back(barrier);
  				}
  			}
  
  			if (m_renderInfo.getDepthStencilAttachmentIndex() && (m_renderInfo.getInputAttachmentIndex(inputAttachmentNdx) == *m_renderInfo.getDepthStencilAttachmentIndex()))
  			{
  				const tcu::TextureFormat	format		= mapVkFormat(m_renderInfo.getDepthStencilAttachment()->getFormat());
  				const bool					hasDepth	= hasDepthComponent(format.order);
  				const bool					hasStencil	= hasStencilComponent(format.order);
  				const VkImageMemoryBarrier	barrier		=
  				{
  					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// sType;
  					DE_NULL,										// pNext;
  
  					VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,	// srcAccessMask
  					VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,			// dstAccessMask
  
  					VK_IMAGE_LAYOUT_GENERAL,						// oldLayout
  					VK_IMAGE_LAYOUT_GENERAL,						// newLayout;
  
  					VK_QUEUE_FAMILY_IGNORED,						// srcQueueFamilyIndex;
  					VK_QUEUE_FAMILY_IGNORED,						// destQueueFamilyIndex;
  
  					m_depthStencilAttachmentImage,					// image;
  					{												// subresourceRange;
  						(hasDepth ? (VkImageAspectFlags)VK_IMAGE_ASPECT_DEPTH_BIT : 0u)
  							| (hasStencil ? (VkImageAspectFlags)VK_IMAGE_ASPECT_STENCIL_BIT : 0u),	// aspect;
  						0,															// baseMipLevel;
  						1,															// mipLevels;
  						0,															// baseArraySlice;
  						1															// arraySize;
  					}
  				};
  
  				srcStages |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
  				dstStages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
  
  				selfDeps.push_back(barrier);
  			}
  		}
  
  		if (!selfDeps.empty())
  			vk.cmdPipelineBarrier(commandBuffer, srcStages, dstStages, VK_DEPENDENCY_BY_REGION_BIT, 0, DE_NULL, 0, DE_NULL, (deUint32)selfDeps.size(), &selfDeps[0]);
  
  		if (m_renderInfo.getRenderQuad())
  		{
  			const VkDeviceSize	offset			= 0;
  			const VkBuffer		vertexBuffer	= *m_vertexBuffer;
  
  			vk.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
  
  			if (m_descriptorSet)
  			{
  				const VkDescriptorSet descriptorSet = *m_descriptorSet;
  				vk.cmdBindDescriptorSets(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1u, &descriptorSet, 0u, NULL);
  			}
  
  			vk.cmdBindVertexBuffers(commandBuffer, 0u, 1u, &vertexBuffer, &offset);
  			vk.cmdDraw(commandBuffer, 6u, 1u, 0u, 0u);
  		}
  	}
  
  private:
  	const SubpassRenderInfo		m_renderInfo;
  	Move<VkCommandBuffer>		m_commandBuffer;
  	Move<VkPipeline>			m_pipeline;
  	Move<VkDescriptorSetLayout>	m_descriptorSetLayout;
  	Move<VkPipelineLayout>		m_pipelineLayout;
  
  	Move<VkShaderModule>		m_vertexShaderModule;
  	Move<VkShaderModule>		m_fragmentShaderModule;
  
  	Move<VkDescriptorPool>		m_descriptorPool;
  	Move<VkDescriptorSet>		m_descriptorSet;
  	Move<VkBuffer>				m_vertexBuffer;
  	de::MovePtr<Allocation>		m_vertexBufferMemory;
  	vector<VkImage>				m_colorAttachmentImages;
  	VkImage						m_depthStencilAttachmentImage;
  };
  
  void pushImageInitializationCommands (const DeviceInterface&								vk,
  									  VkCommandBuffer										commandBuffer,
  									  const vector<Attachment>&								attachmentInfo,
  									  const vector<de::SharedPtr<AttachmentResources> >&	attachmentResources,
  									  deUint32												queueIndex,
  									  const vector<Maybe<VkClearValue> >&					clearValues)
  {
  	{
  		vector<VkImageMemoryBarrier>	initializeLayouts;
  
  		for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
  		{
  			if (!clearValues[attachmentNdx])
  				continue;
  
  			const VkImageMemoryBarrier barrier =
  			{
  				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,							// sType;
  				DE_NULL,														// pNext;
  
  				(VkAccessFlags)0,												// srcAccessMask
  				getAllMemoryReadFlags() | VK_ACCESS_TRANSFER_WRITE_BIT,			// dstAccessMask
  
  				VK_IMAGE_LAYOUT_UNDEFINED,										// oldLayout
  				VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,							// newLayout;
  
  				queueIndex,														// srcQueueFamilyIndex;
  				queueIndex,														// destQueueFamilyIndex;
  
  				attachmentResources[attachmentNdx]->getImage(),					// image;
  				{																// subresourceRange;
  					getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()),		// aspect;
  					0,																	// baseMipLevel;
  					1,																	// mipLevels;
  					0,																	// baseArraySlice;
  					1																	// arraySize;
  				}
  			};
  
  			initializeLayouts.push_back(barrier);
  		}
  
  		if (!initializeLayouts.empty())
  			vk.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
  								  VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0,
  								  0, (const VkMemoryBarrier*)DE_NULL,
  								  0, (const VkBufferMemoryBarrier*)DE_NULL,
  								  (deUint32)initializeLayouts.size(), &initializeLayouts[0]);
  	}
  
  	for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
  	{
  		if (!clearValues[attachmentNdx])
  			continue;
  
  		const tcu::TextureFormat format = mapVkFormat(attachmentInfo[attachmentNdx].getFormat());
  
  		if (hasStencilComponent(format.order) || hasDepthComponent(format.order))
  		{
  			const float						clearNan		= tcu::Float32::nan().asFloat();
  			const float						clearDepth		= hasDepthComponent(format.order) ? clearValues[attachmentNdx]->depthStencil.depth : clearNan;
  			const deUint32					clearStencil	= hasStencilComponent(format.order) ? clearValues[attachmentNdx]->depthStencil.stencil : 0xDEu;
  			const VkClearDepthStencilValue	depthStencil	=
  			{
  				clearDepth,
  				clearStencil
  			};
  			const VkImageSubresourceRange range =
  			{
  				(VkImageAspectFlags)((hasDepthComponent(format.order) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0)
  									 | (hasStencilComponent(format.order) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0)),
  				0,
  				1,
  				0,
  				1
  			};
  
  			vk.cmdClearDepthStencilImage(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depthStencil, 1, &range);
  		}
  		else
  		{
  			const VkImageSubresourceRange	range		=
  			{
  				VK_IMAGE_ASPECT_COLOR_BIT,	// aspectMask;
  				0,							// baseMipLevel;
  				1,							// mipLevels;
  				0,							// baseArrayLayer;
  				1							// layerCount;
  			};
  			const VkClearColorValue			clearColor	= clearValues[attachmentNdx]->color;
  
  			vk.cmdClearColorImage(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range);
  		}
  	}
  
  	{
  		vector<VkImageMemoryBarrier>	renderPassLayouts;
  
  		for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
  		{
  			const VkImageLayout			oldLayout	= clearValues[attachmentNdx] ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
  			const VkImageMemoryBarrier	barrier		=
  			{
  				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,					// sType;
  				DE_NULL,												// pNext;
  
  				(oldLayout != VK_IMAGE_LAYOUT_UNDEFINED ? getAllMemoryWriteFlags() : (VkAccessFlags)0),					// srcAccessMask
  				getAllMemoryReadFlags() | getMemoryFlagsForLayout(attachmentInfo[attachmentNdx].getInitialLayout()),	// dstAccessMask
  
  				oldLayout,												// oldLayout
  				attachmentInfo[attachmentNdx].getInitialLayout(),		// newLayout;
  
  				queueIndex,												// srcQueueFamilyIndex;
  				queueIndex,												// destQueueFamilyIndex;
  
  				attachmentResources[attachmentNdx]->getImage(),			// image;
  				{														// subresourceRange;
  					getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()),		// aspect;
  					0,																	// baseMipLevel;
  					1,																	// mipLevels;
  					0,																	// baseArraySlice;
  					1																	// arraySize;
  				}
  			};
  
  			renderPassLayouts.push_back(barrier);
  		}
  
  		if (!renderPassLayouts.empty())
  			vk.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
  								  VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0,
  								  0, (const VkMemoryBarrier*)DE_NULL,
  								  0, (const VkBufferMemoryBarrier*)DE_NULL,
  								  (deUint32)renderPassLayouts.size(), &renderPassLayouts[0]);
  	}
  }
  
  void pushRenderPassCommands (const DeviceInterface&							vk,
  							 VkCommandBuffer								commandBuffer,
  							 VkRenderPass									renderPass,
  							 VkFramebuffer									framebuffer,
  							 const vector<de::SharedPtr<SubpassRenderer> >&	subpassRenderers,
  							 const UVec2&									renderPos,
  							 const UVec2&									renderSize,
  							 const vector<Maybe<VkClearValue> >&			renderPassClearValues,
  							 TestConfig::RenderTypes						render)
  {
  	const float				clearNan				= tcu::Float32::nan().asFloat();
  	vector<VkClearValue>	attachmentClearValues;
  
  	for (size_t attachmentNdx = 0; attachmentNdx < renderPassClearValues.size(); attachmentNdx++)
  	{
  		if (renderPassClearValues[attachmentNdx])
  			attachmentClearValues.push_back(*renderPassClearValues[attachmentNdx]);
  		else
  			attachmentClearValues.push_back(makeClearValueColorF32(clearNan, clearNan, clearNan, clearNan));
  	}
  
  	{
  		const VkRect2D renderArea =
  		{
  			{ (deInt32)renderPos.x(),	(deInt32)renderPos.y()	},
  			{ renderSize.x(),			renderSize.y()			}
  		};
  
  		for (size_t subpassNdx = 0; subpassNdx < subpassRenderers.size(); subpassNdx++)
  		{
  			const VkSubpassContents	contents = subpassRenderers[subpassNdx]->isSecondary() ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE;
  
  			if (subpassNdx == 0)
  				cmdBeginRenderPass(vk, commandBuffer, renderPass, framebuffer, renderArea, (deUint32)attachmentClearValues.size(), attachmentClearValues.empty() ? DE_NULL : &attachmentClearValues[0], contents);
  			else
  				vk.cmdNextSubpass(commandBuffer, contents);
  
  			if (render)
  			{
  				if (contents == VK_SUBPASS_CONTENTS_INLINE)
  				{
  					subpassRenderers[subpassNdx]->pushRenderCommands(vk, commandBuffer);
  				}
  				else if (contents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS)
  				{
  					const VkCommandBuffer cmd = subpassRenderers[subpassNdx]->getCommandBuffer();
  					vk.cmdExecuteCommands(commandBuffer, 1, &cmd);
  				}
  				else
  					DE_FATAL("Invalid contents");
  			}
  		}
  
  		vk.cmdEndRenderPass(commandBuffer);
  	}
  }
  
  void pushReadImagesToBuffers (const DeviceInterface&								vk,
  							  VkCommandBuffer										commandBuffer,
  							  deUint32												queueIndex,
  
  							  const vector<de::SharedPtr<AttachmentResources> >&	attachmentResources,
  							  const vector<Attachment>&								attachmentInfo,
  							  const vector<bool>&									isLazy,
  
  							  const UVec2&											targetSize)
  {
  	{
  		vector<VkImageMemoryBarrier>	imageBarriers;
  
  		for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
  		{
  			if (isLazy[attachmentNdx])
  				continue;
  
  			const VkImageLayout			oldLayout	= attachmentInfo[attachmentNdx].getFinalLayout();
  			const VkImageMemoryBarrier	barrier		=
  			{
  				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,							// sType
  				DE_NULL,														// pNext
  
  				getAllMemoryWriteFlags() | getMemoryFlagsForLayout(oldLayout),	// srcAccessMask
  				getAllMemoryReadFlags(),										// dstAccessMask
  
  				oldLayout,														// oldLayout
  				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,							// newLayout
  
  				queueIndex,														// srcQueueFamilyIndex
  				queueIndex,														// destQueueFamilyIndex
  
  				attachmentResources[attachmentNdx]->getImage(),					// image
  				{																// subresourceRange
  					getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()),		// aspect;
  					0,																	// baseMipLevel
  					1,																	// mipLevels
  					0,																	// baseArraySlice
  					1																	// arraySize
  				}
  			};
  
  			imageBarriers.push_back(barrier);
  		}
  
  		if (!imageBarriers.empty())
  			vk.cmdPipelineBarrier(commandBuffer,
  								  getAllPipelineStageFlags(),
  								  getAllPipelineStageFlags(),
  								  (VkDependencyFlags)0,
  								  0, (const VkMemoryBarrier*)DE_NULL,
  								  0, (const VkBufferMemoryBarrier*)DE_NULL,
  								  (deUint32)imageBarriers.size(), &imageBarriers[0]);
  	}
  
  	for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
  	{
  		if (isLazy[attachmentNdx])
  			continue;
  
  		const tcu::TextureFormat::ChannelOrder	order	= mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order;
  		const VkBufferImageCopy					rect	=
  		{
  			0, // bufferOffset
  			0, // bufferRowLength
  			0, // bufferImageHeight
  			{							// imageSubresource
  				(vk::VkImageAspectFlags)getPrimaryImageAspect(mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order),	// aspect
  				0,						// mipLevel
  				0,						// arraySlice
  				1						// arraySize
  			},
  			{ 0, 0, 0 },				// imageOffset
  			{ targetSize.x(), targetSize.y(), 1u }		// imageExtent
  		};
  
  		vk.cmdCopyImageToBuffer(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, attachmentResources[attachmentNdx]->getBuffer(), 1, &rect);
  
  		if (tcu::TextureFormat::DS == order)
  		{
  			const VkBufferImageCopy stencilRect =
  			{
  				0,										// bufferOffset
  				0,										// bufferRowLength
  				0,										// bufferImageHeight
  				{									// imageSubresource
  					VK_IMAGE_ASPECT_STENCIL_BIT,	// aspect
  					0,								// mipLevel
  					0,								// arraySlice
  					1								// arraySize
  				},
  				{ 0, 0, 0 },							// imageOffset
  				{ targetSize.x(), targetSize.y(), 1u }	// imageExtent
  			};
  
  			vk.cmdCopyImageToBuffer(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, attachmentResources[attachmentNdx]->getSecondaryBuffer(), 1, &stencilRect);
  		}
  	}
  
  	{
  		vector<VkBufferMemoryBarrier>	bufferBarriers;
  
  		for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
  		{
  			if (isLazy[attachmentNdx])
  				continue;
  
  			const tcu::TextureFormat::ChannelOrder	order			= mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order;
  			const VkBufferMemoryBarrier				bufferBarrier	=
  			{
  				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
  				DE_NULL,
  
  				getAllMemoryWriteFlags(),
  				getAllMemoryReadFlags(),
  
  				queueIndex,
  				queueIndex,
  
  				attachmentResources[attachmentNdx]->getBuffer(),
  				0,
  				attachmentResources[attachmentNdx]->getBufferSize()
  			};
  
  			bufferBarriers.push_back(bufferBarrier);
  
  			if (tcu::TextureFormat::DS == order)
  			{
  				const VkBufferMemoryBarrier secondaryBufferBarrier =
  				{
  					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
  					DE_NULL,
  
  					getAllMemoryWriteFlags(),
  					getAllMemoryReadFlags(),
  
  					queueIndex,
  					queueIndex,
  
  					attachmentResources[attachmentNdx]->getSecondaryBuffer(),
  					0,
  					attachmentResources[attachmentNdx]->getSecondaryBufferSize()
  				};
  
  				bufferBarriers.push_back(secondaryBufferBarrier);
  			}
  		}
  
  		if (!bufferBarriers.empty())
  			vk.cmdPipelineBarrier(commandBuffer,
  								  getAllPipelineStageFlags(),
  								  getAllPipelineStageFlags(),
  								  (VkDependencyFlags)0,
  								  0, (const VkMemoryBarrier*)DE_NULL,
  								  (deUint32)bufferBarriers.size(), &bufferBarriers[0],
  								  0, (const VkImageMemoryBarrier*)DE_NULL);
  	}
  }
  
  class PixelValue
  {
  public:
  				PixelValue		(const Maybe<bool>&	x = nothing<bool>(),
  								 const Maybe<bool>&	y = nothing<bool>(),
  								 const Maybe<bool>&	z = nothing<bool>(),
  								 const Maybe<bool>&	w = nothing<bool>());
  
  	void		setUndefined	(size_t ndx);
  	void		setValue		(size_t ndx, bool value);
  	Maybe<bool>	getValue		(size_t ndx) const;
  
  private:
  	deUint16	m_status;
  };
  
  PixelValue::PixelValue (const Maybe<bool>&	x,
  						const Maybe<bool>&	y,
  						const Maybe<bool>&	z,
  						const Maybe<bool>&	w)
  	: m_status (0)
  {
  	const Maybe<bool> values[] =
  	{
  		x, y, z, w
  	};
  
  	for (size_t ndx = 0; ndx < DE_LENGTH_OF_ARRAY(values); ndx++)
  	{
  		if (values[ndx])
  			setValue(ndx, *values[ndx]);
  		else
  			setUndefined(ndx);
  	}
  
  	DE_ASSERT(m_status <= 0xFFu);
  }
  
  void PixelValue::setUndefined (size_t ndx)
  {
  	DE_ASSERT(ndx < 4);
  	DE_ASSERT(m_status <= 0xFFu);
  
  	m_status &= (deUint16)~(0x1u << (deUint16)(ndx * 2));
  	DE_ASSERT(m_status <= 0xFFu);
  }
  
  void PixelValue::setValue (size_t ndx, bool value)
  {
  	DE_ASSERT(ndx < 4);
  	DE_ASSERT(m_status <= 0xFFu);
  
  	m_status |= (deUint16)(0x1u << (ndx * 2));
  
  	if (value)
  		m_status |= (deUint16)(0x1u << (ndx * 2 + 1));
  	else
  		m_status &= (deUint16)~(0x1u << (deUint16)(ndx * 2 + 1));
  
  	DE_ASSERT(m_status <= 0xFFu);
  }
  
  Maybe<bool> PixelValue::getValue (size_t ndx) const
  {
  	DE_ASSERT(ndx < 4);
  	DE_ASSERT(m_status <= 0xFFu);
  
  	if ((m_status & (0x1u << (deUint16)(ndx * 2))) != 0)
  	{
  		return just((m_status & (0x1u << (deUint32)(ndx * 2 + 1))) != 0);
  	}
  	else
  		return nothing<bool>();
  }
  
  void clearReferenceValues (vector<PixelValue>&	values,
  						   const UVec2&			targetSize,
  						   const UVec2&			offset,
  						   const UVec2&			size,
  						   const BVec4&			mask,
  						   const PixelValue&	value)
  {
  	DE_ASSERT(targetSize.x() * targetSize.y() == (deUint32)values.size());
  	DE_ASSERT(offset.x() + size.x() <= targetSize.x());
  	DE_ASSERT(offset.y() + size.y() <= targetSize.y());
  
  	for (deUint32 y = offset.y(); y < offset.y() + size.y(); y++)
  	for (deUint32 x = offset.x(); x < offset.x() + size.x(); x++)
  	{
  		for (int compNdx = 0; compNdx < 4; compNdx++)
  		{
  			if (mask[compNdx])
  			{
  				if (value.getValue(compNdx))
  					values[x + y * targetSize.x()].setValue(compNdx, *value.getValue(compNdx));
  				else
  					values[x + y * targetSize.x()].setUndefined(compNdx);
  			}
  		}
  	}
  }
  
  void markUndefined (vector<PixelValue>&	values,
  					const BVec4&		mask,
  					const UVec2&		targetSize,
  					const UVec2&		offset,
  					const UVec2&		size)
  {
  	DE_ASSERT(targetSize.x() * targetSize.y() == (deUint32)values.size());
  
  	for (deUint32 y = offset.y(); y < offset.y() + size.y(); y++)
  	for (deUint32 x = offset.x(); x < offset.x() + size.x(); x++)
  	{
  		for (int compNdx = 0; compNdx < 4; compNdx++)
  		{
  			if (mask[compNdx])
  				values[x + y * targetSize.x()].setUndefined(compNdx);
  		}
  	}
  }
  
  PixelValue clearValueToPixelValue (const VkClearValue&			value,
  								   const tcu::TextureFormat&	format)
  {
  	const bool	isDepthAttachment			= hasDepthComponent(format.order);
  	const bool	isStencilAttachment			= hasStencilComponent(format.order);
  	const bool	isDepthOrStencilAttachment	= isDepthAttachment || isStencilAttachment;
  	PixelValue	pixelValue;
  
  	if (isDepthOrStencilAttachment)
  	{
  		if (isDepthAttachment)
  		{
  			if (value.depthStencil.depth == 1.0f)
  				pixelValue.setValue(0, true);
  			else if (value.depthStencil.depth == 0.0f)
  				pixelValue.setValue(0, false);
  			else
  				DE_FATAL("Unknown depth value");
  		}
  
  		if (isStencilAttachment)
  		{
  			if (value.depthStencil.stencil == 0xFFu)
  				pixelValue.setValue(1, true);
  			else if (value.depthStencil.stencil == 0x0u)
  				pixelValue.setValue(1, false);
  			else
  				DE_FATAL("Unknown stencil value");
  		}
  	}
  	else
  	{
  		const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(format.type);
  		const tcu::BVec4				channelMask		= tcu::getTextureFormatChannelMask(format);
  
  		switch (channelClass)
  		{
  			case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
  				for (int i = 0; i < 4; i++)
  				{
  					if (channelMask[i])
  					{
  						if (value.color.int32[i] == 1)
  							pixelValue.setValue(i, true);
  						else if (value.color.int32[i] == 0)
  							pixelValue.setValue(i, false);
  						else
  							DE_FATAL("Unknown clear color value");
  					}
  				}
  				break;
  
  			case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
  				for (int i = 0; i < 4; i++)
  				{
  					if (channelMask[i])
  					{
  						if (value.color.uint32[i] == 1u)
  							pixelValue.setValue(i, true);
  						else if (value.color.uint32[i] == 0u)
  							pixelValue.setValue(i, false);
  						else
  							DE_FATAL("Unknown clear color value");
  					}
  				}
  				break;
  
  			case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
  			case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
  			case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
  				for (int i = 0; i < 4; i++)
  				{
  					if (channelMask[i])
  					{
  						if (value.color.float32[i] == 1.0f)
  							pixelValue.setValue(i, true);
  						else if (value.color.float32[i] == 0.0f)
  							pixelValue.setValue(i, false);
  						else
  							DE_FATAL("Unknown clear color value");
  					}
  				}
  				break;
  
  			default:
  				DE_FATAL("Unknown channel class");
  		}
  	}
  
  	return pixelValue;
  }
  
  void renderReferenceValues (vector<vector<PixelValue> >&		referenceAttachments,
  							const RenderPass&					renderPassInfo,
  							const UVec2&						targetSize,
  							const vector<Maybe<VkClearValue> >&	imageClearValues,
  							const vector<Maybe<VkClearValue> >&	renderPassClearValues,
  							const vector<SubpassRenderInfo>&	subpassRenderInfo,
  							const UVec2&						renderPos,
  							const UVec2&						renderSize)
  {
  	const vector<Subpass>&	subpasses		= renderPassInfo.getSubpasses();
  	vector<bool>			attachmentUsed	(renderPassInfo.getAttachments().size(), false);
  
  	referenceAttachments.resize(renderPassInfo.getAttachments().size());
  
  	for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
  	{
  		const Attachment			attachment	= renderPassInfo.getAttachments()[attachmentNdx];
  		const tcu::TextureFormat	format		= mapVkFormat(attachment.getFormat());
  		vector<PixelValue>&			reference	= referenceAttachments[attachmentNdx];
  
  		reference.resize(targetSize.x() * targetSize.y());
  
  		if (imageClearValues[attachmentNdx])
  			clearReferenceValues(reference, targetSize, UVec2(0, 0), targetSize, BVec4(true), clearValueToPixelValue(*imageClearValues[attachmentNdx], format));
  	}
  
  	for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
  	{
  		const Subpass&						subpass				= subpasses[subpassNdx];
  		const SubpassRenderInfo&			renderInfo			= subpassRenderInfo[subpassNdx];
  		const vector<AttachmentReference>&	colorAttachments	= subpass.getColorAttachments();
  
  		// Apply load op if attachment was used for the first time
  		for (size_t attachmentNdx = 0; attachmentNdx < colorAttachments.size(); attachmentNdx++)
  		{
  			const deUint32 attachmentIndex = colorAttachments[attachmentNdx].getAttachment();
  
  			if (!attachmentUsed[attachmentIndex])
  			{
  				const Attachment&			attachment	= renderPassInfo.getAttachments()[attachmentIndex];
  				vector<PixelValue>&			reference	= referenceAttachments[attachmentIndex];
  				const tcu::TextureFormat	format		= mapVkFormat(attachment.getFormat());
  
  				DE_ASSERT(!tcu::hasDepthComponent(format.order));
  				DE_ASSERT(!tcu::hasStencilComponent(format.order));
  
  				if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
  					clearReferenceValues(reference, targetSize, renderPos, renderSize, BVec4(true), clearValueToPixelValue(*renderPassClearValues[attachmentIndex], format));
  				else if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
  					markUndefined(reference, BVec4(true), targetSize, renderPos, renderSize);
  
  				attachmentUsed[attachmentIndex] = true;
  			}
  		}
  
  		// Apply load op to depth/stencil attachment if it was used for the first time
  		if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
  		{
  			const deUint32 attachmentIndex = subpass.getDepthStencilAttachment().getAttachment();
  
  			// Apply load op if attachment was used for the first time
  			if (!attachmentUsed[attachmentIndex])
  			{
  				const Attachment&			attachment	= renderPassInfo.getAttachments()[attachmentIndex];
  				vector<PixelValue>&			reference	= referenceAttachments[attachmentIndex];
  				const tcu::TextureFormat	format		= mapVkFormat(attachment.getFormat());
  
  				if (tcu::hasDepthComponent(format.order))
  				{
  					if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
  						clearReferenceValues(reference, targetSize, renderPos, renderSize, BVec4(true, false, false, false), clearValueToPixelValue(*renderPassClearValues[attachmentIndex], format));
  					else if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
  						markUndefined(reference, BVec4(true, false, false, false), targetSize, renderPos, renderSize);
  				}
  
  				if (tcu::hasStencilComponent(format.order))
  				{
  					if (attachment.getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
  						clearReferenceValues(reference, targetSize, renderPos, renderSize, BVec4(false, true, false, false), clearValueToPixelValue(*renderPassClearValues[attachmentIndex], format));
  					else if (attachment.getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
  						markUndefined(reference, BVec4(false, true, false, false), targetSize, renderPos, renderSize);
  				}
  
  				attachmentUsed[attachmentIndex] = true;
  			}
  		}
  
  		for (size_t colorClearNdx = 0; colorClearNdx < renderInfo.getColorClears().size(); colorClearNdx++)
  		{
  			const ColorClear&			colorClear		= renderInfo.getColorClears()[colorClearNdx];
  			const UVec2					offset			= colorClear.getOffset();
  			const UVec2					size			= colorClear.getSize();
  			const deUint32				attachmentIndex	= subpass.getColorAttachments()[colorClearNdx].getAttachment();
  			const Attachment&			attachment		= renderPassInfo.getAttachments()[attachmentIndex];
  			const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  			vector<PixelValue>&			reference		= referenceAttachments[attachmentIndex];
  			VkClearValue				value;
  
  			value.color = colorClear.getColor();
  
  			clearReferenceValues(reference, targetSize, offset, size, BVec4(true), clearValueToPixelValue(value, format));
  		}
  
  		if (renderInfo.getDepthStencilClear())
  		{
  			const DepthStencilClear&	dsClear			= *renderInfo.getDepthStencilClear();
  			const UVec2					offset			= dsClear.getOffset();
  			const UVec2					size			= dsClear.getSize();
  			const deUint32				attachmentIndex	= subpass.getDepthStencilAttachment().getAttachment();
  			const Attachment&			attachment		= renderPassInfo.getAttachments()[attachmentIndex];
  			const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  			const bool					hasStencil		= tcu::hasStencilComponent(format.order);
  			const bool					hasDepth		= tcu::hasDepthComponent(format.order);
  			vector<PixelValue>&			reference		= referenceAttachments[attachmentIndex];
  			VkClearValue				value;
  
  			value.depthStencil.depth = dsClear.getDepth();
  			value.depthStencil.stencil = dsClear.getStencil();
  
  			clearReferenceValues(reference, targetSize, offset, size, BVec4(hasDepth, hasStencil, false, false), clearValueToPixelValue(value, format));
  		}
  
  		if (renderInfo.getRenderQuad())
  		{
  			const RenderQuad&	renderQuad	= *renderInfo.getRenderQuad();
  			const Vec2			posA		= renderQuad.getCornerA();
  			const Vec2			posB		= renderQuad.getCornerB();
  			const Vec2			origin		= Vec2((float)renderInfo.getViewportOffset().x(), (float)renderInfo.getViewportOffset().y()) + Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f);
  			const Vec2			p			= Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f);
  			const IVec2			posAI		(deRoundFloatToInt32(origin.x() + (p.x() * posA.x())),
  											 deRoundFloatToInt32(origin.y() + (p.y() * posA.y())));
  			const IVec2			posBI		(deRoundFloatToInt32(origin.x() + (p.x() * posB.x())),
  											 deRoundFloatToInt32(origin.y() + (p.y() * posB.y())));
  
  			DE_ASSERT(posAI.x() < posBI.x());
  			DE_ASSERT(posAI.y() < posBI.y());
  
  			if (subpass.getInputAttachments().empty())
  			{
  				for (size_t attachmentRefNdx = 0; attachmentRefNdx < subpass.getColorAttachments().size(); attachmentRefNdx++)
  				{
  					const deUint32				attachmentIndex	= subpass.getColorAttachments()[attachmentRefNdx].getAttachment();
  					const Attachment&			attachment		= renderPassInfo.getAttachments()[attachmentIndex];
  					const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  					const tcu::BVec4			channelMask		= tcu::getTextureFormatChannelMask(format);
  					vector<PixelValue>&			reference		= referenceAttachments[attachmentIndex];
  
  					for (int y = posAI.y(); y < (int)posBI.y(); y++)
  					for (int x = posAI.x(); x < (int)posBI.x(); x++)
  					{
  						for (int compNdx = 0; compNdx < 4; compNdx++)
  						{
  							const size_t	index	= subpassNdx + attachmentIndex + compNdx;
  							const BoolOp	op		= boolOpFromIndex(index);
  							const bool		boolX	= x % 2 == (int)(index % 2);
  							const bool		boolY	= y % 2 == (int)((index / 2) % 2);
  
  							if (channelMask[compNdx])
  								reference[x + y * targetSize.x()].setValue(compNdx, performBoolOp(op, boolX, boolY));
  						}
  					}
  				}
  
  				if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
  				{
  					const deUint32				attachmentIndex	= subpass.getDepthStencilAttachment().getAttachment();
  					const Attachment&			attachment		= renderPassInfo.getAttachments()[attachmentIndex];
  					const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  					vector<PixelValue>&			reference		= referenceAttachments[attachmentIndex];
  
  					for (int y = posAI.y(); y < (int)posBI.y(); y++)
  					for (int x = posAI.x(); x < (int)posBI.x(); x++)
  					{
  						if (tcu::hasDepthComponent(format.order))
  						{
  							const size_t	index	= subpassNdx + 1;
  							const BoolOp	op		= boolOpFromIndex(index);
  							const bool		boolX	= x % 2 == (int)(index % 2);
  							const bool		boolY	= y % 2 == (int)((index / 2) % 2);
  
  							reference[x + y * targetSize.x()].setValue(0, performBoolOp(op, boolX, boolY));
  						}
  
  						if (tcu::hasStencilComponent(format.order))
  						{
  							const size_t	index	= subpassNdx;
  							reference[x + y * targetSize.x()].setValue(1, (index % 2) == 0);
  						}
  					}
  				}
  			}
  			else
  			{
  				size_t					outputComponentCount	= 0;
  				vector<Maybe<bool> >	inputs;
  
  				DE_ASSERT(posAI.x() < posBI.x());
  				DE_ASSERT(posAI.y() < posBI.y());
  
  				for (size_t attachmentRefNdx = 0; attachmentRefNdx < subpass.getColorAttachments().size(); attachmentRefNdx++)
  				{
  					const deUint32				attachmentIndex	= subpass.getColorAttachments()[attachmentRefNdx].getAttachment();
  					const Attachment&			attachment		= renderPassInfo.getAttachments()[attachmentIndex];
  					const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  					const int					componentCount	= tcu::getNumUsedChannels(format.order);
  
  					outputComponentCount += (size_t)componentCount;
  				}
  
  				if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
  					outputComponentCount++;
  
  				for (int y = posAI.y(); y < (int)posBI.y(); y++)
  				for (int x = posAI.x(); x < (int)posBI.x(); x++)
  				{
  					for (size_t inputAttachmentNdx = 0; inputAttachmentNdx < subpass.getInputAttachments().size(); inputAttachmentNdx++)
  					{
  						const deUint32				attachmentIndex	= subpass.getInputAttachments()[inputAttachmentNdx].getAttachment();
  						const Attachment&			attachment		= renderPassInfo.getAttachments()[attachmentIndex];
  						const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  						const int					componentCount	= tcu::getNumUsedChannels(format.order);
  
  						for (int compNdx = 0; compNdx < componentCount; compNdx++)
  							inputs.push_back(referenceAttachments[attachmentIndex][x + y * targetSize.x()].getValue(compNdx));
  					}
  
  					const size_t inputsPerOutput = inputs.size() >= outputComponentCount
  													? ((inputs.size() / outputComponentCount)
  														+ ((inputs.size() % outputComponentCount) != 0 ? 1 : 0))
  													: 1;
  
  					size_t outputValueNdx = 0;
  
  					for (size_t attachmentRefNdx = 0; attachmentRefNdx < subpass.getColorAttachments().size(); attachmentRefNdx++)
  					{
  						const deUint32				attachmentIndex	= subpass.getColorAttachments()[attachmentRefNdx].getAttachment();
  						const Attachment&			attachment		= renderPassInfo.getAttachments()[attachmentIndex];
  						const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  						vector<PixelValue>&			reference		= referenceAttachments[attachmentIndex];
  						const int					componentCount	= tcu::getNumUsedChannels(format.order);
  
  						for (int compNdx = 0; compNdx < componentCount; compNdx++)
  						{
  							const size_t	index	= subpassNdx + attachmentIndex + outputValueNdx;
  							const BoolOp	op		= boolOpFromIndex(index);
  							const bool		boolX	= x % 2 == (int)(index % 2);
  							const bool		boolY	= y % 2 == (int)((index / 2) % 2);
  							Maybe<bool>		output	= tcu::just(performBoolOp(op, boolX, boolY));
  
  							for (size_t i = 0; i < inputsPerOutput; i++)
  							{
  								if (!output)
  									break;
  								else if (!inputs[((outputValueNdx + compNdx) * inputsPerOutput + i) % inputs.size()])
  									output = tcu::nothing<bool>();
  								else
  									output = (*output) == (*inputs[((outputValueNdx + compNdx) * inputsPerOutput + i) % inputs.size()]);
  							}
  
  							if (output)
  								reference[x + y * targetSize.x()].setValue(compNdx, *output);
  							else
  								reference[x + y * targetSize.x()].setUndefined(compNdx);
  						}
  
  						outputValueNdx += componentCount;
  					}
  
  					if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
  					{
  						const deUint32		attachmentIndex	= subpass.getDepthStencilAttachment().getAttachment();
  						vector<PixelValue>&	reference		= referenceAttachments[attachmentIndex];
  						const size_t		index			= subpassNdx + attachmentIndex;
  						const BoolOp		op				= boolOpFromIndex(index);
  						const bool			boolX			= x % 2 == (int)(index % 2);
  						const bool			boolY			= y % 2 == (int)((index / 2) % 2);
  						Maybe<bool>			output			= tcu::just(performBoolOp(op, boolX, boolY));
  
  						for (size_t i = 0; i < inputsPerOutput; i++)
  						{
  							if (!output)
  								break;
  							else if (inputs[(outputValueNdx * inputsPerOutput + i) % inputs.size()])
  								output = (*output) == (*inputs[(outputValueNdx * inputsPerOutput + i) % inputs.size()]);
  							else
  								output = tcu::nothing<bool>();
  						}
  
  						if (output)
  							reference[x + y * targetSize.x()].setValue(0, *output);
  						else
  							reference[x + y * targetSize.x()].setUndefined(0);
  					}
  
  					inputs.clear();
  				}
  
  				if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
  				{
  					const deUint32				attachmentIndex	= subpass.getDepthStencilAttachment().getAttachment();
  					const Attachment&			attachment		= renderPassInfo.getAttachments()[attachmentIndex];
  					const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  					vector<PixelValue>&			reference		= referenceAttachments[attachmentIndex];
  
  					if (tcu::hasStencilComponent(format.order))
  					{
  						for (int y = posAI.y(); y < (int)posBI.y(); y++)
  						for (int x = posAI.x(); x < (int)posBI.x(); x++)
  						{
  							const size_t	index	= subpassNdx;
  							reference[x + y * targetSize.x()].setValue(1, (index % 2) == 0);
  						}
  					}
  				}
  			}
  		}
  	}
  
  	// Mark all attachments that were used but not stored as undefined
  	for (size_t attachmentIndex = 0; attachmentIndex < renderPassInfo.getAttachments().size(); attachmentIndex++)
  	{
  		const Attachment			attachment					= renderPassInfo.getAttachments()[attachmentIndex];
  		const tcu::TextureFormat	format						= mapVkFormat(attachment.getFormat());
  		vector<PixelValue>&			reference					= referenceAttachments[attachmentIndex];
  		const bool					isStencilAttachment			= hasStencilComponent(format.order);
  		const bool					isDepthOrStencilAttachment	= hasDepthComponent(format.order) || isStencilAttachment;
  
  		if (attachmentUsed[attachmentIndex] && renderPassInfo.getAttachments()[attachmentIndex].getStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
  		{
  			if (isDepthOrStencilAttachment)
  				markUndefined(reference, BVec4(true, false, false, false), targetSize, renderPos, renderSize);
  			else
  				markUndefined(reference, BVec4(true), targetSize, renderPos, renderSize);
  		}
  
  		if (attachmentUsed[attachmentIndex] && isStencilAttachment && renderPassInfo.getAttachments()[attachmentIndex].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
  			markUndefined(reference, BVec4(false, true, false, false), targetSize, renderPos, renderSize);
  	}
  }
  
  void renderReferenceImagesFromValues (vector<tcu::TextureLevel>&			referenceImages,
  									  const vector<vector<PixelValue> >&	referenceValues,
  									  const UVec2&							targetSize,
  									  const RenderPass&						renderPassInfo)
  {
  	referenceImages.resize(referenceValues.size());
  
  	for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
  	{
  		const Attachment			attachment			= renderPassInfo.getAttachments()[attachmentNdx];
  		const tcu::TextureFormat	format				= mapVkFormat(attachment.getFormat());
  		const vector<PixelValue>&	reference			= referenceValues[attachmentNdx];
  		const bool					hasDepth			= tcu::hasDepthComponent(format.order);
  		const bool					hasStencil			= tcu::hasStencilComponent(format.order);
  		const bool					hasDepthOrStencil	= hasDepth || hasStencil;
  		tcu::TextureLevel&			referenceImage		= referenceImages[attachmentNdx];
  
  		referenceImage.setStorage(format, targetSize.x(), targetSize.y());
  
  		if (hasDepthOrStencil)
  		{
  			if (hasDepth)
  			{
  				const PixelBufferAccess depthAccess (tcu::getEffectiveDepthStencilAccess(referenceImage.getAccess(), tcu::Sampler::MODE_DEPTH));
  
  				for (deUint32 y = 0; y < targetSize.y(); y++)
  				for (deUint32 x = 0; x < targetSize.x(); x++)
  				{
  					if (reference[x + y * targetSize.x()].getValue(0))
  					{
  						if (*reference[x + y * targetSize.x()].getValue(0))
  							depthAccess.setPixDepth(1.0f, x, y);
  						else
  							depthAccess.setPixDepth(0.0f, x, y);
  					}
  					else // Fill with 3x3 grid
  						depthAccess.setPixDepth(((x / 3) % 2) == ((y / 3) % 2) ? 0.33f : 0.66f, x, y);
  				}
  			}
  
  			if (hasStencil)
  			{
  				const PixelBufferAccess stencilAccess (tcu::getEffectiveDepthStencilAccess(referenceImage.getAccess(), tcu::Sampler::MODE_STENCIL));
  
  				for (deUint32 y = 0; y < targetSize.y(); y++)
  				for (deUint32 x = 0; x < targetSize.x(); x++)
  				{
  					if (reference[x + y * targetSize.x()].getValue(1))
  					{
  						if (*reference[x + y * targetSize.x()].getValue(1))
  							stencilAccess.setPixStencil(0xFFu, x, y);
  						else
  							stencilAccess.setPixStencil(0x0u, x, y);
  					}
  					else // Fill with 3x3 grid
  						stencilAccess.setPixStencil(((x / 3) % 2) == ((y / 3) % 2) ? 85 : 170, x, y);
  				}
  			}
  		}
  		else
  		{
  			for (deUint32 y = 0; y < targetSize.y(); y++)
  			for (deUint32 x = 0; x < targetSize.x(); x++)
  			{
  				tcu::Vec4 color;
  
  				for (int compNdx = 0; compNdx < 4; compNdx++)
  				{
  					if (reference[x + y * targetSize.x()].getValue(compNdx))
  					{
  						if (*reference[x + y * targetSize.x()].getValue(compNdx))
  							color[compNdx] = 1.0f;
  						else
  							color[compNdx] = 0.0f;
  					}
  					else // Fill with 3x3 grid
  						color[compNdx] = ((compNdx + (x / 3)) % 2) == ((y / 3) % 2) ? 0.33f : 0.66f;
  				}
  
  				referenceImage.getAccess().setPixel(color, x, y);
  			}
  		}
  	}
  }
  
  bool verifyColorAttachment (const vector<PixelValue>&		reference,
  							const ConstPixelBufferAccess&	result,
  							const PixelBufferAccess&		errorImage)
  {
  	const Vec4	red		(1.0f, 0.0f, 0.0f, 1.0f);
  	const Vec4	green	(0.0f, 1.0f, 0.0f, 1.0f);
  	bool		ok		= true;
  
  	DE_ASSERT(result.getWidth() * result.getHeight() == (int)reference.size());
  	DE_ASSERT(result.getWidth() == errorImage.getWidth());
  	DE_ASSERT(result.getHeight() == errorImage.getHeight());
  
  	for (int y = 0; y < result.getHeight(); y++)
  	for (int x = 0; x < result.getWidth(); x++)
  	{
  		const Vec4			resultColor		= result.getPixel(x, y);
  		const PixelValue&	referenceValue	= reference[x + y * result.getWidth()];
  		bool				pixelOk			= true;
  
  		for (int compNdx = 0; compNdx < 4; compNdx++)
  		{
  			const Maybe<bool> maybeValue = referenceValue.getValue(compNdx);
  
  			if (maybeValue)
  			{
  				const bool value = *maybeValue;
  
  				if ((value && (resultColor[compNdx] != 1.0f))
  					|| (!value && resultColor[compNdx] != 0.0f))
  					pixelOk = false;
  			}
  		}
  
  		if (!pixelOk)
  		{
  			errorImage.setPixel(red, x, y);
  			ok = false;
  		}
  		else
  			errorImage.setPixel(green, x, y);
  	}
  
  	return ok;
  }
  
  bool verifyDepthAttachment (const vector<PixelValue>&		reference,
  							const ConstPixelBufferAccess&	result,
  							const PixelBufferAccess&		errorImage)
  {
  	const Vec4	red		(1.0f, 0.0f, 0.0f, 1.0f);
  	const Vec4	green	(0.0f, 1.0f, 0.0f, 1.0f);
  	bool		ok		= true;
  
  	DE_ASSERT(result.getWidth() * result.getHeight() == (int)reference.size());
  	DE_ASSERT(result.getWidth() == errorImage.getWidth());
  	DE_ASSERT(result.getHeight() == errorImage.getHeight());
  
  	for (int y = 0; y < result.getHeight(); y++)
  	for (int x = 0; x < result.getWidth(); x++)
  	{
  		bool pixelOk = true;
  
  		const float			resultDepth		= result.getPixDepth(x, y);
  		const PixelValue&	referenceValue	= reference[x + y * result.getWidth()];
  		const Maybe<bool>	maybeValue		= referenceValue.getValue(0);
  
  		if (maybeValue)
  		{
  			const bool value = *maybeValue;
  
  			if ((value && (resultDepth != 1.0f))
  				|| (!value && resultDepth != 0.0f))
  				pixelOk = false;
  		}
  
  		if (!pixelOk)
  		{
  			errorImage.setPixel(red, x, y);
  			ok = false;
  		}
  		else
  			errorImage.setPixel(green, x, y);
  	}
  
  	return ok;
  }
  
  bool verifyStencilAttachment (const vector<PixelValue>&		reference,
  							  const ConstPixelBufferAccess&	result,
  							  const PixelBufferAccess&		errorImage)
  {
  	const Vec4	red		(1.0f, 0.0f, 0.0f, 1.0f);
  	const Vec4	green	(0.0f, 1.0f, 0.0f, 1.0f);
  	bool		ok		= true;
  
  	DE_ASSERT(result.getWidth() * result.getHeight() == (int)reference.size());
  	DE_ASSERT(result.getWidth() == errorImage.getWidth());
  	DE_ASSERT(result.getHeight() == errorImage.getHeight());
  
  	for (int y = 0; y < result.getHeight(); y++)
  	for (int x = 0; x < result.getWidth(); x++)
  	{
  		bool pixelOk = true;
  
  		const deUint32		resultStencil	= result.getPixStencil(x, y);
  		const PixelValue&	referenceValue	= reference[x + y * result.getWidth()];
  		const Maybe<bool>	maybeValue		= referenceValue.getValue(1);
  
  		if (maybeValue)
  		{
  			const bool value = *maybeValue;
  
  			if ((value && (resultStencil != 0xFFu))
  				|| (!value && resultStencil != 0x0u))
  				pixelOk = false;
  		}
  
  		if (!pixelOk)
  		{
  			errorImage.setPixel(red, x, y);
  			ok = false;
  		}
  		else
  			errorImage.setPixel(green, x, y);
  	}
  
  	return ok;
  }
  
  bool logAndVerifyImages (TestLog&											log,
  						 const DeviceInterface&								vk,
  						 VkDevice											device,
  						 const vector<de::SharedPtr<AttachmentResources> >&	attachmentResources,
  						 const vector<bool>&								attachmentIsLazy,
  						 const RenderPass&									renderPassInfo,
  						 const vector<Maybe<VkClearValue> >&				renderPassClearValues,
  						 const vector<Maybe<VkClearValue> >&				imageClearValues,
  						 const vector<SubpassRenderInfo>&					subpassRenderInfo,
  						 const UVec2&										targetSize,
  						 const TestConfig&									config)
  {
  	vector<vector<PixelValue> >	referenceValues;
  	vector<tcu::TextureLevel>	referenceAttachments;
  	bool						isOk					= true;
  
  	log << TestLog::Message << "Reference images fill undefined pixels with 3x3 grid pattern." << TestLog::EndMessage;
  
  	renderReferenceValues(referenceValues, renderPassInfo, targetSize, imageClearValues, renderPassClearValues, subpassRenderInfo, config.renderPos, config.renderSize);
  	renderReferenceImagesFromValues(referenceAttachments, referenceValues, targetSize, renderPassInfo);
  
  	for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
  	{
  		if (!attachmentIsLazy[attachmentNdx])
  		{
  			const Attachment			attachment		= renderPassInfo.getAttachments()[attachmentNdx];
  			const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  
  			if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order))
  			{
  				const tcu::TextureFormat	depthFormat			= getDepthCopyFormat(attachment.getFormat());
  				const VkDeviceSize			depthBufferSize		= targetSize.x() * targetSize.y() * depthFormat.getPixelSize();
  				void* const					depthPtr			= attachmentResources[attachmentNdx]->getResultMemory().getHostPtr();
  
  				const tcu::TextureFormat	stencilFormat		= getStencilCopyFormat(attachment.getFormat());
  				const VkDeviceSize			stencilBufferSize	= targetSize.x() * targetSize.y() * stencilFormat.getPixelSize();
  				void* const					stencilPtr			= attachmentResources[attachmentNdx]->getSecondaryResultMemory().getHostPtr();
  
  				const VkMappedMemoryRange	ranges[]			=
  				{
  					{
  						VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,								// sType;
  						DE_NULL,															// pNext;
  						attachmentResources[attachmentNdx]->getResultMemory().getMemory(),	// mem;
  						attachmentResources[attachmentNdx]->getResultMemory().getOffset(),	// offset;
  						depthBufferSize														// size;
  					},
  					{
  						VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,										// sType;
  						DE_NULL,																	// pNext;
  						attachmentResources[attachmentNdx]->getSecondaryResultMemory().getMemory(),	// mem;
  						attachmentResources[attachmentNdx]->getSecondaryResultMemory().getOffset(),	// offset;
  						stencilBufferSize															// size;
  					}
  				};
  				VK_CHECK(vk.invalidateMappedMemoryRanges(device, 2u, ranges));
  
  				{
  					const ConstPixelBufferAccess	depthAccess			(depthFormat, targetSize.x(), targetSize.y(), 1, depthPtr);
  					const ConstPixelBufferAccess	stencilAccess		(stencilFormat, targetSize.x(), targetSize.y(), 1, stencilPtr);
  					tcu::TextureLevel				depthErrorImage		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y());
  					tcu::TextureLevel				stencilErrorImage	(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y());
  
  					log << TestLog::Image("Attachment" + de::toString(attachmentNdx) + "Depth", "Attachment " + de::toString(attachmentNdx) + " Depth", depthAccess);
  					log << TestLog::Image("Attachment" + de::toString(attachmentNdx) + "Stencil", "Attachment " + de::toString(attachmentNdx) + " Stencil", stencilAccess);
  
  					log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess());
  
  					if (renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE
  						&& !verifyDepthAttachment(referenceValues[attachmentNdx], depthAccess, depthErrorImage.getAccess()))
  					{
  						log << TestLog::Image("DepthAttachmentError" + de::toString(attachmentNdx), "Depth Attachment Error " + de::toString(attachmentNdx), depthErrorImage.getAccess());
  						isOk = false;
  					}
  
  					if (renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE
  						&& !verifyStencilAttachment(referenceValues[attachmentNdx], stencilAccess, stencilErrorImage.getAccess()))
  					{
  						log << TestLog::Image("StencilAttachmentError" + de::toString(attachmentNdx), "Stencil Attachment Error " + de::toString(attachmentNdx), stencilErrorImage.getAccess());
  						isOk = false;
  					}
  				}
  			}
  			else
  			{
  				const VkDeviceSize			bufferSize	= targetSize.x() * targetSize.y() * format.getPixelSize();
  				void* const					ptr			= attachmentResources[attachmentNdx]->getResultMemory().getHostPtr();
  
  				const VkMappedMemoryRange	range		=
  				{
  					VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,								// sType;
  					DE_NULL,															// pNext;
  					attachmentResources[attachmentNdx]->getResultMemory().getMemory(),	// mem;
  					attachmentResources[attachmentNdx]->getResultMemory().getOffset(),	// offset;
  					bufferSize															// size;
  				};
  				VK_CHECK(vk.invalidateMappedMemoryRanges(device, 1u, &range));
  
  				if (tcu::hasDepthComponent(format.order))
  				{
  					const ConstPixelBufferAccess	access		(format, targetSize.x(), targetSize.y(), 1, ptr);
  					tcu::TextureLevel				errorImage	(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y());
  
  					log << TestLog::Image("Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx), access);
  					log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess());
  
  					if ((renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE || renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE)
  						&& !verifyDepthAttachment(referenceValues[attachmentNdx], access, errorImage.getAccess()))
  					{
  						log << TestLog::Image("AttachmentError" + de::toString(attachmentNdx), "Attachment Error " + de::toString(attachmentNdx), errorImage.getAccess());
  						isOk = false;
  					}
  				}
  				else if (tcu::hasStencilComponent(format.order))
  				{
  					const ConstPixelBufferAccess	access		(format, targetSize.x(), targetSize.y(), 1, ptr);
  					tcu::TextureLevel				errorImage	(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y());
  
  					log << TestLog::Image("Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx), access);
  					log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess());
  
  					if ((renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE || renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE)
  						&& !verifyStencilAttachment(referenceValues[attachmentNdx], access, errorImage.getAccess()))
  					{
  						log << TestLog::Image("AttachmentError" + de::toString(attachmentNdx), "Attachment Error " + de::toString(attachmentNdx), errorImage.getAccess());
  						isOk = false;
  					}
  				}
  				else
  				{
  					const ConstPixelBufferAccess	access		(format, targetSize.x(), targetSize.y(), 1, ptr);
  					tcu::TextureLevel				errorImage	(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y());
  
  					log << TestLog::Image("Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx), access);
  					log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess());
  
  					if ((renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE || renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE)
  						&& !verifyColorAttachment(referenceValues[attachmentNdx], access, errorImage.getAccess()))
  					{
  						log << TestLog::Image("AttachmentError" + de::toString(attachmentNdx), "Attachment Error " + de::toString(attachmentNdx), errorImage.getAccess());
  						isOk = false;
  					}
  				}
  			}
  		}
  	}
  
  	return isOk;
  }
  
  std::string getInputAttachmentType (VkFormat vkFormat)
  {
  	const tcu::TextureFormat		format			= mapVkFormat(vkFormat);
  	const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(format.type);
  
  	switch (channelClass)
  	{
  		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
  			return "isubpassInput";
  
  		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
  			return "usubpassInput";
  
  		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
  		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
  		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
  			return "subpassInput";
  
  		default:
  			DE_FATAL("Unknown channel class");
  			return "";
  	}
  }
  
  std::string getAttachmentType (VkFormat vkFormat)
  {
  	const tcu::TextureFormat		format			= mapVkFormat(vkFormat);
  	const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(format.type);
  
  	switch (channelClass)
  	{
  		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
  			return "ivec4";
  
  		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
  			return "uvec4";
  
  		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
  		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
  		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
  			return "vec4";
  
  		default:
  			DE_FATAL("Unknown channel class");
  			return "";
  	}
  }
  
  void createTestShaders (SourceCollections& dst, TestConfig config)
  {
  	if (config.renderTypes & TestConfig::RENDERTYPES_DRAW)
  	{
  		const vector<Subpass>&	subpasses	= config.renderPass.getSubpasses();
  
  		for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
  		{
  			const Subpass&		subpass					= subpasses[subpassNdx];
  			deUint32			inputAttachmentBinding	= 0;
  			std::ostringstream	vertexShader;
  			std::ostringstream	fragmentShader;
  
  			vertexShader << "#version 310 es\n"
  						 << "layout(location = 0) in highp vec2 a_position;\n"
  						 << "void main (void) {\n"
  						 << "\tgl_Position = vec4(a_position, 1.0, 1.0);\n"
  						 << "}\n";
  
  			fragmentShader << "#version 310 es\n"
  						   << "precision highp float;\n";
  
  			for (size_t attachmentNdx = 0; attachmentNdx < subpass.getInputAttachments().size(); attachmentNdx++)
  			{
  				const deUint32				attachmentIndex	= subpass.getInputAttachments()[attachmentNdx].getAttachment();
  				const Attachment			attachment		= config.renderPass.getAttachments()[attachmentIndex];
  				const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  				const bool					isDepthFormat	= tcu::hasDepthComponent(format.order);
  				const bool					isStencilFormat	= tcu::hasStencilComponent(format.order);
  
  				if (isDepthFormat || isStencilFormat)
  				{
  					if (isDepthFormat)
  					{
  						fragmentShader << "layout(input_attachment_index = " << attachmentNdx << ", set=0, binding=" << inputAttachmentBinding << ") uniform highp subpassInput i_depth" << attachmentNdx << ";\n";
  						inputAttachmentBinding++;
  					}
  
  					if (isStencilFormat)
  					{
  						fragmentShader << "layout(input_attachment_index = " << attachmentNdx << ", set=0, binding=" << inputAttachmentBinding << ") uniform highp usubpassInput i_stencil" << attachmentNdx << ";\n";
  						inputAttachmentBinding++;
  					}
  				}
  				else
  				{
  					const std::string attachmentType = getInputAttachmentType(attachment.getFormat());
  
  					fragmentShader << "layout(input_attachment_index = " << attachmentNdx << ", set=0, binding=" << inputAttachmentBinding << ") uniform highp " << attachmentType << " i_color" << attachmentNdx << ";\n";
  					inputAttachmentBinding++;
  				}
  			}
  
  			for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++)
  			{
  				const std::string attachmentType = getAttachmentType(config.renderPass.getAttachments()[subpass.getColorAttachments()[attachmentNdx].getAttachment()].getFormat());
  				fragmentShader << "layout(location = " << attachmentNdx << ") out highp " << attachmentType << " o_color" << attachmentNdx << ";\n";
  			}
  
  			fragmentShader << "void main (void) {\n";
  
  			if (subpass.getInputAttachments().empty())
  			{
  				for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++)
  				{
  					const deUint32		attachmentIndex	= subpass.getColorAttachments()[attachmentNdx].getAttachment();
  					const std::string	attachmentType	= getAttachmentType(config.renderPass.getAttachments()[attachmentIndex].getFormat());
  
  					fragmentShader << "\to_color" << attachmentNdx << " = " << attachmentType << "(vec4(";
  
  					for (size_t compNdx = 0; compNdx < 4; compNdx++)
  					{
  						const size_t	index	= subpassNdx + attachmentIndex + compNdx;
  						const BoolOp	op		= boolOpFromIndex(index);
  
  						if (compNdx > 0)
  							fragmentShader << ",\n\t\t";
  
  						fragmentShader	<< "((int(gl_FragCoord.x) % 2 == " << (index % 2)
  										<< ") " << boolOpToString(op) << " ("
  										<< "int(gl_FragCoord.y) % 2 == " << ((index / 2) % 2)
  										<< ") ? 1.0 : 0.0)";
  					}
  
  					fragmentShader << "));\n";
  				}
  
  				if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
  				{
  					const size_t	index	= subpassNdx + 1;
  					const BoolOp	op		= boolOpFromIndex(index);
  
  					fragmentShader	<< "\tgl_FragDepth = ((int(gl_FragCoord.x) % 2 == " << (index % 2)
  									<< ") " << boolOpToString(op) << " ("
  									<< "int(gl_FragCoord.y) % 2 == " << ((index / 2) % 2)
  									<< ") ? 1.0 : 0.0);\n";
  				}
  			}
  			else
  			{
  				size_t	inputComponentCount		= 0;
  				size_t	outputComponentCount	= 0;
  
  				for (size_t attachmentNdx = 0; attachmentNdx < subpass.getInputAttachments().size(); attachmentNdx++)
  				{
  					const deUint32				attachmentIndex	= subpass.getInputAttachments()[attachmentNdx].getAttachment();
  					const Attachment			attachment		= config.renderPass.getAttachments()[attachmentIndex];
  					const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  					const size_t				componentCount	= (size_t)tcu::getNumUsedChannels(format.order);
  
  					inputComponentCount += componentCount;
  				}
  
  				for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++)
  				{
  					const deUint32				attachmentIndex	= subpass.getColorAttachments()[attachmentNdx].getAttachment();
  					const Attachment			attachment		= config.renderPass.getAttachments()[attachmentIndex];
  					const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  					const size_t				componentCount	= (size_t)tcu::getNumUsedChannels(format.order);
  
  					outputComponentCount += componentCount;
  				}
  
  				if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
  					outputComponentCount++;
  
  				const size_t inputsPerOutput = inputComponentCount >= outputComponentCount
  												? ((inputComponentCount / outputComponentCount)
  													+ ((inputComponentCount % outputComponentCount) != 0 ? 1 : 0))
  												: 1;
  
  				fragmentShader << "\tbool inputs[" << inputComponentCount << "];\n"
  								  "\tbool outputs[" << outputComponentCount << "];\n";
  
  				size_t inputValueNdx = 0;
  
  				for (size_t attachmentNdx = 0; attachmentNdx < subpass.getInputAttachments().size(); attachmentNdx++)
  				{
  					const char* const	components[]	=
  					{
  						"x", "y", "z", "w"
  					};
  					const deUint32				attachmentIndex	= subpass.getInputAttachments()[attachmentNdx].getAttachment();
  					const Attachment			attachment		= config.renderPass.getAttachments()[attachmentIndex];
  					const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  					const size_t				componentCount	= (size_t)tcu::getNumUsedChannels(format.order);
  					const bool					isDepthFormat	= tcu::hasDepthComponent(format.order);
  					const bool					isStencilFormat	= tcu::hasStencilComponent(format.order);
  
  					if (isDepthFormat || isStencilFormat)
  					{
  						if (isDepthFormat)
  						{
  							fragmentShader << "\tinputs[" << inputValueNdx << "] = 1.0 == float(subpassLoad(i_depth" << attachmentNdx << ").x);\n";
  							inputValueNdx++;
  						}
  
  						if (isStencilFormat)
  						{
  							fragmentShader << "\tinputs[" << inputValueNdx << "] = 255u == subpassLoad(i_stencil" << attachmentNdx << ").x;\n";
  							inputValueNdx++;
  						}
  					}
  					else
  					{
  						for (size_t compNdx = 0; compNdx < componentCount; compNdx++)
  						{
  							fragmentShader << "\tinputs[" << inputValueNdx << "] = 1.0 == float(subpassLoad(i_color" << attachmentNdx << ")." << components[compNdx] << ");\n";
  							inputValueNdx++;
  						}
  					}
  				}
  
  				size_t outputValueNdx = 0;
  
  				for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++)
  				{
  					const deUint32				attachmentIndex	= subpass.getColorAttachments()[attachmentNdx].getAttachment();
  					const Attachment			attachment		= config.renderPass.getAttachments()[attachmentIndex];
  					const std::string			attachmentType	= getAttachmentType(config.renderPass.getAttachments()[attachmentIndex].getFormat());
  					const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
  					const size_t				componentCount	= (size_t)tcu::getNumUsedChannels(format.order);
  
  					for (size_t compNdx = 0; compNdx < componentCount; compNdx++)
  					{
  						const size_t	index	= subpassNdx + attachmentIndex + outputValueNdx;
  						const BoolOp	op		= boolOpFromIndex(index);
  
  						fragmentShader << "\toutputs[" << outputValueNdx + compNdx << "] = "
  										<< "(int(gl_FragCoord.x) % 2 == " << (index % 2)
  										<< ") " << boolOpToString(op) << " ("
  										<< "int(gl_FragCoord.y) % 2 == " << ((index / 2) % 2)
  										<< ");\n";
  
  						for (size_t i = 0; i < inputsPerOutput; i++)
  							fragmentShader << "\toutputs[" << outputValueNdx + compNdx << "] = outputs[" << outputValueNdx + compNdx << "] == inputs[" <<  ((outputValueNdx + compNdx) * inputsPerOutput + i) %  inputComponentCount << "];\n";
  					}
  
  					fragmentShader << "\to_color" << attachmentNdx << " = " << attachmentType << "(";
  
  					for (size_t compNdx = 0; compNdx < 4; compNdx++)
  					{
  						if (compNdx > 0)
  							fragmentShader << ", ";
  
  						if (compNdx < componentCount)
  							fragmentShader << "outputs[" << outputValueNdx + compNdx << "]";
  						else
  							fragmentShader << "0";
  					}
  
  					outputValueNdx += componentCount;
  
  					fragmentShader << ");\n";
  				}
  
  				if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
  				{
  					const deUint32	attachmentIndex	= subpass.getDepthStencilAttachment().getAttachment();
  					const size_t	index			= subpassNdx + attachmentIndex;
  					const BoolOp	op				= boolOpFromIndex(index);
  
  					fragmentShader << "\toutputs[" << outputValueNdx << "] = "
  									<< "(int(gl_FragCoord.x) % 2 == " << (index % 2)
  									<< ") " << boolOpToString(op) << " ("
  									<< "int(gl_FragCoord.y) % 2 == " << ((index / 2) % 2)
  									<< ");\n";
  
  					for (size_t i = 0; i < inputsPerOutput; i++)
  						fragmentShader << "\toutputs[" << outputValueNdx << "] = outputs[" << outputValueNdx << "] == inputs[" <<  (outputValueNdx * inputsPerOutput + i) %  inputComponentCount << "];\n";
  
  					fragmentShader << "\tgl_FragDepth = outputs[" << outputValueNdx << "] ? 1.0 : 0.0;";
  				}
  			}
  
  			fragmentShader << "}\n";
  
  			dst.glslSources.add(de::toString(subpassNdx) + "-vert") << glu::VertexSource(vertexShader.str());
  			dst.glslSources.add(de::toString(subpassNdx) + "-frag") << glu::FragmentSource(fragmentShader.str());
  		}
  	}
  }
  
  void initializeAttachmentIsLazy (vector<bool>& attachmentIsLazy, const vector<Attachment>& attachments, TestConfig::ImageMemory imageMemory)
  {
  	bool lastAttachmentWasLazy = false;
  
  	for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
  	{
  		if (attachments[attachmentNdx].getLoadOp() != VK_ATTACHMENT_LOAD_OP_LOAD
  			&& attachments[attachmentNdx].getStoreOp() != VK_ATTACHMENT_STORE_OP_STORE
  			&& attachments[attachmentNdx].getStencilLoadOp() != VK_ATTACHMENT_LOAD_OP_LOAD
  			&& attachments[attachmentNdx].getStencilStoreOp() != VK_ATTACHMENT_STORE_OP_STORE)
  		{
  			if (imageMemory == TestConfig::IMAGEMEMORY_LAZY || (imageMemory & TestConfig::IMAGEMEMORY_LAZY && !lastAttachmentWasLazy))
  			{
  				attachmentIsLazy.push_back(true);
  				lastAttachmentWasLazy = true;
  			}
  			else if (imageMemory & TestConfig::IMAGEMEMORY_STRICT)
  			{
  				attachmentIsLazy.push_back(false);
  				lastAttachmentWasLazy = false;
  			}
  			else
  				DE_FATAL("Unknown imageMemory");
  		}
  		else
  			attachmentIsLazy.push_back(false);
  	}
  }
  
  enum AttachmentRefType
  {
  	ATTACHMENTREFTYPE_COLOR,
  	ATTACHMENTREFTYPE_DEPTH_STENCIL,
  	ATTACHMENTREFTYPE_INPUT,
  	ATTACHMENTREFTYPE_RESOLVE,
  };
  
  VkImageUsageFlags getImageUsageFromLayout (VkImageLayout layout)
  {
  	switch (layout)
  	{
  		case VK_IMAGE_LAYOUT_GENERAL:
  		case VK_IMAGE_LAYOUT_PREINITIALIZED:
  			return 0;
  
  		case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
  			return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  
  		case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
  		case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
  			return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
  
  		case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
  			return VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
  
  		case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
  			return VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
  
  		case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
  			return VK_IMAGE_USAGE_TRANSFER_DST_BIT;
  
  		default:
  			DE_FATAL("Unexpected image layout");
  			return 0;
  	}
  }
  
  void getImageUsageFromAttachmentReferences(vector<VkImageUsageFlags>& attachmentImageUsage, AttachmentRefType refType, size_t count, const AttachmentReference* references)
  {
  	for (size_t referenceNdx = 0; referenceNdx < count; ++referenceNdx)
  	{
  		const deUint32 attachment = references[referenceNdx].getAttachment();
  
  		if (attachment != VK_ATTACHMENT_UNUSED)
  		{
  			VkImageUsageFlags usage;
  
  			switch (refType)
  			{
  				case ATTACHMENTREFTYPE_COLOR:
  				case ATTACHMENTREFTYPE_RESOLVE:
  					usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  					break;
  
  				case ATTACHMENTREFTYPE_DEPTH_STENCIL:
  					usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
  					break;
  
  				case ATTACHMENTREFTYPE_INPUT:
  					usage = VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
  					break;
  
  				default:
  					DE_FATAL("Unexpected attachment reference type");
  					usage = 0;
  					break;
  			}
  
  			attachmentImageUsage[attachment] |= usage;
  		}
  	}
  }
  
  void getImageUsageFromAttachmentReferences(vector<VkImageUsageFlags>& attachmentImageUsage, AttachmentRefType refType, const vector<AttachmentReference>& references)
  {
  	if (!references.empty())
  	{
  		getImageUsageFromAttachmentReferences(attachmentImageUsage, refType, references.size(), &references[0]);
  	}
  }
  
  void initializeAttachmentImageUsage (Context &context, vector<VkImageUsageFlags>& attachmentImageUsage, const RenderPass& renderPassInfo, const vector<bool>& attachmentIsLazy, const vector<Maybe<VkClearValue> >& clearValues)
  {
  	attachmentImageUsage.resize(renderPassInfo.getAttachments().size(), VkImageUsageFlags(0));
  
  	for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); ++subpassNdx)
  	{
  		const Subpass& subpass = renderPassInfo.getSubpasses()[subpassNdx];
  
  		getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_COLOR, subpass.getColorAttachments());
  		getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_DEPTH_STENCIL, 1, &subpass.getDepthStencilAttachment());
  		getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_INPUT, subpass.getInputAttachments());
  		getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_RESOLVE, subpass.getResolveAttachments());
  	}
  
  	for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
  	{
  		const Attachment& attachment = renderPassInfo.getAttachments()[attachmentNdx];
  		const VkFormatProperties	formatProperties	= getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), attachment.getFormat());
  		const VkFormatFeatureFlags	supportedFeatures	= formatProperties.optimalTilingFeatures;
  
  		if ((supportedFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0)
  			attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_SAMPLED_BIT;
  
  		if ((supportedFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0)
  			attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_STORAGE_BIT;
  
  		attachmentImageUsage[attachmentNdx] |= getImageUsageFromLayout(attachment.getInitialLayout());
  		attachmentImageUsage[attachmentNdx] |= getImageUsageFromLayout(attachment.getFinalLayout());
  
  		if (!attachmentIsLazy[attachmentNdx])
  		{
  			if (clearValues[attachmentNdx])
  				attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
  
  			attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
  		}
  	}
  }
  
  void initializeSubpassIsSecondary (vector<bool>& subpassIsSecondary, const vector<Subpass>& subpasses, TestConfig::CommandBufferTypes commandBuffer)
  {
  	bool lastSubpassWasSecondary = false;
  
  	for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
  	{
  		if (commandBuffer == TestConfig::COMMANDBUFFERTYPES_SECONDARY || (commandBuffer & TestConfig::COMMANDBUFFERTYPES_SECONDARY && !lastSubpassWasSecondary))
  		{
  			subpassIsSecondary.push_back(true);
  			lastSubpassWasSecondary = true;
  		}
  		else if (commandBuffer & TestConfig::COMMANDBUFFERTYPES_INLINE)
  		{
  			subpassIsSecondary.push_back(false);
  			lastSubpassWasSecondary = false;
  		}
  		else
  			DE_FATAL("Unknown commandBuffer");
  	}
  }
  
  void initializeImageClearValues (de::Random& rng, vector<Maybe<VkClearValue> >& clearValues, const vector<Attachment>& attachments, const vector<bool>& isLazy)
  {
  	for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
  	{
  		if (!isLazy[attachmentNdx])
  			clearValues.push_back(just(randomClearValue(attachments[attachmentNdx], rng)));
  		else
  			clearValues.push_back(nothing<VkClearValue>());
  	}
  }
  
  void initializeRenderPassClearValues (de::Random& rng, vector<Maybe<VkClearValue> >& clearValues, const vector<Attachment>& attachments)
  {
  	for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
  	{
  		if (attachments[attachmentNdx].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR
  			|| attachments[attachmentNdx].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
  		{
  			clearValues.push_back(just(randomClearValue(attachments[attachmentNdx], rng)));
  		}
  		else
  			clearValues.push_back(nothing<VkClearValue>());
  	}
  }
  
  void initializeSubpassClearValues (de::Random& rng, vector<vector<VkClearColorValue> >& clearValues, const RenderPass& renderPass)
  {
  	clearValues.resize(renderPass.getSubpasses().size());
  
  	for (size_t subpassNdx = 0; subpassNdx < renderPass.getSubpasses().size(); subpassNdx++)
  	{
  		const Subpass&						subpass				= renderPass.getSubpasses()[subpassNdx];
  		const vector<AttachmentReference>&	colorAttachments	= subpass.getColorAttachments();
  
  		clearValues[subpassNdx].resize(colorAttachments.size());
  
  		for (size_t attachmentRefNdx = 0; attachmentRefNdx < colorAttachments.size(); attachmentRefNdx++)
  		{
  			const AttachmentReference&	attachmentRef	= colorAttachments[attachmentRefNdx];
  			const Attachment&			attachment		= renderPass.getAttachments()[attachmentRef.getAttachment()];
  
  			clearValues[subpassNdx][attachmentRefNdx] = randomColorClearValue(attachment, rng);
  		}
  	}
  }
  
  void logSubpassRenderInfo (TestLog&					log,
  						   const SubpassRenderInfo&	info)
  {
  	log << TestLog::Message << "Viewport, offset: " << info.getViewportOffset() << ", size: " << info.getViewportSize() << TestLog::EndMessage;
  
  	if (info.isSecondary())
  		log << TestLog::Message << "Subpass uses secondary command buffers" << TestLog::EndMessage;
  	else
  		log << TestLog::Message << "Subpass uses inlined commands" << TestLog::EndMessage;
  
  	for (deUint32 attachmentNdx = 0; attachmentNdx < info.getColorClears().size(); attachmentNdx++)
  	{
  		const ColorClear&	colorClear	= info.getColorClears()[attachmentNdx];
  
  		log << TestLog::Message << "Clearing color attachment " << attachmentNdx
  			<< ". Offset: " << colorClear.getOffset()
  			<< ", Size: " << colorClear.getSize()
  			<< ", Color: " << clearColorToString(info.getColorAttachment(attachmentNdx).getFormat(), colorClear.getColor()) << TestLog::EndMessage;
  	}
  
  	if (info.getDepthStencilClear())
  	{
  		const DepthStencilClear&	depthStencilClear	= *info.getDepthStencilClear();
  
  		log << TestLog::Message << "Clearing depth stencil attachment"
  			<< ". Offset: " << depthStencilClear.getOffset()
  			<< ", Size: " << depthStencilClear.getSize()
  			<< ", Depth: " << depthStencilClear.getDepth()
  			<< ", Stencil: " << depthStencilClear.getStencil() << TestLog::EndMessage;
  	}
  
  	if (info.getRenderQuad())
  	{
  		const RenderQuad&	renderQuad	= *info.getRenderQuad();
  
  		log << TestLog::Message << "Rendering grid quad to " << renderQuad.getCornerA() << " -> " << renderQuad.getCornerB() << TestLog::EndMessage;
  	}
  }
  
  void logTestCaseInfo (TestLog&								log,
  					  const TestConfig&						config,
  					  const vector<bool>&					attachmentIsLazy,
  					  const vector<Maybe<VkClearValue> >&	imageClearValues,
  					  const vector<Maybe<VkClearValue> >&	renderPassClearValues,
  					  const vector<SubpassRenderInfo>&		subpassRenderInfo)
  {
  	const RenderPass&	renderPass	= config.renderPass;
  
  	logRenderPassInfo(log, renderPass);
  
  	DE_ASSERT(attachmentIsLazy.size() == renderPass.getAttachments().size());
  	DE_ASSERT(imageClearValues.size() == renderPass.getAttachments().size());
  	DE_ASSERT(renderPassClearValues.size() == renderPass.getAttachments().size());
  
  	log << TestLog::Message << "TargetSize: " << config.targetSize << TestLog::EndMessage;
  	log << TestLog::Message << "Render area, Offset: " << config.renderPos << ", Size: " << config.renderSize << TestLog::EndMessage;
  
  	for (size_t attachmentNdx = 0; attachmentNdx < attachmentIsLazy.size(); attachmentNdx++)
  	{
  		const tcu::ScopedLogSection	section	(log, "Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx));
  
  		if (attachmentIsLazy[attachmentNdx])
  			log << TestLog::Message << "Is lazy." << TestLog::EndMessage;
  
  		if (imageClearValues[attachmentNdx])
  			log << TestLog::Message << "Image is cleared to " << clearValueToString(renderPass.getAttachments()[attachmentNdx].getFormat(), *imageClearValues[attachmentNdx]) << " before rendering." << TestLog::EndMessage;
  
  		if (renderPass.getAttachments()[attachmentNdx].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR && renderPassClearValues[attachmentNdx])
  			log << TestLog::Message << "Attachment is cleared to " << clearValueToString(renderPass.getAttachments()[attachmentNdx].getFormat(), *renderPassClearValues[attachmentNdx]) << " in the beginning of the render pass." << TestLog::EndMessage;
  	}
  
  	for (size_t subpassNdx = 0; subpassNdx < renderPass.getSubpasses().size(); subpassNdx++)
  	{
  		const tcu::ScopedLogSection section (log, "Subpass" + de::toString(subpassNdx), "Subpass " + de::toString(subpassNdx));
  
  		logSubpassRenderInfo(log, subpassRenderInfo[subpassNdx]);
  	}
  }
  
  float roundToViewport (float x, deUint32 offset, deUint32 size)
  {
  	const float		origin	= (float)(offset) + ((float(size) / 2.0f));
  	const float		p		= (float)(size) / 2.0f;
  	const deInt32	xi		= deRoundFloatToInt32(origin + (p * x));
  
  	return (((float)xi) - origin) / p;
  }
  
  void initializeSubpassRenderInfo (vector<SubpassRenderInfo>& renderInfos, de::Random& rng, const RenderPass& renderPass, const TestConfig& config)
  {
  	const TestConfig::CommandBufferTypes	commandBuffer			= config.commandBufferTypes;
  	const vector<Subpass>&					subpasses				= renderPass.getSubpasses();
  	bool									lastSubpassWasSecondary	= false;
  
  	for (deUint32 subpassNdx = 0; subpassNdx < (deUint32)subpasses.size(); subpassNdx++)
  	{
  		const Subpass&				subpass				= subpasses[subpassNdx];
  		const bool					subpassIsSecondary	= commandBuffer == TestConfig::COMMANDBUFFERTYPES_SECONDARY
  														|| (commandBuffer & TestConfig::COMMANDBUFFERTYPES_SECONDARY && !lastSubpassWasSecondary) ? true : false;
  		const UVec2					viewportSize		((config.renderSize * UVec2(2)) / UVec2(3));
  		const UVec2					viewportOffset		(config.renderPos.x() + (subpassNdx % 2) * (config.renderSize.x() / 3),
  														 config.renderPos.y() + ((subpassNdx / 2) % 2) * (config.renderSize.y() / 3));
  
  		vector<ColorClear>			colorClears;
  		Maybe<DepthStencilClear>	depthStencilClear;
  		Maybe<RenderQuad>			renderQuad;
  
  		lastSubpassWasSecondary		= subpassIsSecondary;
  
  		if (config.renderTypes & TestConfig::RENDERTYPES_CLEAR)
  		{
  			const vector<AttachmentReference>&	colorAttachments	= subpass.getColorAttachments();
  
  			for (size_t attachmentRefNdx = 0; attachmentRefNdx < colorAttachments.size(); attachmentRefNdx++)
  			{
  				const AttachmentReference&	attachmentRef	= colorAttachments[attachmentRefNdx];
  				const Attachment&			attachment		= renderPass.getAttachments()[attachmentRef.getAttachment()];
  				const UVec2					size			((viewportSize * UVec2(2)) / UVec2(3));
  				const UVec2					offset			(viewportOffset.x() + ((deUint32)attachmentRefNdx % 2u) * (viewportSize.x() / 3u),
  															 viewportOffset.y() + (((deUint32)attachmentRefNdx / 2u) % 2u) * (viewportSize.y() / 3u));
  				const VkClearColorValue		color			= randomColorClearValue(attachment, rng);
  
  				colorClears.push_back(ColorClear(offset, size, color));
  			}
  
  			if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
  			{
  				const Attachment&	attachment	= renderPass.getAttachments()[subpass.getDepthStencilAttachment().getAttachment()];
  				const UVec2			size		((viewportSize * UVec2(2)) / UVec2(3));
  				const UVec2			offset		(viewportOffset.x() + ((deUint32)colorAttachments.size() % 2u) * (viewportSize.x() / 3u),
  												 viewportOffset.y() + (((deUint32)colorAttachments.size() / 2u) % 2u) * (viewportSize.y() / 3u));
  				const VkClearValue	value		= randomClearValue(attachment, rng);
  
  				depthStencilClear = tcu::just(DepthStencilClear(offset, size, value.depthStencil.depth, value.depthStencil.stencil));
  			}
  		}
  
  		if (config.renderTypes & TestConfig::RENDERTYPES_DRAW)
  		{
  			const float	w	= (subpassNdx % 2) == 0 ? 1.0f : 1.25f;
  			const float	h	= (subpassNdx % 2) == 0 ? 1.25f : 1.0f;
  
  			const float	x0	= roundToViewport((subpassNdx % 2) == 0 ? 1.0f - w : -1.0f, viewportOffset.x(), viewportSize.x());
  			const float	x1	= roundToViewport((subpassNdx % 2) == 0 ? 1.0f : -1.0f + w, viewportOffset.x(), viewportSize.x());
  
  			const float	y0	= roundToViewport(((subpassNdx / 2) % 2) == 0 ? 1.0f - h : -1.0f, viewportOffset.y(), viewportSize.y());
  			const float	y1	= roundToViewport(((subpassNdx / 2) % 2) == 0 ? 1.0f : -1.0f + h, viewportOffset.y(), viewportSize.y());
  
  			renderQuad = tcu::just(RenderQuad(tcu::Vec2(x0, y0), tcu::Vec2(x1, y1)));
  		}
  
  		renderInfos.push_back(SubpassRenderInfo(renderPass, subpassNdx, subpassIsSecondary, viewportOffset, viewportSize, renderQuad, colorClears, depthStencilClear));
  	}
  }
  
  void checkTextureFormatSupport (TestLog&					log,
  								const InstanceInterface&	vk,
  								VkPhysicalDevice			device,
  								const vector<Attachment>&	attachments)
  {
  	bool supported = true;
  
  	for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
  	{
  		const Attachment&			attachment					= attachments[attachmentNdx];
  		const tcu::TextureFormat	format						= mapVkFormat(attachment.getFormat());
  		const bool					isDepthOrStencilAttachment	= hasDepthComponent(format.order) || hasStencilComponent(format.order);
  		const VkFormatFeatureFlags	flags						= isDepthOrStencilAttachment? VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT : VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
  		VkFormatProperties			properties;
  
  		vk.getPhysicalDeviceFormatProperties(device, attachment.getFormat(), &properties);
  
  		if ((properties.optimalTilingFeatures & flags) != flags)
  		{
  			supported = false;
  			log << TestLog::Message << "Format: " << attachment.getFormat() << " not supported as " << (isDepthOrStencilAttachment ? "depth stencil attachment" : "color attachment") << TestLog::EndMessage;
  		}
  	}
  
  	if (!supported)
  		TCU_THROW(NotSupportedError, "Format not supported");
  }
  
  tcu::TestStatus renderPassTest (Context& context, TestConfig config)
  {
  	const UVec2							targetSize			= config.targetSize;
  	const UVec2							renderPos			= config.renderPos;
  	const UVec2							renderSize			= config.renderSize;
  	const RenderPass&					renderPassInfo		= config.renderPass;
  
  	TestLog&							log					= context.getTestContext().getLog();
  	de::Random							rng					(config.seed);
  
  	vector<bool>						attachmentIsLazy;
  	vector<VkImageUsageFlags>			attachmentImageUsage;
  	vector<Maybe<VkClearValue> >		imageClearValues;
  	vector<Maybe<VkClearValue> >		renderPassClearValues;
  
  	vector<bool>						subpassIsSecondary;
  	vector<SubpassRenderInfo>			subpassRenderInfo;
  	vector<vector<VkClearColorValue> >	subpassColorClearValues;
  
  	initializeAttachmentIsLazy(attachmentIsLazy, renderPassInfo.getAttachments(), config.imageMemory);
  	initializeImageClearValues(rng, imageClearValues, renderPassInfo.getAttachments(), attachmentIsLazy);
  	initializeAttachmentImageUsage(context, attachmentImageUsage, renderPassInfo, attachmentIsLazy, imageClearValues);
  	initializeRenderPassClearValues(rng, renderPassClearValues, renderPassInfo.getAttachments());
  
  	initializeSubpassIsSecondary(subpassIsSecondary, renderPassInfo.getSubpasses(), config.commandBufferTypes);
  	initializeSubpassClearValues(rng, subpassColorClearValues, renderPassInfo);
  	initializeSubpassRenderInfo(subpassRenderInfo, rng, renderPassInfo, config);
  
  	logTestCaseInfo(log, config, attachmentIsLazy, imageClearValues, renderPassClearValues, subpassRenderInfo);
  
  	checkTextureFormatSupport(log, context.getInstanceInterface(), context.getPhysicalDevice(), config.renderPass.getAttachments());
  
  	{
  		const vk::VkPhysicalDeviceProperties properties = vk::getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice());
  
  		log << TestLog::Message << "Max color attachments: " << properties.limits.maxColorAttachments << TestLog::EndMessage;
  
  		for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++)
  		{
  			 if (renderPassInfo.getSubpasses()[subpassNdx].getColorAttachments().size() > (size_t)properties.limits.maxColorAttachments)
  				 TCU_THROW(NotSupportedError, "Subpass uses more than maxColorAttachments.");
  		}
  	}
  
  	{
  		const VkDevice								device								= context.getDevice();
  		const DeviceInterface&						vk									= context.getDeviceInterface();
  		const VkQueue								queue								= context.getUniversalQueue();
  		const deUint32								queueIndex							= context.getUniversalQueueFamilyIndex();
  		Allocator&									allocator							= context.getDefaultAllocator();
  
  		const Unique<VkRenderPass>					renderPass							(createRenderPass(vk, device, renderPassInfo));
  		const Unique<VkCommandPool>					commandBufferPool					(createCommandPool(vk, device, queueIndex, 0));
  		const Unique<VkCommandBuffer>				initializeImagesCommandBuffer		(allocateCommandBuffer(vk, device, *commandBufferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
  		const Unique<VkCommandBuffer>				renderCommandBuffer					(allocateCommandBuffer(vk, device, *commandBufferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
  		const Unique<VkCommandBuffer>				readImagesToBuffersCommandBuffer	(allocateCommandBuffer(vk, device, *commandBufferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
  
  		vector<de::SharedPtr<AttachmentResources> >	attachmentResources;
  		vector<de::SharedPtr<SubpassRenderer> >		subpassRenderers;
  		vector<VkImage>								attachmentImages;
  		vector<VkImageView>							attachmentViews;
  		vector<pair<VkImageView, VkImageView> >		inputAttachmentViews;
  
  		for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
  		{
  			const Attachment&	attachmentInfo	= renderPassInfo.getAttachments()[attachmentNdx];
  
  			attachmentResources.push_back(de::SharedPtr<AttachmentResources>(new AttachmentResources(vk, device, allocator, queueIndex, targetSize, attachmentInfo, attachmentImageUsage[attachmentNdx])));
  			attachmentViews.push_back(attachmentResources[attachmentNdx]->getAttachmentView());
  			attachmentImages.push_back(attachmentResources[attachmentNdx]->getImage());
  
  			inputAttachmentViews.push_back(attachmentResources[attachmentNdx]->getInputAttachmentViews());
  		}
  
  		beginCommandBuffer(vk, *initializeImagesCommandBuffer, (VkCommandBufferUsageFlags)0, DE_NULL, 0, DE_NULL, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0);
  		pushImageInitializationCommands(vk, *initializeImagesCommandBuffer, renderPassInfo.getAttachments(), attachmentResources, queueIndex, imageClearValues);
  		endCommandBuffer(vk, *initializeImagesCommandBuffer);
  
  		{
  			const Unique<VkFramebuffer> framebuffer (createFramebuffer(vk, device, *renderPass, targetSize, attachmentViews));
  
  			for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++)
  				subpassRenderers.push_back(de::SharedPtr<SubpassRenderer>(new SubpassRenderer(context, vk, device, allocator, *renderPass, *framebuffer, *commandBufferPool, queueIndex, attachmentImages, inputAttachmentViews, subpassRenderInfo[subpassNdx], config.renderPass.getAttachments())));
  
  			beginCommandBuffer(vk, *renderCommandBuffer, (VkCommandBufferUsageFlags)0, DE_NULL, 0, DE_NULL, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0);
  			pushRenderPassCommands(vk, *renderCommandBuffer, *renderPass, *framebuffer, subpassRenderers, renderPos, renderSize, renderPassClearValues, config.renderTypes);
  			endCommandBuffer(vk, *renderCommandBuffer);
  
  			beginCommandBuffer(vk, *readImagesToBuffersCommandBuffer, (VkCommandBufferUsageFlags)0, DE_NULL, 0, DE_NULL, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0);
  			pushReadImagesToBuffers(vk, *readImagesToBuffersCommandBuffer, queueIndex, attachmentResources, renderPassInfo.getAttachments(), attachmentIsLazy, targetSize);
  			endCommandBuffer(vk, *readImagesToBuffersCommandBuffer);
  			{
  				const VkCommandBuffer commandBuffers[] =
  				{
  					*initializeImagesCommandBuffer,
  					*renderCommandBuffer,
  					*readImagesToBuffersCommandBuffer
  				};
  				const Unique<VkFence>	fence		(createFence(vk, device, 0u));
  
  				queueSubmit(vk, queue, DE_LENGTH_OF_ARRAY(commandBuffers), commandBuffers, *fence);
  				waitForFences(vk, device, 1, &fence.get(), VK_TRUE, ~0ull);
  			}
  		}
  
  		if (logAndVerifyImages(log, vk, device, attachmentResources, attachmentIsLazy, renderPassInfo, renderPassClearValues, imageClearValues, subpassRenderInfo, targetSize, config))
  			return tcu::TestStatus::pass("Pass");
  		else
  			return tcu::TestStatus::fail("Result verification failed");
  	}
  }
  
  static const VkFormat s_coreColorFormats[] =
  {
  	VK_FORMAT_R5G6B5_UNORM_PACK16,
  	VK_FORMAT_R8_UNORM,
  	VK_FORMAT_R8_SNORM,
  	VK_FORMAT_R8_UINT,
  	VK_FORMAT_R8_SINT,
  	VK_FORMAT_R8G8_UNORM,
  	VK_FORMAT_R8G8_SNORM,
  	VK_FORMAT_R8G8_UINT,
  	VK_FORMAT_R8G8_SINT,
  	VK_FORMAT_R8G8B8A8_UNORM,
  	VK_FORMAT_R8G8B8A8_SNORM,
  	VK_FORMAT_R8G8B8A8_UINT,
  	VK_FORMAT_R8G8B8A8_SINT,
  	VK_FORMAT_R8G8B8A8_SRGB,
  	VK_FORMAT_A8B8G8R8_UNORM_PACK32,
  	VK_FORMAT_A8B8G8R8_SNORM_PACK32,
  	VK_FORMAT_A8B8G8R8_UINT_PACK32,
  	VK_FORMAT_A8B8G8R8_SINT_PACK32,
  	VK_FORMAT_A8B8G8R8_SRGB_PACK32,
  	VK_FORMAT_B8G8R8A8_UNORM,
  	VK_FORMAT_B8G8R8A8_SRGB,
  	VK_FORMAT_A2R10G10B10_UNORM_PACK32,
  	VK_FORMAT_A2B10G10R10_UNORM_PACK32,
  	VK_FORMAT_A2B10G10R10_UINT_PACK32,
  	VK_FORMAT_R16_UNORM,
  	VK_FORMAT_R16_SNORM,
  	VK_FORMAT_R16_UINT,
  	VK_FORMAT_R16_SINT,
  	VK_FORMAT_R16_SFLOAT,
  	VK_FORMAT_R16G16_UNORM,
  	VK_FORMAT_R16G16_SNORM,
  	VK_FORMAT_R16G16_UINT,
  	VK_FORMAT_R16G16_SINT,
  	VK_FORMAT_R16G16_SFLOAT,
  	VK_FORMAT_R16G16B16A16_UNORM,
  	VK_FORMAT_R16G16B16A16_SNORM,
  	VK_FORMAT_R16G16B16A16_UINT,
  	VK_FORMAT_R16G16B16A16_SINT,
  	VK_FORMAT_R16G16B16A16_SFLOAT,
  	VK_FORMAT_R32_UINT,
  	VK_FORMAT_R32_SINT,
  	VK_FORMAT_R32_SFLOAT,
  	VK_FORMAT_R32G32_UINT,
  	VK_FORMAT_R32G32_SINT,
  	VK_FORMAT_R32G32_SFLOAT,
  	VK_FORMAT_R32G32B32A32_UINT,
  	VK_FORMAT_R32G32B32A32_SINT,
  	VK_FORMAT_R32G32B32A32_SFLOAT
  };
  
  static const VkFormat s_coreDepthStencilFormats[] =
  {
  	VK_FORMAT_D16_UNORM,
  
  	VK_FORMAT_X8_D24_UNORM_PACK32,
  	VK_FORMAT_D32_SFLOAT,
  
  	VK_FORMAT_D24_UNORM_S8_UINT,
  	VK_FORMAT_D32_SFLOAT_S8_UINT
  };
  
  void addAttachmentTests (tcu::TestCaseGroup* group)
  {
  	const deUint32 attachmentCounts[] = { 1, 3, 4, 8 };
  	const VkAttachmentLoadOp loadOps[] =
  	{
  		VK_ATTACHMENT_LOAD_OP_LOAD,
  		VK_ATTACHMENT_LOAD_OP_CLEAR,
  		VK_ATTACHMENT_LOAD_OP_DONT_CARE
  	};
  
  	const VkAttachmentStoreOp storeOps[] =
  	{
  		VK_ATTACHMENT_STORE_OP_STORE,
  		VK_ATTACHMENT_STORE_OP_DONT_CARE
  	};
  
  	const VkImageLayout initialAndFinalColorLayouts[] =
  	{
  		VK_IMAGE_LAYOUT_GENERAL,
  		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  		VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
  		VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
  	};
  
  	const VkImageLayout initialAndFinalDepthStencilLayouts[] =
  	{
  		VK_IMAGE_LAYOUT_GENERAL,
  		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
  		VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
  		VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
  		VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
  	};
  
  	const VkImageLayout subpassLayouts[] =
  	{
  		VK_IMAGE_LAYOUT_GENERAL,
  		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
  	};
  
  	const VkImageLayout depthStencilLayouts[] =
  	{
  		VK_IMAGE_LAYOUT_GENERAL,
  		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
  	};
  
  	const TestConfig::RenderTypes renderCommands[] =
  	{
  		TestConfig::RENDERTYPES_NONE,
  		TestConfig::RENDERTYPES_CLEAR,
  		TestConfig::RENDERTYPES_DRAW,
  		TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW,
  	};
  
  	const TestConfig::CommandBufferTypes commandBuffers[] =
  	{
  		TestConfig::COMMANDBUFFERTYPES_INLINE,
  		TestConfig::COMMANDBUFFERTYPES_SECONDARY,
  		TestConfig::COMMANDBUFFERTYPES_INLINE|TestConfig::COMMANDBUFFERTYPES_SECONDARY
  	};
  
  	const TestConfig::ImageMemory imageMemories[] =
  	{
  		TestConfig::IMAGEMEMORY_STRICT,
  		TestConfig::IMAGEMEMORY_LAZY,
  		TestConfig::IMAGEMEMORY_STRICT|TestConfig::IMAGEMEMORY_LAZY
  	};
  
  	const UVec2 targetSizes[] =
  	{
  		UVec2(64, 64),
  		UVec2(63, 65)
  	};
  
  	const UVec2 renderPositions[] =
  	{
  		UVec2(0, 0),
  		UVec2(3, 17)
  	};
  
  	const UVec2 renderSizes[] =
  	{
  		UVec2(32, 32),
  		UVec2(60, 47)
  	};
  
  	tcu::TestContext&	testCtx	= group->getTestContext();
  	de::Random			rng		(1433774382u);
  
  	for (size_t attachmentCountNdx = 0; attachmentCountNdx < DE_LENGTH_OF_ARRAY(attachmentCounts); attachmentCountNdx++)
  	{
  		const deUint32					attachmentCount			= attachmentCounts[attachmentCountNdx];
  		const deUint32					testCaseCount			= (attachmentCount == 1 ? 100 : 200);
  		de::MovePtr<tcu::TestCaseGroup>	attachmentCountGroup	(new tcu::TestCaseGroup(testCtx, de::toString(attachmentCount).c_str(), de::toString(attachmentCount).c_str()));
  
  		for (size_t testCaseNdx = 0; testCaseNdx < testCaseCount; testCaseNdx++)
  		{
  			const bool					useDepthStencil		= rng.getBool();
  			VkImageLayout				depthStencilLayout	= VK_IMAGE_LAYOUT_GENERAL;
  			vector<Attachment>			attachments;
  			vector<AttachmentReference>	colorAttachmentReferences;
  
  			for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++)
  			{
  				const VkSampleCountFlagBits	sampleCount		= VK_SAMPLE_COUNT_1_BIT;
  				const VkFormat				format			= rng.choose<VkFormat>(DE_ARRAY_BEGIN(s_coreColorFormats), DE_ARRAY_END(s_coreColorFormats));
  				const VkAttachmentLoadOp	loadOp			= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
  				const VkAttachmentStoreOp	storeOp			= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
  
  				const VkImageLayout			initialLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts));
  				const VkImageLayout			finalizeLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts));
  				const VkImageLayout			subpassLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
  
  				const VkAttachmentLoadOp	stencilLoadOp	= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
  				const VkAttachmentStoreOp	stencilStoreOp	= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
  
  				attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout));
  				colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
  			}
  
  			if (useDepthStencil)
  			{
  				const VkSampleCountFlagBits	sampleCount		= VK_SAMPLE_COUNT_1_BIT;
  				const VkFormat				format			= rng.choose<VkFormat>(DE_ARRAY_BEGIN(s_coreDepthStencilFormats), DE_ARRAY_END(s_coreDepthStencilFormats));
  				const VkAttachmentLoadOp	loadOp			= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
  				const VkAttachmentStoreOp	storeOp			= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
  
  				const VkImageLayout			initialLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts));
  				const VkImageLayout			finalizeLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts));
  
  				const VkAttachmentLoadOp	stencilLoadOp	= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
  				const VkAttachmentStoreOp	stencilStoreOp	= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
  
  				depthStencilLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(depthStencilLayouts), DE_ARRAY_END(depthStencilLayouts));
  				attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout));
  			}
  
  			{
  				const TestConfig::RenderTypes			render			= rng.choose<TestConfig::RenderTypes>(DE_ARRAY_BEGIN(renderCommands), DE_ARRAY_END(renderCommands));
  				const TestConfig::CommandBufferTypes	commandBuffer	= rng.choose<TestConfig::CommandBufferTypes>(DE_ARRAY_BEGIN(commandBuffers), DE_ARRAY_END(commandBuffers));
  				const TestConfig::ImageMemory			imageMemory		= rng.choose<TestConfig::ImageMemory>(DE_ARRAY_BEGIN(imageMemories), DE_ARRAY_END(imageMemories));
  				const vector<Subpass>					subpasses		(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference((useDepthStencil ? (deUint32)(attachments.size() - 1) : VK_ATTACHMENT_UNUSED), depthStencilLayout), vector<deUint32>()));
  				const vector<SubpassDependency>			deps;
  
  				const string							testCaseName	= de::toString(attachmentCountNdx * testCaseCount + testCaseNdx);
  				const RenderPass						renderPass		(attachments, subpasses, deps);
  				const UVec2								targetSize		= rng.choose<UVec2>(DE_ARRAY_BEGIN(targetSizes), DE_ARRAY_END(targetSizes));
  				const UVec2								renderPos		= rng.choose<UVec2>(DE_ARRAY_BEGIN(renderPositions), DE_ARRAY_END(renderPositions));
  				const UVec2								renderSize		= rng.choose<UVec2>(DE_ARRAY_BEGIN(renderSizes), DE_ARRAY_END(renderSizes));
  
  				addFunctionCaseWithPrograms<TestConfig>(attachmentCountGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, TestConfig(renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, 1293809));
  			}
  		}
  
  		group->addChild(attachmentCountGroup.release());
  	}
  }
  
  template<typename T>
  T chooseRandom (de::Random& rng, const set<T>& values)
  {
  	size_t							ndx		= ((size_t)rng.getUint32()) % values.size();
  	typename set<T>::const_iterator	iter	= values.begin();
  
  	for (; ndx > 0; ndx--)
  		iter++;
  
  	return *iter;
  }
  
  void addAttachmentAllocationTests (tcu::TestCaseGroup* group)
  {
  	const deUint32 attachmentCounts[] = { 4, 8 };
  	const VkAttachmentLoadOp loadOps[] =
  	{
  		VK_ATTACHMENT_LOAD_OP_LOAD,
  		VK_ATTACHMENT_LOAD_OP_CLEAR,
  		VK_ATTACHMENT_LOAD_OP_DONT_CARE
  	};
  
  	const VkAttachmentStoreOp storeOps[] =
  	{
  		VK_ATTACHMENT_STORE_OP_STORE,
  		VK_ATTACHMENT_STORE_OP_DONT_CARE
  	};
  
  	const VkImageLayout initialAndFinalColorLayouts[] =
  	{
  		VK_IMAGE_LAYOUT_GENERAL,
  		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  		VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
  		VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
  	};
  
  	const VkImageLayout initialAndFinalDepthStencilLayouts[] =
  	{
  		VK_IMAGE_LAYOUT_GENERAL,
  		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
  		VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
  		VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
  		VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
  	};
  
  	const VkImageLayout subpassLayouts[] =
  	{
  		VK_IMAGE_LAYOUT_GENERAL,
  		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  	};
  
  	enum AllocationType
  	{
  		// Each pass uses one more attachmen than previous one
  		ALLOCATIONTYPE_GROW,
  		// Each pass uses one less attachment than previous one
  		ALLOCATIONTYPE_SHRINK,
  		// Each pass drops one attachment and picks up new one
  		ALLOCATIONTYPE_ROLL,
  		// Start by growing and end by shrinking
  		ALLOCATIONTYPE_GROW_SHRINK,
  		// Each subpass has single input and single output attachment
  		ALLOCATIONTYPE_IO_CHAIN,
  		// Each subpass has multiple inputs and multiple outputs attachment
  		ALLOCATIONTYPE_IO_GENERIC
  	};
  
  	const AllocationType allocationTypes[] =
  	{
  		ALLOCATIONTYPE_GROW,
  		ALLOCATIONTYPE_SHRINK,
  		ALLOCATIONTYPE_ROLL,
  		ALLOCATIONTYPE_GROW_SHRINK,
  		ALLOCATIONTYPE_IO_CHAIN,
  		ALLOCATIONTYPE_IO_GENERIC
  	};
  
  	const char* const allocationTypeStr[] =
  	{
  		"grow",
  		"shrink",
  		"roll",
  		"grow_shrink",
  		"input_output_chain",
  		"input_output",
  	};
  
  	const TestConfig::RenderTypes renderCommands[] =
  	{
  		TestConfig::RENDERTYPES_NONE,
  		TestConfig::RENDERTYPES_CLEAR,
  		TestConfig::RENDERTYPES_DRAW,
  		TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW,
  	};
  
  	const TestConfig::CommandBufferTypes commandBuffers[] =
  	{
  		TestConfig::COMMANDBUFFERTYPES_INLINE,
  		TestConfig::COMMANDBUFFERTYPES_SECONDARY,
  		TestConfig::COMMANDBUFFERTYPES_INLINE|TestConfig::COMMANDBUFFERTYPES_SECONDARY
  	};
  
  	const TestConfig::ImageMemory imageMemories[] =
  	{
  		TestConfig::IMAGEMEMORY_STRICT,
  		TestConfig::IMAGEMEMORY_LAZY,
  		TestConfig::IMAGEMEMORY_STRICT|TestConfig::IMAGEMEMORY_LAZY
  	};
  
  	const UVec2 targetSizes[] =
  	{
  		UVec2(64, 64),
  		UVec2(63, 65)
  	};
  
  	const UVec2 renderPositions[] =
  	{
  		UVec2(0, 0),
  		UVec2(3, 17)
  	};
  
  	const UVec2 renderSizes[] =
  	{
  		UVec2(32, 32),
  		UVec2(60, 47)
  	};
  
  	tcu::TestContext&				testCtx	= group->getTestContext();
  	de::Random						rng		(3700649827u);
  
  	for (size_t allocationTypeNdx = 0; allocationTypeNdx < DE_LENGTH_OF_ARRAY(allocationTypes); allocationTypeNdx++)
  	{
  		const AllocationType			allocationType		= allocationTypes[allocationTypeNdx];
  		const size_t					testCaseCount		= 100;
  		de::MovePtr<tcu::TestCaseGroup>	allocationTypeGroup	(new tcu::TestCaseGroup(testCtx, allocationTypeStr[allocationTypeNdx], allocationTypeStr[allocationTypeNdx]));
  
  		for (size_t testCaseNdx = 0; testCaseNdx < testCaseCount; testCaseNdx++)
  		{
  			if (allocationType == ALLOCATIONTYPE_IO_GENERIC)
  			{
  				const deUint32		attachmentCount	= 4u + rng.getUint32() % 31u;
  				const deUint32		subpassCount	= 4u + rng.getUint32() % 31u;
  				vector<Attachment>	attachments;
  
  				set<deUint32>		definedAttachments;
  
  				vector<Subpass>		subpasses;
  				set<deUint32>		colorAttachments;
  				set<deUint32>		depthStencilAttachments;
  
  				for (deUint32 attachmentIndex = 0; attachmentIndex < attachmentCount; attachmentIndex++)
  				{
  					const bool					isDepthStencilAttachment	= rng.getFloat() < 0.01f;
  					const VkSampleCountFlagBits	sampleCount					= VK_SAMPLE_COUNT_1_BIT;
  					const VkAttachmentLoadOp	loadOp						= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
  					const VkAttachmentStoreOp	storeOp						= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
  
  					const VkImageLayout			initialLayout				= isDepthStencilAttachment
  																			? rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts))
  																			: rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts));
  					const VkImageLayout			finalizeLayout				= isDepthStencilAttachment
  																			? rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts))
  																			: rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts));
  
  					const VkAttachmentLoadOp	stencilLoadOp				= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
  					const VkAttachmentStoreOp	stencilStoreOp				= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
  
  					if (isDepthStencilAttachment)
  					{
  						const VkFormat	format	= rng.choose<VkFormat>(DE_ARRAY_BEGIN(s_coreDepthStencilFormats), DE_ARRAY_END(s_coreDepthStencilFormats));
  
  						if (loadOp == VK_ATTACHMENT_LOAD_OP_LOAD || loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
  							|| stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD || stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
  							definedAttachments.insert(attachmentIndex);
  
  						depthStencilAttachments.insert(attachmentIndex);
  
  						attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout));
  					}
  					else
  					{
  						const VkFormat	format	= rng.choose<VkFormat>(DE_ARRAY_BEGIN(s_coreColorFormats), DE_ARRAY_END(s_coreColorFormats));
  
  						if (loadOp == VK_ATTACHMENT_LOAD_OP_LOAD || loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
  							definedAttachments.insert(attachmentIndex);
  
  						colorAttachments.insert(attachmentIndex);
  
  						attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout));
  					}
  				}
  				vector<Maybe<deUint32> >	lastUseOfAttachment	(attachments.size(), nothing<deUint32>());
  				vector<SubpassDependency>	deps;
  
  				for (deUint32 subpassIndex = 0; subpassIndex < subpassCount; subpassIndex++)
  				{
  					const deUint32				colorAttachmentCount		= depthStencilAttachments.empty()
  																			? 1 + rng.getUint32() % de::min(4u, (deUint32)colorAttachments.size())
  																			: rng.getUint32() % (de::min(4u, (deUint32)colorAttachments.size()) + 1u);
  					const deUint32				inputAttachmentCount		= rng.getUint32() % (deUint32)(de::min<size_t>(4, definedAttachments.size()) + 1);
  					const bool					useDepthStencilAttachment	= !depthStencilAttachments.empty() && (colorAttachmentCount == 0 || rng.getBool());
  					std::vector<deUint32>		subpassColorAttachments		(colorAttachmentCount);
  					std::vector<deUint32>		subpassInputAttachments		(inputAttachmentCount);
  					Maybe<deUint32>				depthStencilAttachment		(useDepthStencilAttachment
  																			? just(chooseRandom(rng, depthStencilAttachments))
  																			: nothing<deUint32>());
  					std::vector<deUint32>		subpassPreserveAttachments;
  
  					rng.choose(colorAttachments.begin(), colorAttachments.end(), subpassColorAttachments.begin(), colorAttachmentCount);
  					rng.choose(definedAttachments.begin(), definedAttachments.end(), subpassInputAttachments.begin(), inputAttachmentCount);
  
  					for (size_t colorAttachmentNdx = 0; colorAttachmentNdx < subpassColorAttachments.size(); colorAttachmentNdx++)
  						definedAttachments.insert(subpassColorAttachments[colorAttachmentNdx]);
  
  					if (depthStencilAttachment)
  						definedAttachments.insert(*depthStencilAttachment);
  
  					{
  						std::vector<AttachmentReference>	inputAttachmentReferences;
  						std::vector<AttachmentReference>	colorAttachmentReferences;
  						AttachmentReference					depthStencilAttachmentReference (VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL);
  
  						for (size_t colorAttachmentNdx = 0; colorAttachmentNdx < subpassColorAttachments.size(); colorAttachmentNdx++)
  						{
  							const deUint32		colorAttachmentIndex	= subpassColorAttachments[colorAttachmentNdx];
  							// \todo [mika 2016-08-25] Check if attachment is not used as input attachment and use other image layouts
  							const VkImageLayout	subpassLayout			= VK_IMAGE_LAYOUT_GENERAL;
  
  							if (lastUseOfAttachment[colorAttachmentIndex])
  							{
  								const bool byRegion = rng.getBool();
  
  								deps.push_back(SubpassDependency(*lastUseOfAttachment[colorAttachmentIndex], subpassIndex,
  																 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  																	| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  																	| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  																	| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  																 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  																	| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  																	| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  																	| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  																 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
  																 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
  
  																 byRegion ? (VkDependencyFlags)VK_DEPENDENCY_BY_REGION_BIT : 0u));
  							}
  
  							lastUseOfAttachment[colorAttachmentIndex] = just(subpassIndex);
  
  							colorAttachmentReferences.push_back(AttachmentReference((deUint32)subpassColorAttachments[colorAttachmentNdx], subpassLayout));
  						}
  
  						for (size_t inputAttachmentNdx = 0; inputAttachmentNdx < subpassInputAttachments.size(); inputAttachmentNdx++)
  						{
  							const deUint32		inputAttachmentIndex	= subpassInputAttachments[inputAttachmentNdx];
  							// \todo [mika 2016-08-25] Check if attachment is not used as color attachment and use other image layouts
  							const VkImageLayout	subpassLayout			= VK_IMAGE_LAYOUT_GENERAL;
  
  							if(lastUseOfAttachment[inputAttachmentIndex])
  							{
  								if(*lastUseOfAttachment[inputAttachmentIndex] == subpassIndex)
  								{
  									deps.push_back(SubpassDependency(subpassIndex, subpassIndex,
  																	 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  																		| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  																		| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  																		| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  																	 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  																		| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  																		| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  																		| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  																	 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
  																	 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
  
  																	 VK_DEPENDENCY_BY_REGION_BIT));
  								}
  								else
  								{
  									const bool byRegion = rng.getBool();
  
  									deps.push_back(SubpassDependency(*lastUseOfAttachment[inputAttachmentIndex], subpassIndex,
  																	 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  																		| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  																		| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  																		| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  																	 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  																		| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  																		| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  																		| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  																	 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
  																	 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
  
  																	 byRegion ? (VkDependencyFlags)VK_DEPENDENCY_BY_REGION_BIT : 0u));
  								}
  
  								lastUseOfAttachment[inputAttachmentIndex] = just(subpassIndex);
  
  								inputAttachmentReferences.push_back(AttachmentReference((deUint32)subpassInputAttachments[inputAttachmentNdx], subpassLayout));
  							}
  						}
  
  						if (depthStencilAttachment)
  						{
  							// \todo [mika 2016-08-25] Check if attachment is not used as input attachment and use other image layouts
  							if (lastUseOfAttachment[*depthStencilAttachment])
  							{
  								if(*lastUseOfAttachment[*depthStencilAttachment] == subpassIndex)
  								{
  									deps.push_back(SubpassDependency(subpassIndex, subpassIndex,
  																	 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  																		| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  																		| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  																		| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  																	 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  																		| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  																		| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  																		| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  																	 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
  																	 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
  
  																	 VK_DEPENDENCY_BY_REGION_BIT));
  								}
  								else
  								{
  									const bool byRegion = rng.getBool();
  
  									deps.push_back(SubpassDependency(*lastUseOfAttachment[*depthStencilAttachment], subpassIndex,
  																	 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  																		| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  																		| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  																		| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  																	 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  																		| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  																		| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  																		| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  																	 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
  																	 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
  
  																	 byRegion ? (VkDependencyFlags)VK_DEPENDENCY_BY_REGION_BIT : 0u));
  								}
  							}
  
  							lastUseOfAttachment[*depthStencilAttachment] = just(subpassIndex);
  							depthStencilAttachmentReference = AttachmentReference(*depthStencilAttachment, VK_IMAGE_LAYOUT_GENERAL);
  						}
  						else
  							depthStencilAttachmentReference = AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL);
  
  						vector<deUint32>	preserveAttachments;
  						for (deUint32 attachmentIndex = 0; attachmentIndex < (deUint32)attachments.size(); attachmentIndex++)
  						{
  							if (lastUseOfAttachment[attachmentIndex] && (*lastUseOfAttachment[attachmentIndex]) != subpassIndex)
  								preserveAttachments.push_back(attachmentIndex);
  						}
  
  						subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u,
  												inputAttachmentReferences,
  												colorAttachmentReferences,
  												vector<AttachmentReference>(),
  												depthStencilAttachmentReference,
  												preserveAttachments));
  					}
  				}
  				{
  					const TestConfig::RenderTypes			render			= rng.choose<TestConfig::RenderTypes>(DE_ARRAY_BEGIN(renderCommands), DE_ARRAY_END(renderCommands));
  					const TestConfig::CommandBufferTypes	commandBuffer	= rng.choose<TestConfig::CommandBufferTypes>(DE_ARRAY_BEGIN(commandBuffers), DE_ARRAY_END(commandBuffers));
  					const TestConfig::ImageMemory			imageMemory		= rng.choose<TestConfig::ImageMemory>(DE_ARRAY_BEGIN(imageMemories), DE_ARRAY_END(imageMemories));
  
  					const string							testCaseName	= de::toString(testCaseNdx);
  					const UVec2								targetSize		= rng.choose<UVec2>(DE_ARRAY_BEGIN(targetSizes), DE_ARRAY_END(targetSizes));
  					const UVec2								renderPos		= rng.choose<UVec2>(DE_ARRAY_BEGIN(renderPositions), DE_ARRAY_END(renderPositions));
  					const UVec2								renderSize		= rng.choose<UVec2>(DE_ARRAY_BEGIN(renderSizes), DE_ARRAY_END(renderSizes));
  
  					const RenderPass						renderPass		(attachments, subpasses, deps);
  
  					addFunctionCaseWithPrograms<TestConfig>(allocationTypeGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, TestConfig(renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, 80329));
  				}
  			}
  			else
  			{
  				const deUint32		attachmentCount	= rng.choose<deUint32>(DE_ARRAY_BEGIN(attachmentCounts), DE_ARRAY_END(attachmentCounts));
  				vector<Attachment>	attachments;
  				vector<Subpass>		subpasses;
  
  				for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++)
  				{
  					const VkSampleCountFlagBits	sampleCount		= VK_SAMPLE_COUNT_1_BIT;
  					const VkFormat				format			= rng.choose<VkFormat>(DE_ARRAY_BEGIN(s_coreColorFormats), DE_ARRAY_END(s_coreColorFormats));
  					const VkAttachmentLoadOp	loadOp			= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
  					const VkAttachmentStoreOp	storeOp			= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
  
  					const VkImageLayout			initialLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts));
  					const VkImageLayout			finalizeLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts));
  
  					const VkAttachmentLoadOp	stencilLoadOp	= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
  					const VkAttachmentStoreOp	stencilStoreOp	= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
  
  					attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout));
  				}
  
  				if (allocationType == ALLOCATIONTYPE_GROW)
  				{
  					for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
  					{
  						vector<AttachmentReference>	colorAttachmentReferences;
  
  						for (size_t attachmentNdx = 0; attachmentNdx < subpassNdx + 1; attachmentNdx++)
  						{
  							const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
  
  							colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
  						}
  
  						subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u,
  												vector<AttachmentReference>(),
  												colorAttachmentReferences,
  												vector<AttachmentReference>(),
  												AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  												vector<deUint32>()));
  					}
  				}
  				else if (allocationType == ALLOCATIONTYPE_SHRINK)
  				{
  					for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
  					{
  						vector<AttachmentReference>	colorAttachmentReferences;
  
  						for (size_t attachmentNdx = 0; attachmentNdx < (attachmentCount - subpassNdx); attachmentNdx++)
  						{
  							const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
  
  							colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
  						}
  
  						subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u,
  													vector<AttachmentReference>(),
  													colorAttachmentReferences,
  													vector<AttachmentReference>(),
  													AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  													vector<deUint32>()));
  					}
  				}
  				else if (allocationType == ALLOCATIONTYPE_ROLL)
  				{
  					for (size_t subpassNdx = 0; subpassNdx < attachmentCount / 2; subpassNdx++)
  					{
  						vector<AttachmentReference>	colorAttachmentReferences;
  
  						for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount / 2; attachmentNdx++)
  						{
  							const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
  
  							colorAttachmentReferences.push_back(AttachmentReference((deUint32)(subpassNdx + attachmentNdx), subpassLayout));
  						}
  
  						subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u,
  													vector<AttachmentReference>(),
  													colorAttachmentReferences,
  													vector<AttachmentReference>(),
  													AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  													vector<deUint32>()));
  					}
  				}
  				else if (allocationType == ALLOCATIONTYPE_GROW_SHRINK)
  				{
  					for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
  					{
  						vector<AttachmentReference>	colorAttachmentReferences;
  
  						for (size_t attachmentNdx = 0; attachmentNdx < subpassNdx + 1; attachmentNdx++)
  						{
  							const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
  
  							colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
  						}
  
  						subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u,
  													vector<AttachmentReference>(),
  													colorAttachmentReferences,
  													vector<AttachmentReference>(),
  													AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  													vector<deUint32>()));
  					}
  
  					for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
  					{
  						vector<AttachmentReference>	colorAttachmentReferences;
  
  						for (size_t attachmentNdx = 0; attachmentNdx < (attachmentCount - subpassNdx); attachmentNdx++)
  						{
  							const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
  
  							colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
  						}
  
  						subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u,
  											vector<AttachmentReference>(),
  											colorAttachmentReferences,
  											vector<AttachmentReference>(),
  											AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  											vector<deUint32>()));
  					}
  				}
  				else if (allocationType == ALLOCATIONTYPE_IO_CHAIN)
  				{
  					subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u,
  											vector<AttachmentReference>(),
  											vector<AttachmentReference>(1, AttachmentReference(0, rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts)))),
  											vector<AttachmentReference>(),
  											AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  											vector<deUint32>()));
  
  					for (size_t subpassNdx = 1; subpassNdx < attachmentCount; subpassNdx++)
  					{
  						subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u,
  												vector<AttachmentReference>(1, AttachmentReference((deUint32)(subpassNdx - 1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)),
  												vector<AttachmentReference>(1, AttachmentReference((deUint32)(subpassNdx), rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts)))),
  												vector<AttachmentReference>(),
  												AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  												vector<deUint32>()));
  					}
  				}
  				else
  					DE_FATAL("Unknown allocation type");
  
  				{
  					const TestConfig::RenderTypes			render			= rng.choose<TestConfig::RenderTypes>(DE_ARRAY_BEGIN(renderCommands), DE_ARRAY_END(renderCommands));
  					const TestConfig::CommandBufferTypes	commandBuffer	= rng.choose<TestConfig::CommandBufferTypes>(DE_ARRAY_BEGIN(commandBuffers), DE_ARRAY_END(commandBuffers));
  					const TestConfig::ImageMemory			imageMemory		= rng.choose<TestConfig::ImageMemory>(DE_ARRAY_BEGIN(imageMemories), DE_ARRAY_END(imageMemories));
  
  					const string							testCaseName	= de::toString(testCaseNdx);
  					const UVec2								targetSize		= rng.choose<UVec2>(DE_ARRAY_BEGIN(targetSizes), DE_ARRAY_END(targetSizes));
  					const UVec2								renderPos		= rng.choose<UVec2>(DE_ARRAY_BEGIN(renderPositions), DE_ARRAY_END(renderPositions));
  					const UVec2								renderSize		= rng.choose<UVec2>(DE_ARRAY_BEGIN(renderSizes), DE_ARRAY_END(renderSizes));
  
  					vector<SubpassDependency>				deps;
  
  					for (size_t subpassNdx = 0; subpassNdx < subpasses.size() - 1; subpassNdx++)
  					{
  						const bool byRegion				= rng.getBool();
  						deps.push_back(SubpassDependency((deUint32)subpassNdx, (deUint32)subpassNdx + 1,
  														 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  															| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  															| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  															| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  														 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  															| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  															| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  															| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  
  														 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
  														 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
  
  														 byRegion ? (VkDependencyFlags)VK_DEPENDENCY_BY_REGION_BIT : 0u));
  					}
  
  					const RenderPass					renderPass		(attachments, subpasses, deps);
  
  					addFunctionCaseWithPrograms<TestConfig>(allocationTypeGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, TestConfig(renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, 80329));
  				}
  			}
  		}
  		group->addChild(allocationTypeGroup.release());
  	}
  }
  
  void addSimpleTests (tcu::TestCaseGroup* group)
  {
  	const UVec2	targetSize	(64, 64);
  	const UVec2	renderPos	(0, 0);
  	const UVec2	renderSize	(64, 64);
  
  	// color
  	{
  		const RenderPass	renderPass	(vector<Attachment>(1, Attachment(VK_FORMAT_R8G8B8A8_UNORM,
  																		  VK_SAMPLE_COUNT_1_BIT,
  																		  VK_ATTACHMENT_LOAD_OP_CLEAR,
  																		  VK_ATTACHMENT_STORE_OP_STORE,
  																		  VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  																		  VK_ATTACHMENT_STORE_OP_DONT_CARE,
  																		  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  																		  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
  										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  																	0u,
  																	vector<AttachmentReference>(),
  																	vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
  																	vector<AttachmentReference>(),
  																	AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  																	vector<deUint32>())),
  										 vector<SubpassDependency>());
  
  		addFunctionCaseWithPrograms<TestConfig>(group, "color", "Single color attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
  	}
  
  	// depth
  	{
  		const RenderPass	renderPass	(vector<Attachment>(1, Attachment(VK_FORMAT_X8_D24_UNORM_PACK32,
  																		  VK_SAMPLE_COUNT_1_BIT,
  																		  VK_ATTACHMENT_LOAD_OP_CLEAR,
  																		  VK_ATTACHMENT_STORE_OP_STORE,
  																		  VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  																		  VK_ATTACHMENT_STORE_OP_DONT_CARE,
  																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
  																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)),
  										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  																	0u,
  																	vector<AttachmentReference>(),
  																	vector<AttachmentReference>(),
  																	vector<AttachmentReference>(),
  																	AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  																	vector<deUint32>())),
  										 vector<SubpassDependency>());
  
  		addFunctionCaseWithPrograms<TestConfig>(group, "depth", "Single depth attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
  	}
  
  	// stencil
  	{
  		const RenderPass	renderPass	(vector<Attachment>(1, Attachment(VK_FORMAT_S8_UINT,
  																		  VK_SAMPLE_COUNT_1_BIT,
  																		  VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  																		  VK_ATTACHMENT_STORE_OP_DONT_CARE,
  																		  VK_ATTACHMENT_LOAD_OP_CLEAR,
  																		  VK_ATTACHMENT_STORE_OP_STORE,
  																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
  																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)),
  										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  																	0u,
  																	vector<AttachmentReference>(),
  																	vector<AttachmentReference>(),
  																	vector<AttachmentReference>(),
  																	AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  																	vector<deUint32>())),
  										 vector<SubpassDependency>());
  
  		addFunctionCaseWithPrograms<TestConfig>(group, "stencil", "Single stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
  	}
  
  	// depth_stencil
  	{
  		const RenderPass	renderPass	(vector<Attachment>(1, Attachment(VK_FORMAT_D24_UNORM_S8_UINT,
  																		  VK_SAMPLE_COUNT_1_BIT,
  																		  VK_ATTACHMENT_LOAD_OP_CLEAR,
  																		  VK_ATTACHMENT_STORE_OP_STORE,
  																		  VK_ATTACHMENT_LOAD_OP_CLEAR,
  																		  VK_ATTACHMENT_STORE_OP_STORE,
  																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
  																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)),
  										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  																	0u,
  																	vector<AttachmentReference>(),
  																	vector<AttachmentReference>(),
  																	vector<AttachmentReference>(),
  																	AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  																	vector<deUint32>())),
  										 vector<SubpassDependency>());
  
  		addFunctionCaseWithPrograms<TestConfig>(group, "depth_stencil", "Single depth stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
  	}
  
  	// color_depth
  	{
  		const Attachment	attachments[] =
  		{
  			Attachment(VK_FORMAT_R8G8B8A8_UNORM,
  					   VK_SAMPLE_COUNT_1_BIT,
  					   VK_ATTACHMENT_LOAD_OP_CLEAR,
  					   VK_ATTACHMENT_STORE_OP_STORE,
  					   VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  					   VK_ATTACHMENT_STORE_OP_DONT_CARE,
  					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
  			Attachment(VK_FORMAT_X8_D24_UNORM_PACK32,
  					   VK_SAMPLE_COUNT_1_BIT,
  					   VK_ATTACHMENT_LOAD_OP_CLEAR,
  					   VK_ATTACHMENT_STORE_OP_STORE,
  					   VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  					   VK_ATTACHMENT_STORE_OP_DONT_CARE,
  					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
  					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  		};
  
  		const RenderPass	renderPass	(vector<Attachment>(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)),
  										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  																	0u,
  																	vector<AttachmentReference>(),
  																	vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
  																	vector<AttachmentReference>(),
  																	AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  																	vector<deUint32>())),
  										 vector<SubpassDependency>());
  
  		addFunctionCaseWithPrograms<TestConfig>(group, "color_depth", "Color and depth attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
  	}
  
  	// color_stencil
  	{
  		const Attachment	attachments[] =
  		{
  			Attachment(VK_FORMAT_R8G8B8A8_UNORM,
  					   VK_SAMPLE_COUNT_1_BIT,
  					   VK_ATTACHMENT_LOAD_OP_CLEAR,
  					   VK_ATTACHMENT_STORE_OP_STORE,
  					   VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  					   VK_ATTACHMENT_STORE_OP_DONT_CARE,
  					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
  			Attachment(VK_FORMAT_S8_UINT,
  					   VK_SAMPLE_COUNT_1_BIT,
  					   VK_ATTACHMENT_LOAD_OP_CLEAR,
  					   VK_ATTACHMENT_STORE_OP_STORE,
  					   VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  					   VK_ATTACHMENT_STORE_OP_DONT_CARE,
  					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
  					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  		};
  
  		const RenderPass	renderPass	(vector<Attachment>(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)),
  										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  																	0u,
  																	vector<AttachmentReference>(),
  																	vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
  																	vector<AttachmentReference>(),
  																	AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  																	vector<deUint32>())),
  										 vector<SubpassDependency>());
  
  
  		addFunctionCaseWithPrograms<TestConfig>(group, "color_stencil", "Color and stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
  	}
  
  	// color_depth_stencil
  	{
  		const Attachment	attachments[] =
  		{
  			Attachment(VK_FORMAT_R8G8B8A8_UNORM,
  					   VK_SAMPLE_COUNT_1_BIT,
  					   VK_ATTACHMENT_LOAD_OP_CLEAR,
  					   VK_ATTACHMENT_STORE_OP_STORE,
  					   VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  					   VK_ATTACHMENT_STORE_OP_DONT_CARE,
  					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
  			Attachment(VK_FORMAT_D24_UNORM_S8_UINT,
  					   VK_SAMPLE_COUNT_1_BIT,
  					   VK_ATTACHMENT_LOAD_OP_CLEAR,
  					   VK_ATTACHMENT_STORE_OP_STORE,
  					   VK_ATTACHMENT_LOAD_OP_CLEAR,
  					   VK_ATTACHMENT_STORE_OP_STORE,
  					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
  					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  		};
  
  		const RenderPass	renderPass	(vector<Attachment>(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)),
  										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  																	0u,
  																	vector<AttachmentReference>(),
  																	vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
  																	vector<AttachmentReference>(),
  																	AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  																	vector<deUint32>())),
  										 vector<SubpassDependency>());
  
  		addFunctionCaseWithPrograms<TestConfig>(group, "color_depth_stencil", "Color, depth and stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
  	}
  }
  
  std::string formatToName (VkFormat format)
  {
  	const std::string	formatStr	= de::toString(format);
  	const std::string	prefix		= "VK_FORMAT_";
  
  	DE_ASSERT(formatStr.substr(0, prefix.length()) == prefix);
  
  	return de::toLower(formatStr.substr(prefix.length()));
  }
  
  void addFormatTests (tcu::TestCaseGroup* group)
  {
  	tcu::TestContext&	testCtx		= group->getTestContext();
  
  	const UVec2			targetSize	(64, 64);
  	const UVec2			renderPos	(0, 0);
  	const UVec2			renderSize	(64, 64);
  
  	const struct
  	{
  		const char* const			str;
  		const VkAttachmentStoreOp	op;
  	} storeOps[] =
  	{
  		{ "store",		VK_ATTACHMENT_STORE_OP_STORE		},
  		{ "dont_care",	VK_ATTACHMENT_STORE_OP_DONT_CARE	}
  	};
  
  	const struct
  	{
  		const char* const			str;
  		const VkAttachmentLoadOp	op;
  	} loadOps[] =
  	{
  		{ "clear",		VK_ATTACHMENT_LOAD_OP_CLEAR		},
  		{ "load",		VK_ATTACHMENT_LOAD_OP_LOAD		},
  		{ "dont_care",	VK_ATTACHMENT_LOAD_OP_DONT_CARE	}
  	};
  
  	const struct
  	{
  		 const char* const				str;
  		 const TestConfig::RenderTypes	types;
  	} renderTypes[] =
  	{
  		{ "clear",		TestConfig::RENDERTYPES_CLEAR								},
  		{ "draw",		TestConfig::RENDERTYPES_DRAW								},
  		{ "clear_draw",	TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW	}
  	};
  
  	// Color formats
  	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_coreColorFormats); formatNdx++)
  	{
  		const VkFormat					format		= s_coreColorFormats[formatNdx];
  		de::MovePtr<tcu::TestCaseGroup>	formatGroup	(new tcu::TestCaseGroup(testCtx, formatToName(format).c_str(), de::toString(format).c_str()));
  
  		for (size_t loadOpNdx = 0; loadOpNdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpNdx++)
  		{
  			const VkAttachmentLoadOp		loadOp	= loadOps[loadOpNdx].op;
  			de::MovePtr<tcu::TestCaseGroup>	loadOpGroup	(new tcu::TestCaseGroup(testCtx, loadOps[loadOpNdx].str, loadOps[loadOpNdx].str));
  
  			for (size_t renderTypeNdx = 0; renderTypeNdx < DE_LENGTH_OF_ARRAY(renderTypes); renderTypeNdx++)
  			{
  				const RenderPass	renderPass	(vector<Attachment>(1, Attachment(format,
  																				  VK_SAMPLE_COUNT_1_BIT,
  																				  loadOp,
  																				  VK_ATTACHMENT_STORE_OP_STORE,
  																				  VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  																				  VK_ATTACHMENT_STORE_OP_DONT_CARE,
  																				  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  																				  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
  												 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  																			0u,
  																			vector<AttachmentReference>(),
  																			vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
  																			vector<AttachmentReference>(),
  																			AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  																			vector<deUint32>())),
  												 vector<SubpassDependency>());
  
  				addFunctionCaseWithPrograms<TestConfig>(loadOpGroup.get(), renderTypes[renderTypeNdx].str, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
  			}
  
  			formatGroup->addChild(loadOpGroup.release());
  		}
  
  		{
  			de::MovePtr<tcu::TestCaseGroup>	inputGroup (new tcu::TestCaseGroup(testCtx, "input", "Test attachment format as input"));
  
  			for (size_t loadOpNdx = 0; loadOpNdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpNdx++)
  			{
  				const VkAttachmentLoadOp		loadOp		= loadOps[loadOpNdx].op;
  				de::MovePtr<tcu::TestCaseGroup>	loadOpGroup	(new tcu::TestCaseGroup(testCtx, loadOps[loadOpNdx].str, loadOps[loadOpNdx].str));
  
  				for (size_t storeOpNdx = 0; storeOpNdx < DE_LENGTH_OF_ARRAY(storeOps); storeOpNdx++)
  				{
  					const VkAttachmentStoreOp		storeOp			= storeOps[storeOpNdx].op;
  					de::MovePtr<tcu::TestCaseGroup>	storeOpGroup	(new tcu::TestCaseGroup(testCtx, storeOps[storeOpNdx].str, storeOps[storeOpNdx].str));
  
  					for (size_t renderTypeNdx = 0; renderTypeNdx < DE_LENGTH_OF_ARRAY(renderTypes); renderTypeNdx++)
  					{
  						{
  							vector<Attachment>			attachments;
  							vector<Subpass>				subpasses;
  							vector<SubpassDependency>	deps;
  
  							attachments.push_back(Attachment(format,
  															 VK_SAMPLE_COUNT_1_BIT,
  															 loadOp,
  															 storeOp,
  															 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  															 VK_ATTACHMENT_STORE_OP_DONT_CARE,
  															 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  															 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
  
  							attachments.push_back(Attachment(vk::VK_FORMAT_R8G8B8A8_UNORM,
  															 VK_SAMPLE_COUNT_1_BIT,
  															 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  															 VK_ATTACHMENT_STORE_OP_STORE,
  															 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  															 VK_ATTACHMENT_STORE_OP_DONT_CARE,
  															 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  															 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
  
  							subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  														0u,
  														vector<AttachmentReference>(),
  														vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
  														vector<AttachmentReference>(),
  														AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  														vector<deUint32>()));
  							subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  														0u,
  														vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)),
  														vector<AttachmentReference>(1, AttachmentReference(1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
  														vector<AttachmentReference>(),
  														AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  														vector<deUint32>()));
  
  							deps.push_back(SubpassDependency(0, 1,
  
  															vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
  															vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
  
  															vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
  															vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
  															vk::VK_DEPENDENCY_BY_REGION_BIT));
  
  							{
  								const RenderPass renderPass (attachments, subpasses, deps);
  
  								addFunctionCaseWithPrograms<TestConfig>(storeOpGroup.get(), renderTypes[renderTypeNdx].str, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246));
  							}
  						}
  						{
  							vector<Attachment>			attachments;
  							vector<Subpass>				subpasses;
  							vector<SubpassDependency>	deps;
  
  							attachments.push_back(Attachment(format,
  															 VK_SAMPLE_COUNT_1_BIT,
  															 loadOp,
  															 storeOp,
  															 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  															 VK_ATTACHMENT_STORE_OP_DONT_CARE,
  															 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  															 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
  
  							subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  														0u,
  														vector<AttachmentReference>(),
  														vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
  														vector<AttachmentReference>(),
  														AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  														vector<deUint32>()));
  							subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  														0u,
  														vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_GENERAL)),
  														vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_GENERAL)),
  														vector<AttachmentReference>(),
  														AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  														vector<deUint32>()));
  
  							deps.push_back(SubpassDependency(0, 1,
  															vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
  															vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
  
  															vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
  															vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
  															vk::VK_DEPENDENCY_BY_REGION_BIT));
  
  							{
  								const RenderPass renderPass (attachments, subpasses, deps);
  
  								addFunctionCaseWithPrograms<TestConfig>(storeOpGroup.get(), string("self_dep_") + renderTypes[renderTypeNdx].str, string("self_dep_") + renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246));
  							}
  						}
  					}
  
  					loadOpGroup->addChild(storeOpGroup.release());
  				}
  
  				inputGroup->addChild(loadOpGroup.release());
  			}
  
  			formatGroup->addChild(inputGroup.release());
  		}
  
  		group->addChild(formatGroup.release());
  	}
  
  	// Depth stencil formats
  	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_coreDepthStencilFormats); formatNdx++)
  	{
  		const VkFormat					vkFormat		= s_coreDepthStencilFormats[formatNdx];
  		de::MovePtr<tcu::TestCaseGroup>	formatGroup	(new tcu::TestCaseGroup(testCtx, formatToName(vkFormat).c_str(), de::toString(vkFormat).c_str()));
  
  		for (size_t loadOpNdx = 0; loadOpNdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpNdx++)
  		{
  			const VkAttachmentLoadOp		loadOp	= loadOps[loadOpNdx].op;
  			de::MovePtr<tcu::TestCaseGroup>	loadOpGroup	(new tcu::TestCaseGroup(testCtx, loadOps[loadOpNdx].str, loadOps[loadOpNdx].str));
  
  			for (size_t renderTypeNdx = 0; renderTypeNdx < DE_LENGTH_OF_ARRAY(renderTypes); renderTypeNdx++)
  			{
  				const tcu::TextureFormat	format				= mapVkFormat(vkFormat);
  				const bool					isStencilAttachment	= hasStencilComponent(format.order);
  				const bool					isDepthAttachment	= hasDepthComponent(format.order);
  				const RenderPass			renderPass			(vector<Attachment>(1, Attachment(vkFormat,
  																				  VK_SAMPLE_COUNT_1_BIT,
  																				  isDepthAttachment ? loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  																				  isDepthAttachment ? VK_ATTACHMENT_STORE_OP_STORE :VK_ATTACHMENT_STORE_OP_DONT_CARE,
  																				  isStencilAttachment ? loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  																				  isStencilAttachment ? VK_ATTACHMENT_STORE_OP_STORE :VK_ATTACHMENT_STORE_OP_DONT_CARE,
  																				  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
  																				  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)),
  												 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  																			0u,
  																			vector<AttachmentReference>(),
  																			vector<AttachmentReference>(),
  																			vector<AttachmentReference>(),
  																			AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  																			vector<deUint32>())),
  												 vector<SubpassDependency>());
  
  				addFunctionCaseWithPrograms<TestConfig>(loadOpGroup.get(), renderTypes[renderTypeNdx].str, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
  			}
  
  			formatGroup->addChild(loadOpGroup.release());
  		}
  
  		{
  			de::MovePtr<tcu::TestCaseGroup>	inputGroup (new tcu::TestCaseGroup(testCtx, "input", "Test attachment format as input"));
  
  			for (size_t loadOpNdx = 0; loadOpNdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpNdx++)
  			{
  				const VkAttachmentLoadOp		loadOp		= loadOps[loadOpNdx].op;
  				de::MovePtr<tcu::TestCaseGroup>	loadOpGroup	(new tcu::TestCaseGroup(testCtx, loadOps[loadOpNdx].str, loadOps[loadOpNdx].str));
  
  				for (size_t storeOpNdx = 0; storeOpNdx < DE_LENGTH_OF_ARRAY(storeOps); storeOpNdx++)
  				{
  					const VkAttachmentStoreOp		storeOp			= storeOps[storeOpNdx].op;
  					de::MovePtr<tcu::TestCaseGroup>	storeOpGroup	(new tcu::TestCaseGroup(testCtx, storeOps[storeOpNdx].str, storeOps[storeOpNdx].str));
  
  					for (size_t renderTypeNdx = 0; renderTypeNdx < DE_LENGTH_OF_ARRAY(renderTypes); renderTypeNdx++)
  					{
  						{
  							vector<Attachment>			attachments;
  							vector<Subpass>				subpasses;
  							vector<SubpassDependency>	deps;
  
  							attachments.push_back(Attachment(vkFormat,
  															 VK_SAMPLE_COUNT_1_BIT,
  															 loadOp,
  															 storeOp,
  															 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  															 VK_ATTACHMENT_STORE_OP_DONT_CARE,
  															 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
  															 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
  
  							attachments.push_back(Attachment(vk::VK_FORMAT_R8G8B8A8_UNORM,
  															 VK_SAMPLE_COUNT_1_BIT,
  															 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  															 VK_ATTACHMENT_STORE_OP_STORE,
  															 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  															 VK_ATTACHMENT_STORE_OP_DONT_CARE,
  															 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
  															 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
  
  							subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  														0u,
  														vector<AttachmentReference>(),
  														vector<AttachmentReference>(),
  														vector<AttachmentReference>(),
  														AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  														vector<deUint32>()));
  							subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  														0u,
  														vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)),
  														vector<AttachmentReference>(1, AttachmentReference(1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
  														vector<AttachmentReference>(),
  														AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
  														vector<deUint32>()));
  
  							deps.push_back(SubpassDependency(0, 1,
  															vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
  															vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
  
  															vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
  															vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
  															0u));
  
  							deps.push_back(SubpassDependency(1, 1,
  															vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
  															vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
  
  															vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
  															vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
  															vk::VK_DEPENDENCY_BY_REGION_BIT));
  							{
  								const RenderPass renderPass (attachments, subpasses, deps);
  
  								addFunctionCaseWithPrograms<TestConfig>(storeOpGroup.get(), renderTypes[renderTypeNdx].str, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246));
  							}
  						}
  						{
  							vector<Attachment>			attachments;
  							vector<Subpass>				subpasses;
  							vector<SubpassDependency>	deps;
  
  							attachments.push_back(Attachment(vkFormat,
  															 VK_SAMPLE_COUNT_1_BIT,
  															 loadOp,
  															 storeOp,
  															 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  															 VK_ATTACHMENT_STORE_OP_DONT_CARE,
  															 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
  															 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
  
  							subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  														0u,
  														vector<AttachmentReference>(),
  														vector<AttachmentReference>(),
  														vector<AttachmentReference>(),
  														AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
  														vector<deUint32>()));
  							subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
  														0u,
  														vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_GENERAL)),
  														vector<AttachmentReference>(),
  														vector<AttachmentReference>(),
  														AttachmentReference(0, VK_IMAGE_LAYOUT_GENERAL),
  														vector<deUint32>()));
  
  							deps.push_back(SubpassDependency(0, 1,
  															vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
  															vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
  
  															vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
  															vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
  															vk::VK_DEPENDENCY_BY_REGION_BIT));
  
  							{
  								const RenderPass renderPass (attachments, subpasses, deps);
  
  								addFunctionCaseWithPrograms<TestConfig>(storeOpGroup.get(), string("self_dep_") + renderTypes[renderTypeNdx].str, string("self_dep_") + renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246));
  							}
  						}
  					}
  
  					loadOpGroup->addChild(storeOpGroup.release());
  				}
  
  				inputGroup->addChild(loadOpGroup.release());
  			}
  
  			formatGroup->addChild(inputGroup.release());
  		}
  
  		group->addChild(formatGroup.release());
  	}
  }
  
  } // anonymous
  
  tcu::TestCaseGroup* createRenderPassTests (tcu::TestContext& testCtx)
  {
  	de::MovePtr<tcu::TestCaseGroup>	renderpassTests	(new tcu::TestCaseGroup(testCtx, "renderpass", "RenderPass Tests"));
  
  	addTestGroup(renderpassTests.get(), "simple", "Simple basic render pass tests", addSimpleTests);
  	addTestGroup(renderpassTests.get(), "formats", "Tests for different image formats.", addFormatTests);
  	addTestGroup(renderpassTests.get(), "attachment", "Attachment format and count tests with load and store ops and image layouts", addAttachmentTests);
  	addTestGroup(renderpassTests.get(), "attachment_allocation", "Attachment allocation tests", addAttachmentAllocationTests);
  
  	return renderpassTests.release();
  }
  
  } // vkt
  