text: /*-------------------------------------------------------------------------
   * Vulkan Conformance Tests
   * ------------------------
   *
   * Copyright (c) 2015 The Khronos Group Inc.
   * Copyright (c) 2015 Samsung Electronics Co., Ltd.
   * 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.
   *
   *//*--------------------------------------------------------------------*/
  
  #include "vkDefs.hpp"
  #include "vktTestCaseUtil.hpp"
  #include "vkBuilderUtil.hpp"
  #include "vkPlatform.hpp"
  #include "vkRefUtil.hpp"
  #include "vkQueryUtil.hpp"
  #include "vkMemUtil.hpp"
  #include "vkDeviceUtil.hpp"
  #include "vkCmdUtil.hpp"
  #include "vkObjUtil.hpp"
  #include "tcuTextureUtil.hpp"
  #include "vkImageUtil.hpp"
  #include "vkPrograms.hpp"
  #include "vkTypeUtil.hpp"
  #include "vkAllocationCallbackUtil.hpp"
  #include "vkCmdUtil.hpp"
  #include "vkBarrierUtil.hpp"
  #include "vkBufferWithMemory.hpp"
  #include "vkImageWithMemory.hpp"
  #include "vktApiCommandBuffersTests.hpp"
  #include "vktApiBufferComputeInstance.hpp"
  #include "vktApiComputeInstanceResultBuffer.hpp"
  #include "deSharedPtr.hpp"
  #include "deRandom.hpp"
  #include <sstream>
  #include <limits>
  
  namespace vkt
  {
  namespace api
  {
  namespace
  {
  
  using namespace vk;
  
  typedef de::SharedPtr<vk::Unique<vk::VkEvent> >	VkEventSp;
  
  // Global variables
  const deUint64								INFINITE_TIMEOUT		= ~(deUint64)0u;
  
  
  template <deUint32 NumBuffers>
  class CommandBufferBareTestEnvironment
  {
  public:
  											CommandBufferBareTestEnvironment	(Context&						context,
  																				 VkCommandPoolCreateFlags		commandPoolCreateFlags);
  
  	VkCommandPool							getCommandPool						(void) const					{ return *m_commandPool; }
  	VkCommandBuffer							getCommandBuffer					(deUint32 bufferIndex) const;
  
  protected:
  	Context&								m_context;
  	const VkDevice							m_device;
  	const DeviceInterface&					m_vkd;
  	const VkQueue							m_queue;
  	const deUint32							m_queueFamilyIndex;
  	Allocator&								m_allocator;
  
  	// \note All VkCommandBuffers are allocated from m_commandPool so there is no need
  	//       to free them separately as the auto-generated dtor will do that through
  	//       destroying the pool.
  	Move<VkCommandPool>						m_commandPool;
  	VkCommandBuffer							m_primaryCommandBuffers[NumBuffers];
  };
  
  template <deUint32 NumBuffers>
  CommandBufferBareTestEnvironment<NumBuffers>::CommandBufferBareTestEnvironment(Context& context, VkCommandPoolCreateFlags commandPoolCreateFlags)
  	: m_context								(context)
  	, m_device								(context.getDevice())
  	, m_vkd									(context.getDeviceInterface())
  	, m_queue								(context.getUniversalQueue())
  	, m_queueFamilyIndex					(context.getUniversalQueueFamilyIndex())
  	, m_allocator							(context.getDefaultAllocator())
  {
  	m_commandPool = createCommandPool(m_vkd, m_device, commandPoolCreateFlags, m_queueFamilyIndex);
  
  	const VkCommandBufferAllocateInfo		cmdBufferAllocateInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// VkStructureType             sType;
  		DE_NULL,													// const void*                 pNext;
  		*m_commandPool,												// VkCommandPool               commandPool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// VkCommandBufferLevel        level;
  		NumBuffers												// deUint32                    commandBufferCount;
  	};
  
  	VK_CHECK(m_vkd.allocateCommandBuffers(m_device, &cmdBufferAllocateInfo, m_primaryCommandBuffers));
  }
  
  template <deUint32 NumBuffers>
  VkCommandBuffer CommandBufferBareTestEnvironment<NumBuffers>::getCommandBuffer(deUint32 bufferIndex) const
  {
  	DE_ASSERT(bufferIndex < NumBuffers);
  	return m_primaryCommandBuffers[bufferIndex];
  }
  
  class CommandBufferRenderPassTestEnvironment : public CommandBufferBareTestEnvironment<1>
  {
  public:
  											CommandBufferRenderPassTestEnvironment	(Context&						context,
  																					 VkCommandPoolCreateFlags		commandPoolCreateFlags);
  
  	VkRenderPass							getRenderPass							(void) const { return *m_renderPass; }
  	VkFramebuffer							getFrameBuffer							(void) const { return *m_frameBuffer; }
  	VkCommandBuffer							getPrimaryCommandBuffer					(void) const { return getCommandBuffer(0); }
  	VkCommandBuffer							getSecondaryCommandBuffer				(void) const { return *m_secondaryCommandBuffer; }
  
  	void									beginPrimaryCommandBuffer				(VkCommandBufferUsageFlags usageFlags);
  	void									beginSecondaryCommandBuffer				(VkCommandBufferUsageFlags usageFlags, bool framebufferHint);
  	void									beginRenderPass							(VkSubpassContents content);
  	void									submitPrimaryCommandBuffer				(void);
  	de::MovePtr<tcu::TextureLevel>			readColorAttachment						(void);
  
  	static const VkImageType				DEFAULT_IMAGE_TYPE;
  	static const VkFormat					DEFAULT_IMAGE_FORMAT;
  	static const VkExtent3D					DEFAULT_IMAGE_SIZE;
  	static const VkRect2D					DEFAULT_IMAGE_AREA;
  
  protected:
  
  	Move<VkImage>							m_colorImage;
  	Move<VkImageView>						m_colorImageView;
  	Move<VkRenderPass>						m_renderPass;
  	Move<VkFramebuffer>						m_frameBuffer;
  	de::MovePtr<Allocation>					m_colorImageMemory;
  	Move<VkCommandBuffer>					m_secondaryCommandBuffer;
  
  };
  
  const VkImageType		CommandBufferRenderPassTestEnvironment::DEFAULT_IMAGE_TYPE		= VK_IMAGE_TYPE_2D;
  const VkFormat			CommandBufferRenderPassTestEnvironment::DEFAULT_IMAGE_FORMAT	= VK_FORMAT_R8G8B8A8_UINT;
  const VkExtent3D		CommandBufferRenderPassTestEnvironment::DEFAULT_IMAGE_SIZE		= {255, 255, 1};
  const VkRect2D			CommandBufferRenderPassTestEnvironment::DEFAULT_IMAGE_AREA		=
  {
  	{ 0u, 0u, },												//	VkOffset2D	offset;
  	{ DEFAULT_IMAGE_SIZE.width,	DEFAULT_IMAGE_SIZE.height },	//	VkExtent2D	extent;
  };
  
  CommandBufferRenderPassTestEnvironment::CommandBufferRenderPassTestEnvironment(Context& context, VkCommandPoolCreateFlags commandPoolCreateFlags)
  	: CommandBufferBareTestEnvironment<1>		(context, commandPoolCreateFlags)
  {
  	m_renderPass = makeRenderPass(m_vkd, m_device, DEFAULT_IMAGE_FORMAT);
  
  	{
  		const VkImageCreateInfo					imageCreateInfo			=
  		{
  			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		// VkStructureType			sType;
  			DE_NULL,									// const void*				pNext;
  			0u,											// VkImageCreateFlags		flags;
  			DEFAULT_IMAGE_TYPE,							// VkImageType				imageType;
  			DEFAULT_IMAGE_FORMAT,						// VkFormat					format;
  			DEFAULT_IMAGE_SIZE,							// VkExtent3D				extent;
  			1,											// deUint32					mipLevels;
  			1,											// deUint32					arrayLayers;
  			VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits	samples;
  			VK_IMAGE_TILING_OPTIMAL,					// VkImageTiling			tiling;
  			VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
  			VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
  			VK_IMAGE_USAGE_TRANSFER_DST_BIT,			// VkImageUsageFlags		usage;
  			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode			sharingMode;
  			1,											// deUint32					queueFamilyIndexCount;
  			&m_queueFamilyIndex,						// const deUint32*			pQueueFamilyIndices;
  			VK_IMAGE_LAYOUT_UNDEFINED					// VkImageLayout			initialLayout;
  		};
  
  		m_colorImage = createImage(m_vkd, m_device, &imageCreateInfo, DE_NULL);
  	}
  
  	m_colorImageMemory = m_allocator.allocate(getImageMemoryRequirements(m_vkd, m_device, *m_colorImage), MemoryRequirement::Any);
  	VK_CHECK(m_vkd.bindImageMemory(m_device, *m_colorImage, m_colorImageMemory->getMemory(), m_colorImageMemory->getOffset()));
  
  	{
  		const VkImageViewCreateInfo				imageViewCreateInfo		=
  		{
  			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	// VkStructureType				sType;
  			DE_NULL,									// const void*					pNext;
  			0u,											// VkImageViewCreateFlags		flags;
  			*m_colorImage,								// VkImage						image;
  			VK_IMAGE_VIEW_TYPE_2D,						// VkImageViewType				viewType;
  			DEFAULT_IMAGE_FORMAT,						// VkFormat						format;
  			{
  				VK_COMPONENT_SWIZZLE_R,
  				VK_COMPONENT_SWIZZLE_G,
  				VK_COMPONENT_SWIZZLE_B,
  				VK_COMPONENT_SWIZZLE_A
  			},											// VkComponentMapping			components;
  			{
  				VK_IMAGE_ASPECT_COLOR_BIT,					// VkImageAspectFlags			aspectMask;
  				0u,											// deUint32						baseMipLevel;
  				1u,											// deUint32						mipLevels;
  				0u,											// deUint32						baseArrayLayer;
  				1u,											// deUint32						arraySize;
  			},											// VkImageSubresourceRange		subresourceRange;
  		};
  
  		m_colorImageView = createImageView(m_vkd, m_device, &imageViewCreateInfo, DE_NULL);
  	}
  
  	{
  		const VkImageView						attachmentViews[1]		=
  		{
  			*m_colorImageView
  		};
  
  		const VkFramebufferCreateInfo			framebufferCreateInfo	=
  		{
  			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,	// VkStructureType			sType;
  			DE_NULL,									// const void*				pNext;
  			0u,											// VkFramebufferCreateFlags	flags;
  			*m_renderPass,								// VkRenderPass				renderPass;
  			1,											// deUint32					attachmentCount;
  			attachmentViews,							// const VkImageView*		pAttachments;
  			DEFAULT_IMAGE_SIZE.width,					// deUint32					width;
  			DEFAULT_IMAGE_SIZE.height,					// deUint32					height;
  			1u,											// deUint32					layers;
  		};
  
  		m_frameBuffer = createFramebuffer(m_vkd, m_device, &framebufferCreateInfo, DE_NULL);
  	}
  
  	{
  		const VkCommandBufferAllocateInfo		cmdBufferAllocateInfo	=
  		{
  			VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// VkStructureType             sType;
  			DE_NULL,													// const void*                 pNext;
  			*m_commandPool,												// VkCommandPool               commandPool;
  			VK_COMMAND_BUFFER_LEVEL_SECONDARY,							// VkCommandBufferLevel        level;
  			1u															// deUint32                    commandBufferCount;
  		};
  
  		m_secondaryCommandBuffer = allocateCommandBuffer(m_vkd, m_device, &cmdBufferAllocateInfo);
  
  	}
  }
  
  void CommandBufferRenderPassTestEnvironment::beginRenderPass(VkSubpassContents content)
  {
  	vk::beginRenderPass(m_vkd, m_primaryCommandBuffers[0], *m_renderPass, *m_frameBuffer, DEFAULT_IMAGE_AREA, tcu::UVec4(17, 59, 163, 251), content);
  }
  
  void CommandBufferRenderPassTestEnvironment::beginPrimaryCommandBuffer(VkCommandBufferUsageFlags usageFlags)
  {
  	beginCommandBuffer(m_vkd, m_primaryCommandBuffers[0], usageFlags);
  }
  
  void CommandBufferRenderPassTestEnvironment::beginSecondaryCommandBuffer(VkCommandBufferUsageFlags usageFlags, bool framebufferHint)
  {
  	const VkCommandBufferInheritanceInfo	commandBufferInheritanceInfo =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,		// VkStructureType                  sType;
  		DE_NULL,												// const void*                      pNext;
  		*m_renderPass,											// VkRenderPass                     renderPass;
  		0u,														// deUint32                         subpass;
  		(framebufferHint ? *m_frameBuffer : DE_NULL),			// VkFramebuffer                    framebuffer;
  		VK_FALSE,												// VkBool32                         occlusionQueryEnable;
  		0u,														// VkQueryControlFlags              queryFlags;
  		0u														// VkQueryPipelineStatisticFlags    pipelineStatistics;
  	};
  
  	const VkCommandBufferBeginInfo			commandBufferBeginInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,			// VkStructureType                          sType;
  		DE_NULL,												// const void*                              pNext;
  		usageFlags,												// VkCommandBufferUsageFlags                flags;
  		&commandBufferInheritanceInfo							// const VkCommandBufferInheritanceInfo*    pInheritanceInfo;
  	};
  
  	VK_CHECK(m_vkd.beginCommandBuffer(*m_secondaryCommandBuffer, &commandBufferBeginInfo));
  
  }
  
  void CommandBufferRenderPassTestEnvironment::submitPrimaryCommandBuffer(void)
  {
  	submitCommandsAndWait(m_vkd, m_device, m_queue, *m_primaryCommandBuffers);
  }
  
  de::MovePtr<tcu::TextureLevel> CommandBufferRenderPassTestEnvironment::readColorAttachment ()
  {
  	Move<VkBuffer>					buffer;
  	de::MovePtr<Allocation>			bufferAlloc;
  	const tcu::TextureFormat		tcuFormat		= mapVkFormat(DEFAULT_IMAGE_FORMAT);
  	const VkDeviceSize				pixelDataSize	= DEFAULT_IMAGE_SIZE.height * DEFAULT_IMAGE_SIZE.height * tcuFormat.getPixelSize();
  	de::MovePtr<tcu::TextureLevel>	resultLevel		(new tcu::TextureLevel(tcuFormat, DEFAULT_IMAGE_SIZE.width, DEFAULT_IMAGE_SIZE.height));
  
  	// Create destination buffer
  	{
  		const VkBufferCreateInfo bufferParams =
  		{
  			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
  			DE_NULL,									// const void*			pNext;
  			0u,											// VkBufferCreateFlags	flags;
  			pixelDataSize,								// VkDeviceSize			size;
  			VK_BUFFER_USAGE_TRANSFER_DST_BIT,			// VkBufferUsageFlags	usage;
  			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
  			0u,											// deUint32				queueFamilyIndexCount;
  			DE_NULL										// const deUint32*		pQueueFamilyIndices;
  		};
  
  		buffer		= createBuffer(m_vkd, m_device, &bufferParams);
  		bufferAlloc = m_allocator.allocate(getBufferMemoryRequirements(m_vkd, m_device, *buffer), MemoryRequirement::HostVisible);
  		VK_CHECK(m_vkd.bindBufferMemory(m_device, *buffer, bufferAlloc->getMemory(), bufferAlloc->getOffset()));
  	}
  
  	// Copy image to buffer
  	beginPrimaryCommandBuffer(0);
  	copyImageToBuffer(m_vkd, m_primaryCommandBuffers[0], *m_colorImage, *buffer, tcu::IVec2(DEFAULT_IMAGE_SIZE.width, DEFAULT_IMAGE_SIZE.height));
  	endCommandBuffer(m_vkd, m_primaryCommandBuffers[0]);
  
  	submitPrimaryCommandBuffer();
  
  	// Read buffer data
  	invalidateAlloc(m_vkd, m_device, *bufferAlloc);
  	tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), bufferAlloc->getHostPtr()));
  
  	return resultLevel;
  }
  
  
  // Testcases
  /********* 19.1. Command Pools (5.1 in VK 1.0 Spec) ***************************/
  tcu::TestStatus createPoolNullParamsTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	createCommandPool(vk, vkDevice, 0u, queueFamilyIndex);
  
  	return tcu::TestStatus::pass("Command Pool allocated correctly.");
  }
  
  tcu::TestStatus createPoolNonNullAllocatorTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  	const VkAllocationCallbacks*			allocationCallbacks		= getSystemAllocator();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		0u,															// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  
  	createCommandPool(vk, vkDevice, &cmdPoolParams, allocationCallbacks);
  
  	return tcu::TestStatus::pass("Command Pool allocated correctly.");
  }
  
  tcu::TestStatus createPoolTransientBitTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,						// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  
  	createCommandPool(vk, vkDevice, &cmdPoolParams, DE_NULL);
  
  	return tcu::TestStatus::pass("Command Pool allocated correctly.");
  }
  
  tcu::TestStatus createPoolResetBitTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  
  	createCommandPool(vk, vkDevice, &cmdPoolParams, DE_NULL);
  
  	return tcu::TestStatus::pass("Command Pool allocated correctly.");
  }
  
  tcu::TestStatus resetPoolReleaseResourcesBitTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		0u,															// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams, DE_NULL));
  
  	VK_CHECK(vk.resetCommandPool(vkDevice, *cmdPool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT));
  
  	return tcu::TestStatus::pass("Command Pool allocated correctly.");
  }
  
  tcu::TestStatus resetPoolNoFlagsTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		0u,															// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams, DE_NULL));
  
  	VK_CHECK(vk.resetCommandPool(vkDevice, *cmdPool, 0u));
  
  	return tcu::TestStatus::pass("Command Pool allocated correctly.");
  }
  
  bool executeCommandBuffer (const VkDevice			device,
  						   const DeviceInterface&	vk,
  						   const VkQueue			queue,
  						   const VkCommandBuffer	commandBuffer,
  						   const bool				exitBeforeEndCommandBuffer = false)
  {
  	const Unique<VkEvent>			event					(createEvent(vk, device));
  	beginCommandBuffer(vk, commandBuffer, 0u);
  	{
  		const VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  		vk.cmdSetEvent(commandBuffer, *event, stageMask);
  		if (exitBeforeEndCommandBuffer)
  			return exitBeforeEndCommandBuffer;
  	}
  	endCommandBuffer(vk, commandBuffer);
  
  	submitCommandsAndWait(vk, device, queue, commandBuffer);
  
  	// check if buffer has been executed
  	const VkResult result = vk.getEventStatus(device, *event);
  	return result == VK_EVENT_SET;
  }
  
  tcu::TestStatus resetPoolReuseTest (Context& context)
  {
  	const VkDevice						vkDevice			= context.getDevice();
  	const DeviceInterface&				vk					= context.getDeviceInterface();
  	const deUint32						queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
  	const VkQueue						queue				= context.getUniversalQueue();
  
  	const VkCommandPoolCreateInfo		cmdPoolParams		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,	// sType;
  		DE_NULL,									// pNext;
  		0u,											// flags;
  		queueFamilyIndex							// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>			cmdPool				(createCommandPool(vk, vkDevice, &cmdPoolParams, DE_NULL));
  	const VkCommandBufferAllocateInfo	cmdBufParams		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// sType;
  		DE_NULL,										// pNext;
  		*cmdPool,										// commandPool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// level;
  		1u												// bufferCount;
  	};
  	const Move<VkCommandBuffer>			commandBuffers[]	=
  	{
  		allocateCommandBuffer(vk, vkDevice, &cmdBufParams),
  		allocateCommandBuffer(vk, vkDevice, &cmdBufParams)
  	};
  
  	if (!executeCommandBuffer(vkDevice, vk, queue, *(commandBuffers[0])))
  		return tcu::TestStatus::fail("Failed");
  	if (!executeCommandBuffer(vkDevice, vk, queue, *(commandBuffers[1]), true))
  		return tcu::TestStatus::fail("Failed");
  
  	VK_CHECK(vk.resetCommandPool(vkDevice, *cmdPool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT));
  
  	if (!executeCommandBuffer(vkDevice, vk, queue, *(commandBuffers[0])))
  		return tcu::TestStatus::fail("Failed");
  	if (!executeCommandBuffer(vkDevice, vk, queue, *(commandBuffers[1])))
  		return tcu::TestStatus::fail("Failed");
  
  	{
  		const Unique<VkCommandBuffer> afterResetCommandBuffers(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  		if (!executeCommandBuffer(vkDevice, vk, queue, *afterResetCommandBuffers))
  			return tcu::TestStatus::fail("Failed");
  	}
  
  	return tcu::TestStatus::pass("Passed");
  }
  
  /******** 19.2. Command Buffer Lifetime (5.2 in VK 1.0 Spec) ******************/
  tcu::TestStatus allocatePrimaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// commandPool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// level;
  		1u,															// bufferCount;
  	};
  	const Unique<VkCommandBuffer>			cmdBuf					(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	return tcu::TestStatus::pass("Buffer was created correctly.");
  }
  
  tcu::TestStatus allocateManyPrimaryBuffersTest(Context& context)
  {
  
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// \todo Determining the minimum number of command buffers should be a function of available system memory and driver capabilities.
  #if (DE_PTR_SIZE == 4)
  	const unsigned minCommandBuffer = 1024;
  #else
  	const unsigned minCommandBuffer = 10000;
  #endif
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		minCommandBuffer,											//	uint32_t					bufferCount;
  	};
  
  	// do not keep the handles to buffers, as they will be freed with command pool
  
  	// allocate the minimum required amount of buffers
  	VkCommandBuffer cmdBuffers[minCommandBuffer];
  	VK_CHECK(vk.allocateCommandBuffers(vkDevice, &cmdBufParams, cmdBuffers));
  
  	std::ostringstream out;
  	out << "allocateManyPrimaryBuffersTest succeded: created " << minCommandBuffer << " command buffers";
  
  	return tcu::TestStatus::pass(out.str());
  }
  
  tcu::TestStatus allocateSecondaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// commandPool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							// level;
  		1u,															// bufferCount;
  	};
  	const Unique<VkCommandBuffer>			cmdBuf					(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	return tcu::TestStatus::pass("Buffer was created correctly.");
  }
  
  tcu::TestStatus allocateManySecondaryBuffersTest(Context& context)
  {
  
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// \todo Determining the minimum number of command buffers should be a function of available system memory and driver capabilities.
  #if (DE_PTR_SIZE == 4)
  	const unsigned minCommandBuffer = 1024;
  #else
  	const unsigned minCommandBuffer = 10000;
  #endif
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							//	VkCommandBufferLevel		level;
  		minCommandBuffer,											//	uint32_t					bufferCount;
  	};
  
  	// do not keep the handles to buffers, as they will be freed with command pool
  
  	// allocate the minimum required amount of buffers
  	VkCommandBuffer cmdBuffers[minCommandBuffer];
  	VK_CHECK(vk.allocateCommandBuffers(vkDevice, &cmdBufParams, cmdBuffers));
  
  	std::ostringstream out;
  	out << "allocateManySecondaryBuffersTest succeded: created " << minCommandBuffer << " command buffers";
  
  	return tcu::TestStatus::pass(out.str());
  }
  
  tcu::TestStatus executePrimaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	// record primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf, 0u);
  	{
  		// allow execution of event during every stage of pipeline
  		VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  		// record setting event
  		vk.cmdSetEvent(*primCmdBuf, *event,stageMask);
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf.get());
  
  	// check if buffer has been executed
  	VkResult result = vk.getEventStatus(vkDevice,*event);
  	if (result == VK_EVENT_SET)
  		return tcu::TestStatus::pass("Execute Primary Command Buffer succeeded");
  
  	return tcu::TestStatus::fail("Execute Primary Command Buffer FAILED");
  }
  
  tcu::TestStatus executeLargePrimaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  	const deUint32							LARGE_BUFFER_SIZE		= 10000;
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	std::vector<VkEventSp>					events;
  	for (deUint32 ndx = 0; ndx < LARGE_BUFFER_SIZE; ++ndx)
  		events.push_back(VkEventSp(new vk::Unique<VkEvent>(createEvent(vk, vkDevice))));
  
  	// record primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf, 0u);
  	{
  		// set all the events
  		for (deUint32 ndx = 0; ndx < LARGE_BUFFER_SIZE; ++ndx)
  		{
  			vk.cmdSetEvent(*primCmdBuf, events[ndx]->get(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  		}
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf.get());
  
  	// check if the buffer was executed correctly - all events had their status
  	// changed
  	tcu::TestStatus testResult = tcu::TestStatus::incomplete();
  
  	for (deUint32 ndx = 0; ndx < LARGE_BUFFER_SIZE; ++ndx)
  	{
  		if (vk.getEventStatus(vkDevice, events[ndx]->get()) != VK_EVENT_SET)
  		{
  			testResult = tcu::TestStatus::fail("An event was not set.");
  			break;
  		}
  	}
  
  	if (!testResult.isComplete())
  		testResult = tcu::TestStatus::pass("All events set correctly.");
  
  	return testResult;
  }
  
  tcu::TestStatus resetBufferImplicitlyTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// level;
  		1u,															// bufferCount;
  	};
  	const Unique<VkCommandBuffer>			cmdBuf						(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// Put the command buffer in recording state.
  	beginCommandBuffer(vk, *cmdBuf, 0u);
  	{
  		// Set the event
  		vk.cmdSetEvent(*cmdBuf, *event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  	}
  	endCommandBuffer(vk, *cmdBuf);
  
  	submitCommandsAndWait(vk, vkDevice, queue, cmdBuf.get());
  
  	// Check if the buffer was executed
  	if (vk.getEventStatus(vkDevice, *event) != VK_EVENT_SET)
  		return tcu::TestStatus::fail("Failed to set the event.");
  
  	// Reset the event
  	vk.resetEvent(vkDevice, *event);
  	if(vk.getEventStatus(vkDevice, *event) != VK_EVENT_RESET)
  		return tcu::TestStatus::fail("Failed to reset the event.");
  
  	// Reset the command buffer by putting it in recording state again. This
  	// should empty the command buffer.
  	beginCommandBuffer(vk, *cmdBuf, 0u);
  	endCommandBuffer(vk, *cmdBuf);
  
  	// Submit the command buffer after resetting. It should have no commands
  	// recorded, so the event should remain unsignaled.
  	submitCommandsAndWait(vk, vkDevice, queue, cmdBuf.get());
  
  	// Check if the event remained unset.
  	if(vk.getEventStatus(vkDevice, *event) == VK_EVENT_RESET)
  		return tcu::TestStatus::pass("Buffer was reset correctly.");
  	else
  		return tcu::TestStatus::fail("Buffer was not reset correctly.");
  }
  
  using  de::SharedPtr;
  typedef SharedPtr<Unique<VkEvent> >			VkEventShared;
  
  template<typename T>
  inline SharedPtr<Unique<T> > makeSharedPtr (Move<T> move)
  {
  	return SharedPtr<Unique<T> >(new Unique<T>(move));
  }
  
  bool submitAndCheck (Context& context, std::vector<VkCommandBuffer>& cmdBuffers, std::vector <VkEventShared>& events)
  {
  	const VkDevice						vkDevice	= context.getDevice();
  	const DeviceInterface&				vk			= context.getDeviceInterface();
  	const VkQueue						queue		= context.getUniversalQueue();
  	const Unique<VkFence>				fence		(createFence(vk, vkDevice));
  
  	const VkSubmitInfo					submitInfo	=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,				// sType
  		DE_NULL,									// pNext
  		0u,											// waitSemaphoreCount
  		DE_NULL,									// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,		// pWaitDstStageMask
  		static_cast<deUint32>(cmdBuffers.size()),	// commandBufferCount
  		&cmdBuffers[0],								// pCommandBuffers
  		0u,											// signalSemaphoreCount
  		DE_NULL,									// pSignalSemaphores
  	};
  
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, fence.get()));
  	VK_CHECK(vk.waitForFences(vkDevice, 1u, &fence.get(), 0u, INFINITE_TIMEOUT));
  
  	for(int eventNdx = 0; eventNdx < static_cast<int>(events.size()); ++eventNdx)
  	{
  		if (vk.getEventStatus(vkDevice, **events[eventNdx]) != VK_EVENT_SET)
  			return false;
  		vk.resetEvent(vkDevice, **events[eventNdx]);
  	}
  
  	return true;
  }
  
  void createCommadBuffers (const DeviceInterface&		vk,
  						  const VkDevice				vkDevice,
  						  deUint32						bufferCount,
  						  VkCommandPool					pool,
  						  const VkCommandBufferLevel	cmdBufferLevel,
  						  VkCommandBuffer*				pCommandBuffers)
  {
  	const VkCommandBufferAllocateInfo		cmdBufParams	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	//	VkStructureType				sType;
  		DE_NULL,										//	const void*					pNext;
  		pool,											//	VkCommandPool				pool;
  		cmdBufferLevel,									//	VkCommandBufferLevel		level;
  		bufferCount,									//	uint32_t					bufferCount;
  	};
  	VK_CHECK(vk.allocateCommandBuffers(vkDevice, &cmdBufParams, pCommandBuffers));
  }
  
  void addCommandsToBuffer (const DeviceInterface& vk, std::vector<VkCommandBuffer>& cmdBuffers, std::vector <VkEventShared>& events)
  {
  	const VkCommandBufferInheritanceInfo	secCmdBufInheritInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		(VkRenderPass)0u,								// renderPass
  		0u,												// subpass
  		(VkFramebuffer)0u,								// framebuffer
  		VK_FALSE,										// occlusionQueryEnable
  		(VkQueryControlFlags)0u,						// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,				// pipelineStatistics
  	};
  
  	const VkCommandBufferBeginInfo		cmdBufBeginInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	// sType
  		DE_NULL,										// pNext
  		0u,												// flags
  		&secCmdBufInheritInfo,							// pInheritanceInfo;
  	};
  
  	for(int bufferNdx = 0; bufferNdx < static_cast<int>(cmdBuffers.size()); ++bufferNdx)
  	{
  		VK_CHECK(vk.beginCommandBuffer(cmdBuffers[bufferNdx], &cmdBufBeginInfo));
  		vk.cmdSetEvent(cmdBuffers[bufferNdx], **events[bufferNdx % events.size()], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  		endCommandBuffer(vk, cmdBuffers[bufferNdx]);
  	}
  }
  
  bool executeSecondaryCmdBuffer (Context&						context,
  								VkCommandPool					pool,
  								std::vector<VkCommandBuffer>&	cmdBuffersSecondary,
  								std::vector <VkEventShared>&	events)
  {
  	const VkDevice					vkDevice		= context.getDevice();
  	const DeviceInterface&			vk				= context.getDeviceInterface();
  	std::vector<VkCommandBuffer>	cmdBuffer		(1);
  
  	createCommadBuffers(vk, vkDevice, 1u, pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, &cmdBuffer[0]);
  	beginCommandBuffer(vk, cmdBuffer[0], 0u);
  	vk.cmdExecuteCommands(cmdBuffer[0], static_cast<deUint32>(cmdBuffersSecondary.size()), &cmdBuffersSecondary[0]);
  	endCommandBuffer(vk, cmdBuffer[0]);
  
  	bool returnValue = submitAndCheck(context, cmdBuffer, events);
  	vk.freeCommandBuffers(vkDevice, pool, 1u, &cmdBuffer[0]);
  	return returnValue;
  }
  
  tcu::TestStatus trimCommandPoolTest (Context& context, const VkCommandBufferLevel cmdBufferLevel)
  {
  	if (!context.isDeviceFunctionalitySupported("VK_KHR_maintenance1"))
  		TCU_THROW(NotSupportedError, "Extension VK_KHR_maintenance1 not supported");
  
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	//test parameters
  	const deUint32							cmdBufferIterationCount	= 300u;
  	const deUint32							cmdBufferCount			= 10u;
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	std::vector <VkEventShared>				events;
  	for (deUint32 ndx = 0u; ndx < cmdBufferCount; ++ndx)
  		events.push_back(makeSharedPtr(createEvent(vk, vkDevice)));
  
  	{
  		std::vector<VkCommandBuffer> cmdBuffers(cmdBufferCount);
  		createCommadBuffers(vk, vkDevice, cmdBufferCount, *cmdPool, cmdBufferLevel, &cmdBuffers[0]);
  
  		for (deUint32 cmdBufferIterationrNdx = 0; cmdBufferIterationrNdx < cmdBufferIterationCount; ++cmdBufferIterationrNdx)
  		{
  			addCommandsToBuffer(vk, cmdBuffers, events);
  
  			//Peak, situation when we use a lot more command buffers
  			if (cmdBufferIterationrNdx % 10u == 0)
  			{
  				std::vector<VkCommandBuffer> cmdBuffersPeak(cmdBufferCount * 10u);
  				createCommadBuffers(vk, vkDevice, static_cast<deUint32>(cmdBuffersPeak.size()), *cmdPool, cmdBufferLevel, &cmdBuffersPeak[0]);
  				addCommandsToBuffer(vk, cmdBuffersPeak, events);
  
  				switch(cmdBufferLevel)
  				{
  					case VK_COMMAND_BUFFER_LEVEL_PRIMARY:
  						if (!submitAndCheck(context, cmdBuffersPeak, events))
  							return tcu::TestStatus::fail("Fail");
  						break;
  					case VK_COMMAND_BUFFER_LEVEL_SECONDARY:
  						if (!executeSecondaryCmdBuffer(context, *cmdPool, cmdBuffersPeak, events))
  							return tcu::TestStatus::fail("Fail");
  						break;
  					default:
  						DE_ASSERT(0);
  				}
  				vk.freeCommandBuffers(vkDevice, *cmdPool, static_cast<deUint32>(cmdBuffersPeak.size()), &cmdBuffersPeak[0]);
  			}
  
  			vk.trimCommandPool(vkDevice, *cmdPool, (VkCommandPoolTrimFlags)0);
  
  			switch(cmdBufferLevel)
  			{
  				case VK_COMMAND_BUFFER_LEVEL_PRIMARY:
  					if (!submitAndCheck(context, cmdBuffers, events))
  						return tcu::TestStatus::fail("Fail");
  					break;
  				case VK_COMMAND_BUFFER_LEVEL_SECONDARY:
  					if (!executeSecondaryCmdBuffer(context, *cmdPool, cmdBuffers, events))
  						return tcu::TestStatus::fail("Fail");
  					break;
  				default:
  					DE_ASSERT(0);
  			}
  
  			for (deUint32 bufferNdx = cmdBufferIterationrNdx % 3u; bufferNdx < cmdBufferCount; bufferNdx+=2u)
  			{
  				vk.freeCommandBuffers(vkDevice, *cmdPool, 1u, &cmdBuffers[bufferNdx]);
  				createCommadBuffers(vk, vkDevice, 1u, *cmdPool, cmdBufferLevel, &cmdBuffers[bufferNdx]);
  			}
  		}
  	}
  
  	return tcu::TestStatus::pass("Pass");
  }
  
  /******** 19.3. Command Buffer Recording (5.3 in VK 1.0 Spec) *****************/
  tcu::TestStatus recordSinglePrimaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// record primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf, 0u);
  	{
  		// record setting event
  		vk.cmdSetEvent(*primCmdBuf, *event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	return tcu::TestStatus::pass("Primary buffer recorded successfully.");
  }
  
  tcu::TestStatus recordLargePrimaryBufferTest(Context &context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	// record primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf, 0u);
  	{
  		// allow execution of event during every stage of pipeline
  		VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  		// define minimal amount of commands to accept
  		const long long unsigned minNumCommands = 10000llu;
  
  		for ( long long unsigned currentCommands = 0; currentCommands < minNumCommands / 2; ++currentCommands )
  		{
  			// record setting event
  			vk.cmdSetEvent(*primCmdBuf, *event,stageMask);
  
  			// record resetting event
  			vk.cmdResetEvent(*primCmdBuf, *event,stageMask);
  		}
  
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf.get());
  
  	return tcu::TestStatus::pass("hugeTest succeeded");
  }
  
  tcu::TestStatus recordSingleSecondaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			secCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	const VkCommandBufferInheritanceInfo	secCmdBufInheritInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		(VkRenderPass)0u,											// renderPass
  		0u,															// subpass
  		(VkFramebuffer)0u,											// framebuffer
  		VK_FALSE,													// occlusionQueryEnable
  		(VkQueryControlFlags)0u,									// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,							// pipelineStatistics
  	};
  	const VkCommandBufferBeginInfo			secCmdBufBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  		DE_NULL,
  		0,															// flags
  		&secCmdBufInheritInfo,
  	};
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// record primary command buffer
  	VK_CHECK(vk.beginCommandBuffer(*secCmdBuf, &secCmdBufBeginInfo));
  	{
  		// record setting event
  		vk.cmdSetEvent(*secCmdBuf, *event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  	}
  	endCommandBuffer(vk, *secCmdBuf);
  
  	return tcu::TestStatus::pass("Secondary buffer recorded successfully.");
  }
  
  tcu::TestStatus recordLargeSecondaryBufferTest(Context &context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	const VkCommandBufferAllocateInfo		secCmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			secCmdBuf				(allocateCommandBuffer(vk, vkDevice, &secCmdBufParams));
  
  	const VkCommandBufferInheritanceInfo	secCmdBufInheritInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		(VkRenderPass)0u,											// renderPass
  		0u,															// subpass
  		(VkFramebuffer)0u,											// framebuffer
  		VK_FALSE,													// occlusionQueryEnable
  		(VkQueryControlFlags)0u,									// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,							// pipelineStatistics
  	};
  	const VkCommandBufferBeginInfo			secCmdBufBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  		DE_NULL,
  		0,															// flags
  		&secCmdBufInheritInfo,
  	};
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	// record primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf, 0u);
  	{
  		// record secondary command buffer
  		VK_CHECK(vk.beginCommandBuffer(*secCmdBuf, &secCmdBufBeginInfo));
  		{
  			// allow execution of event during every stage of pipeline
  			VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  			// define minimal amount of commands to accept
  			const long long unsigned minNumCommands = 10000llu;
  
  			for ( long long unsigned currentCommands = 0; currentCommands < minNumCommands / 2; ++currentCommands )
  			{
  				// record setting event
  				vk.cmdSetEvent(*primCmdBuf, *event,stageMask);
  
  				// record resetting event
  				vk.cmdResetEvent(*primCmdBuf, *event,stageMask);
  			}
  		}
  
  		// end recording of secondary buffers
  		endCommandBuffer(vk, *secCmdBuf);
  
  		// execute secondary buffer
  		vk.cmdExecuteCommands(*primCmdBuf, 1, &secCmdBuf.get());
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf.get());
  
  	return tcu::TestStatus::pass("hugeTest succeeded");
  }
  
  tcu::TestStatus submitPrimaryBufferTwiceTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	// record primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf, 0u);
  	{
  		// allow execution of event during every stage of pipeline
  		VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  		// record setting event
  		vk.cmdSetEvent(*primCmdBuf, *event,stageMask);
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf.get());
  
  	// check if buffer has been executed
  	VkResult result = vk.getEventStatus(vkDevice,*event);
  	if (result != VK_EVENT_SET)
  		return tcu::TestStatus::fail("Submit Twice Test FAILED");
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf.get());
  
  	// check if buffer has been executed
  	result = vk.getEventStatus(vkDevice,*event);
  	if (result != VK_EVENT_SET)
  		return tcu::TestStatus::fail("Submit Twice Test FAILED");
  	else
  		return tcu::TestStatus::pass("Submit Twice Test succeeded");
  }
  
  tcu::TestStatus submitSecondaryBufferTwiceTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  
  	const Unique<VkCommandBuffer>			primCmdBuf1				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  	const Unique<VkCommandBuffer>			primCmdBuf2				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// Secondary Command buffer
  	const VkCommandBufferAllocateInfo		secCmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			secCmdBuf				(allocateCommandBuffer(vk, vkDevice, &secCmdBufParams));
  
  	const VkCommandBufferInheritanceInfo	secCmdBufInheritInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		(VkRenderPass)0u,											// renderPass
  		0u,															// subpass
  		(VkFramebuffer)0u,											// framebuffer
  		VK_FALSE,													// occlusionQueryEnable
  		(VkQueryControlFlags)0u,									// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,							// pipelineStatistics
  	};
  	const VkCommandBufferBeginInfo			secCmdBufBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  		DE_NULL,
  		0u,															// flags
  		&secCmdBufInheritInfo,
  	};
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	// record first primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf1, 0u);
  	{
  		// record secondary command buffer
  		VK_CHECK(vk.beginCommandBuffer(*secCmdBuf, &secCmdBufBeginInfo));
  		{
  			// allow execution of event during every stage of pipeline
  			VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  			// record setting event
  			vk.cmdSetEvent(*secCmdBuf, *event,stageMask);
  		}
  
  		// end recording of secondary buffers
  		endCommandBuffer(vk, *secCmdBuf);
  
  		// execute secondary buffer
  		vk.cmdExecuteCommands(*primCmdBuf1, 1, &secCmdBuf.get());
  	}
  	endCommandBuffer(vk, *primCmdBuf1);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf1.get());
  
  	// check if secondary buffer has been executed
  	VkResult result = vk.getEventStatus(vkDevice,*event);
  	if (result != VK_EVENT_SET)
  		return tcu::TestStatus::fail("Submit Twice Secondary Command Buffer FAILED");
  
  	// reset first primary buffer
  	vk.resetCommandBuffer( *primCmdBuf1, 0u);
  
  	// reset event to allow receiving it again
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	// record second primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf2, 0u);
  	{
  		// execute secondary buffer
  		vk.cmdExecuteCommands(*primCmdBuf2, 1, &secCmdBuf.get());
  	}
  	// end recording
  	endCommandBuffer(vk, *primCmdBuf2);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf2.get());
  
  	// check if secondary buffer has been executed
  	result = vk.getEventStatus(vkDevice,*event);
  	if (result != VK_EVENT_SET)
  		return tcu::TestStatus::fail("Submit Twice Secondary Command Buffer FAILED");
  	else
  		return tcu::TestStatus::pass("Submit Twice Secondary Command Buffer succeeded");
  }
  
  tcu::TestStatus oneTimeSubmitFlagPrimaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	// record primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf);
  	{
  		// allow execution of event during every stage of pipeline
  		VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  		// record setting event
  		vk.cmdSetEvent(*primCmdBuf, *event,stageMask);
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf.get());
  
  	// check if buffer has been executed
  	VkResult result = vk.getEventStatus(vkDevice,*event);
  	if (result != VK_EVENT_SET)
  		return tcu::TestStatus::fail("oneTimeSubmitFlagPrimaryBufferTest FAILED");
  
  	// record primary command buffer again - implicit reset because of VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
  	beginCommandBuffer(vk, *primCmdBuf);
  	{
  		// allow execution of event during every stage of pipeline
  		VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  		// record setting event
  		vk.cmdSetEvent(*primCmdBuf, *event,stageMask);
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf.get());
  
  	// check if buffer has been executed
  	result = vk.getEventStatus(vkDevice,*event);
  	if (result != VK_EVENT_SET)
  		return tcu::TestStatus::fail("oneTimeSubmitFlagPrimaryBufferTest FAILED");
  	else
  		return tcu::TestStatus::pass("oneTimeSubmitFlagPrimaryBufferTest succeeded");
  }
  
  tcu::TestStatus oneTimeSubmitFlagSecondaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  
  	const Unique<VkCommandBuffer>			primCmdBuf1				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  	const Unique<VkCommandBuffer>			primCmdBuf2				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// Secondary Command buffer
  	const VkCommandBufferAllocateInfo		secCmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			secCmdBuf				(allocateCommandBuffer(vk, vkDevice, &secCmdBufParams));
  
  	const VkCommandBufferInheritanceInfo	secCmdBufInheritInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		(VkRenderPass)0u,											// renderPass
  		0u,															// subpass
  		(VkFramebuffer)0u,											// framebuffer
  		VK_FALSE,													// occlusionQueryEnable
  		(VkQueryControlFlags)0u,									// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,							// pipelineStatistics
  	};
  	const VkCommandBufferBeginInfo			secCmdBufBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  		DE_NULL,
  		VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,				// flags
  		&secCmdBufInheritInfo,
  	};
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	// record first primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf1, 0u);
  	{
  		// record secondary command buffer
  		VK_CHECK(vk.beginCommandBuffer(*secCmdBuf, &secCmdBufBeginInfo));
  		{
  			// allow execution of event during every stage of pipeline
  			VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  			// record setting event
  			vk.cmdSetEvent(*secCmdBuf, *event,stageMask);
  		}
  
  		// end recording of secondary buffers
  		endCommandBuffer(vk, *secCmdBuf);
  
  		// execute secondary buffer
  		vk.cmdExecuteCommands(*primCmdBuf1, 1, &secCmdBuf.get());
  	}
  	endCommandBuffer(vk, *primCmdBuf1);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf1.get());
  
  	// check if secondary buffer has been executed
  	VkResult result = vk.getEventStatus(vkDevice,*event);
  	if (result != VK_EVENT_SET)
  		return tcu::TestStatus::fail("Submit Twice Secondary Command Buffer FAILED");
  
  	// reset first primary buffer
  	vk.resetCommandBuffer( *primCmdBuf1, 0u);
  
  	// reset event to allow receiving it again
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	// record secondary command buffer again
  	VK_CHECK(vk.beginCommandBuffer(*secCmdBuf, &secCmdBufBeginInfo));
  	{
  		// allow execution of event during every stage of pipeline
  		VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  		// record setting event
  		vk.cmdSetEvent(*secCmdBuf, *event,stageMask);
  	}
  	// end recording of secondary buffers
  	endCommandBuffer(vk, *secCmdBuf);
  
  	// record second primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf2, 0u);
  	{
  		// execute secondary buffer
  		vk.cmdExecuteCommands(*primCmdBuf2, 1, &secCmdBuf.get());
  	}
  	// end recording
  	endCommandBuffer(vk, *primCmdBuf2);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf2.get());
  
  	// check if secondary buffer has been executed
  	result = vk.getEventStatus(vkDevice,*event);
  	if (result != VK_EVENT_SET)
  		return tcu::TestStatus::fail("oneTimeSubmitFlagSecondaryBufferTest FAILED");
  	else
  		return tcu::TestStatus::pass("oneTimeSubmitFlagSecondaryBufferTest succeeded");
  }
  
  tcu::TestStatus renderPassContinueTest(Context& context, bool framebufferHint)
  {
  	const DeviceInterface&					vkd						= context.getDeviceInterface();
  	CommandBufferRenderPassTestEnvironment	env						(context, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
  
  	VkCommandBuffer							primaryCommandBuffer	= env.getPrimaryCommandBuffer();
  	VkCommandBuffer							secondaryCommandBuffer	= env.getSecondaryCommandBuffer();
  	const deUint32							clearColor[4]			= { 2, 47, 131, 211 };
  
  	const VkClearAttachment					clearAttachment			=
  	{
  		VK_IMAGE_ASPECT_COLOR_BIT,									// VkImageAspectFlags	aspectMask;
  		0,															// deUint32				colorAttachment;
  		makeClearValueColorU32(clearColor[0],
  							   clearColor[1],
  							   clearColor[2],
  							   clearColor[3])						// VkClearValue			clearValue;
  	};
  
  	const VkClearRect						clearRect				=
  	{
  		CommandBufferRenderPassTestEnvironment::DEFAULT_IMAGE_AREA,	// VkRect2D	rect;
  		0u,															// deUint32	baseArrayLayer;
  		1u															// deUint32	layerCount;
  	};
  
  	env.beginSecondaryCommandBuffer(VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, framebufferHint);
  	vkd.cmdClearAttachments(secondaryCommandBuffer, 1, &clearAttachment, 1, &clearRect);
  	endCommandBuffer(vkd, secondaryCommandBuffer);
  
  
  	env.beginPrimaryCommandBuffer(0);
  	env.beginRenderPass(VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
  	vkd.cmdExecuteCommands(primaryCommandBuffer, 1, &secondaryCommandBuffer);
  	endRenderPass(vkd, primaryCommandBuffer);
  
  	endCommandBuffer(vkd, primaryCommandBuffer);
  
  	env.submitPrimaryCommandBuffer();
  
  	de::MovePtr<tcu::TextureLevel>			result					= env.readColorAttachment();
  	tcu::PixelBufferAccess					pixelBufferAccess		= result->getAccess();
  
  	for (deUint32 i = 0; i < (CommandBufferRenderPassTestEnvironment::DEFAULT_IMAGE_SIZE.width * CommandBufferRenderPassTestEnvironment::DEFAULT_IMAGE_SIZE.height); ++i)
  	{
  		deUint8* colorData = reinterpret_cast<deUint8*>(pixelBufferAccess.getDataPtr());
  		for (int colorComponent = 0; colorComponent < 4; ++colorComponent)
  			if (colorData[i * 4 + colorComponent] != clearColor[colorComponent])
  				return tcu::TestStatus::fail("clear value mismatch");
  	}
  
  	return tcu::TestStatus::pass("render pass continue test passed");
  }
  
  tcu::TestStatus simultaneousUsePrimaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					eventOne				(createEvent(vk, vkDevice));
  	const Unique<VkEvent>					eventTwo				(createEvent(vk, vkDevice));
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *eventOne));
  
  	// record primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf, VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT);
  	{
  		// wait for event
  		vk.cmdWaitEvents(*primCmdBuf, 1u, &eventOne.get(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0u, DE_NULL, 0u, DE_NULL, 0u, DE_NULL);
  
  		// Set the second event
  		vk.cmdSetEvent(*primCmdBuf, eventTwo.get(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	// create fence to wait for execution of queue
  	const Unique<VkFence>					fence1					(createFence(vk, vkDevice));
  	const Unique<VkFence>					fence2					(createFence(vk, vkDevice));
  
  	const VkSubmitInfo						submitInfo				=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		0u,															// waitSemaphoreCount
  		DE_NULL,													// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,						// pWaitDstStageMask
  		1,															// commandBufferCount
  		&primCmdBuf.get(),											// pCommandBuffers
  		0u,															// signalSemaphoreCount
  		DE_NULL,													// pSignalSemaphores
  	};
  
  	// submit first buffer
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence1));
  
  	// submit second buffer
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence2));
  
  	// wait for both buffer to stop at event for 100 microseconds
  	vk.waitForFences(vkDevice, 1, &fence1.get(), 0u, 100000);
  	vk.waitForFences(vkDevice, 1, &fence2.get(), 0u, 100000);
  
  	// set event
  	VK_CHECK(vk.setEvent(vkDevice, *eventOne));
  
  	// wait for end of execution of the first buffer
  	VK_CHECK(vk.waitForFences(vkDevice, 1, &fence1.get(), 0u, INFINITE_TIMEOUT));
  	// wait for end of execution of the second buffer
  	VK_CHECK(vk.waitForFences(vkDevice, 1, &fence2.get(), 0u, INFINITE_TIMEOUT));
  
  	// TODO: this will be true if the command buffer was executed only once
  	// TODO: add some test that will say if it was executed twice
  
  	// check if buffer has been executed
  	VkResult result = vk.getEventStatus(vkDevice, *eventTwo);
  	if (result == VK_EVENT_SET)
  		return tcu::TestStatus::pass("simultaneous use - primary buffers test succeeded");
  	else
  		return tcu::TestStatus::fail("simultaneous use - primary buffers test FAILED");
  }
  
  tcu::TestStatus simultaneousUseSecondaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// Secondary Command buffer params
  	const VkCommandBufferAllocateInfo		secCmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			secCmdBuf				(allocateCommandBuffer(vk, vkDevice, &secCmdBufParams));
  
  	const VkCommandBufferInheritanceInfo	secCmdBufInheritInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		(VkRenderPass)0u,											// renderPass
  		0u,															// subpass
  		(VkFramebuffer)0u,											// framebuffer
  		VK_FALSE,													// occlusionQueryEnable
  		(VkQueryControlFlags)0u,									// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,							// pipelineStatistics
  	};
  	const VkCommandBufferBeginInfo			secCmdBufBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  		DE_NULL,
  		VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,				// flags
  		&secCmdBufInheritInfo,
  	};
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					eventOne				(createEvent(vk, vkDevice));
  	const Unique<VkEvent>					eventTwo				(createEvent(vk, vkDevice));
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *eventOne));
  	VK_CHECK(vk.resetEvent(vkDevice, *eventTwo));
  
  	// record secondary command buffer
  	VK_CHECK(vk.beginCommandBuffer(*secCmdBuf, &secCmdBufBeginInfo));
  	{
  		// allow execution of event during every stage of pipeline
  		VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  		// wait for event
  		vk.cmdWaitEvents(*secCmdBuf, 1, &eventOne.get(), stageMask, stageMask, 0, DE_NULL, 0u, DE_NULL, 0u, DE_NULL);
  
  		// reset event
  		vk.cmdSetEvent(*secCmdBuf, *eventTwo, stageMask);
  	}
  	// end recording of secondary buffers
  	endCommandBuffer(vk, *secCmdBuf);
  
  	// record primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf, 0u);
  	{
  		// execute secondary buffer
  		vk.cmdExecuteCommands(*primCmdBuf, 1, &secCmdBuf.get());
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	// create fence to wait for execution of queue
  	const Unique<VkFence>					fence					(createFence(vk, vkDevice));
  
  	const VkSubmitInfo						submitInfo				=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		0u,															// waitSemaphoreCount
  		DE_NULL,													// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,						// pWaitDstStageMask
  		1,															// commandBufferCount
  		&primCmdBuf.get(),											// pCommandBuffers
  		0u,															// signalSemaphoreCount
  		DE_NULL,													// pSignalSemaphores
  	};
  
  	// submit primary buffer, the secondary should be executed too
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
  
  	// wait for both buffers to stop at event for 100 microseconds
  	vk.waitForFences(vkDevice, 1, &fence.get(), 0u, 100000);
  
  	// set event
  	VK_CHECK(vk.setEvent(vkDevice, *eventOne));
  
  	// wait for end of execution of queue
  	VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), 0u, INFINITE_TIMEOUT));
  
  	// TODO: this will be true if the command buffer was executed only once
  	// TODO: add some test that will say if it was executed twice
  
  	// check if secondary buffer has been executed
  	VkResult result = vk.getEventStatus(vkDevice,*eventTwo);
  	if (result == VK_EVENT_SET)
  		return tcu::TestStatus::pass("Simultaneous Secondary Command Buffer Execution succeeded");
  	else
  		return tcu::TestStatus::fail("Simultaneous Secondary Command Buffer Execution FAILED");
  }
  
  tcu::TestStatus simultaneousUseSecondaryBufferOnePrimaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice = context.getDevice();
  	const DeviceInterface&					vk = context.getDeviceInterface();
  	const VkQueue							queue = context.getUniversalQueue();
  	const deUint32							queueFamilyIndex = context.getUniversalQueueFamilyIndex();
  	Allocator&								allocator = context.getDefaultAllocator();
  	const ComputeInstanceResultBuffer		result(vk, vkDevice, allocator, 0.0f);
  
  	const VkCommandPoolCreateInfo			cmdPoolParams =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// Secondary Command buffer params
  	const VkCommandBufferAllocateInfo		secCmdBufParams =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			secCmdBuf(allocateCommandBuffer(vk, vkDevice, &secCmdBufParams));
  
  	const VkCommandBufferInheritanceInfo	secCmdBufInheritInfo =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		(VkRenderPass)0u,
  		0u,															// subpass
  		(VkFramebuffer)0u,
  		VK_FALSE,													// occlusionQueryEnable
  		(VkQueryControlFlags)0u,
  		(VkQueryPipelineStatisticFlags)0u,
  	};
  	const VkCommandBufferBeginInfo			secCmdBufBeginInfo =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  		DE_NULL,
  		VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,				// flags
  		&secCmdBufInheritInfo,
  	};
  
  	const deUint32							offset = (0u);
  	const deUint32							addressableSize = 256;
  	const deUint32							dataSize = 8;
  	de::MovePtr<Allocation>					bufferMem;
  	const Unique<VkBuffer>					buffer(createDataBuffer(context, offset, addressableSize, 0x00, dataSize, 0x5A, &bufferMem));
  	// Secondary command buffer will have a compute shader that does an atomic increment to make sure that all instances of secondary buffers execute
  	const Unique<VkDescriptorSetLayout>		descriptorSetLayout(createDescriptorSetLayout(context));
  	const Unique<VkDescriptorPool>			descriptorPool(createDescriptorPool(context));
  	const Unique<VkDescriptorSet>			descriptorSet(createDescriptorSet(context, *descriptorPool, *descriptorSetLayout, *buffer, offset, result.getBuffer()));
  	const VkDescriptorSet					descriptorSets[] = { *descriptorSet };
  	const int								numDescriptorSets = DE_LENGTH_OF_ARRAY(descriptorSets);
  
  	const VkPipelineLayoutCreateInfo layoutCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,				// sType
  		DE_NULL,													// pNext
  		(VkPipelineLayoutCreateFlags)0,
  		numDescriptorSets,											// setLayoutCount
  		&descriptorSetLayout.get(),									// pSetLayouts
  		0u,															// pushConstantRangeCount
  		DE_NULL,													// pPushConstantRanges
  	};
  	Unique<VkPipelineLayout>				pipelineLayout(createPipelineLayout(vk, vkDevice, &layoutCreateInfo));
  
  	const Unique<VkShaderModule>			computeModule(createShaderModule(vk, vkDevice, context.getBinaryCollection().get("compute_increment"), (VkShaderModuleCreateFlags)0u));
  
  	const VkPipelineShaderStageCreateInfo	shaderCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
  		DE_NULL,
  		(VkPipelineShaderStageCreateFlags)0,
  		VK_SHADER_STAGE_COMPUTE_BIT,								// stage
  		*computeModule,												// shader
  		"main",
  		DE_NULL,													// pSpecializationInfo
  	};
  
  	const VkComputePipelineCreateInfo		pipelineCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
  		DE_NULL,
  		0u,															// flags
  		shaderCreateInfo,											// cs
  		*pipelineLayout,											// layout
  		(vk::VkPipeline)0,											// basePipelineHandle
  		0u,															// basePipelineIndex
  	};
  
  	const VkBufferMemoryBarrier				bufferBarrier =
  	{
  		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,					// sType
  		DE_NULL,													// pNext
  		VK_ACCESS_SHADER_WRITE_BIT,									// srcAccessMask
  		VK_ACCESS_HOST_READ_BIT,									// dstAccessMask
  		VK_QUEUE_FAMILY_IGNORED,									// srcQueueFamilyIndex
  		VK_QUEUE_FAMILY_IGNORED,									// destQueueFamilyIndex
  		*buffer,													// buffer
  		(VkDeviceSize)0u,											// offset
  		(VkDeviceSize)VK_WHOLE_SIZE,								// size
  	};
  
  	const Unique<VkPipeline>				pipeline(createComputePipeline(vk, vkDevice, (VkPipelineCache)0u, &pipelineCreateInfo));
  
  	// record secondary command buffer
  	VK_CHECK(vk.beginCommandBuffer(*secCmdBuf, &secCmdBufBeginInfo));
  	{
  		vk.cmdBindPipeline(*secCmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
  		vk.cmdBindDescriptorSets(*secCmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, numDescriptorSets, descriptorSets, 0, 0);
  		vk.cmdDispatch(*secCmdBuf, 1u, 1u, 1u);
  		vk.cmdPipelineBarrier(*secCmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
  						  0, (const VkMemoryBarrier*)DE_NULL,
  						  1, &bufferBarrier,
  						  0, (const VkImageMemoryBarrier*)DE_NULL);
  	}
  	// end recording of secondary buffer
  	endCommandBuffer(vk, *secCmdBuf);
  
  	// record primary command buffer
  	beginCommandBuffer(vk, *primCmdBuf, 0u);
  	{
  		// execute secondary buffer twice in same primary
  		vk.cmdExecuteCommands(*primCmdBuf, 1, &secCmdBuf.get());
  		vk.cmdExecuteCommands(*primCmdBuf, 1, &secCmdBuf.get());
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf.get());
  
  	deUint32 resultCount;
  	result.readResultContentsTo(&resultCount);
  	// check if secondary buffer has been executed
  	if (resultCount == 2)
  		return tcu::TestStatus::pass("Simultaneous Secondary Command Buffer Execution succeeded");
  	else
  		return tcu::TestStatus::fail("Simultaneous Secondary Command Buffer Execution FAILED");
  }
  
  enum class BadInheritanceInfoCase
  {
  	RANDOM_PTR = 0,
  	RANDOM_PTR_CONTINUATION,
  	RANDOM_DATA_PTR,
  	INVALID_STRUCTURE_TYPE,
  	VALID_NONSENSE_TYPE,
  };
  
  tcu::TestStatus badInheritanceInfoTest (Context& context, BadInheritanceInfoCase testCase)
  {
  	const auto&							vkd					= context.getDeviceInterface();
  	const auto							device				= context.getDevice();
  	const auto							queue				= context.getUniversalQueue();
  	const auto							queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
  	auto&								allocator			= context.getDefaultAllocator();
  	const ComputeInstanceResultBuffer	result				(vkd, device, allocator, 0.0f);
  
  	// Command pool and command buffer.
  	const auto							cmdPool			= makeCommandPool(vkd, device, queueFamilyIndex);
  	const auto							cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
  	const auto							cmdBuffer		= cmdBufferPtr.get();
  
  	// Buffers, descriptor set layouts and descriptor sets.
  	const deUint32							offset			= 0u;
  	const deUint32							addressableSize	= 256u;
  	const deUint32							dataSize		= 8u;
  
  	// The uniform buffer will not be used by the shader but is needed by auxiliar functions here.
  	de::MovePtr<Allocation>					bufferMem;
  	const Unique<VkBuffer>					buffer(createDataBuffer(context, offset, addressableSize, 0x00, dataSize, 0x5A, &bufferMem));
  
  	const Unique<VkDescriptorSetLayout>		descriptorSetLayout	(createDescriptorSetLayout(context));
  	const Unique<VkDescriptorPool>			descriptorPool		(createDescriptorPool(context));
  	const Unique<VkDescriptorSet>			descriptorSet		(createDescriptorSet(context, *descriptorPool, *descriptorSetLayout, *buffer, offset, result.getBuffer()));
  	const VkDescriptorSet					descriptorSets[]	= { *descriptorSet };
  	const int								numDescriptorSets	= DE_LENGTH_OF_ARRAY(descriptorSets);
  
  	// Pipeline layout.
  	const auto								pipelineLayout		= makePipelineLayout(vkd, device, descriptorSetLayout.get());
  
  	// Compute shader module.
  	const Unique<VkShaderModule>			computeModule		(createShaderModule(vkd, device, context.getBinaryCollection().get("compute_increment"), (VkShaderModuleCreateFlags)0u));
  
  	const VkPipelineShaderStageCreateInfo	shaderCreateInfo	=
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
  		DE_NULL,
  		(VkPipelineShaderStageCreateFlags)0,
  		VK_SHADER_STAGE_COMPUTE_BIT,								// stage
  		*computeModule,												// shader
  		"main",
  		DE_NULL,													// pSpecializationInfo
  	};
  
  	const VkComputePipelineCreateInfo		pipelineCreateInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
  		DE_NULL,
  		0u,															// flags
  		shaderCreateInfo,											// cs
  		*pipelineLayout,											// layout
  		(vk::VkPipeline)0,											// basePipelineHandle
  		0u,															// basePipelineIndex
  	};
  
  	const Unique<VkPipeline>				pipeline			(createComputePipeline(vkd, device, (VkPipelineCache)0u, &pipelineCreateInfo));
  
  	// Compute to host barrier to read result.
  	const VkBufferMemoryBarrier				bufferBarrier		=
  	{
  		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,					// sType
  		DE_NULL,													// pNext
  		VK_ACCESS_SHADER_WRITE_BIT,									// srcAccessMask
  		VK_ACCESS_HOST_READ_BIT,									// dstAccessMask
  		VK_QUEUE_FAMILY_IGNORED,									// srcQueueFamilyIndex
  		VK_QUEUE_FAMILY_IGNORED,									// destQueueFamilyIndex
  		*buffer,													// buffer
  		(VkDeviceSize)0u,											// offset
  		(VkDeviceSize)VK_WHOLE_SIZE,								// size
  	};
  
  	// Record command buffer and submit it.
  	VkCommandBufferBeginInfo				beginInfo			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	//	VkStructureType							sType;
  		nullptr,										//	const void*								pNext;
  		0u,												//	VkCommandBufferUsageFlags				flags;
  		nullptr,										//	const VkCommandBufferInheritanceInfo*	pInheritanceInfo;
  	};
  
  	// Structures used in different test types.
  	VkCommandBufferInheritanceInfo			inheritanceInfo;
  	VkBufferCreateInfo						validNonsenseStructure;
  	struct
  	{
  		VkStructureType	sType;
  		void*			pNext;
  	} invalidStructure;
  
  	if (testCase == BadInheritanceInfoCase::RANDOM_PTR || testCase == BadInheritanceInfoCase::RANDOM_PTR_CONTINUATION)
  	{
  		de::Random						rnd		(1602600778u);
  		VkCommandBufferInheritanceInfo*	info;
  		auto							ptrData	= reinterpret_cast<deUint8*>(&info);
  
  		// Fill pointer value with pseudorandom garbage.
  		for (size_t i = 0; i < sizeof(info); ++i)
  			*ptrData++ = rnd.getUint8();
  
  		beginInfo.pInheritanceInfo = info;
  
  		// Try to trick the implementation into reading pInheritanceInfo one more way.
  		if (testCase == BadInheritanceInfoCase::RANDOM_PTR_CONTINUATION)
  			beginInfo.flags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
  
  	}
  	else if (testCase == BadInheritanceInfoCase::RANDOM_DATA_PTR)
  	{
  		de::Random		rnd	(1602601141u);
  		auto			itr	= reinterpret_cast<deUint8*>(&inheritanceInfo);
  
  		// Fill inheritance info data structure with random data.
  		for (size_t i = 0; i < sizeof(inheritanceInfo); ++i)
  			*itr++ = rnd.getUint8();
  
  		beginInfo.pInheritanceInfo = &inheritanceInfo;
  	}
  	else if (testCase == BadInheritanceInfoCase::INVALID_STRUCTURE_TYPE)
  	{
  		de::Random	rnd			(1602658515u);
  		auto		ptrData		= reinterpret_cast<deUint8*>(&(invalidStructure.pNext));
  		invalidStructure.sType	= VK_STRUCTURE_TYPE_MAX_ENUM;
  
  		// Fill pNext pointer with random data.
  		for (size_t i = 0; i < sizeof(invalidStructure.pNext); ++i)
  			*ptrData++ = rnd.getUint8();
  
  		beginInfo.pInheritanceInfo = reinterpret_cast<VkCommandBufferInheritanceInfo*>(&invalidStructure);
  	}
  	else if (testCase == BadInheritanceInfoCase::VALID_NONSENSE_TYPE)
  	{
  		validNonsenseStructure.sType					= VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  		validNonsenseStructure.pNext					= nullptr;
  		validNonsenseStructure.flags					= 0u;
  		validNonsenseStructure.size						= 1024u;
  		validNonsenseStructure.usage					= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
  		validNonsenseStructure.sharingMode				= VK_SHARING_MODE_EXCLUSIVE;
  		validNonsenseStructure.queueFamilyIndexCount	= 0u;
  		validNonsenseStructure.pQueueFamilyIndices		= nullptr;
  
  		beginInfo.pInheritanceInfo						= reinterpret_cast<VkCommandBufferInheritanceInfo*>(&validNonsenseStructure);
  	}
  	else
  	{
  		DE_ASSERT(false);
  	}
  
  	VK_CHECK(vkd.beginCommandBuffer(cmdBuffer, &beginInfo));
  	{
  		vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
  		vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, numDescriptorSets, descriptorSets, 0, 0);
  		vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
  		vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
  							   0, (const VkMemoryBarrier*)DE_NULL,
  							   1, &bufferBarrier,
  							   0, (const VkImageMemoryBarrier*)DE_NULL);
  	}
  	endCommandBuffer(vkd, cmdBuffer);
  	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
  
  	deUint32 resultCount;
  	result.readResultContentsTo(&resultCount);
  
  	// Make sure the command buffer was run.
  	if (resultCount != 1u)
  	{
  		std::ostringstream msg;
  		msg << "Invalid value found in results buffer (expected value 1u but found " << resultCount << ")";
  		return tcu::TestStatus::fail(msg.str());
  	}
  
  	return tcu::TestStatus::pass("Pass");
  }
  
  tcu::TestStatus simultaneousUseSecondaryBufferTwoPrimaryBuffersTest(Context& context)
  {
  	const VkDevice							vkDevice = context.getDevice();
  	const DeviceInterface&					vk = context.getDeviceInterface();
  	const VkQueue							queue = context.getUniversalQueue();
  	const deUint32							queueFamilyIndex = context.getUniversalQueueFamilyIndex();
  	Allocator&								allocator = context.getDefaultAllocator();
  	const ComputeInstanceResultBuffer		result(vk, vkDevice, allocator, 0.0f);
  
  	const VkCommandPoolCreateInfo			cmdPoolParams =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	// Two separate primary cmd buffers that will be executed with the same secondary cmd buffer
  	const deUint32 numPrimCmdBufs = 2;
  	const Unique<VkCommandBuffer>			primCmdBufOne(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  	const Unique<VkCommandBuffer>			primCmdBufTwo(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  	VkCommandBuffer primCmdBufs[numPrimCmdBufs];
  	primCmdBufs[0] = primCmdBufOne.get();
  	primCmdBufs[1] = primCmdBufTwo.get();
  
  	// Secondary Command buffer params
  	const VkCommandBufferAllocateInfo		secCmdBufParams =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			secCmdBuf(allocateCommandBuffer(vk, vkDevice, &secCmdBufParams));
  
  	const VkCommandBufferBeginInfo			primCmdBufBeginInfo =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  		DE_NULL,
  		0,															// flags
  		(const VkCommandBufferInheritanceInfo*)DE_NULL,
  	};
  
  	const VkCommandBufferInheritanceInfo	secCmdBufInheritInfo =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		(VkRenderPass)0u,											// renderPass
  		0u,															// subpass
  		(VkFramebuffer)0u,											// framebuffer
  		VK_FALSE,													// occlusionQueryEnable
  		(VkQueryControlFlags)0u,									// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,							// pipelineStatistics
  	};
  	const VkCommandBufferBeginInfo			secCmdBufBeginInfo =
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  		DE_NULL,
  		VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,				// flags
  		&secCmdBufInheritInfo,
  	};
  
  	const deUint32							offset = (0u);
  	const deUint32							addressableSize = 256;
  	const deUint32							dataSize = 8;
  	de::MovePtr<Allocation>					bufferMem;
  	const Unique<VkBuffer>					buffer(createDataBuffer(context, offset, addressableSize, 0x00, dataSize, 0x5A, &bufferMem));
  	// Secondary command buffer will have a compute shader that does an atomic increment to make sure that all instances of secondary buffers execute
  	const Unique<VkDescriptorSetLayout>		descriptorSetLayout(createDescriptorSetLayout(context));
  	const Unique<VkDescriptorPool>			descriptorPool(createDescriptorPool(context));
  	const Unique<VkDescriptorSet>			descriptorSet(createDescriptorSet(context, *descriptorPool, *descriptorSetLayout, *buffer, offset, result.getBuffer()));
  	const VkDescriptorSet					descriptorSets[] = { *descriptorSet };
  	const int								numDescriptorSets = DE_LENGTH_OF_ARRAY(descriptorSets);
  
  	const VkPipelineLayoutCreateInfo layoutCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,				// sType
  		DE_NULL,													// pNext
  		(VkPipelineLayoutCreateFlags)0,
  		numDescriptorSets,											// setLayoutCount
  		&descriptorSetLayout.get(),									// pSetLayouts
  		0u,															// pushConstantRangeCount
  		DE_NULL,													// pPushConstantRanges
  	};
  	Unique<VkPipelineLayout>				pipelineLayout(createPipelineLayout(vk, vkDevice, &layoutCreateInfo));
  
  	const Unique<VkShaderModule>			computeModule(createShaderModule(vk, vkDevice, context.getBinaryCollection().get("compute_increment"), (VkShaderModuleCreateFlags)0u));
  
  	const VkPipelineShaderStageCreateInfo	shaderCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
  		DE_NULL,
  		(VkPipelineShaderStageCreateFlags)0,
  		VK_SHADER_STAGE_COMPUTE_BIT,								// stage
  		*computeModule,												// shader
  		"main",
  		DE_NULL,													// pSpecializationInfo
  	};
  
  	const VkComputePipelineCreateInfo		pipelineCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
  		DE_NULL,
  		0u,															// flags
  		shaderCreateInfo,											// cs
  		*pipelineLayout,											// layout
  		(vk::VkPipeline)0,											// basePipelineHandle
  		0u,															// basePipelineIndex
  	};
  
  	const Unique<VkPipeline>				pipeline(createComputePipeline(vk, vkDevice, (VkPipelineCache)0u, &pipelineCreateInfo));
  
  	// record secondary command buffer
  	VK_CHECK(vk.beginCommandBuffer(*secCmdBuf, &secCmdBufBeginInfo));
  	{
  		vk.cmdBindPipeline(*secCmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
  		vk.cmdBindDescriptorSets(*secCmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, numDescriptorSets, descriptorSets, 0, 0);
  		vk.cmdDispatch(*secCmdBuf, 1u, 1u, 1u);
  	}
  	// end recording of secondary buffer
  	endCommandBuffer(vk, *secCmdBuf);
  
  	// record primary command buffers
  	// Insert one instance of same secondary command buffer into two separate primary command buffers
  	VK_CHECK(vk.beginCommandBuffer(*primCmdBufOne, &primCmdBufBeginInfo));
  	{
  		vk.cmdExecuteCommands(*primCmdBufOne, 1, &secCmdBuf.get());
  	}
  	endCommandBuffer(vk, *primCmdBufOne);
  
  	VK_CHECK(vk.beginCommandBuffer(*primCmdBufTwo, &primCmdBufBeginInfo));
  	{
  		vk.cmdExecuteCommands(*primCmdBufTwo, 1, &secCmdBuf.get());
  	}
  	endCommandBuffer(vk, *primCmdBufTwo);
  
  	// create fence to wait for execution of queue
  	const Unique<VkFence>					fence(createFence(vk, vkDevice));
  
  	const VkSubmitInfo						submitInfo =
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		0u,															// waitSemaphoreCount
  		DE_NULL,													// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,						// pWaitDstStageMask
  		numPrimCmdBufs,												// commandBufferCount
  		primCmdBufs,												// pCommandBuffers
  		0u,															// signalSemaphoreCount
  		DE_NULL,													// pSignalSemaphores
  	};
  
  	// submit primary buffers, the secondary should be executed too
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
  
  	// wait for end of execution of queue
  	VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), 0u, INFINITE_TIMEOUT));
  
  	deUint32 resultCount;
  	result.readResultContentsTo(&resultCount);
  	// check if secondary buffer has been executed
  	if (resultCount == 2)
  		return tcu::TestStatus::pass("Simultaneous Secondary Command Buffer Execution succeeded");
  	else
  		return tcu::TestStatus::fail("Simultaneous Secondary Command Buffer Execution FAILED");
  }
  
  tcu::TestStatus recordBufferQueryPreciseWithFlagTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	if (!context.getDeviceFeatures().inheritedQueries)
  		TCU_THROW(NotSupportedError, "Inherited queries feature is not supported");
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		primCmdBufParams		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// level;
  		1u,															// flags;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &primCmdBufParams));
  
  	// Secondary Command buffer params
  	const VkCommandBufferAllocateInfo		secCmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							// level;
  		1u,															// flags;
  	};
  	const Unique<VkCommandBuffer>			secCmdBuf				(allocateCommandBuffer(vk, vkDevice, &secCmdBufParams));
  
  	const VkCommandBufferBeginInfo			primBufferBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		(const VkCommandBufferInheritanceInfo*)DE_NULL,
  	};
  
  	const VkCommandBufferInheritanceInfo	secBufferInheritInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		0u,															// renderPass
  		0u,															// subpass
  		0u,															// framebuffer
  		VK_TRUE,													// occlusionQueryEnable
  		VK_QUERY_CONTROL_PRECISE_BIT,								// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,							// pipelineStatistics
  	};
  	const VkCommandBufferBeginInfo			secBufferBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		&secBufferInheritInfo,
  	};
  
  	const VkQueryPoolCreateInfo				queryPoolCreateInfo		=
  	{
  		VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,					// sType
  		DE_NULL,													// pNext
  		(VkQueryPoolCreateFlags)0,									// flags
  		VK_QUERY_TYPE_OCCLUSION,									// queryType
  		1u,															// entryCount
  		0u,															// pipelineStatistics
  	};
  	Unique<VkQueryPool>						queryPool				(createQueryPool(vk, vkDevice, &queryPoolCreateInfo));
  
  	VK_CHECK(vk.beginCommandBuffer(secCmdBuf.get(), &secBufferBeginInfo));
  	endCommandBuffer(vk, secCmdBuf.get());
  
  	VK_CHECK(vk.beginCommandBuffer(primCmdBuf.get(), &primBufferBeginInfo));
  	{
  		vk.cmdResetQueryPool(primCmdBuf.get(), queryPool.get(), 0u, 1u);
  		vk.cmdBeginQuery(primCmdBuf.get(), queryPool.get(), 0u, VK_QUERY_CONTROL_PRECISE_BIT);
  		{
  			vk.cmdExecuteCommands(primCmdBuf.get(), 1u, &secCmdBuf.get());
  		}
  		vk.cmdEndQuery(primCmdBuf.get(), queryPool.get(), 0u);
  	}
  	endCommandBuffer(vk, primCmdBuf.get());
  
  	return tcu::TestStatus::pass("Successfully recorded a secondary command buffer allowing a precise occlusion query.");
  }
  
  tcu::TestStatus recordBufferQueryImpreciseWithFlagTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	if (!context.getDeviceFeatures().inheritedQueries)
  		TCU_THROW(NotSupportedError, "Inherited queries feature is not supported");
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		primCmdBufParams		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// level;
  		1u,															// flags;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &primCmdBufParams));
  
  	// Secondary Command buffer params
  	const VkCommandBufferAllocateInfo		secCmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							// level;
  		1u,															// flags;
  	};
  	const Unique<VkCommandBuffer>			secCmdBuf				(allocateCommandBuffer(vk, vkDevice, &secCmdBufParams));
  
  	const VkCommandBufferBeginInfo			primBufferBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		(const VkCommandBufferInheritanceInfo*)DE_NULL,
  	};
  
  	const VkCommandBufferInheritanceInfo	secBufferInheritInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		0u,															// renderPass
  		0u,															// subpass
  		0u,															// framebuffer
  		VK_TRUE,													// occlusionQueryEnable
  		VK_QUERY_CONTROL_PRECISE_BIT,								// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,							// pipelineStatistics
  	};
  	const VkCommandBufferBeginInfo			secBufferBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		&secBufferInheritInfo,
  	};
  
  	// Create an occlusion query with VK_QUERY_CONTROL_PRECISE_BIT set
  	const VkQueryPoolCreateInfo				queryPoolCreateInfo		=
  	{
  		VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,					// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		VK_QUERY_TYPE_OCCLUSION,									// queryType
  		1u,															// entryCount
  		0u,															// pipelineStatistics
  	};
  	Unique<VkQueryPool>						queryPool				(createQueryPool(vk, vkDevice, &queryPoolCreateInfo));
  
  	VK_CHECK(vk.beginCommandBuffer(secCmdBuf.get(), &secBufferBeginInfo));
  	endCommandBuffer(vk, secCmdBuf.get());
  
  	VK_CHECK(vk.beginCommandBuffer(primCmdBuf.get(), &primBufferBeginInfo));
  	{
  		vk.cmdResetQueryPool(primCmdBuf.get(), queryPool.get(), 0u, 1u);
  		vk.cmdBeginQuery(primCmdBuf.get(), queryPool.get(), 0u, VK_QUERY_CONTROL_PRECISE_BIT);
  		{
  			vk.cmdExecuteCommands(primCmdBuf.get(), 1u, &secCmdBuf.get());
  		}
  		vk.cmdEndQuery(primCmdBuf.get(), queryPool.get(), 0u);
  	}
  	endCommandBuffer(vk, primCmdBuf.get());
  
  	return tcu::TestStatus::pass("Successfully recorded a secondary command buffer allowing a precise occlusion query.");
  }
  
  tcu::TestStatus recordBufferQueryImpreciseWithoutFlagTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	if (!context.getDeviceFeatures().inheritedQueries)
  		TCU_THROW(NotSupportedError, "Inherited queries feature is not supported");
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		primCmdBufParams		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// level;
  		1u,															// flags;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &primCmdBufParams));
  
  	// Secondary Command buffer params
  	const VkCommandBufferAllocateInfo		secCmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							// level;
  		1u,															// flags;
  	};
  	const Unique<VkCommandBuffer>			secCmdBuf				(allocateCommandBuffer(vk, vkDevice, &secCmdBufParams));
  
  	const VkCommandBufferBeginInfo			primBufferBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		(const VkCommandBufferInheritanceInfo*)DE_NULL,
  	};
  
  	const VkCommandBufferInheritanceInfo	secBufferInheritInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		0u,															// renderPass
  		0u,															// subpass
  		0u,															// framebuffer
  		VK_TRUE,													// occlusionQueryEnable
  		0u,															// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,							// pipelineStatistics
  	};
  	const VkCommandBufferBeginInfo			secBufferBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		&secBufferInheritInfo,
  	};
  
  	// Create an occlusion query with VK_QUERY_CONTROL_PRECISE_BIT set
  	const VkQueryPoolCreateInfo				queryPoolCreateInfo		=
  	{
  		VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,					// sType
  		DE_NULL,													// pNext
  		(VkQueryPoolCreateFlags)0,
  		VK_QUERY_TYPE_OCCLUSION,
  		1u,
  		0u,
  	};
  	Unique<VkQueryPool>						queryPool				(createQueryPool(vk, vkDevice, &queryPoolCreateInfo));
  
  	VK_CHECK(vk.beginCommandBuffer(secCmdBuf.get(), &secBufferBeginInfo));
  	endCommandBuffer(vk, secCmdBuf.get());
  
  	VK_CHECK(vk.beginCommandBuffer(primCmdBuf.get(), &primBufferBeginInfo));
  	{
  		vk.cmdResetQueryPool(primCmdBuf.get(), queryPool.get(), 0u, 1u);
  		vk.cmdBeginQuery(primCmdBuf.get(), queryPool.get(), 0u, VK_QUERY_CONTROL_PRECISE_BIT);
  		{
  			vk.cmdExecuteCommands(primCmdBuf.get(), 1u, &secCmdBuf.get());
  		}
  		vk.cmdEndQuery(primCmdBuf.get(), queryPool.get(), 0u);
  	}
  	endCommandBuffer(vk, primCmdBuf.get());
  
  	return tcu::TestStatus::pass("Successfully recorded a secondary command buffer allowing a precise occlusion query.");
  }
  
  /******** 19.4. Command Buffer Submission (5.4 in VK 1.0 Spec) ****************/
  tcu::TestStatus submitBufferCountNonZero(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const deUint32							BUFFER_COUNT			= 5u;
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		0u,															// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// level;
  		BUFFER_COUNT,												// bufferCount;
  	};
  	VkCommandBuffer cmdBuffers[BUFFER_COUNT];
  	VK_CHECK(vk.allocateCommandBuffers(vkDevice, &cmdBufParams, cmdBuffers));
  
  	const VkCommandBufferBeginInfo			cmdBufBeginInfo			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		(const VkCommandBufferInheritanceInfo*)DE_NULL,
  	};
  
  	std::vector<VkEventSp>					events;
  	for (deUint32 ndx = 0; ndx < BUFFER_COUNT; ++ndx)
  	{
  		events.push_back(VkEventSp(new vk::Unique<VkEvent>(createEvent(vk, vkDevice))));
  	}
  
  	// Record the command buffers
  	for (deUint32 ndx = 0; ndx < BUFFER_COUNT; ++ndx)
  	{
  		VK_CHECK(vk.beginCommandBuffer(cmdBuffers[ndx], &cmdBufBeginInfo));
  		{
  			vk.cmdSetEvent(cmdBuffers[ndx], events[ndx]->get(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  		}
  		endCommandBuffer(vk, cmdBuffers[ndx]);
  	}
  
  	// We'll use a fence to wait for the execution of the queue
  	const Unique<VkFence>					fence					(createFence(vk, vkDevice));
  
  	const VkSubmitInfo						submitInfo				=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		0u,															// waitSemaphoreCount
  		DE_NULL,													// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,						// pWaitDstStageMask
  		BUFFER_COUNT,												// commandBufferCount
  		cmdBuffers,													// pCommandBuffers
  		0u,															// signalSemaphoreCount
  		DE_NULL,													// pSignalSemaphores
  	};
  
  	// Submit the alpha command buffer to the queue
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, fence.get()));
  	// Wait for the queue
  	VK_CHECK(vk.waitForFences(vkDevice, 1u, &fence.get(), VK_TRUE, INFINITE_TIMEOUT));
  
  	// Check if the buffers were executed
  	tcu::TestStatus testResult = tcu::TestStatus::incomplete();
  
  	for (deUint32 ndx = 0; ndx < BUFFER_COUNT; ++ndx)
  	{
  		if (vk.getEventStatus(vkDevice, events[ndx]->get()) != VK_EVENT_SET)
  		{
  			testResult = tcu::TestStatus::fail("Failed to set the event.");
  			break;
  		}
  	}
  
  	if (!testResult.isComplete())
  		testResult = tcu::TestStatus::pass("All buffers were submitted and executed correctly.");
  
  	return testResult;
  }
  
  tcu::TestStatus submitBufferCountEqualZero(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const deUint32							BUFFER_COUNT			= 2u;
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		0u,															// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// level;
  		BUFFER_COUNT,												// bufferCount;
  	};
  	VkCommandBuffer cmdBuffers[BUFFER_COUNT];
  	VK_CHECK(vk.allocateCommandBuffers(vkDevice, &cmdBufParams, cmdBuffers));
  
  	const VkCommandBufferBeginInfo			cmdBufBeginInfo			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		(const VkCommandBufferInheritanceInfo*)DE_NULL,
  	};
  
  	std::vector<VkEventSp>					events;
  	for (deUint32 ndx = 0; ndx < BUFFER_COUNT; ++ndx)
  		events.push_back(VkEventSp(new vk::Unique<VkEvent>(createEvent(vk, vkDevice))));
  
  	// Record the command buffers
  	for (deUint32 ndx = 0; ndx < BUFFER_COUNT; ++ndx)
  	{
  		VK_CHECK(vk.beginCommandBuffer(cmdBuffers[ndx], &cmdBufBeginInfo));
  		{
  			vk.cmdSetEvent(cmdBuffers[ndx], events[ndx]->get(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  		}
  		endCommandBuffer(vk, cmdBuffers[ndx]);
  	}
  
  	// We'll use a fence to wait for the execution of the queue
  	const Unique<VkFence>					fenceZero				(createFence(vk, vkDevice));
  	const Unique<VkFence>					fenceOne				(createFence(vk, vkDevice));
  
  	const VkSubmitInfo						submitInfoCountZero		=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		0u,															// waitSemaphoreCount
  		DE_NULL,													// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,						// pWaitDstStageMask
  		1u,															// commandBufferCount
  		&cmdBuffers[0],												// pCommandBuffers
  		0u,															// signalSemaphoreCount
  		DE_NULL,													// pSignalSemaphores
  	};
  
  	const VkSubmitInfo						submitInfoCountOne		=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		0u,															// waitSemaphoreCount
  		DE_NULL,													// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,						// pWaitDstStageMask
  		1u,															// commandBufferCount
  		&cmdBuffers[1],												// pCommandBuffers
  		0u,															// signalSemaphoreCount
  		DE_NULL,													// pSignalSemaphores
  	};
  
  	// Submit the command buffers to the queue
  	// We're performing two submits to make sure that the first one has
  	// a chance to be processed before we check the event's status
  	VK_CHECK(vk.queueSubmit(queue, 0, &submitInfoCountZero, fenceZero.get()));
  	VK_CHECK(vk.queueSubmit(queue, 1, &submitInfoCountOne, fenceOne.get()));
  
  	const VkFence							fences[]				=
  	{
  		fenceZero.get(),
  		fenceOne.get(),
  	};
  
  	// Wait for the queue
  	VK_CHECK(vk.waitForFences(vkDevice, (deUint32)DE_LENGTH_OF_ARRAY(fences), fences, VK_TRUE, INFINITE_TIMEOUT));
  
  	// Check if the first buffer was executed
  	tcu::TestStatus testResult = tcu::TestStatus::incomplete();
  
  	if (vk.getEventStatus(vkDevice, events[0]->get()) == VK_EVENT_SET)
  		testResult = tcu::TestStatus::fail("The first event was signaled.");
  	else
  		testResult = tcu::TestStatus::pass("The first submission was ignored.");
  
  	return testResult;
  }
  
  tcu::TestStatus submitBufferWaitSingleSemaphore(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// VkStructureType				sType;
  		DE_NULL,													// const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// VkCommandPoolCreateFlags		flags;
  		queueFamilyIndex,											// deUint32						queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// VkStructureType				sType;
  		DE_NULL,													// const void*					pNext;
  		*cmdPool,													// VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// VkCommandBufferLevel			level;
  		1u,															// uint32_t						bufferCount;
  	};
  
  	// Create two command buffers
  	const Unique<VkCommandBuffer>			primCmdBuf1				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  	const Unique<VkCommandBuffer>			primCmdBuf2				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	const VkCommandBufferBeginInfo			primCmdBufBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0,															// flags
  		DE_NULL														// const VkCommandBufferInheritanceInfo*	pInheritanceInfo;
  	};
  
  	// create two events that will be used to check if command buffers has been executed
  	const Unique<VkEvent>					event1					(createEvent(vk, vkDevice));
  	const Unique<VkEvent>					event2					(createEvent(vk, vkDevice));
  
  	// reset events
  	VK_CHECK(vk.resetEvent(vkDevice, *event1));
  	VK_CHECK(vk.resetEvent(vkDevice, *event2));
  
  	// record first command buffer
  	VK_CHECK(vk.beginCommandBuffer(*primCmdBuf1, &primCmdBufBeginInfo));
  	{
  		// allow execution of event during every stage of pipeline
  		VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  		// record setting event
  		vk.cmdSetEvent(*primCmdBuf1, *event1,stageMask);
  	}
  	endCommandBuffer(vk, *primCmdBuf1);
  
  	// record second command buffer
  	VK_CHECK(vk.beginCommandBuffer(*primCmdBuf2, &primCmdBufBeginInfo));
  	{
  		// allow execution of event during every stage of pipeline
  		VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  		// record setting event
  		vk.cmdSetEvent(*primCmdBuf2, *event2,stageMask);
  	}
  	endCommandBuffer(vk, *primCmdBuf2);
  
  	// create fence to wait for execution of queue
  	const Unique<VkFence>					fence					(createFence(vk, vkDevice));
  
  	// create semaphore for use in this test
  	const Unique <VkSemaphore>				semaphore				(createSemaphore(vk, vkDevice));
  
  	// create submit info for first buffer - signalling semaphore
  	const VkSubmitInfo						submitInfo1				=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		0u,															// waitSemaphoreCount
  		DE_NULL,													// pWaitSemaphores
  		DE_NULL,													// pWaitDstStageMask
  		1,															// commandBufferCount
  		&primCmdBuf1.get(),											// pCommandBuffers
  		1u,															// signalSemaphoreCount
  		&semaphore.get(),											// pSignalSemaphores
  	};
  
  	// Submit the command buffer to the queue
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo1, *fence));
  
  	// wait for end of execution of queue
  	VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), 0u, INFINITE_TIMEOUT));
  
  	// check if buffer has been executed
  	VkResult result = vk.getEventStatus(vkDevice,*event1);
  	if (result != VK_EVENT_SET)
  		return tcu::TestStatus::fail("Submit Buffer and Wait for Single Semaphore Test FAILED");
  
  	const VkPipelineStageFlags				waitDstStageFlags		= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
  
  	// create submit info for second buffer - waiting for semaphore
  	const VkSubmitInfo						submitInfo2				=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		1u,															// waitSemaphoreCount
  		&semaphore.get(),											// pWaitSemaphores
  		&waitDstStageFlags,											// pWaitDstStageMask
  		1,															// commandBufferCount
  		&primCmdBuf2.get(),											// pCommandBuffers
  		0u,															// signalSemaphoreCount
  		DE_NULL,													// pSignalSemaphores
  	};
  
  	// reset fence, so it can be used again
  	VK_CHECK(vk.resetFences(vkDevice, 1u, &fence.get()));
  
  	// Submit the second command buffer to the queue
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo2, *fence));
  
  	// wait for end of execution of queue
  	VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), 0u, INFINITE_TIMEOUT));
  
  	// check if second buffer has been executed
  	// if it has been executed, it means that the semaphore was signalled - so test if passed
  	result = vk.getEventStatus(vkDevice,*event1);
  	if (result != VK_EVENT_SET)
  		return tcu::TestStatus::fail("Submit Buffer and Wait for Single Semaphore Test FAILED");
  
  	return tcu::TestStatus::pass("Submit Buffer and Wait for Single Semaphore Test succeeded");
  }
  
  tcu::TestStatus submitBufferWaitManySemaphores(Context& context)
  {
  	// This test will create numSemaphores semaphores, and signal them in NUM_SEMAPHORES submits to queue
  	// After that the numSubmissions queue submissions will wait for each semaphore
  
  	const deUint32							numSemaphores			= 10u;  // it must be multiply of numSubmission
  	const deUint32							numSubmissions			= 2u;
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// VkStructureType				sType;
  		DE_NULL,													// const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// VkCommandPoolCreateFlags		flags;
  		queueFamilyIndex,											// deUint32						queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// VkStructureType				sType;
  		DE_NULL,													// const void*					pNext;
  		*cmdPool,													// VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// VkCommandBufferLevel			level;
  		1u,															// uint32_t						bufferCount;
  	};
  
  	// Create command buffer
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	const VkCommandBufferBeginInfo			primCmdBufBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0,															// flags
  		DE_NULL														// const VkCommandBufferInheritanceInfo*	pInheritanceInfo;
  	};
  
  	// create event that will be used to check if command buffers has been executed
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// reset event - at creation state is undefined
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	// record command buffer
  	VK_CHECK(vk.beginCommandBuffer(*primCmdBuf, &primCmdBufBeginInfo));
  	{
  		// allow execution of event during every stage of pipeline
  		VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  		// record setting event
  		vk.cmdSetEvent(*primCmdBuf, *event,stageMask);
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	// create fence to wait for execution of queue
  	const Unique<VkFence>					fence					(createFence(vk, vkDevice));
  
  	// numSemaphores is declared const, so this array can be static
  	// the semaphores will be destroyed automatically at end of scope
  	Move <VkSemaphore>						semaphoreArray[numSemaphores];
  	VkSemaphore								semaphores[numSemaphores];
  
  	for (deUint32 idx = 0; idx < numSemaphores; ++idx) {
  		// create semaphores for use in this test
  		semaphoreArray[idx] = createSemaphore(vk, vkDevice);
  		semaphores[idx] = semaphoreArray[idx].get();
  	}
  
  	{
  		// create submit info for buffer - signal semaphores
  		const VkSubmitInfo submitInfo1 =
  		{
  			VK_STRUCTURE_TYPE_SUBMIT_INFO,							// sType
  			DE_NULL,												// pNext
  			0u,														// waitSemaphoreCount
  			DE_NULL,												// pWaitSemaphores
  			DE_NULL,												// pWaitDstStageMask
  			1,														// commandBufferCount
  			&primCmdBuf.get(),										// pCommandBuffers
  			numSemaphores,											// signalSemaphoreCount
  			semaphores												// pSignalSemaphores
  		};
  		// Submit the command buffer to the queue
  		VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo1, *fence));
  
  		// wait for end of execution of queue
  		VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), 0u, INFINITE_TIMEOUT));
  
  		// check if buffer has been executed
  		VkResult result = vk.getEventStatus(vkDevice,*event);
  		if (result != VK_EVENT_SET)
  			return tcu::TestStatus::fail("Submit Buffer and Wait for Many Semaphores Test FAILED");
  
  		// reset event, so next buffers can set it again
  		VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  		// reset fence, so it can be used again
  		VK_CHECK(vk.resetFences(vkDevice, 1u, &fence.get()));
  	}
  
  	const deUint32							numberOfSemaphoresToBeWaitedByOneSubmission	= numSemaphores / numSubmissions;
  	const std::vector<VkPipelineStageFlags>	waitDstStageFlags							(numberOfSemaphoresToBeWaitedByOneSubmission, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
  
  	// the following code waits for the semaphores set above - numSubmissions queues will wait for each semaphore from above
  	for (deUint32 idxSubmission = 0; idxSubmission < numSubmissions; ++idxSubmission) {
  
  		// create submit info for buffer - waiting for semaphore
  		const VkSubmitInfo				submitInfo2				=
  		{
  			VK_STRUCTURE_TYPE_SUBMIT_INFO,												// sType
  			DE_NULL,																	// pNext
  			numberOfSemaphoresToBeWaitedByOneSubmission,								// waitSemaphoreCount
  			semaphores + (numberOfSemaphoresToBeWaitedByOneSubmission * idxSubmission),	// pWaitSemaphores
  			waitDstStageFlags.data(),													// pWaitDstStageMask
  			1,																			// commandBufferCount
  			&primCmdBuf.get(),															// pCommandBuffers
  			0u,																			// signalSemaphoreCount
  			DE_NULL,																	// pSignalSemaphores
  		};
  
  		// Submit the second command buffer to the queue
  		VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo2, *fence));
  
  		// wait for 1 second.
  		VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), 0u, 1000 * 1000 * 1000));
  
  		// check if second buffer has been executed
  		// if it has been executed, it means that the semaphore was signalled - so test if passed
  		VkResult result = vk.getEventStatus(vkDevice,*event);
  		if (result != VK_EVENT_SET)
  			return tcu::TestStatus::fail("Submit Buffer and Wait for Many Semaphores Test FAILED");
  
  		// reset fence, so it can be used again
  		VK_CHECK(vk.resetFences(vkDevice, 1u, &fence.get()));
  
  		// reset event, so next buffers can set it again
  		VK_CHECK(vk.resetEvent(vkDevice, *event));
  	}
  
  	return tcu::TestStatus::pass("Submit Buffer and Wait for Many Semaphores Test succeeded");
  }
  
  tcu::TestStatus submitBufferNullFence(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const short								BUFFER_COUNT			= 2;
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		0u,															// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// level;
  		1u,															// bufferCount;
  	};
  	VkCommandBuffer cmdBuffers[BUFFER_COUNT];
  	for (deUint32 ndx = 0; ndx < BUFFER_COUNT; ++ndx)
  		VK_CHECK(vk.allocateCommandBuffers(vkDevice, &cmdBufParams, &cmdBuffers[ndx]));
  
  	const VkCommandBufferBeginInfo			cmdBufBeginInfo			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		(const VkCommandBufferInheritanceInfo*)DE_NULL,
  	};
  
  	std::vector<VkEventSp>					events;
  	for (deUint32 ndx = 0; ndx < BUFFER_COUNT; ++ndx)
  		events.push_back(VkEventSp(new vk::Unique<VkEvent>(createEvent(vk, vkDevice))));
  
  	// Record the command buffers
  	for (deUint32 ndx = 0; ndx < BUFFER_COUNT; ++ndx)
  	{
  		VK_CHECK(vk.beginCommandBuffer(cmdBuffers[ndx], &cmdBufBeginInfo));
  		{
  			vk.cmdSetEvent(cmdBuffers[ndx], events[ndx]->get(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  		}
  		endCommandBuffer(vk, cmdBuffers[ndx]);
  	}
  
  	// We'll use a fence to wait for the execution of the queue
  	const Unique<VkFence>					fence					(createFence(vk, vkDevice));
  
  	const VkSubmitInfo						submitInfoNullFence		=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		0u,															// waitSemaphoreCount
  		DE_NULL,													// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,						// pWaitDstStageMask
  		1u,															// commandBufferCount
  		&cmdBuffers[0],												// pCommandBuffers
  		0u,															// signalSemaphoreCount
  		DE_NULL,													// pSignalSemaphores
  	};
  
  	const VkSubmitInfo						submitInfoNonNullFence	=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		0u,															// waitSemaphoreCount
  		DE_NULL,													// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,						// pWaitDstStageMask
  		1u,															// commandBufferCount
  		&cmdBuffers[1],												// pCommandBuffers
  		0u,															// signalSemaphoreCount
  		DE_NULL,													// pSignalSemaphores
  	};
  
  	// Perform two submissions - one with no fence, the other one with a valid
  	// fence Hoping submitting the other buffer will give the first one time to
  	// execute
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfoNullFence, DE_NULL));
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfoNonNullFence, fence.get()));
  
  	// Wait for the queue
  	VK_CHECK(vk.waitForFences(vkDevice, 1u, &fence.get(), VK_TRUE, INFINITE_TIMEOUT));
  
  
  	tcu::TestStatus testResult = tcu::TestStatus::incomplete();
  
  	//Fence guaranteed that all buffers submited before fence were executed
  	if (vk.getEventStatus(vkDevice, events[0]->get()) != VK_EVENT_SET || vk.getEventStatus(vkDevice, events[1]->get()) != VK_EVENT_SET)
  	{
  		testResult = tcu::TestStatus::fail("One of the buffers was not executed.");
  	}
  	else
  	{
  		testResult = tcu::TestStatus::pass("Buffers have been submitted and executed correctly.");
  	}
  
  	vk.queueWaitIdle(queue);
  	return testResult;
  }
  
  tcu::TestStatus submitTwoBuffersOneBufferNullWithFence(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  	const deUint32							BUFFER_COUNT			= 2u;
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,			// sType;
  		DE_NULL,											// pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,	// flags;
  		queueFamilyIndex,									// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// sType;
  		DE_NULL,										// pNext;
  		*cmdPool,										// pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// level;
  		BUFFER_COUNT,									// bufferCount;
  	};
  
  	VkCommandBuffer							cmdBuffers[BUFFER_COUNT];
  	VK_CHECK(vk.allocateCommandBuffers(vkDevice, &cmdBufParams, cmdBuffers));
  
  	const VkCommandBufferBeginInfo			cmdBufBeginInfo			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	// sType
  		DE_NULL,										// pNext
  		0u,												// flags
  		(const VkCommandBufferInheritanceInfo*)DE_NULL,	// pInheritanceInfo
  	};
  
  	std::vector<VkEventSp>					events;
  	for (deUint32 ndx = 0; ndx < BUFFER_COUNT; ++ndx)
  		events.push_back(VkEventSp(new vk::Unique<VkEvent>(createEvent(vk, vkDevice))));
  
  	// Record the command buffers
  	for (deUint32 ndx = 0; ndx < BUFFER_COUNT; ++ndx)
  	{
  		VK_CHECK(vk.beginCommandBuffer(cmdBuffers[ndx], &cmdBufBeginInfo));
  		{
  			vk.cmdSetEvent(cmdBuffers[ndx], events[ndx]->get(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  		}
  		VK_CHECK(vk.endCommandBuffer(cmdBuffers[ndx]));
  	}
  
  	// First command buffer
  	const VkSubmitInfo						submitInfoNonNullFirst	=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,				// sType
  		DE_NULL,									// pNext
  		0u,											// waitSemaphoreCount
  		DE_NULL,									// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,		// pWaitDstStageMask
  		1u,											// commandBufferCount
  		&cmdBuffers[0],								// pCommandBuffers
  		0u,											// signalSemaphoreCount
  		DE_NULL,									// pSignalSemaphores
  	};
  
  	// Second command buffer
  	const VkSubmitInfo						submitInfoNonNullSecond	=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,				// sType
  		DE_NULL,									// pNext
  		0u,											// waitSemaphoreCount
  		DE_NULL,									// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,		// pWaitDstStageMask
  		1u,											// commandBufferCount
  		&cmdBuffers[1],								// pCommandBuffers
  		0u,											// signalSemaphoreCount
  		DE_NULL,									// pSignalSemaphores
  	};
  
  	// Fence will be submitted with the null queue
  	const Unique<VkFence>					fence					(createFence(vk, vkDevice));
  
  	// Perform two separate queueSubmit calls on the same queue followed
  	// by a third call with no submitInfos and with a valid fence
  	VK_CHECK(vk.queueSubmit(queue,	1u,	&submitInfoNonNullFirst,	DE_NULL));
  	VK_CHECK(vk.queueSubmit(queue,	1u,	&submitInfoNonNullSecond,	DE_NULL));
  	VK_CHECK(vk.queueSubmit(queue,	0u,	DE_NULL,					fence.get()));
  
  	// Wait for the queue
  	VK_CHECK(vk.waitForFences(vkDevice, 1u, &fence.get(), VK_TRUE, INFINITE_TIMEOUT));
  
  	return tcu::TestStatus::pass("Buffers have been submitted correctly");
  }
  
  /******** 19.5. Secondary Command Buffer Execution (5.6 in VK 1.0 Spec) *******/
  tcu::TestStatus executeSecondaryBufferTest(Context& context)
  {
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// flags;
  		queueFamilyIndex,											// queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// commandPool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// level;
  		1u,															// bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBuf				(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// Secondary Command buffer
  	const VkCommandBufferAllocateInfo		secCmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType;
  		DE_NULL,													// pNext;
  		*cmdPool,													// commandPool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							// level;
  		1u,															// bufferCount;
  	};
  	const Unique<VkCommandBuffer>			secCmdBuf				(allocateCommandBuffer(vk, vkDevice, &secCmdBufParams));
  
  	const VkCommandBufferBeginInfo			primCmdBufBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		(const VkCommandBufferInheritanceInfo*)DE_NULL,
  	};
  
  	const VkCommandBufferInheritanceInfo	secCmdBufInheritInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		DE_NULL,													// renderPass
  		0u,															// subpass
  		DE_NULL,													// framebuffer
  		VK_FALSE,													// occlusionQueryEnable
  		(VkQueryControlFlags)0u,									// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,							// pipelineStatistics
  	};
  	const VkCommandBufferBeginInfo			secCmdBufBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		&secCmdBufInheritInfo,
  	};
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					event					(createEvent(vk, vkDevice));
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *event));
  
  	// record secondary command buffer
  	VK_CHECK(vk.beginCommandBuffer(*secCmdBuf, &secCmdBufBeginInfo));
  	{
  		// allow execution of event during every stage of pipeline
  		VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  		// record setting event
  		vk.cmdSetEvent(*secCmdBuf, *event, stageMask);
  	}
  	// end recording of the secondary buffer
  	endCommandBuffer(vk, *secCmdBuf);
  
  	// record primary command buffer
  	VK_CHECK(vk.beginCommandBuffer(*primCmdBuf, &primCmdBufBeginInfo));
  	{
  		// execute secondary buffer
  		vk.cmdExecuteCommands(*primCmdBuf, 1u, &secCmdBuf.get());
  	}
  	endCommandBuffer(vk, *primCmdBuf);
  
  	submitCommandsAndWait(vk, vkDevice, queue, primCmdBuf.get());
  
  	// check if secondary buffer has been executed
  	VkResult result = vk.getEventStatus(vkDevice, *event);
  	if (result == VK_EVENT_SET)
  		return tcu::TestStatus::pass("executeSecondaryBufferTest succeeded");
  
  	return tcu::TestStatus::fail("executeSecondaryBufferTest FAILED");
  }
  
  tcu::TestStatus executeSecondaryBufferTwiceTest(Context& context)
  {
  	const deUint32							BUFFER_COUNT			= 10u;
  	const VkDevice							vkDevice				= context.getDevice();
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  
  	const VkCommandPoolCreateInfo			cmdPoolParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType				sType;
  		DE_NULL,													//	const void*					pNext;
  		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			//	VkCommandPoolCreateFlags	flags;
  		queueFamilyIndex,											//	deUint32					queueFamilyIndex;
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
  
  	// Command buffer
  	const VkCommandBufferAllocateInfo		cmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							//	VkCommandBufferLevel		level;
  		1u,															//	uint32_t					bufferCount;
  	};
  	const Unique<VkCommandBuffer>			primCmdBufOne			(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  	const Unique<VkCommandBuffer>			primCmdBufTwo			(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
  
  	// Secondary Command buffers params
  	const VkCommandBufferAllocateInfo		secCmdBufParams			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				//	VkStructureType			sType;
  		DE_NULL,													//	const void*				pNext;
  		*cmdPool,													//	VkCommandPool				pool;
  		VK_COMMAND_BUFFER_LEVEL_SECONDARY,							//	VkCommandBufferLevel		level;
  		BUFFER_COUNT,												//	uint32_t					bufferCount;
  	};
  	VkCommandBuffer cmdBuffers[BUFFER_COUNT];
  	VK_CHECK(vk.allocateCommandBuffers(vkDevice, &secCmdBufParams, cmdBuffers));
  
  	const VkCommandBufferBeginInfo			primCmdBufBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  		DE_NULL,
  		0,															// flags
  		(const VkCommandBufferInheritanceInfo*)DE_NULL,
  	};
  
  	const VkCommandBufferInheritanceInfo	secCmdBufInheritInfo	=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
  		DE_NULL,
  		(VkRenderPass)0u,											// renderPass
  		0u,															// subpass
  		(VkFramebuffer)0u,											// framebuffer
  		VK_FALSE,													// occlusionQueryEnable
  		(VkQueryControlFlags)0u,									// queryFlags
  		(VkQueryPipelineStatisticFlags)0u,							// pipelineStatistics
  	};
  	const VkCommandBufferBeginInfo			secCmdBufBeginInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  		DE_NULL,
  		VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,				// flags
  		&secCmdBufInheritInfo,
  	};
  
  	// create event that will be used to check if secondary command buffer has been executed
  	const Unique<VkEvent>					eventOne				(createEvent(vk, vkDevice));
  
  	// reset event
  	VK_CHECK(vk.resetEvent(vkDevice, *eventOne));
  
  	for (deUint32 ndx = 0; ndx < BUFFER_COUNT; ++ndx)
  	{
  		// record secondary command buffer
  		VK_CHECK(vk.beginCommandBuffer(cmdBuffers[ndx], &secCmdBufBeginInfo));
  		{
  			// allow execution of event during every stage of pipeline
  			VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  
  			// wait for event
  			vk.cmdWaitEvents(cmdBuffers[ndx], 1, &eventOne.get(), stageMask, stageMask, 0, DE_NULL, 0u, DE_NULL, 0u, DE_NULL);
  		}
  		// end recording of secondary buffers
  		endCommandBuffer(vk, cmdBuffers[ndx]);
  	}
  
  	// record primary command buffer one
  	VK_CHECK(vk.beginCommandBuffer(*primCmdBufOne, &primCmdBufBeginInfo));
  	{
  		// execute one secondary buffer
  		vk.cmdExecuteCommands(*primCmdBufOne, 1, cmdBuffers );
  	}
  	endCommandBuffer(vk, *primCmdBufOne);
  
  	// record primary command buffer two
  	VK_CHECK(vk.beginCommandBuffer(*primCmdBufTwo, &primCmdBufBeginInfo));
  	{
  		// execute one secondary buffer with all buffers
  		vk.cmdExecuteCommands(*primCmdBufTwo, BUFFER_COUNT, cmdBuffers );
  	}
  	endCommandBuffer(vk, *primCmdBufTwo);
  
  	// create fence to wait for execution of queue
  	const Unique<VkFence>					fenceOne				(createFence(vk, vkDevice));
  	const Unique<VkFence>					fenceTwo				(createFence(vk, vkDevice));
  
  	const VkSubmitInfo						submitInfoOne			=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		0u,															// waitSemaphoreCount
  		DE_NULL,													// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,						// pWaitDstStageMask
  		1,															// commandBufferCount
  		&primCmdBufOne.get(),										// pCommandBuffers
  		0u,															// signalSemaphoreCount
  		DE_NULL,													// pSignalSemaphores
  	};
  
  	// submit primary buffer, the secondary should be executed too
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfoOne, *fenceOne));
  
  	// wait for buffer to stop at event for 100 microseconds
  	vk.waitForFences(vkDevice, 1, &fenceOne.get(), 0u, 100000);
  
  	const VkSubmitInfo						submitInfoTwo			=
  	{
  		VK_STRUCTURE_TYPE_SUBMIT_INFO,								// sType
  		DE_NULL,													// pNext
  		0u,															// waitSemaphoreCount
  		DE_NULL,													// pWaitSemaphores
  		(const VkPipelineStageFlags*)DE_NULL,						// pWaitDstStageMask
  		1,															// commandBufferCount
  		&primCmdBufTwo.get(),										// pCommandBuffers
  		0u,															// signalSemaphoreCount
  		DE_NULL,													// pSignalSemaphores
  	};
  
  	// submit second primary buffer, the secondary should be executed too
  	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfoTwo, *fenceTwo));
  
  	// wait for all buffers to stop at event for 100 microseconds
  	vk.waitForFences(vkDevice, 1, &fenceOne.get(), 0u, 100000);
  
  	// now all buffers are waiting at eventOne
  	// set event eventOne
  	VK_CHECK(vk.setEvent(vkDevice, *eventOne));
  
  	// wait for end of execution of fenceOne
  	VK_CHECK(vk.waitForFences(vkDevice, 1, &fenceOne.get(), 0u, INFINITE_TIMEOUT));
  
  	// wait for end of execution of second queue
  	VK_CHECK(vk.waitForFences(vkDevice, 1, &fenceTwo.get(), 0u, INFINITE_TIMEOUT));
  
  	return tcu::TestStatus::pass("executeSecondaryBufferTwiceTest succeeded");
  }
  
  /******** 19.6. Commands Allowed Inside Command Buffers (? in VK 1.0 Spec) **/
  tcu::TestStatus orderBindPipelineTest(Context& context)
  {
  	const DeviceInterface&					vk						= context.getDeviceInterface();
  	const VkDevice							device					= context.getDevice();
  	const VkQueue							queue					= context.getUniversalQueue();
  	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
  	Allocator&								allocator				= context.getDefaultAllocator();
  	const ComputeInstanceResultBuffer		result					(vk, device, allocator);
  
  	enum
  	{
  		ADDRESSABLE_SIZE = 256, // allocate a lot more than required
  	};
  
  	const tcu::Vec4							colorA1					= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
  	const tcu::Vec4							colorA2					= tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
  	const tcu::Vec4							colorB1					= tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
  	const tcu::Vec4							colorB2					= tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
  
  	const deUint32							dataOffsetA				= (0u);
  	const deUint32							dataOffsetB				= (0u);
  	const deUint32							viewOffsetA				= (0u);
  	const deUint32							viewOffsetB				= (0u);
  	const deUint32							bufferSizeA				= dataOffsetA + ADDRESSABLE_SIZE;
  	const deUint32							bufferSizeB				= dataOffsetB + ADDRESSABLE_SIZE;
  
  	de::MovePtr<Allocation>					bufferMemA;
  	const Unique<VkBuffer>					bufferA					(createColorDataBuffer(dataOffsetA, bufferSizeA, colorA1, colorA2, &bufferMemA, context));
  
  	de::MovePtr<Allocation>					bufferMemB;
  	const Unique<VkBuffer>					bufferB					(createColorDataBuffer(dataOffsetB, bufferSizeB, colorB1, colorB2, &bufferMemB, context));
  
  	const Unique<VkDescriptorSetLayout>		descriptorSetLayout		(createDescriptorSetLayout(context));
  	const Unique<VkDescriptorPool>			descriptorPool			(createDescriptorPool(context));
  	const Unique<VkDescriptorSet>			descriptorSet			(createDescriptorSet(*descriptorPool, *descriptorSetLayout, *bufferA, viewOffsetA, *bufferB, viewOffsetB, result.getBuffer(), context));
  	const VkDescriptorSet					descriptorSets[]		= { *descriptorSet };
  	const int								numDescriptorSets		= DE_LENGTH_OF_ARRAY(descriptorSets);
  
  	const VkPipelineLayoutCreateInfo layoutCreateInfo =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,				// sType
  		DE_NULL,													// pNext
  		(VkPipelineLayoutCreateFlags)0,
  		numDescriptorSets,											// setLayoutCount
  		&descriptorSetLayout.get(),									// pSetLayouts
  		0u,															// pushConstantRangeCount
  		DE_NULL,													// pPushConstantRanges
  	};
  	Unique<VkPipelineLayout>				pipelineLayout			(createPipelineLayout(vk, device, &layoutCreateInfo));
  
  	const Unique<VkShaderModule>			computeModuleGood		(createShaderModule(vk, device, context.getBinaryCollection().get("compute_good"), (VkShaderModuleCreateFlags)0u));
  	const Unique<VkShaderModule>			computeModuleBad		(createShaderModule(vk, device, context.getBinaryCollection().get("compute_bad"),  (VkShaderModuleCreateFlags)0u));
  
  	const VkPipelineShaderStageCreateInfo	shaderCreateInfoGood	=
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
  		DE_NULL,
  		(VkPipelineShaderStageCreateFlags)0,
  		VK_SHADER_STAGE_COMPUTE_BIT,								// stage
  		*computeModuleGood,											// shader
  		"main",
  		DE_NULL,													// pSpecializationInfo
  	};
  
  	const VkPipelineShaderStageCreateInfo	shaderCreateInfoBad	=
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
  		DE_NULL,
  		(vk::VkPipelineShaderStageCreateFlags)0,
  		vk::VK_SHADER_STAGE_COMPUTE_BIT,							// stage
  		*computeModuleBad,											// shader
  		"main",
  		DE_NULL,													// pSpecializationInfo
  	};
  
  	const VkComputePipelineCreateInfo		createInfoGood			=
  	{
  		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
  		DE_NULL,
  		0u,															// flags
  		shaderCreateInfoGood,										// cs
  		*pipelineLayout,											// layout
  		(vk::VkPipeline)0,											// basePipelineHandle
  		0u,															// basePipelineIndex
  	};
  
  	const VkComputePipelineCreateInfo		createInfoBad			=
  	{
  		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
  		DE_NULL,
  		0u,															// flags
  		shaderCreateInfoBad,										// cs
  		*pipelineLayout,											// descriptorSetLayout.get()
  		(VkPipeline)0,												// basePipelineHandle
  		0u,															// basePipelineIndex
  	};
  
  	const Unique<VkPipeline>				pipelineGood			(createComputePipeline(vk, device, (VkPipelineCache)0u, &createInfoGood));
  	const Unique<VkPipeline>				pipelineBad				(createComputePipeline(vk, device, (VkPipelineCache)0u, &createInfoBad));
  
  	const VkAccessFlags						inputBit				= (VK_ACCESS_UNIFORM_READ_BIT);
  	const VkBufferMemoryBarrier				bufferBarriers[]		=
  	{
  		{
  			VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
  			DE_NULL,
  			VK_ACCESS_HOST_WRITE_BIT,									// srcAccessMask
  			inputBit,													// dstAccessMask
  			VK_QUEUE_FAMILY_IGNORED,									// srcQueueFamilyIndex
  			VK_QUEUE_FAMILY_IGNORED,									// destQueueFamilyIndex
  			*bufferA,													// buffer
  			(VkDeviceSize)0u,											// offset
  			(VkDeviceSize)bufferSizeA,									// size
  		},
  		{
  			VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
  			DE_NULL,
  			VK_ACCESS_HOST_WRITE_BIT,									// srcAccessMask
  			inputBit,													// dstAccessMask
  			VK_QUEUE_FAMILY_IGNORED,									// srcQueueFamilyIndex
  			VK_QUEUE_FAMILY_IGNORED,									// destQueueFamilyIndex
  			*bufferB,													// buffer
  			(VkDeviceSize)0u,											// offset
  			(VkDeviceSize)bufferSizeB,									// size
  		}
  	};
  
  	const deUint32							numSrcBuffers			= 1u;
  
  	const deUint32* const					dynamicOffsets			= (DE_NULL);
  	const deUint32							numDynamicOffsets		= (0);
  	const int								numPreBarriers			= numSrcBuffers;
  	const vk::VkBufferMemoryBarrier* const	postBarriers			= result.getResultReadBarrier();
  	const int								numPostBarriers			= 1;
  	const tcu::Vec4							refQuadrantValue14		= (colorA2);
  	const tcu::Vec4							refQuadrantValue23		= (colorA1);
  	const tcu::Vec4							references[4]			=
  	{
  		refQuadrantValue14,
  		refQuadrantValue23,
  		refQuadrantValue23,
  		refQuadrantValue14,
  	};
  	tcu::Vec4								results[4];
  
  	// submit and wait begin
  
  	const tcu::UVec3 numWorkGroups = tcu::UVec3(4, 1u, 1);
  
  	const VkCommandPoolCreateInfo			cmdPoolCreateInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType;
  		DE_NULL,													// pNext
  		VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,						// flags
  		queueFamilyIndex,											// queueFamilyIndex
  	};
  	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, device, &cmdPoolCreateInfo));
  	const VkCommandBufferAllocateInfo		cmdBufCreateInfo		=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,				// sType
  		DE_NULL,													// pNext
  		*cmdPool,													// commandPool
  		VK_COMMAND_BUFFER_LEVEL_PRIMARY,							// level
  		1u,															// bufferCount;
  	};
  
  	const VkCommandBufferBeginInfo			cmdBufBeginInfo			=
  	{
  		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,				// sType
  		DE_NULL,													// pNext
  		0u,															// flags
  		(const VkCommandBufferInheritanceInfo*)DE_NULL,
  	};
  
  	const Unique<VkCommandBuffer>			cmd						(allocateCommandBuffer(vk, device, &cmdBufCreateInfo));
  
  	VK_CHECK(vk.beginCommandBuffer(*cmd, &cmdBufBeginInfo));
  
  	vk.cmdBindPipeline(*cmd, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineBad);
  	vk.cmdBindPipeline(*cmd, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineGood);
  	vk.cmdBindDescriptorSets(*cmd, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, numDescriptorSets, descriptorSets, numDynamicOffsets, dynamicOffsets);
  
  	if (numPreBarriers)
  		vk.cmdPipelineBarrier(*cmd, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0,
  							  0, (const VkMemoryBarrier*)DE_NULL,
  							  numPreBarriers, bufferBarriers,
  							  0, (const VkImageMemoryBarrier*)DE_NULL);
  
  	vk.cmdDispatch(*cmd, numWorkGroups.x(), numWorkGroups.y(), numWorkGroups.z());
  	vk.cmdPipelineBarrier(*cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
  						  0, (const VkMemoryBarrier*)DE_NULL,
  						  numPostBarriers, postBarriers,
  						  0, (const VkImageMemoryBarrier*)DE_NULL);
  	endCommandBuffer(vk, *cmd);
  
  	// run
  	// submit second primary buffer, the secondary should be executed too
  	submitCommandsAndWait(vk, device, queue, cmd.get());
  
  	// submit and wait end
  	result.readResultContentsTo(&results);
  
  	// verify
  	if (results[0] == references[0] &&
  		results[1] == references[1] &&
  		results[2] == references[2] &&
  		results[3] == references[3])
  	{
  		return tcu::TestStatus::pass("Pass");
  	}
  	else if (results[0] == tcu::Vec4(-1.0f) &&
  			 results[1] == tcu::Vec4(-1.0f) &&
  			 results[2] == tcu::Vec4(-1.0f) &&
  			 results[3] == tcu::Vec4(-1.0f))
  	{
  		context.getTestContext().getLog()
  		<< tcu::TestLog::Message
  		<< "Result buffer was not written to."
  		<< tcu::TestLog::EndMessage;
  		return tcu::TestStatus::fail("Result buffer was not written to");
  	}
  	else
  	{
  		context.getTestContext().getLog()
  		<< tcu::TestLog::Message
  		<< "Error expected ["
  		<< references[0] << ", "
  		<< references[1] << ", "
  		<< references[2] << ", "
  		<< references[3] << "], got ["
  		<< results[0] << ", "
  		<< results[1] << ", "
  		<< results[2] << ", "
  		<< results[3] << "]"
  		<< tcu::TestLog::EndMessage;
  		return tcu::TestStatus::fail("Invalid result values");
  	}
  }
  
  enum StateTransitionTest
  {
  	STT_RECORDING_TO_INITIAL	= 0,
  	STT_EXECUTABLE_TO_INITIAL,
  	STT_RECORDING_TO_INVALID,
  	STT_EXECUTABLE_TO_INVALID,
  };
  
  tcu::TestStatus executeStateTransitionTest(Context& context, StateTransitionTest type)
  {
  	const VkDevice					vkDevice			= context.getDevice();
  	const DeviceInterface&			vk					= context.getDeviceInterface();
  	const VkQueue					queue				= context.getUniversalQueue();
  	const deUint32					queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
  	const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
  	const Unique<VkCommandBuffer>	cmdBuffer			(allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
  	const Unique<VkEvent>			globalEvent			(createEvent(vk, vkDevice));
  
  	VK_CHECK(vk.resetEvent(vkDevice, *globalEvent));
  
  	switch (type)
  	{
  		case STT_RECORDING_TO_INITIAL:
  		{
  			beginCommandBuffer(vk, *cmdBuffer, 0u);
  			vk.cmdSetEvent(*cmdBuffer, *globalEvent, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  			break;
  			// command buffer is still in recording state
  		}
  		case STT_EXECUTABLE_TO_INITIAL:
  		{
  			beginCommandBuffer(vk, *cmdBuffer, 0u);
  			vk.cmdSetEvent(*cmdBuffer, *globalEvent, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  			endCommandBuffer(vk, *cmdBuffer);
  			break;
  			// command buffer is still in executable state
  		}
  		case STT_RECORDING_TO_INVALID:
  		{
  			VkSubpassDescription subpassDescription;
  			deMemset(&subpassDescription, 0, sizeof(VkSubpassDescription));
  			subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
  
  			VkRenderPassCreateInfo renderPassCreateInfo
  			{
  				VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
  				DE_NULL, 0, 0, DE_NULL,
  				1, &subpassDescription, 0, DE_NULL
  			};
  
  			// Error here - renderpass and framebuffer were created localy
  			Move <VkRenderPass> renderPass = createRenderPass(vk, vkDevice, &renderPassCreateInfo);
  
  			VkFramebufferCreateInfo framebufferCreateInfo
  			{
  				VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, DE_NULL,
  				0, *renderPass, 0, DE_NULL, 16, 16, 1
  			};
  			Move <VkFramebuffer> framebuffer = createFramebuffer(vk, vkDevice, &framebufferCreateInfo);
  
  			VkRenderPassBeginInfo renderPassBeginInfo =
  			{
  				VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
  				DE_NULL, *renderPass, *framebuffer, { { 0, 0 }, { 16, 16 } },
  				0, DE_NULL
  			};
  
  			beginCommandBuffer(vk, *cmdBuffer, 0u);
  			vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
  			vk.cmdEndRenderPass(*cmdBuffer);
  
  			// not executing endCommandBuffer(vk, *cmdBuffer);
  			// command buffer is still in recording state
  			break;
  			// renderpass and framebuffer are destroyed; command buffer should be now in invalid state
  		}
  		case STT_EXECUTABLE_TO_INVALID:
  		{
  			// create event that will be used to check if command buffer has been executed
  			const Unique<VkEvent> localEvent(createEvent(vk, vkDevice));
  			VK_CHECK(vk.resetEvent(vkDevice, *localEvent));
  
  			beginCommandBuffer(vk, *cmdBuffer, 0u);
  			vk.cmdSetEvent(*cmdBuffer, *localEvent, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  			endCommandBuffer(vk, *cmdBuffer);
  			// command buffer is in executable state
  			break;
  			// localEvent is destroyed; command buffer should be now in invalid state
  		}
  	}
  
  	VK_CHECK(vk.resetEvent(vkDevice, *globalEvent));
  
  	vk.resetCommandBuffer(*cmdBuffer, 0u);
  	// command buffer should now be back in initial state
  
  	// verify commandBuffer
  	beginCommandBuffer(vk, *cmdBuffer, 0u);
  	vk.cmdSetEvent(*cmdBuffer, *globalEvent, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  	endCommandBuffer(vk, *cmdBuffer);
  	submitCommandsAndWait(vk, vkDevice, queue, *cmdBuffer);
  
  	// check if buffer has been executed
  	VkResult result = vk.getEventStatus(vkDevice, *globalEvent);
  	if (result != VK_EVENT_SET)
  		return tcu::TestStatus::fail("Submit failed");
  
  	return tcu::TestStatus::pass("Pass");
  }
  
  // Shaders
  void genComputeSource (SourceCollections& programCollection)
  {
  	const char* const						versionDecl				= glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
  	std::ostringstream						bufGood;
  
  	bufGood << versionDecl << "\n"
  	<< ""
  	<< "layout(local_size_x = 1u, local_size_y = 1u, local_size_z = 1u) in;\n"
  	<< "layout(set = 0, binding = 1u, std140) uniform BufferName\n"
  	<< "{\n"
  	<< "	highp vec4 colorA;\n"
  	<< "	highp vec4 colorB;\n"
  	<< "} b_instance;\n"
  	<< "layout(set = 0, binding = 0, std140) writeonly buffer OutBuf\n"
  	<< "{\n"
  	<< "	highp vec4 read_colors[4];\n"
  	<< "} b_out;\n"
  	<< "void main(void)\n"
  	<< "{\n"
  	<< "	highp int quadrant_id = int(gl_WorkGroupID.x);\n"
  	<< "	highp vec4 result_color;\n"
  	<< "	if (quadrant_id == 1 || quadrant_id == 2)\n"
  	<< "		result_color = b_instance.colorA;\n"
  	<< "	else\n"
  	<< "		result_color = b_instance.colorB;\n"
  	<< "	b_out.read_colors[gl_WorkGroupID.x] = result_color;\n"
  	<< "}\n";
  
  	programCollection.glslSources.add("compute_good") << glu::ComputeSource(bufGood.str());
  
  	std::ostringstream	bufBad;
  
  	bufBad	<< versionDecl << "\n"
  	<< ""
  	<< "layout(local_size_x = 1u, local_size_y = 1u, local_size_z = 1u) in;\n"
  	<< "layout(set = 0, binding = 1u, std140) uniform BufferName\n"
  	<< "{\n"
  	<< "	highp vec4 colorA;\n"
  	<< "	highp vec4 colorB;\n"
  	<< "} b_instance;\n"
  	<< "layout(set = 0, binding = 0, std140) writeonly buffer OutBuf\n"
  	<< "{\n"
  	<< "	highp vec4 read_colors[4];\n"
  	<< "} b_out;\n"
  	<< "void main(void)\n"
  	<< "{\n"
  	<< "	highp int quadrant_id = int(gl_WorkGroupID.x);\n"
  	<< "	highp vec4 result_color;\n"
  	<< "	if (quadrant_id == 1 || quadrant_id == 2)\n"
  	<< "		result_color = b_instance.colorA;\n"
  	<< "	else\n"
  	<< "		result_color = b_instance.colorB;\n"
  	<< "	b_out.read_colors[gl_WorkGroupID.x] = vec4(0.0, 0.0, 0.0, 0.0);\n"
  	<< "}\n";
  
  	programCollection.glslSources.add("compute_bad") << glu::ComputeSource(bufBad.str());
  }
  
  void genComputeIncrementSource (SourceCollections& programCollection)
  {
  	const char* const						versionDecl = glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
  	std::ostringstream						bufIncrement;
  
  	bufIncrement << versionDecl << "\n"
  		<< ""
  		<< "layout(local_size_x = 1u, local_size_y = 1u, local_size_z = 1u) in;\n"
  		<< "layout(set = 0, binding = 0, std140) buffer InOutBuf\n"
  		<< "{\n"
  		<< "    coherent uint count;\n"
  		<< "} b_in_out;\n"
  		<< "void main(void)\n"
  		<< "{\n"
  		<< "	atomicAdd(b_in_out.count, 1u);\n"
  		<< "}\n";
  
  	programCollection.glslSources.add("compute_increment") << glu::ComputeSource(bufIncrement.str());
  }
  
  void genComputeIncrementSourceBadInheritance(SourceCollections& programCollection, BadInheritanceInfoCase testCase)
  {
  	DE_UNREF(testCase);
  	return genComputeIncrementSource(programCollection);
  }
  
  void checkEventSupport (Context& context)
  {
  	if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && !context.getPortabilitySubsetFeatures().events)
  		TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Events are not supported by this implementation");
  }
  
  void checkEventSupport (Context& context, const VkCommandBufferLevel)
  {
  	checkEventSupport(context);
  }
  
  struct ManyDrawsParams
  {
  	VkCommandBufferLevel	level;
  	VkExtent3D				imageExtent;
  	deUint32				seed;
  
  	ManyDrawsParams(VkCommandBufferLevel level_, const VkExtent3D& extent_, deUint32 seed_)
  		: level			(level_)
  		, imageExtent	(extent_)
  		, seed			(seed_)
  	{}
  };
  
  struct ManyDrawsVertex
  {
  	using Color = tcu::Vector<deUint8, 4>;
  
  	tcu::Vec2	coords;
  	Color		color;
  
  	ManyDrawsVertex (const tcu::Vec2& coords_, const Color& color_) : coords(coords_), color(color_) {}
  };
  
  VkFormat getSupportedDepthStencilFormat (const InstanceInterface& vki, VkPhysicalDevice physDev)
  {
  	const VkFormat				formatList[]	= { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT };
  	const VkFormatFeatureFlags	requirements	= (VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
  
  	for (int i = 0; i < DE_LENGTH_OF_ARRAY(formatList); ++i)
  	{
  		const auto properties = getPhysicalDeviceFormatProperties(vki, physDev, formatList[i]);
  		if ((properties.optimalTilingFeatures & requirements) == requirements)
  			return formatList[i];
  	}
  
  	TCU_THROW(NotSupportedError, "No suitable depth/stencil format support");
  	return VK_FORMAT_UNDEFINED;
  }
  
  class ManyDrawsCase : public TestCase
  {
  public:
  							ManyDrawsCase			(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const ManyDrawsParams& params);
  	virtual					~ManyDrawsCase			(void) {}
  
  	virtual void			checkSupport			(Context& context) const;
  	virtual void			initPrograms			(vk::SourceCollections& programCollection) const;
  	virtual TestInstance*	createInstance			(Context& context) const;
  
  	static VkFormat			getColorFormat			(void) { return VK_FORMAT_R8G8B8A8_UINT; }
  
  protected:
  	ManyDrawsParams			m_params;
  };
  
  class ManyDrawsInstance : public TestInstance
  {
  public:
  								ManyDrawsInstance	(Context& context, const ManyDrawsParams& params);
  	virtual						~ManyDrawsInstance	(void) {}
  
  	virtual tcu::TestStatus		iterate				(void);
  
  protected:
  	ManyDrawsParams				m_params;
  };
  
  using BufferPtr = de::MovePtr<BufferWithMemory>;
  using ImagePtr = de::MovePtr<ImageWithMemory>;
  
  struct ManyDrawsVertexBuffers
  {
  	BufferPtr stagingBuffer;
  	BufferPtr vertexBuffer;
  };
  
  struct ManyDrawsAllocatedData
  {
  	ManyDrawsVertexBuffers	frontBuffers;
  	ManyDrawsVertexBuffers	backBuffers;
  	ImagePtr				colorAttachment;
  	ImagePtr				dsAttachment;
  	BufferPtr				colorCheckBuffer;
  	BufferPtr				stencilCheckBuffer;
  
  	static deUint32 calcNumPixels (const VkExtent3D& extent)
  	{
  		DE_ASSERT(extent.depth == 1u);
  		return (extent.width * extent.height);
  	}
  	static deUint32 calcNumVertices (const VkExtent3D& extent)
  	{
  		// One triangle (3 vertices) per output image pixel.
  		return (calcNumPixels(extent) * 3u);
  	}
  
  	static VkDeviceSize calcVertexBufferSize (const VkExtent3D& extent)
  	{
  		return calcNumVertices(extent) * sizeof(ManyDrawsVertex);
  	}
  
  	static void makeVertexBuffers (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, VkDeviceSize size, ManyDrawsVertexBuffers& buffers)
  	{
  		const auto stagingBufferInfo	= makeBufferCreateInfo(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
  		const auto vertexBufferInfo		= makeBufferCreateInfo(size, (VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
  
  		buffers.stagingBuffer	= BufferPtr(new BufferWithMemory(vkd, device, alloc, stagingBufferInfo, MemoryRequirement::HostVisible));
  		buffers.vertexBuffer	= BufferPtr(new BufferWithMemory(vkd, device, alloc, vertexBufferInfo, MemoryRequirement::Any));
  	}
  
  	ManyDrawsAllocatedData (const DeviceInterface &vkd, VkDevice device, Allocator &alloc, const VkExtent3D& imageExtent, VkFormat colorFormat, VkFormat dsFormat)
  	{
  		const auto numPixels		= calcNumPixels(imageExtent);
  		const auto vertexBufferSize	= calcVertexBufferSize(imageExtent);
  
  		makeVertexBuffers(vkd, device, alloc, vertexBufferSize, frontBuffers);
  		makeVertexBuffers(vkd, device, alloc, vertexBufferSize, backBuffers);
  
  		const auto colorUsage	= (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
  		const auto dsUsage		= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
  
  		const VkImageCreateInfo colorAttachmentInfo =
  		{
  			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
  			nullptr,								//	const void*				pNext;
  			0u,										//	VkImageCreateFlags		flags;
  			VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
  			colorFormat,							//	VkFormat				format;
  			imageExtent,							//	VkExtent3D				extent;
  			1u,										//	deUint32				mipLevels;
  			1u,										//	deUint32				arrayLayers;
  			VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
  			VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
  			colorUsage,								//	VkImageUsageFlags		usage;
  			VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
  			0u,										//	deUint32				queueFamilyIndexCount;
  			nullptr,								//	const deUint32*			pQueueFamilyIndices;
  			VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
  		};
  		colorAttachment = ImagePtr(new ImageWithMemory(vkd, device, alloc, colorAttachmentInfo, MemoryRequirement::Any));
  
  		const VkImageCreateInfo dsAttachmentInfo =
  		{
  			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
  			nullptr,								//	const void*				pNext;
  			0u,										//	VkImageCreateFlags		flags;
  			VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
  			dsFormat,								//	VkFormat				format;
  			imageExtent,							//	VkExtent3D				extent;
  			1u,										//	deUint32				mipLevels;
  			1u,										//	deUint32				arrayLayers;
  			VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
  			VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
  			dsUsage,								//	VkImageUsageFlags		usage;
  			VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
  			0u,										//	deUint32				queueFamilyIndexCount;
  			nullptr,								//	const deUint32*			pQueueFamilyIndices;
  			VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
  		};
  		dsAttachment = ImagePtr(new ImageWithMemory(vkd, device, alloc, dsAttachmentInfo, MemoryRequirement::Any));
  
  		const auto colorCheckBufferSize		= static_cast<VkDeviceSize>(numPixels * tcu::getPixelSize(mapVkFormat(colorFormat)));
  		const auto colorCheckBufferInfo		= makeBufferCreateInfo(colorCheckBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
  
  		colorCheckBuffer = BufferPtr(new BufferWithMemory(vkd, device, alloc, colorCheckBufferInfo, MemoryRequirement::HostVisible));
  
  		const auto stencilFormat			= tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8);
  		const auto stencilCheckBufferSize	= static_cast<VkDeviceSize>(numPixels * tcu::getPixelSize(stencilFormat));
  		const auto stencilCheckBufferInfo	= makeBufferCreateInfo(stencilCheckBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
  
  		stencilCheckBuffer = BufferPtr(new BufferWithMemory(vkd, device, alloc, stencilCheckBufferInfo, MemoryRequirement::HostVisible));
  	}
  };
  
  ManyDrawsCase::ManyDrawsCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const ManyDrawsParams& params)
  	: TestCase	(testCtx, name, description)
  	, m_params	(params)
  {}
  
  void ManyDrawsCase::checkSupport (Context& context) const
  {
  	const auto& vki			= context.getInstanceInterface();
  	const auto	physDev		= context.getPhysicalDevice();
  	const auto&	vkd			= context.getDeviceInterface();
  	const auto	device		= context.getDevice();
  	auto&		alloc		= context.getDefaultAllocator();
  	const auto	dsFormat	= getSupportedDepthStencilFormat(vki, physDev);
  
  	try
  	{
  		ManyDrawsAllocatedData allocatedData(vkd, device, alloc, m_params.imageExtent, getColorFormat(), dsFormat);
  	}
  	catch (const vk::Error& err)
  	{
  		const auto result = err.getError();
  		if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_ERROR_OUT_OF_DEVICE_MEMORY)
  			TCU_THROW(NotSupportedError, "Not enough memory to run this test");
  		throw;
  	}
  }
  
  void ManyDrawsCase::initPrograms (vk::SourceCollections& programCollection) const
  {
  	std::ostringstream vert;
  	vert
  		<< "#version 450\n"
  		<< "\n"
  		<< "layout(location=0) in vec2 inCoords;\n"
  		<< "layout(location=1) in uvec4 inColor;\n"
  		<< "\n"
  		<< "layout(location=0) out flat uvec4 outColor;\n"
  		<< "\n"
  		<< "void main()\n"
  		<< "{\n"
  		<< "    gl_Position = vec4(inCoords, 0.0, 1.0);\n"
  		<< "    outColor = inColor;\n"
  		<< "}\n"
  		;
  
  	std::ostringstream frag;
  	frag
  		<< "#version 450\n"
  		<< "\n"
  		<< "layout(location=0) in flat uvec4 inColor;\n"
  		<< "layout(location=0) out uvec4 outColor;\n"
  		<< "\n"
  		<< "void main()\n"
  		<< "{\n"
  		<< "	outColor = inColor;\n"
  		<< "}\n"
  		;
  
  	programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
  	programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
  }
  
  TestInstance* ManyDrawsCase::createInstance (Context& context) const
  {
  	return new ManyDrawsInstance(context, m_params);
  }
  
  ManyDrawsInstance::ManyDrawsInstance (Context& context, const ManyDrawsParams& params)
  	: TestInstance	(context)
  	, m_params		(params)
  {}
  
  void copyAndFlush (const DeviceInterface& vkd, VkDevice device, BufferWithMemory& buffer, const std::vector<ManyDrawsVertex>& vertices)
  {
  	auto& alloc		= buffer.getAllocation();
  	void* hostPtr	= alloc.getHostPtr();
  
  	deMemcpy(hostPtr, vertices.data(), de::dataSize(vertices));
  	flushAlloc(vkd, device, alloc);
  }
  
  tcu::TestStatus ManyDrawsInstance::iterate (void)
  {
  	const auto&	vki					= m_context.getInstanceInterface();
  	const auto	physDev				= m_context.getPhysicalDevice();
  	const auto&	vkd					= m_context.getDeviceInterface();
  	const auto	device				= m_context.getDevice();
  	auto&		alloc				= m_context.getDefaultAllocator();
  	const auto	qIndex				= m_context.getUniversalQueueFamilyIndex();
  	const auto	queue				= m_context.getUniversalQueue();
  
  	const auto	colorFormat			= ManyDrawsCase::getColorFormat();
  	const auto	dsFormat			= getSupportedDepthStencilFormat(vki, physDev);
  	const auto	vertexBufferSize	= ManyDrawsAllocatedData::calcVertexBufferSize(m_params.imageExtent);
  	const auto	vertexBufferOffset	= static_cast<VkDeviceSize>(0);
  	const auto	numPixels			= ManyDrawsAllocatedData::calcNumPixels(m_params.imageExtent);
  	const auto	numVertices			= ManyDrawsAllocatedData::calcNumVertices(m_params.imageExtent);
  	const auto	alphaValue			= std::numeric_limits<deUint8>::max();
  	const auto	pixelWidth			= 2.0f / static_cast<float>(m_params.imageExtent.width);	// Normalized size.
  	const auto	pixelWidthHalf		= pixelWidth / 2.0f;										// Normalized size.
  	const auto	pixelHeight			= 2.0f / static_cast<float>(m_params.imageExtent.height);	// Normalized size.
  	const auto	useSecondary		= (m_params.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY);
  
  	// Allocate all needed data up front.
  	ManyDrawsAllocatedData testData(vkd, device, alloc, m_params.imageExtent, colorFormat, dsFormat);
  
  	// Generate random colors.
  	de::Random							rnd(m_params.seed);
  	std::vector<ManyDrawsVertex::Color>	colors;
  
  	colors.reserve(numPixels);
  	for (deUint32 i = 0; i < numPixels; ++i)
  	{
  #if 0
  		const deUint8 red	= ((i      ) & 0xFFu);
  		const deUint8 green	= ((i >>  8) & 0xFFu);
  		const deUint8 blue	= ((i >> 16) & 0xFFu);
  		colors.push_back(ManyDrawsVertex::Color(red, green, blue, alphaValue));
  #else
  		colors.push_back(ManyDrawsVertex::Color(rnd.getUint8(), rnd.getUint8(), rnd.getUint8(), alphaValue));
  #endif
  	}
  
  	// Fill vertex data. One triangle per pixel, front and back.
  	std::vector<ManyDrawsVertex> frontVector;
  	std::vector<ManyDrawsVertex> backVector;
  	frontVector.reserve(numVertices);
  	backVector.reserve(numVertices);
  
  	for (deUint32 y = 0; y < m_params.imageExtent.height; ++y)
  	for (deUint32 x = 0; x < m_params.imageExtent.width; ++x)
  	{
  		float x_left	= static_cast<float>(x) * pixelWidth - 1.0f;
  		float x_mid		= x_left + pixelWidthHalf;
  		float x_right	= x_left + pixelWidth;
  		float y_top		= static_cast<float>(y) * pixelHeight - 1.0f;
  		float y_bottom	= y_top + pixelHeight;
  
  		// Triangles in the "back" mesh will have different colors.
  		const auto		colorIdx		= y * m_params.imageExtent.width + x;
  		const auto&		frontColor		= colors[colorIdx];
  		const auto&		backColor		= colors[colors.size() - 1u - colorIdx];
  
  		const tcu::Vec2	triangle[3u]	=
  		{
  			tcu::Vec2(x_left, y_top),
  			tcu::Vec2(x_right, y_top),
  			tcu::Vec2(x_mid, y_bottom),
  		};
  
  		frontVector.emplace_back(triangle[0], frontColor);
  		frontVector.emplace_back(triangle[1], frontColor);
  		frontVector.emplace_back(triangle[2], frontColor);
  
  		backVector.emplace_back(triangle[0], backColor);
  		backVector.emplace_back(triangle[1], backColor);
  		backVector.emplace_back(triangle[2], backColor);
  	}
  
  	// Copy vertex data to staging buffers.
  	copyAndFlush(vkd, device, *testData.frontBuffers.stagingBuffer, frontVector);
  	copyAndFlush(vkd, device, *testData.backBuffers.stagingBuffer, backVector);
  
  	// Color attachment view.
  	const auto		colorResourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
  	const auto		colorAttachmentView	= makeImageView(vkd, device, testData.colorAttachment->get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorResourceRange);
  
  	// Depth/stencil attachment view.
  	const auto		dsResourceRange		= makeImageSubresourceRange((VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
  	const auto		dsAttachmentView	= makeImageView(vkd, device, testData.dsAttachment->get(), VK_IMAGE_VIEW_TYPE_2D, dsFormat, dsResourceRange);
  
  	const VkImageView	attachmentArray[]	= { colorAttachmentView.get(), dsAttachmentView.get() };
  	const auto			numAttachments		= static_cast<deUint32>(DE_LENGTH_OF_ARRAY(attachmentArray));
  
  	const auto renderPass	= makeRenderPass(vkd, device, colorFormat, dsFormat);
  	const auto framebuffer	= makeFramebuffer(vkd, device, renderPass.get(), numAttachments, attachmentArray, m_params.imageExtent.width, m_params.imageExtent.height);
  
  	const auto vertModule	= createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
  	const auto fragModule	= createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
  
  	const std::vector<VkViewport>	viewports	(1u, makeViewport(m_params.imageExtent));
  	const std::vector<VkRect2D>		scissors	(1u, makeRect2D(m_params.imageExtent));
  
  	const auto descriptorSetLayout	= DescriptorSetLayoutBuilder().build(vkd, device);
  	const auto pipelineLayout		= makePipelineLayout(vkd, device, descriptorSetLayout.get());
  
  	const VkVertexInputBindingDescription bindings[] =
  	{
  		makeVertexInputBindingDescription(0u, static_cast<deUint32>(sizeof(ManyDrawsVertex)), VK_VERTEX_INPUT_RATE_VERTEX),
  	};
  
  	const VkVertexInputAttributeDescription attributes[] =
  	{
  		makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(ManyDrawsVertex, coords))),
  		makeVertexInputAttributeDescription(1u, 0u, VK_FORMAT_R8G8B8A8_UINT, static_cast<deUint32>(offsetof(ManyDrawsVertex, color))),
  	};
  
  	const VkPipelineVertexInputStateCreateInfo inputState =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
  		nullptr,													//	const void*									pNext;
  		0u,															//	VkPipelineVertexInputStateCreateFlags		flags;
  		static_cast<deUint32>(DE_LENGTH_OF_ARRAY(bindings)),		//	deUint32									vertexBindingDescriptionCount;
  		bindings,													//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
  		static_cast<deUint32>(DE_LENGTH_OF_ARRAY(attributes)),		//	deUint32									vertexAttributeDescriptionCount;
  		attributes,													//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
  	};
  
  	// Stencil state: this is key for checking and obtaining the right results. The stencil buffer will be cleared to 0. The first
  	// set of draws ("front" set of triangles) will pass the test and increment the stencil value to 1. The second set of draws
  	// ("back" set of triangles, not really in the back because all of them have depth 0.0) will not pass the stencil test then, but
  	// still increment the stencil value to 2.
  	//
  	// At the end of the test, if every draw command was executed correctly in the expected order, the color buffer will have the
  	// colors of the front set, and the stencil buffer will be full of 2s.
  	const auto stencilOpState = makeStencilOpState(VK_STENCIL_OP_INCREMENT_AND_CLAMP, VK_STENCIL_OP_INCREMENT_AND_CLAMP, VK_STENCIL_OP_KEEP,
  		VK_COMPARE_OP_EQUAL, 0xFFu, 0xFFu, 0u);
  
  	const VkPipelineDepthStencilStateCreateInfo dsState =
  	{
  		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType                          sType
  		nullptr,													// const void*                              pNext
  		0u,															// VkPipelineDepthStencilStateCreateFlags   flags
  		VK_FALSE,													// VkBool32                                 depthTestEnable
  		VK_FALSE,													// VkBool32                                 depthWriteEnable
  		VK_COMPARE_OP_NEVER,										// VkCompareOp                              depthCompareOp
  		VK_FALSE,													// VkBool32                                 depthBoundsTestEnable
  		VK_TRUE,													// VkBool32                                 stencilTestEnable
  		stencilOpState,												// VkStencilOpState                         front
  		stencilOpState,												// VkStencilOpState                         back
  		0.0f,														// float                                    minDepthBounds
  		1.0f,														// float                                    maxDepthBounds
  	};
  
  	const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
  			vertModule.get(), DE_NULL, DE_NULL, DE_NULL, fragModule.get(),
  			renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u,
  			&inputState, nullptr, nullptr, &dsState);
  
  	// Command pool and buffers.
  	using CmdBufferPtr = Move<VkCommandBuffer>;
  	const auto cmdPool = makeCommandPool(vkd, device, qIndex);
  
  	CmdBufferPtr	primaryCmdBufferPtr;
  	CmdBufferPtr	secondaryCmdBufferPtr;
  	VkCommandBuffer	primaryCmdBuffer;
  	VkCommandBuffer	secondaryCmdBuffer;
  	VkCommandBuffer	drawsCmdBuffer;
  
  	primaryCmdBufferPtr		= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
  	primaryCmdBuffer		= primaryCmdBufferPtr.get();
  	drawsCmdBuffer			= primaryCmdBuffer;
  	beginCommandBuffer(vkd, primaryCmdBuffer);
  
  	// Clear values.
  	std::vector<VkClearValue> clearValues(2u);
  	clearValues[0] = makeClearValueColorU32(0u, 0u, 0u, 0u);
  	clearValues[1] = makeClearValueDepthStencil(1.0f, 0u);
  
  	// Copy staging buffers to vertex buffers.
  	const auto copyRegion = makeBufferCopy(0ull, 0ull, vertexBufferSize);
  	vkd.cmdCopyBuffer(primaryCmdBuffer, testData.frontBuffers.stagingBuffer->get(), testData.frontBuffers.vertexBuffer->get(), 1u, &copyRegion);
  	vkd.cmdCopyBuffer(primaryCmdBuffer, testData.backBuffers.stagingBuffer->get(), testData.backBuffers.vertexBuffer->get(), 1u, &copyRegion);
  
  	// Use barrier for vertex reads.
  	const auto vertexBarier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT);
  	vkd.cmdPipelineBarrier(primaryCmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0u, 1u, &vertexBarier, 0u, nullptr, 0u, nullptr);
  
  	// Change depth/stencil attachment layout.
  	const auto dsBarrier = makeImageMemoryBarrier(0, (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, testData.dsAttachment->get(), dsResourceRange);
  	vkd.cmdPipelineBarrier(primaryCmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT), 0u, 0u, nullptr, 0u, nullptr, 1u, &dsBarrier);
  
  	beginRenderPass(vkd, primaryCmdBuffer, renderPass.get(), framebuffer.get(),
  		scissors[0], static_cast<deUint32>(clearValues.size()), clearValues.data(),
  		(useSecondary ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE));
  
  	if (useSecondary)
  	{
  		secondaryCmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY);
  		secondaryCmdBuffer		= secondaryCmdBufferPtr.get();
  		drawsCmdBuffer			= secondaryCmdBuffer;
  
  		const VkCommandBufferInheritanceInfo inheritanceInfo =
  		{
  			VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,	//	VkStructureType					sType;
  			nullptr,											//	const void*						pNext;
  			renderPass.get(),									//	VkRenderPass					renderPass;
  			0u,													//	deUint32						subpass;
  			framebuffer.get(),									//	VkFramebuffer					framebuffer;
  			0u,													//	VkBool32						occlusionQueryEnable;
  			0u,													//	VkQueryControlFlags				queryFlags;
  			0u,													//	VkQueryPipelineStatisticFlags	pipelineStatistics;
  		};
  
  		const VkCommandBufferUsageFlags	usageFlags	= (VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
  		const VkCommandBufferBeginInfo	beginInfo	=
  		{
  			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  			nullptr,
  			usageFlags,										//	VkCommandBufferUsageFlags				flags;
  			&inheritanceInfo,								//	const VkCommandBufferInheritanceInfo*	pInheritanceInfo;
  		};
  
  		VK_CHECK(vkd.beginCommandBuffer(secondaryCmdBuffer, &beginInfo));
  	}
  
  	// Bind pipeline.
  	vkd.cmdBindPipeline(drawsCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
  
  	// Draw triangles in front.
  	vkd.cmdBindVertexBuffers(drawsCmdBuffer, 0u, 1u, &testData.frontBuffers.vertexBuffer->get(), &vertexBufferOffset);
  	for (deUint32 i = 0; i < numPixels; ++i)
  		vkd.cmdDraw(drawsCmdBuffer, 3u, 1u, i*3u, 0u);
  
  	// Draw triangles in the "back". This should have no effect due to the stencil test.
  	vkd.cmdBindVertexBuffers(drawsCmdBuffer, 0u, 1u, &testData.backBuffers.vertexBuffer->get(), &vertexBufferOffset);
  	for (deUint32 i = 0; i < numPixels; ++i)
  		vkd.cmdDraw(drawsCmdBuffer, 3u, 1u, i*3u, 0u);
  
  	if (useSecondary)
  	{
  		endCommandBuffer(vkd, secondaryCmdBuffer);
  		vkd.cmdExecuteCommands(primaryCmdBuffer, 1u, &secondaryCmdBuffer);
  	}
  
  	endRenderPass(vkd, primaryCmdBuffer);
  
  	// Copy color and depth/stencil attachments to verification buffers.
  	const auto colorAttachmentBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, testData.colorAttachment->get(), colorResourceRange);
  	vkd.cmdPipelineBarrier(primaryCmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &colorAttachmentBarrier);
  
  	const auto colorResourceLayers	= makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
  	const auto colorCopyRegion		= makeBufferImageCopy(m_params.imageExtent, colorResourceLayers);
  	vkd.cmdCopyImageToBuffer(primaryCmdBuffer, testData.colorAttachment->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, testData.colorCheckBuffer->get(), 1u, &colorCopyRegion);
  
  	const auto stencilAttachmentBarrier = makeImageMemoryBarrier(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, testData.dsAttachment->get(), dsResourceRange);
  	vkd.cmdPipelineBarrier(primaryCmdBuffer, (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT), VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &stencilAttachmentBarrier);
  
  	const auto stencilResourceLayers	= makeImageSubresourceLayers(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 0u, 1u);
  	const auto stencilCopyRegion		= makeBufferImageCopy(m_params.imageExtent, stencilResourceLayers);
  	vkd.cmdCopyImageToBuffer(primaryCmdBuffer, testData.dsAttachment->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, testData.stencilCheckBuffer->get(), 1u, &stencilCopyRegion);
  
  	const auto verificationBuffersBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
  	vkd.cmdPipelineBarrier(primaryCmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &verificationBuffersBarrier, 0u, nullptr, 0u, nullptr);
  
  	endCommandBuffer(vkd, primaryCmdBuffer);
  	submitCommandsAndWait(vkd, device, queue, primaryCmdBuffer);
  
  	// Check buffer contents.
  	auto& colorCheckBufferAlloc	= testData.colorCheckBuffer->getAllocation();
  	void* colorCheckBufferData	= colorCheckBufferAlloc.getHostPtr();
  	invalidateAlloc(vkd, device, colorCheckBufferAlloc);
  
  	auto& stencilCheckBufferAlloc	= testData.stencilCheckBuffer->getAllocation();
  	void* stencilCheckBufferData	= stencilCheckBufferAlloc.getHostPtr();
  	invalidateAlloc(vkd, device, stencilCheckBufferAlloc);
  
  	const auto iWidth			= static_cast<int>(m_params.imageExtent.width);
  	const auto iHeight			= static_cast<int>(m_params.imageExtent.height);
  	const auto colorTcuFormat	= mapVkFormat(colorFormat);
  	const auto stencilTcuFormat	= tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8);
  
  	tcu::TextureLevel			referenceLevel		(colorTcuFormat, iWidth, iHeight);
  	tcu::PixelBufferAccess		referenceAccess		= referenceLevel.getAccess();
  	tcu::TextureLevel			colorErrorLevel		(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), iWidth, iHeight);
  	tcu::PixelBufferAccess		colorErrorAccess	= colorErrorLevel.getAccess();
  	tcu::TextureLevel			stencilErrorLevel	(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), iWidth, iHeight);
  	tcu::PixelBufferAccess		stencilErrorAccess	= stencilErrorLevel.getAccess();
  	tcu::ConstPixelBufferAccess	colorAccess			(colorTcuFormat, iWidth, iHeight, 1, colorCheckBufferData);
  	tcu::ConstPixelBufferAccess	stencilAccess		(stencilTcuFormat, iWidth, iHeight, 1, stencilCheckBufferData);
  	const tcu::Vec4				green				(0.0f, 1.0f, 0.0f, 1.0f);
  	const tcu::Vec4				red					(1.0f, 0.0f, 0.0f, 1.0f);
  	const int					expectedStencil		= 2;
  	bool						colorFail			= false;
  	bool						stencilFail			= false;
  
  	for (int y = 0; y < iHeight; ++y)
  	for (int x = 0; x < iWidth; ++x)
  	{
  		const tcu::UVec4	colorValue		= colorAccess.getPixelUint(x, y);
  		const auto			expectedPixel	= colors[y * iWidth + x];
  		const tcu::UVec4	expectedValue	(expectedPixel.x(), expectedPixel.y(), expectedPixel.z(), expectedPixel.w());
  		const bool			colorMismatch	= (colorValue != expectedValue);
  
  		const auto			stencilValue	= stencilAccess.getPixStencil(x, y);
  		const bool			stencilMismatch	= (stencilValue != expectedStencil);
  
  		referenceAccess.setPixel(expectedValue, x, y);
  		colorErrorAccess.setPixel((colorMismatch ? red : green), x, y);
  		stencilErrorAccess.setPixel((stencilMismatch ? red : green), x, y);
  
  		if (stencilMismatch)
  			stencilFail = true;
  
  		if (colorMismatch)
  			colorFail = true;
  	}
  
  	if (colorFail || stencilFail)
  	{
  		auto& log = m_context.getTestContext().getLog();
  		log
  			<< tcu::TestLog::ImageSet("Result", "")
  			<< tcu::TestLog::Image("ColorOutput", "", colorAccess)
  			<< tcu::TestLog::Image("ColorReference", "", referenceAccess)
  			<< tcu::TestLog::Image("ColorError", "", colorErrorAccess)
  			<< tcu::TestLog::Image("StencilError", "", stencilErrorAccess)
  			<< tcu::TestLog::EndImageSet
  			;
  		TCU_FAIL("Mismatched output and reference color or stencil; please check test log --");
  	}
  
  	return tcu::TestStatus::pass("Pass");
  }
  
  } // anonymous
  
  tcu::TestCaseGroup* createCommandBuffersTests (tcu::TestContext& testCtx)
  {
  	de::MovePtr<tcu::TestCaseGroup>	commandBuffersTests	(new tcu::TestCaseGroup(testCtx, "command_buffers", "Command Buffers Tests"));
  
  	/* 19.1. Command Pools (5.1 in VK 1.0 Spec) */
  	addFunctionCase				(commandBuffersTests.get(), "pool_create_null_params",			"",	createPoolNullParamsTest);
  	addFunctionCase				(commandBuffersTests.get(), "pool_create_non_null_allocator",	"",	createPoolNonNullAllocatorTest);
  	addFunctionCase				(commandBuffersTests.get(), "pool_create_transient_bit",		"",	createPoolTransientBitTest);
  	addFunctionCase				(commandBuffersTests.get(), "pool_create_reset_bit",			"",	createPoolResetBitTest);
  	addFunctionCase				(commandBuffersTests.get(), "pool_reset_release_res",			"",	resetPoolReleaseResourcesBitTest);
  	addFunctionCase				(commandBuffersTests.get(), "pool_reset_no_flags_res",			"",	resetPoolNoFlagsTest);
  	addFunctionCase				(commandBuffersTests.get(), "pool_reset_reuse",					"",	checkEventSupport, resetPoolReuseTest);
  	/* 19.2. Command Buffer Lifetime (5.2 in VK 1.0 Spec) */
  	addFunctionCase				(commandBuffersTests.get(), "allocate_single_primary",			"", allocatePrimaryBufferTest);
  	addFunctionCase				(commandBuffersTests.get(), "allocate_many_primary",			"",	allocateManyPrimaryBuffersTest);
  	addFunctionCase				(commandBuffersTests.get(), "allocate_single_secondary",		"", allocateSecondaryBufferTest);
  	addFunctionCase				(commandBuffersTests.get(), "allocate_many_secondary",			"", allocateManySecondaryBuffersTest);
  	addFunctionCase				(commandBuffersTests.get(), "execute_small_primary",			"",	checkEventSupport, executePrimaryBufferTest);
  	addFunctionCase				(commandBuffersTests.get(), "execute_large_primary",			"",	checkEventSupport, executeLargePrimaryBufferTest);
  	addFunctionCase				(commandBuffersTests.get(), "reset_implicit",					"", checkEventSupport, resetBufferImplicitlyTest);
  	addFunctionCase				(commandBuffersTests.get(), "trim_command_pool",				"", checkEventSupport, trimCommandPoolTest, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
  	addFunctionCase				(commandBuffersTests.get(), "trim_command_pool_secondary",		"", checkEventSupport, trimCommandPoolTest, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
  	/* 19.3. Command Buffer Recording (5.3 in VK 1.0 Spec) */
  	addFunctionCase				(commandBuffersTests.get(), "record_single_primary",			"",	checkEventSupport, recordSinglePrimaryBufferTest);
  	addFunctionCase				(commandBuffersTests.get(), "record_many_primary",				"", checkEventSupport, recordLargePrimaryBufferTest);
  	addFunctionCase				(commandBuffersTests.get(), "record_single_secondary",			"",	checkEventSupport, recordSingleSecondaryBufferTest);
  	addFunctionCase				(commandBuffersTests.get(), "record_many_secondary",			"", checkEventSupport, recordLargeSecondaryBufferTest);
  	{
  		deUint32	seed		= 1614182419u;
  		const auto	smallExtent	= makeExtent3D(128u, 128u, 1u);
  		const auto	largeExtent	= makeExtent3D(512u, 512u, 1u);
  
  		commandBuffersTests->addChild(new ManyDrawsCase(testCtx, "record_many_draws_primary_1",		"", ManyDrawsParams(VK_COMMAND_BUFFER_LEVEL_PRIMARY,	smallExtent,	seed++)));
  		commandBuffersTests->addChild(new ManyDrawsCase(testCtx, "record_many_draws_primary_2",		"", ManyDrawsParams(VK_COMMAND_BUFFER_LEVEL_PRIMARY,	largeExtent,	seed++)));
  		commandBuffersTests->addChild(new ManyDrawsCase(testCtx, "record_many_draws_secondary_1",	"", ManyDrawsParams(VK_COMMAND_BUFFER_LEVEL_SECONDARY,	smallExtent,	seed++)));
  		commandBuffersTests->addChild(new ManyDrawsCase(testCtx, "record_many_draws_secondary_2",	"", ManyDrawsParams(VK_COMMAND_BUFFER_LEVEL_SECONDARY,	largeExtent,	seed++)));
  	}
  	addFunctionCase				(commandBuffersTests.get(), "submit_twice_primary",				"",	checkEventSupport, submitPrimaryBufferTwiceTest);
  	addFunctionCase				(commandBuffersTests.get(), "submit_twice_secondary",			"",	checkEventSupport, submitSecondaryBufferTwiceTest);
  	addFunctionCase				(commandBuffersTests.get(), "record_one_time_submit_primary",	"",	checkEventSupport, oneTimeSubmitFlagPrimaryBufferTest);
  	addFunctionCase				(commandBuffersTests.get(), "record_one_time_submit_secondary",	"",	checkEventSupport, oneTimeSubmitFlagSecondaryBufferTest);
  	addFunctionCase				(commandBuffersTests.get(), "render_pass_continue",				"",	renderPassContinueTest, true);
  	addFunctionCase				(commandBuffersTests.get(), "render_pass_continue_no_fb",		"",	renderPassContinueTest, false);
  	addFunctionCase				(commandBuffersTests.get(), "record_simul_use_primary",			"",	checkEventSupport, simultaneousUsePrimaryBufferTest);
  	addFunctionCase				(commandBuffersTests.get(), "record_simul_use_secondary",		"",	checkEventSupport, simultaneousUseSecondaryBufferTest);
  	addFunctionCaseWithPrograms (commandBuffersTests.get(), "record_simul_use_secondary_one_primary", "", genComputeIncrementSource, simultaneousUseSecondaryBufferOnePrimaryBufferTest);
  	addFunctionCaseWithPrograms (commandBuffersTests.get(), "record_simul_use_secondary_two_primary", "", genComputeIncrementSource, simultaneousUseSecondaryBufferTwoPrimaryBuffersTest);
  	addFunctionCase				(commandBuffersTests.get(), "record_query_precise_w_flag",		"",	recordBufferQueryPreciseWithFlagTest);
  	addFunctionCase				(commandBuffersTests.get(), "record_query_imprecise_w_flag",	"",	recordBufferQueryImpreciseWithFlagTest);
  	addFunctionCase				(commandBuffersTests.get(), "record_query_imprecise_wo_flag",	"",	recordBufferQueryImpreciseWithoutFlagTest);
  	addFunctionCaseWithPrograms (commandBuffersTests.get(), "bad_inheritance_info_random",		"", genComputeIncrementSourceBadInheritance, badInheritanceInfoTest, BadInheritanceInfoCase::RANDOM_PTR);
  	addFunctionCaseWithPrograms (commandBuffersTests.get(), "bad_inheritance_info_random_cont",	"", genComputeIncrementSourceBadInheritance, badInheritanceInfoTest, BadInheritanceInfoCase::RANDOM_PTR_CONTINUATION);
  	addFunctionCaseWithPrograms (commandBuffersTests.get(), "bad_inheritance_info_random_data",	"", genComputeIncrementSourceBadInheritance, badInheritanceInfoTest, BadInheritanceInfoCase::RANDOM_DATA_PTR);
  	addFunctionCaseWithPrograms (commandBuffersTests.get(), "bad_inheritance_info_invalid_type", "", genComputeIncrementSourceBadInheritance, badInheritanceInfoTest, BadInheritanceInfoCase::INVALID_STRUCTURE_TYPE);
  	addFunctionCaseWithPrograms (commandBuffersTests.get(), "bad_inheritance_info_valid_nonsense_type", "", genComputeIncrementSourceBadInheritance, badInheritanceInfoTest, BadInheritanceInfoCase::VALID_NONSENSE_TYPE);
  	/* 19.4. Command Buffer Submission (5.4 in VK 1.0 Spec) */
  	addFunctionCase				(commandBuffersTests.get(), "submit_count_non_zero",			"", checkEventSupport, submitBufferCountNonZero);
  	addFunctionCase				(commandBuffersTests.get(), "submit_count_equal_zero",			"", checkEventSupport, submitBufferCountEqualZero);
  	addFunctionCase				(commandBuffersTests.get(), "submit_wait_single_semaphore",		"", checkEventSupport, submitBufferWaitSingleSemaphore);
  	addFunctionCase				(commandBuffersTests.get(), "submit_wait_many_semaphores",		"", checkEventSupport, submitBufferWaitManySemaphores);
  	addFunctionCase				(commandBuffersTests.get(), "submit_null_fence",				"", checkEventSupport, submitBufferNullFence);
  	addFunctionCase				(commandBuffersTests.get(), "submit_two_buffers_one_buffer_null_with_fence", "", checkEventSupport, submitTwoBuffersOneBufferNullWithFence);
  	/* 19.5. Secondary Command Buffer Execution (5.6 in VK 1.0 Spec) */
  	addFunctionCase				(commandBuffersTests.get(), "secondary_execute",				"",	checkEventSupport, executeSecondaryBufferTest);
  	addFunctionCase				(commandBuffersTests.get(), "secondary_execute_twice",			"",	checkEventSupport, executeSecondaryBufferTwiceTest);
  	/* 19.6. Commands Allowed Inside Command Buffers (? in VK 1.0 Spec) */
  	addFunctionCaseWithPrograms (commandBuffersTests.get(), "order_bind_pipeline",				"", genComputeSource, orderBindPipelineTest);
  	/* Verify untested transitions between command buffer states */
  	addFunctionCase				(commandBuffersTests.get(), "recording_to_ininitial",			"", executeStateTransitionTest, STT_RECORDING_TO_INITIAL);
  	addFunctionCase				(commandBuffersTests.get(), "executable_to_ininitial",			"", executeStateTransitionTest, STT_EXECUTABLE_TO_INITIAL);
  	addFunctionCase				(commandBuffersTests.get(), "recording_to_invalid",				"", executeStateTransitionTest, STT_RECORDING_TO_INVALID);
  	addFunctionCase				(commandBuffersTests.get(), "executable_to_invalid",			"", executeStateTransitionTest, STT_EXECUTABLE_TO_INVALID);
  
  	return commandBuffersTests.release();
  }
  
  } // api
  } // vkt
  
  