More EXT_color_write_enable tests.

New tests:
dEQP-VK.pipeline.*.color_write_enable_maxa.*

Components: Vulkan

VK-GL-CTS issue: 3569

Change-Id: I9db26fe0cbee3134b174efcebf8a795b7b676a28
diff --git a/android/cts/main/vk-master-2022-03-01/pipeline.txt b/android/cts/main/vk-master-2022-03-01/pipeline.txt
index bc868b6..8561044 100644
--- a/android/cts/main/vk-master-2022-03-01/pipeline.txt
+++ b/android/cts/main/vk-master-2022-03-01/pipeline.txt
Binary files differ
diff --git a/android/cts/main/vk-master/pipeline.txt b/android/cts/main/vk-master/pipeline.txt
index f93d738..a0714ab 100644
--- a/android/cts/main/vk-master/pipeline.txt
+++ b/android/cts/main/vk-master/pipeline.txt
Binary files differ
diff --git a/android/cts/main/vksc-main/pipeline.txt b/android/cts/main/vksc-main/pipeline.txt
index 56e2c41..01b1001 100644
--- a/android/cts/main/vksc-main/pipeline.txt
+++ b/android/cts/main/vksc-main/pipeline.txt
Binary files differ
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineColorWriteEnableTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineColorWriteEnableTests.cpp
index 61b3e36..02813f9 100644
--- a/external/vulkancts/modules/vulkan/pipeline/vktPipelineColorWriteEnableTests.cpp
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineColorWriteEnableTests.cpp
@@ -1123,6 +1123,641 @@
 
 } // anonymous namespace
 
+namespace
+{
+using namespace vk;
+using namespace tcu;
+
+struct TestParams
+{
+	deUint32	width;
+	deUint32	height;
+	VkFormat	format;
+	deUint32	attachmentCount;
+	deUint32	attachmentMore;
+	bool		setCweBeforePlBind;
+	bool		colorWriteEnables;
+	PipelineConstructionType pct;
+	bool selectOptimalBlendableFormat (const InstanceInterface&, VkPhysicalDevice);
+};
+
+class ColorWriteEnable2Test : public vkt::TestCase
+{
+public:
+								ColorWriteEnable2Test	(TestContext&		testCtx,
+														 const std::string&	name,
+														 const std::string& description,
+														 const TestParams&	testParams)
+									: vkt::TestCase		(testCtx, name, description)
+									, m_params		(testParams) { }
+
+	virtual						~ColorWriteEnable2Test	() = default;
+
+	virtual void				checkSupport			(Context&			context) const override;
+	virtual void				initPrograms			(SourceCollections&	programCollection) const override;
+	virtual vkt::TestInstance*	createInstance			(Context&			context) const override;
+
+private:
+	mutable TestParams			m_params;
+
+};
+
+class ColorWriteEnable2Instance : public vkt::TestInstance
+{
+public:
+	typedef std::vector<VkBool32>	ColorWriteEnables;
+	struct Attachment
+	{
+		de::MovePtr<ImageWithMemory>	image;
+		Move<VkImageView>				view;
+		Attachment () = default;
+		DE_UNUSED_FUNCTION Attachment (Attachment&& other);
+	};
+	struct Attachments
+	{
+		std::vector<Attachment>	attachments;
+		Move<VkFramebuffer>		framebuffer;
+		Attachments () = default;
+		Attachments (Attachments&& other);
+	};
+									ColorWriteEnable2Instance	(Context&						context,
+																 const TestParams&				testParams);
+	virtual							~ColorWriteEnable2Instance	() = default;
+	de::MovePtr<BufferWithMemory>	createVerrtexBuffer			() const;
+	Attachments						createAttachments			(VkRenderPass					renderPass,
+																 deUint32						colorAttachmentCount) const;
+	Move<VkRenderPass>				createRenderPass			(deUint32						colorAttachmentCount) const;
+
+	void							setupAndBuildPipeline		(GraphicsPipelineWrapper&		owner,
+																 VkPipelineLayout				pipelineLayout,
+																 VkRenderPass					renderPass,
+																 deUint32						colorAttachmentCount,
+																 const ColorWriteEnables&		colorWriteEnables,
+																 bool							dynamic) const;
+	virtual TestStatus				iterate						() override;
+	TestStatus						testSetCWEbeforePlBind		();
+	TestStatus						testSetCWEafterPlBind		();
+	bool							verifyAttachment			(deUint32						attachmentIndex,
+																 const ConstPixelBufferAccess&	attachmentContent,
+																 const ColorWriteEnables&		colorWriteEnables,
+																 const Vec4&					background) const;
+private:
+	const TestParams			m_params;
+	const DeviceInterface&		m_vkd;
+	const VkDevice				m_device;
+	Allocator&					m_allocator;
+	const Move<VkShaderModule>	m_vertex;
+	const Move<VkShaderModule>	m_fragment;
+};
+
+ColorWriteEnable2Instance::Attachment::Attachment (Attachment&& other)
+	: image			(std::move(other.image))
+	, view			(std::move(other.view))
+{
+}
+ColorWriteEnable2Instance::Attachments::Attachments (Attachments&& other)
+	: attachments	(std::move(other.attachments))
+	, framebuffer	(std::move(other.framebuffer))
+{
+}
+
+bool TestParams::selectOptimalBlendableFormat (const InstanceInterface& vk, VkPhysicalDevice dev)
+{
+	auto doesFormatMatch = [](const VkFormat fmt) -> bool
+	{
+		const auto tcuFmt = mapVkFormat(fmt);
+		return tcuFmt.order == TextureFormat::ChannelOrder::RGBA
+				|| tcuFmt.order == TextureFormat::ChannelOrder::sRGBA;
+	};
+
+	VkFormatProperties2 props{};
+	const VkFormatFeatureFlags flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT
+										| VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT
+										| VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
+	for (int f = VK_FORMAT_R64G64B64A64_SFLOAT; f > 0; --f)
+	{
+		props.sType				= VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
+		props.pNext				= nullptr;
+		props.formatProperties	= {};
+		const VkFormat			fmt = static_cast<VkFormat>(f);
+		vk.getPhysicalDeviceFormatProperties2(dev, fmt, &props);
+		if (doesFormatMatch(fmt) && ((props.formatProperties.optimalTilingFeatures & flags) == flags))
+		{
+			this->format = fmt;
+			return true;
+		}
+	}
+	return false;
+}
+
+void ColorWriteEnable2Test::checkSupport (Context& context) const
+{
+	const auto&	vki				= context.getInstanceInterface();
+	const auto	physicalDevice	= context.getPhysicalDevice();
+
+	if (m_params.colorWriteEnables)
+	{
+		context.requireDeviceFunctionality("VK_EXT_color_write_enable");
+	}
+
+	DE_ASSERT(m_params.attachmentCount >= 1);
+	auto maxColorAttachments = context.getDeviceProperties().limits.maxColorAttachments;
+	if ((m_params.attachmentCount + m_params.attachmentMore) > maxColorAttachments)
+	{
+		std::stringstream ss;
+		if (m_params.attachmentMore)
+		{
+			ss << "Sum of color attachments (" << m_params.attachmentCount << " + " << m_params.attachmentMore << ")";
+		}
+		else
+		{
+			ss << "Color attachment count of " << m_params.attachmentCount;
+		}
+		ss << " exceeds maximum number of color attachments supported by device which is " << maxColorAttachments;
+		ss.flush();
+		TCU_THROW(NotSupportedError, ss.str());
+	}
+
+	if ( ! m_params.selectOptimalBlendableFormat(vki, physicalDevice))
+		TCU_THROW(NotSupportedError, "Required color image features not supported");
+
+	checkPipelineLibraryRequirements(vki, physicalDevice, m_params.pct);
+}
+
+void ColorWriteEnable2Test::initPrograms (SourceCollections& programCollection) const
+{
+	const char			nl = '\n';
+	const deUint32		ac = m_params.attachmentCount;
+	std::ostringstream	vs;
+	std::ostringstream	fs;
+
+	vs	<< "#version 450"									<<	nl
+		<< "layout(location=0) in vec4 position;"			<<	nl
+		<< "void main() {"									<<	nl
+		<< "    gl_Position = vec4(position.xy, 0.0, 1.0);"	<<	nl
+		<< "}"												<<	nl;
+	programCollection.glslSources.add("vert") << glu::VertexSource(vs.str());
+
+	fs	<< "#version 450"											<<	nl
+		<< "layout(std430, push_constant) uniform PC"				<<	nl
+		<< "{ uint attachments; } params;"							<<	nl
+		<< "layout(location = 0) out vec4 colors[" << ac << "];"	<<	nl
+		<< "void main() {"											<<	nl
+		<< "    for (uint a = 0; a < params.attachments; ++a) {"	<<	nl
+		<< "        colors[a] = vec4(pow(0.5, float(a+1)));"		<<	nl
+		<< "}}"														<<	nl;
+	programCollection.glslSources.add("frag") << glu::FragmentSource(fs.str());
+}
+
+TestInstance* ColorWriteEnable2Test::createInstance (Context& context) const
+{
+	return new ColorWriteEnable2Instance(context, m_params);
+}
+
+ColorWriteEnable2Instance::ColorWriteEnable2Instance (Context& context, const TestParams& testParams)
+	: vkt::TestInstance	(context)
+	, m_params		(testParams)
+	, m_vkd				(context.getDeviceInterface())
+	, m_device			(context.getDevice())
+	, m_allocator		(context.getDefaultAllocator())
+	, m_vertex			(createShaderModule(m_vkd, m_device, context.getBinaryCollection().get("vert")))
+	, m_fragment		(createShaderModule(m_vkd, m_device, context.getBinaryCollection().get("frag")))
+{
+}
+
+Move<VkRenderPass> ColorWriteEnable2Instance::createRenderPass (deUint32 colorAttachmentCount) const
+{
+	const std::vector<VkAttachmentDescription> attachmentDescriptions(
+		colorAttachmentCount,
+		VkAttachmentDescription
+		{
+			0u,											//	VkAttachmentDescriptionFlags	flags;
+			m_params.format,							//	VkFormat						format;
+			VK_SAMPLE_COUNT_1_BIT,						//	VkSampleCountFlagBits			samples;
+			VK_ATTACHMENT_LOAD_OP_CLEAR,				//	VkAttachmentLoadOp				loadOp;
+			VK_ATTACHMENT_STORE_OP_STORE,				//	VkAttachmentStoreOp				storeOp;
+			VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				stencilLoadOp;
+			VK_ATTACHMENT_STORE_OP_DONT_CARE,			//	VkAttachmentStoreOp				stencilStoreOp;
+			VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout					initialLayout;
+			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
+		}
+	);
+
+	std::vector<VkAttachmentReference> colorAttachmentReference;
+	for (deUint32 i = 0u; i < colorAttachmentCount; ++i)
+	{
+		colorAttachmentReference.push_back(VkAttachmentReference
+			{
+				i,											//	deUint32		attachment;
+				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	//	VkImageLayout	layout;
+			}
+		);
+	}
+
+	const VkSubpassDescription subpassDescription
+	{
+		0u,												//	VkSubpassDescriptionFlags		flags;
+		VK_PIPELINE_BIND_POINT_GRAPHICS,				//	VkPipelineBindPoint				pipelineBindPoint;
+		0u,												//	deUint32						inputAttachmentCount;
+		nullptr,										//	const VkAttachmentReference*	pInputAttachments;
+		deUint32(attachmentDescriptions.size()),		//	deUint32						colorAttachmentCount;
+		colorAttachmentReference.data(),				//	const VkAttachmentReference*	pColorAttachments;
+		nullptr,										//	const VkAttachmentReference*	pResolveAttachments;
+		nullptr,										//	const VkAttachmentReference*	pDepthStencilAttachment;
+		0u,												//	deUint32						preserveAttachmentCount;
+		nullptr,										//	const deUint32*					pPreserveAttachments;
+	};
+
+	const VkRenderPassCreateInfo renderPassCreateInfo
+	{
+		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,				//	VkStructureType					sType;
+		nullptr,												//	const void*						pNext;
+		0u,														//	VkRenderPassCreateFlags			flags;
+		static_cast<deUint32>(attachmentDescriptions.size()),	//	deUint32						attachmentCount;
+		attachmentDescriptions.data(),							//	const VkAttachmentDescription*	pAttachments;
+		1u,														//	deUint32						subpassCount;
+		&subpassDescription,									//	const VkSubpassDescription*		pSubpasses;
+		0u,														//	deUint32						dependencyCount;
+		nullptr,												//	const VkSubpassDependency*		pDependencies;
+	};
+
+	return vk::createRenderPass(m_vkd, m_device, &renderPassCreateInfo);
+}
+
+de::MovePtr<BufferWithMemory> ColorWriteEnable2Instance::createVerrtexBuffer () const
+{
+	const std::vector<float> quad
+	{
+		-1.0f, -1.0f, 0.0f, 0.0f,
+		+1.0f, -1.0f, 0.0f, 0.0f,
+		-1.0f, +1.0f, 0.0f, 0.0f,
+		-1.0f, +1.0f, 0.0f, 0.0f,
+		+1.0f, -1.0f, 0.0f, 0.0f,
+		+1.0f, +1.0f, 0.0f, 0.0f
+	};
+
+	const auto						vertDataSize	= quad.size() * sizeof(float);
+	const auto						vertBufferInfo	= makeBufferCreateInfo(static_cast<VkDeviceSize>(vertDataSize), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+	de::MovePtr<BufferWithMemory>	vertBuffer		(new BufferWithMemory(m_vkd, m_device, m_allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible));
+	auto&							alloc			= vertBuffer->getAllocation();
+
+	deMemcpy(reinterpret_cast<char*>(alloc.getHostPtr()), quad.data(), vertDataSize);
+	flushAlloc(m_vkd, m_device, alloc);
+
+	return vertBuffer;
+}
+
+ColorWriteEnable2Instance::Attachments ColorWriteEnable2Instance::createAttachments (VkRenderPass renderPass, deUint32 colorAttachmentCount) const
+{
+	const VkExtent3D			extent				{ m_params.width, m_params.height, 1u };
+	const VkImageUsageFlags		imageUsage			= (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+	const auto					imageSubresource	= vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+	const deUint32				queueIndex			= m_context.getUniversalQueueFamilyIndex();
+	Allocator&					allocator			= m_context.getDefaultAllocator();
+
+	std::vector<Attachment>		attachments			(colorAttachmentCount);
+	std::vector<VkImageView>	views				(colorAttachmentCount);
+
+	for (deUint32 i = 0; i < colorAttachmentCount; ++i)
+	{
+		auto& attachment = attachments[i];
+
+		const VkImageCreateInfo imageCreateInfo
+		{
+			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		//	VkStructureType			sType;
+			nullptr,									//	const void*				pNext;
+			0u,											//	VkImageCreateFlags		flags;
+			VK_IMAGE_TYPE_2D,							//	VkImageType				imageType;
+			m_params.format,							//	VkFormat				format;
+			extent,										//	VkExtent3D				extent;
+			1u,											//	deUint32				mipLevels;
+			1u,											//	deUint32				arrayLayers;
+			VK_SAMPLE_COUNT_1_BIT,						//	VkSampleCountFlagBits	samples;
+			VK_IMAGE_TILING_OPTIMAL,					//	VkImageTiling			tiling;
+			imageUsage,									//	VkImageUsageFlags		usage;
+			VK_SHARING_MODE_EXCLUSIVE,					//	VkSharingMode			sharingMode;
+			1u,											//	deUint32				queueFamilyIndexCount;
+			&queueIndex,								//	const deUint32*			pQueueFamilyIndices;
+			VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout			initialLayout;
+		};
+		attachment.image = de::MovePtr<ImageWithMemory>(new ImageWithMemory(m_vkd, m_device, allocator, imageCreateInfo, MemoryRequirement::Any));
+
+		attachment.view	= makeImageView(m_vkd, m_device, **attachment.image, VK_IMAGE_VIEW_TYPE_2D, m_params.format, imageSubresource);
+
+		views[i] = *attachment.view;
+	}
+
+	const VkFramebufferCreateInfo framebufferCreateInfo
+	{
+		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		//	VkStructureType				sType;
+		nullptr,										//	const void*					pNext;
+		0u,												//	VkFramebufferCreateFlags	flags;
+		renderPass,										//	VkRenderPass				renderPass;
+		colorAttachmentCount,							//	deUint32					attachmentCount;
+		views.data(),									//	const VkImageView*			pAttachments;
+		m_params.width,									//	deUint32					width;
+		m_params.height,								//	deUint32					height;
+		1u,												//	deUint32					layers;
+	};
+
+	Attachments result;
+	result.attachments = std::move(attachments);
+	result.framebuffer = createFramebuffer(m_vkd, m_device, &framebufferCreateInfo);
+
+	return result;
+}
+
+void ColorWriteEnable2Instance::setupAndBuildPipeline (GraphicsPipelineWrapper&		owner,
+													   VkPipelineLayout				pipelineLayout,
+													   VkRenderPass					renderPass,
+													   deUint32						colorAttachmentCount,
+													   const ColorWriteEnables&		colorWriteEnables,
+													   bool							dynamic) const
+{
+	const std::vector<VkViewport>	viewports		{ makeViewport(m_params.width, m_params.height) };
+	const std::vector<VkRect2D>		scissors		{ makeRect2D(m_params.width, m_params.height) };
+
+	const auto						vertexBinding	= makeVertexInputBindingDescription(0u, static_cast<deUint32>(4 * sizeof(float)), VK_VERTEX_INPUT_RATE_VERTEX);
+	const auto						vertexAttrib	= makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u);
+
+	const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
+		nullptr,														//	const void*									pNext;
+		0u,																//	VkPipelineVertexInputStateCreateFlags		flags;
+		1u,																//	deUint32									vertexBindingDescriptionCount;
+		&vertexBinding,													//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
+		1u,																//	deUint32									vertexAttributeDescriptionCount;
+		&vertexAttrib													//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
+	};
+
+	const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType							sType;
+		nullptr,														//	const void*								pNext;
+		0u,																//	VkPipelineInputAssemblyStateCreateFlags	flags;
+		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							//	VkPrimitiveTopology						topology;
+		VK_FALSE,														//	VkBool32								primitiveRestartEnable;
+	};
+
+	const VkDynamicState cweDynamicStates[1] { VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT };
+	const VkPipelineDynamicStateCreateInfo	dynamicStateCreateInfo
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
+		nullptr,												//	const void*							pNext;
+		0u,														//	VkPipelineDynamicStateCreateFlags	flags;
+		1u,														//	deUint32							dynamicStateCount;
+		cweDynamicStates										//	const VkDynamicState*				pDynamicStates;
+	};
+
+	std::vector<vk::VkPipelineColorBlendAttachmentState> colorBlendAttachmentStates(
+		colorAttachmentCount,
+		VkPipelineColorBlendAttachmentState
+		{
+			VK_TRUE,											// VkBool32                 blendEnable
+			VK_BLEND_FACTOR_CONSTANT_COLOR,						// VkBlendFactor            srcColorBlendFactor
+			VK_BLEND_FACTOR_ZERO,								// VkBlendFactor            dstColorBlendFactor
+			VK_BLEND_OP_ADD,									// VkBlendOp                colorBlendOp
+			VK_BLEND_FACTOR_CONSTANT_ALPHA,						// VkBlendFactor            srcAlphaBlendFactor
+			VK_BLEND_FACTOR_ZERO,								// VkBlendFactor            dstAlphaBlendFactor
+			VK_BLEND_OP_ADD,									// VkBlendOp                alphaBlendOp
+			VkColorComponentFlags(0)							// VkColorComponentFlags    colorWriteMask
+		}
+	);
+	for (deUint32 i = 0; i < colorAttachmentCount; ++i)
+	{
+		VkColorComponentFlags colorWriteMask(  VK_COLOR_COMPONENT_R_BIT
+											 | VK_COLOR_COMPONENT_G_BIT
+											 | VK_COLOR_COMPONENT_B_BIT
+											 | VK_COLOR_COMPONENT_A_BIT);
+		switch (i % 4)
+		{
+			case 0: colorWriteMask &= (~(VK_COLOR_COMPONENT_R_BIT)); break;
+			case 1: colorWriteMask &= (~(VK_COLOR_COMPONENT_G_BIT)); break;
+			case 2: colorWriteMask &= (~(VK_COLOR_COMPONENT_B_BIT)); break;
+			case 3: colorWriteMask &= (~(VK_COLOR_COMPONENT_A_BIT)); break;
+		}
+		colorBlendAttachmentStates[i].colorWriteMask = colorWriteMask;
+	}
+
+	const bool cweAllowed = (dynamic && m_params.colorWriteEnables);
+
+	if (cweAllowed)
+	{
+		DE_ASSERT(colorWriteEnables.size() >= colorAttachmentCount);
+	}
+
+	const VkPipelineColorWriteCreateInfoEXT colorWriteCreateInfo
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT,			// VkStructureType	sType;
+		nullptr,														// const void*		pNext;
+		colorAttachmentCount,											// deUint32			attachmentCount;
+		colorWriteEnables.data()										// const VkBool32*	pColorWriteEnables;
+	};
+
+	const float blend = 0.5f;
+
+	const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType                               sType
+		cweAllowed ? &colorWriteCreateInfo : nullptr,					// const void*                                   pNext
+		0u,																// VkPipelineColorBlendStateCreateFlags          flags
+		VK_FALSE,														// VkBool32                                      logicOpEnable
+		VK_LOGIC_OP_CLEAR,												// VkLogicOp                                     logicOp
+		colorAttachmentCount,											// deUint32                                      attachmentCount
+		colorBlendAttachmentStates.data(),								// const VkPipelineColorBlendAttachmentState*    pAttachments
+		{ blend, blend, blend, blend }									// float                                         blendConstants[4]
+	};
+
+	owner
+		.setDefaultRasterizationState()
+		.setDefaultDepthStencilState()
+		.setDefaultMultisampleState()
+		.setDynamicState(cweAllowed ? &dynamicStateCreateInfo : nullptr)
+		.setupVertexInputStete(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
+		.setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, renderPass, 0u, *m_vertex)
+		.setupFragmentShaderState(pipelineLayout, renderPass, 0u, *m_fragment)
+		.setupFragmentOutputState(renderPass, 0u, &colorBlendStateCreateInfo)
+		.setMonolithicPipelineLayout(pipelineLayout)
+		.buildPipeline();
+}
+
+bool ColorWriteEnable2Instance::verifyAttachment (deUint32						attachmentIndex,
+												  const ConstPixelBufferAccess&	attachmentContent,
+												  const ColorWriteEnables&		colorWriteEnables,
+												  const Vec4&					background) const
+{
+	const auto	maskColor	= [&](Vec4 color) -> Vec4 {
+		color[attachmentIndex % 4] = background[attachmentIndex % 4];
+		return color;
+	};
+	const Vec4	source		(powf(0.5f, static_cast<float>(attachmentIndex + 1)));
+	const Vec4	blend		(0.5f);
+	const Vec4	expected	= m_params.colorWriteEnables
+								? (colorWriteEnables[attachmentIndex] != VK_FALSE)
+								  ? maskColor(source * blend)
+								  : background
+								 : maskColor(source * blend);
+	deUint32	failures	= 0;
+
+	for (deUint32 y = 0; y < m_params.height; ++y)
+	{
+		for (deUint32 x = 0; x < m_params.width; ++x)
+		{
+			const auto result = attachmentContent.getPixel(x, y);
+			if (result != expected) ++failures;
+		}
+	}
+
+	return (0 == failures);
+}
+
+TestStatus ColorWriteEnable2Instance::iterate (void)
+{
+	return m_params.setCweBeforePlBind
+			? testSetCWEbeforePlBind()
+			: testSetCWEafterPlBind();
+}
+
+TestStatus ColorWriteEnable2Instance::testSetCWEbeforePlBind ()
+{
+	const VkQueue							queue			= m_context.getUniversalQueue();
+	const deUint32							queueIndex		= m_context.getUniversalQueueFamilyIndex();
+	const VkRect2D							renderArea		= makeRect2D(m_params.width, m_params.height);
+	const deUint32							attachmentCount	= m_params.attachmentCount;
+
+	struct { deUint32 attachments; }		pushConstant	{ 1u };
+	const VkPushConstantRange				pcRange			= makePushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(pushConstant));
+
+	de::MovePtr<BufferWithMemory>			vertexBuffer	= createVerrtexBuffer();
+
+	std::vector<Move<VkRenderPass>>			renderPasses;
+	std::vector<Attachments>				attachments;
+	for (deUint32 i = 0; i < attachmentCount; ++i)
+	{
+		renderPasses.emplace_back(createRenderPass(i+1));
+		attachments.emplace_back(createAttachments(*renderPasses.back(), (i+1)));
+	}
+	const Vec4								background		(0.75f, 0.75f, 0.75f, 0.75f);
+	std::vector<VkClearValue>				clearValues		(attachmentCount, makeClearValueColor(background));
+
+	ColorWriteEnables						writeEnables	(attachmentCount + m_params.attachmentMore, VK_TRUE);
+	for (deUint32 i = 0; i < attachmentCount; ++i)	writeEnables[i] = (i % 2) ? VK_TRUE : VK_FALSE;
+
+	Move<VkPipelineLayout>					pipelineLayout	= makePipelineLayout(m_vkd, m_device, 0u, nullptr, 1u, &pcRange);
+
+	std::vector<GraphicsPipelineWrapper>	pipelines;
+	for (deUint32 i = 0; i < attachmentCount; ++i)
+	{
+		pipelines.emplace_back(m_vkd, m_device, m_params.pct);
+		setupAndBuildPipeline(pipelines.back(), *pipelineLayout, *renderPasses[i], (i+1), writeEnables, true);
+	}
+
+	Move<VkCommandPool>						cmdPool			= makeCommandPool(m_vkd, m_device, queueIndex);
+	Move<VkCommandBuffer>					cmdBuff			= allocateCommandBuffer(m_vkd, m_device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+
+	beginCommandBuffer(m_vkd, *cmdBuff);
+		m_vkd.cmdBindVertexBuffers(*cmdBuff, 0u, 1u, &vertexBuffer->get(), &static_cast<const VkDeviceSize&>(0));
+
+		if (m_params.colorWriteEnables) // this condition always met
+		{
+			m_vkd.cmdSetColorWriteEnableEXT(*cmdBuff, static_cast<deUint32>(writeEnables.size()), writeEnables.data());
+		}
+
+		for (deUint32 a = 0; a < attachmentCount; ++a)
+		{
+			pushConstant.attachments = (a + 1);
+			m_vkd.cmdPushConstants(*cmdBuff, *pipelineLayout, pcRange.stageFlags, pcRange.offset, pcRange.size, &pushConstant);
+
+			m_vkd.cmdBindPipeline(*cmdBuff, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[a].getPipeline());
+			beginRenderPass(m_vkd, *cmdBuff, *renderPasses[a], *attachments[a].framebuffer, renderArea, attachmentCount, clearValues.data());
+				m_vkd.cmdDraw(*cmdBuff, 6u, 1u, 0u, 0u);
+			endRenderPass(m_vkd, *cmdBuff);
+		}
+
+	endCommandBuffer(m_vkd, *cmdBuff);
+
+	submitCommandsAndWait(m_vkd, m_device, queue, *cmdBuff);
+
+	deUint32 failureCount = 0;
+	for (deUint32 i = 0; i < attachmentCount; ++i)
+	for (deUint32 a = 0; a < (i + 1); ++a)
+	{
+		const auto	colorBuffer = readColorAttachment(m_vkd, m_device, queue, queueIndex, m_allocator,
+													  **attachments[i].attachments[a].image, m_params.format,
+													  UVec2(m_params.width, m_params.height));
+		failureCount += verifyAttachment(a, colorBuffer->getAccess(), writeEnables, background) ? 0u : 1u;
+	}
+
+	return (0u == failureCount) ? TestStatus::pass("") : TestStatus::fail("");
+}
+
+TestStatus ColorWriteEnable2Instance::testSetCWEafterPlBind ()
+{
+	const VkQueue							queue			= m_context.getUniversalQueue();
+	const deUint32							queueIndex		= m_context.getUniversalQueueFamilyIndex();
+	const VkRect2D							renderArea		= makeRect2D(m_params.width, m_params.height);
+	const deUint32							attachmentCount	= m_params.attachmentCount;
+
+	struct { deUint32 attachments; } const	pushConstant	{ attachmentCount };
+	const VkPushConstantRange				pcRange			= makePushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(pushConstant));
+
+	de::MovePtr<BufferWithMemory>			vertexBuffer	= createVerrtexBuffer();
+	Move<VkRenderPass>						renderPass		= createRenderPass(attachmentCount);
+	Attachments								attachments		= createAttachments(*renderPass, attachmentCount);
+	const Vec4								background		(0.75f, 0.75f, 0.75f, 0.75f);
+	std::vector<VkClearValue>				clearValues		(attachmentCount, makeClearValueColor(background));
+
+	ColorWriteEnables						writeEnables	(attachmentCount + m_params.attachmentMore, VK_TRUE);
+	for (deUint32 i = 0; i < attachmentCount; ++i)	writeEnables[i] = (i % 2) ? VK_TRUE : VK_FALSE;
+
+	Move<VkPipelineLayout>					pipelineLayout	= makePipelineLayout(m_vkd, m_device, 0u, nullptr, 1u, &pcRange);
+
+	std::vector<GraphicsPipelineWrapper>	pipelines;
+	for (deUint32 i = 0; i < attachmentCount; ++i)
+	{
+		pipelines.emplace_back(m_vkd, m_device, m_params.pct);
+		setupAndBuildPipeline(pipelines.back(), *pipelineLayout, *renderPass, (i+1), writeEnables, ((attachmentCount-i) % 2));
+	}
+
+	Move<VkCommandPool>						cmdPool			= makeCommandPool(m_vkd, m_device, queueIndex);
+	Move<VkCommandBuffer>					cmdBuff			= allocateCommandBuffer(m_vkd, m_device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+
+	beginCommandBuffer(m_vkd, *cmdBuff);
+		m_vkd.cmdBindVertexBuffers(*cmdBuff, 0u, 1u, &vertexBuffer->get(), &static_cast<const VkDeviceSize&>(0));
+		m_vkd.cmdPushConstants(*cmdBuff, *pipelineLayout, pcRange.stageFlags, pcRange.offset, pcRange.size, &pushConstant);
+
+		for (deUint32 i = 0; i < attachmentCount; ++i)
+		{
+			m_vkd.cmdBindPipeline(*cmdBuff, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[i].getPipeline());
+		}
+
+		if (m_params.colorWriteEnables) // this condition always met
+		{
+			m_vkd.cmdSetColorWriteEnableEXT(*cmdBuff, static_cast<deUint32>(writeEnables.size()), writeEnables.data());
+		}
+
+		beginRenderPass(m_vkd, *cmdBuff, *renderPass, *attachments.framebuffer, renderArea, attachmentCount, clearValues.data());
+			m_vkd.cmdDraw(*cmdBuff, 6u, 1u, 0u, 0u);
+		endRenderPass(m_vkd, *cmdBuff);
+	endCommandBuffer(m_vkd, *cmdBuff);
+
+	submitCommandsAndWait(m_vkd, m_device, queue, *cmdBuff);
+
+	deUint32 failureCount = 0;
+	for (deUint32 a = 0; a < attachmentCount; ++a)
+	{
+		const auto	colorBuffer = readColorAttachment(m_vkd, m_device, queue, queueIndex, m_allocator,
+													  **attachments.attachments[a].image, m_params.format,
+													  UVec2(m_params.width, m_params.height));
+		failureCount += verifyAttachment(a, colorBuffer->getAccess(), writeEnables, background) ? 0u : 1u;
+	}
+
+	return (0u == failureCount) ? TestStatus::pass("") : TestStatus::fail("");
+}
+
+} // unnamed namespace
+
 tcu::TestCaseGroup* createColorWriteEnableTests (tcu::TestContext& testCtx, vk::PipelineConstructionType pct)
 {
 	de::MovePtr<tcu::TestCaseGroup> colorWriteEnableGroup(new tcu::TestCaseGroup(testCtx, "color_write_enable", "Tests for VK_EXT_color_write_enable"));
@@ -1226,5 +1861,54 @@
 	return colorWriteEnableGroup.release();
 }
 
+tcu::TestCaseGroup* createColorWriteEnable2Tests (tcu::TestContext& testCtx, vk::PipelineConstructionType pct)
+{
+	const deUint32		attachmentCounts[]	{ 4,5,6 };
+	const deUint32		attachentMores[]	{ 0,1,3,5 };
+
+	//std::pair<bool, const char*>
+	//	static const	cweVariants[]
+	//{
+	//	{ true,		"cwe_enabled" },
+	//	{ false,	"cwe_disabled" }
+	//};
+
+	std::pair<bool, const char*>
+		static const	setCweMoments[]
+	{
+		{ true,		"cwe_before_bind" },
+		{ false,	"cwe_after_bind" }
+	};
+
+
+	tcu::TestCaseGroup* rootGroup = new tcu::TestCaseGroup(testCtx, "color_write_enable_maxa", "Tests for VK_EXT_color_write_enable");
+
+	for (const auto& setCweMoment : setCweMoments)
+	{
+		tcu::TestCaseGroup* setCweGroup = new tcu::TestCaseGroup(testCtx, setCweMoment.second, "A moment when cmdSetColorWriteEnableEXT() is called");
+
+		for (auto attachmentCount : attachmentCounts)
+		{
+			for (auto attachentMore : attachentMores)
+			{
+				const std::string title = "attachments" + std::to_string(attachmentCount) + "_more" + std::to_string(attachentMore);
+
+				TestParams p;
+				p.format				= VK_FORMAT_UNDEFINED;
+				p.width					= 32;
+				p.height				= 32;
+				p.setCweBeforePlBind	= setCweMoment.first;
+				p.colorWriteEnables		= true;
+				p.attachmentCount		= attachmentCount;
+				p.attachmentMore		= attachentMore;
+				p.pct					= pct;
+				setCweGroup->addChild(new ColorWriteEnable2Test(testCtx, title, "", p));
+			}
+		}
+		rootGroup->addChild(setCweGroup);
+	}
+	return rootGroup;
+}
+
 } // pipeline
 } // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineColorWriteEnableTests.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineColorWriteEnableTests.hpp
index 9719fbb..6e90e45 100644
--- a/external/vulkancts/modules/vulkan/pipeline/vktPipelineColorWriteEnableTests.hpp
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineColorWriteEnableTests.hpp
@@ -32,6 +32,7 @@
 {
 
 tcu::TestCaseGroup* createColorWriteEnableTests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType);
+tcu::TestCaseGroup* createColorWriteEnable2Tests (tcu::TestContext& testCtx, vk::PipelineConstructionType pct);
 
 } // pipeline
 } // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp
index c058f0c..6dea2c2 100644
--- a/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp
@@ -129,6 +129,7 @@
 	group->addChild(createBindPointTests				(testCtx, pipelineConstructionType));
 #endif // CTS_USES_VULKANSC
 	group->addChild(createColorWriteEnableTests			(testCtx, pipelineConstructionType));
+	group->addChild(createColorWriteEnable2Tests		(testCtx, pipelineConstructionType));
 
 	// NOTE: all new pipeline tests should use GraphicsPipelineWrapper for pipeline creation
 
diff --git a/external/vulkancts/mustpass/main/vk-default/pipeline.txt b/external/vulkancts/mustpass/main/vk-default/pipeline.txt
index 2145a04..e49cb9a 100644
--- a/external/vulkancts/mustpass/main/vk-default/pipeline.txt
+++ b/external/vulkancts/mustpass/main/vk-default/pipeline.txt
Binary files differ
diff --git a/external/vulkancts/mustpass/main/vksc-default/pipeline.txt b/external/vulkancts/mustpass/main/vksc-default/pipeline.txt
index 56e2c41..01b1001 100644
--- a/external/vulkancts/mustpass/main/vksc-default/pipeline.txt
+++ b/external/vulkancts/mustpass/main/vksc-default/pipeline.txt
Binary files differ