• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2021 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*
20  * \file
21  * \brief Tests for Color Write Enable
22 *//*--------------------------------------------------------------------*/
23 
24 #include "vktPipelineColorWriteEnableTests.hpp"
25 #include "vktPipelineImageUtil.hpp"
26 #include "vktTestCase.hpp"
27 
28 #include "vkDefs.hpp"
29 #include "vkTypeUtil.hpp"
30 #include "vkQueryUtil.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkBufferWithMemory.hpp"
33 #include "vkImageWithMemory.hpp"
34 #include "vkBarrierUtil.hpp"
35 #include "vkBuilderUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkImageUtil.hpp"
38 
39 #include "tcuVector.hpp"
40 #include "tcuMaybe.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuVectorUtil.hpp"
43 
44 #include "deUniquePtr.hpp"
45 #include "deStringUtil.hpp"
46 
47 #include <vector>
48 #include <sstream>
49 #include <algorithm>
50 #include <utility>
51 #include <iterator>
52 #include <string>
53 #include <limits>
54 #include <memory>
55 #include <functional>
56 
57 namespace vkt
58 {
59 namespace pipeline
60 {
61 
62 namespace
63 {
64 
65 // Framebuffer size.
66 constexpr deUint32 kFramebufferWidth  = 64u;
67 constexpr deUint32 kFramebufferHeight = 64u;
68 
69 // Image formats.
70 constexpr	vk::VkFormat	kColorFormat	= vk::VK_FORMAT_R8G8B8A8_UNORM;
71 const		tcu::Vec4		kColorThreshold	(0.005f); // 1/255 < 0.005 < 2/255.
72 
73 constexpr	deUint32		kNumColorAttachments = 3u;
74 
75 const vk::VkFormat kDepthStencilFormats[] =
76 {
77 	vk::VK_FORMAT_D32_SFLOAT_S8_UINT,
78 	vk::VK_FORMAT_D24_UNORM_S8_UINT
79 };
80 
81 constexpr auto kCoordsSize = static_cast<deUint32>(2 * sizeof(float));
82 
83 using Bool32Vec = std::vector<vk::VkBool32>;
84 
85 // Generic, to be used with any state than can be set statically and, as an option, dynamically.
86 template<typename T>
87 struct StaticAndDynamicPair
88 {
89 	T				staticValue;
90 	tcu::Maybe<T>	dynamicValue;
91 
92 	// Helper constructor to set a static value and no dynamic value.
StaticAndDynamicPairvkt::pipeline::__anon117cea180111::StaticAndDynamicPair93 	StaticAndDynamicPair (const T& value)
94 		: staticValue	(value)
95 		, dynamicValue	(tcu::Nothing)
96 	{
97 	}
98 
99 	// Helper constructor to set both.
StaticAndDynamicPairvkt::pipeline::__anon117cea180111::StaticAndDynamicPair100 	StaticAndDynamicPair (const T& sVal, const T& dVal)
101 		: staticValue	(sVal)
102 		, dynamicValue	(tcu::just<T>(dVal))
103 	{
104 	}
105 
106 	// If the dynamic value is present, swap static and dynamic values.
swapValuesvkt::pipeline::__anon117cea180111::StaticAndDynamicPair107 	void swapValues (void)
108 	{
109 		if (!dynamicValue)
110 			return;
111 		std::swap(staticValue, dynamicValue.get());
112 	}
113 };
114 
115 const tcu::Vec4	kDefaultTriangleColor (0.0f, 0.0f, 1.0f, 1.0f);	// Opaque blue.
116 const tcu::Vec4	kDefaultClearColor    (0.0f, 0.0f, 0.0f, 1.0f);	// Opaque black.
117 
118 struct MeshParams
119 {
120 	tcu::Vec4	color;
121 	float		depth;
122 	float		scaleX;
123 	float		scaleY;
124 	float		offsetX;
125 	float		offsetY;
126 
MeshParamsvkt::pipeline::__anon117cea180111::MeshParams127 	MeshParams (const tcu::Vec4&	color_		= kDefaultTriangleColor,
128 				float				depth_		= 0.0f,
129 				float				scaleX_		= 1.0f,
130 				float				scaleY_		= 1.0f,
131 				float				offsetX_	= 0.0f,
132 				float				offsetY_	= 0.0f)
133 		: color		(color_)
134 		, depth		(depth_)
135 		, scaleX	(scaleX_)
136 		, scaleY	(scaleY_)
137 		, offsetX	(offsetX_)
138 		, offsetY	(offsetY_)
139 	{}
140 };
141 
142 enum class SequenceOrdering
143 {
144 	CMD_BUFFER_START	= 0,	// Set state at the start of the command buffer.
145 	BEFORE_DRAW			= 1,	// After binding dynamic pipeline and just before drawing.
146 	BETWEEN_PIPELINES	= 2,	// After a static state pipeline has been bound but before the dynamic state pipeline has been bound.
147 	AFTER_PIPELINES		= 3,	// After a static state pipeline and a second dynamic state pipeline have been bound.
148 	BEFORE_GOOD_STATIC	= 4,	// Before a static state pipeline with the correct values has been bound.
149 	TWO_DRAWS_DYNAMIC	= 5,	// Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again.
150 	TWO_DRAWS_STATIC	= 6,	// Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again.
151 };
152 
153 struct TestConfig
154 {
155 	vk::PipelineConstructionType	pipelineConstructionType;
156 
157 	// Main sequence ordering.
158 	SequenceOrdering				sequenceOrdering;
159 
160 	// Drawing parameters.
161 	MeshParams						meshParams;
162 
163 	// Clearing parameters for the framebuffer.
164 	tcu::Vec4						clearColorValue;
165 	float							clearDepthValue;
166 
167 	// Channels to enable
168 	tcu::BVec4						channelMask;
169 
170 	// Expected output in the attachments.
171 	std::vector<tcu::Vec4>			expectedColor;
172 	float							expectedDepth;
173 
174 	// Static and dynamic pipeline configuration.
175 	StaticAndDynamicPair<Bool32Vec>	colorWriteEnableConfig;
176 
177 	// Sane defaults.
TestConfigvkt::pipeline::__anon117cea180111::TestConfig178 	TestConfig (vk::PipelineConstructionType constructionType, SequenceOrdering ordering)
179 		: pipelineConstructionType		(constructionType)
180 		, sequenceOrdering				(ordering)
181 		, clearColorValue				(kDefaultClearColor)
182 		, clearDepthValue				(1.0f)
183 		, expectedColor					(kNumColorAttachments, kDefaultTriangleColor)
184 		, expectedDepth					(1.0f)
185 		, colorWriteEnableConfig		(Bool32Vec(1u, VK_TRUE))
186 		, m_swappedValues				(false)
187 	{
188 	}
189 
190 	// Returns true if we should use the static and dynamic values exchanged.
191 	// This makes the static part of the pipeline have the actual expected values.
isReversedvkt::pipeline::__anon117cea180111::TestConfig192 	bool isReversed () const
193 	{
194 		return (sequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
195 				sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC);
196 	}
197 
198 	// Swaps static and dynamic configuration values.
swapValuesvkt::pipeline::__anon117cea180111::TestConfig199 	void swapValues ()
200 	{
201 		colorWriteEnableConfig.swapValues();
202 		m_swappedValues = !m_swappedValues;
203 	}
204 
205 	// Returns the number of iterations when recording commands.
numIterationsvkt::pipeline::__anon117cea180111::TestConfig206 	deUint32 numIterations () const
207 	{
208 		deUint32 iterations = 0u;
209 
210 		switch (sequenceOrdering)
211 		{
212 		case SequenceOrdering::TWO_DRAWS_DYNAMIC:
213 		case SequenceOrdering::TWO_DRAWS_STATIC:
214 			iterations = 2u;
215 			break;
216 		default:
217 			iterations = 1u;
218 			break;
219 		}
220 
221 		return iterations;
222 	}
223 
224 private:
225 	// Color Write Enable cases as created by createColorWriteEnableTests() are based on the assumption that, when a state
226 	// has a static and a dynamic value configured at the same time, the static value is wrong and the dynamic value will give
227 	// expected results. That's appropriate for most test variants, but in some others we want to reverse the situation: a dynamic
228 	// pipeline with wrong values and a static one with good values.
229 	//
230 	// Instead of modifying how tests are created, we use isReversed() and swapValues() above, allowing us to swap static and
231 	// dynamic values and to know if we should do it for a given test case. However, we need to know were the good value is at any
232 	// given point in time in order to correctly answer some questions while running the test. m_swappedValues tracks that state.
233 	bool m_swappedValues;
234 };
235 
236 struct PushConstants
237 {
238 	tcu::Vec4	triangleColor;
239 	float		meshDepth;
240 	float		scaleX;
241 	float		scaleY;
242 	float		offsetX;
243 	float		offsetY;
244 };
245 
246 class ColorWriteEnableTest : public vkt::TestCase
247 {
248 public:
249 							ColorWriteEnableTest		(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig);
~ColorWriteEnableTest(void)250 	virtual					~ColorWriteEnableTest		(void) {}
251 
252 	virtual void			checkSupport					(Context& context) const;
253 	virtual void			initPrograms					(vk::SourceCollections& programCollection) const;
254 	virtual TestInstance*	createInstance					(Context& context) const;
255 
256 private:
257 	TestConfig				m_testConfig;
258 };
259 
260 class ColorWriteEnableInstance : public vkt::TestInstance
261 {
262 public:
263 								ColorWriteEnableInstance	(Context& context, const TestConfig& testConfig);
~ColorWriteEnableInstance(void)264 	virtual						~ColorWriteEnableInstance	(void) {}
265 
266 	virtual tcu::TestStatus		iterate							(void);
267 
268 private:
269 	TestConfig					m_testConfig;
270 };
271 
ColorWriteEnableTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestConfig & testConfig)272 ColorWriteEnableTest::ColorWriteEnableTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig)
273 	: vkt::TestCase	(testCtx, name, description)
274 	, m_testConfig	(testConfig)
275 {
276 }
277 
checkSupport(Context & context) const278 void ColorWriteEnableTest::checkSupport (Context& context) const
279 {
280 	const auto&	vki				= context.getInstanceInterface();
281 	const auto	physicalDevice	= context.getPhysicalDevice();
282 
283 	// This is always required.
284 	context.requireDeviceFunctionality("VK_EXT_color_write_enable");
285 
286 	// Check color image format support (depth/stencil will be chosen at runtime).
287 	const vk::VkFormatFeatureFlags	kColorFeatures	= (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
288 	const auto						colorProperties	= vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kColorFormat);
289 
290 	if ((colorProperties.optimalTilingFeatures & kColorFeatures) != kColorFeatures)
291 		TCU_THROW(NotSupportedError, "Required color image features not supported");
292 
293 	checkPipelineLibraryRequirements(vki, physicalDevice, m_testConfig.pipelineConstructionType);
294 }
295 
initPrograms(vk::SourceCollections & programCollection) const296 void ColorWriteEnableTest::initPrograms (vk::SourceCollections& programCollection) const
297 {
298 	std::ostringstream pushSource;
299 	pushSource
300 		<< "layout(push_constant, std430) uniform PushConstantsBlock {\n"
301 		<< "    vec4  triangleColor;\n"
302 		<< "    float depthValue;\n"
303 		<< "    float scaleX;\n"
304 		<< "    float scaleY;\n"
305 		<< "    float offsetX;\n"
306 		<< "    float offsetY;\n"
307 		<< "} pushConstants;\n"
308 		;
309 
310 	std::ostringstream vertSource;
311 	vertSource
312 		<< "#version 450\n"
313 		<< pushSource.str()
314 		<< "layout(location=0) in vec2 position;\n"
315 		<< "out gl_PerVertex\n"
316 		<< "{\n"
317 		<< "    vec4 gl_Position;\n"
318 		<< "};\n"
319 		<< "void main() {\n"
320 		<< "    vec2 vertexCoords = position;\n"
321 		<< "    gl_Position = vec4(vertexCoords.x * pushConstants.scaleX + pushConstants.offsetX, vertexCoords.y * pushConstants.scaleY + pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
322 		<< "}\n"
323 		;
324 
325 	std::ostringstream fragOutputs;
326 	std::ostringstream colorWrite;
327 	for (deUint32 i = 0u; i < kNumColorAttachments; ++i)
328 	{
329 		fragOutputs << "layout(location=" << i << ") out vec4 color" << i << ";\n";
330 		colorWrite << "    color" << i << " = pushConstants.triangleColor * " << powf(0.5f, static_cast<float>(i)) << ";\n";
331 	}
332 
333 	std::ostringstream fragSource;
334 	fragSource
335 		<< "#version 450\n"
336 		<< pushSource.str()
337 		<< fragOutputs.str()
338 		<< "void main() {\n"
339 		<< colorWrite.str()
340 		<< "}\n"
341 		;
342 
343 	programCollection.glslSources.add("vert") << glu::VertexSource(vertSource.str());
344 	programCollection.glslSources.add("frag") << glu::FragmentSource(fragSource.str());
345 }
346 
createInstance(Context & context) const347 TestInstance* ColorWriteEnableTest::createInstance (Context& context) const
348 {
349 	return new ColorWriteEnableInstance(context, m_testConfig);
350 }
351 
ColorWriteEnableInstance(Context & context,const TestConfig & testConfig)352 ColorWriteEnableInstance::ColorWriteEnableInstance(Context& context, const TestConfig& testConfig)
353 	: vkt::TestInstance	(context)
354 	, m_testConfig		(testConfig)
355 {
356 }
357 
logErrors(tcu::TestLog & log,const std::string & setName,const std::string & setDesc,const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & errorMask)358 void logErrors(tcu::TestLog& log, const std::string& setName, const std::string& setDesc, const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& errorMask)
359 {
360 	log << tcu::TestLog::ImageSet(setName, setDesc)
361 		<< tcu::TestLog::Image(setName + "Result", "Result image", result)
362 		<< tcu::TestLog::Image(setName + "ErrorMask", "Error mask with errors marked in red", errorMask)
363 		<< tcu::TestLog::EndImageSet;
364 }
365 
366 // Sets values for dynamic states if needed according to the test configuration.
setDynamicStates(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer)367 void setDynamicStates(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer)
368 {
369 	if (testConfig.colorWriteEnableConfig.dynamicValue)
370 	{
371 		const auto& colorWriteEnables = testConfig.colorWriteEnableConfig.dynamicValue.get();
372 		vkd.cmdSetColorWriteEnableEXT(cmdBuffer, static_cast<deUint32>(colorWriteEnables.size()), colorWriteEnables.data());
373 	}
374 }
375 
iterate(void)376 tcu::TestStatus ColorWriteEnableInstance::iterate (void)
377 {
378 	using ImageWithMemoryVec	= std::vector<std::unique_ptr<vk::ImageWithMemory>>;
379 	using ImageViewVec			= std::vector<vk::Move<vk::VkImageView>>;
380 	using FramebufferVec		= std::vector<vk::Move<vk::VkFramebuffer>>;
381 
382 	const auto&	vki					= m_context.getInstanceInterface();
383 	const auto&	vkd					= m_context.getDeviceInterface();
384 	const auto	physicalDevice		= m_context.getPhysicalDevice();
385 	const auto	device				= m_context.getDevice();
386 	auto&		allocator			= m_context.getDefaultAllocator();
387 	const auto	queue				= m_context.getUniversalQueue();
388 	const auto	queueIndex			= m_context.getUniversalQueueFamilyIndex();
389 	auto&		log					= m_context.getTestContext().getLog();
390 
391 	const auto	kReversed			= m_testConfig.isReversed();
392 	const auto	kNumIterations		= m_testConfig.numIterations();
393 	const auto	kSequenceOrdering	= m_testConfig.sequenceOrdering;
394 
395 	const auto						kFramebufferExtent	= vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u);
396 	const vk::VkImageUsageFlags		kColorUsage			= (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
397 	const vk::VkImageUsageFlags		kDSUsage			= (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
398 	const vk::VkFormatFeatureFlags	kDSFeatures			= (vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
399 
400 	// Choose depth/stencil format.
401 	vk::VkFormat dsFormat = vk::VK_FORMAT_UNDEFINED;
402 
403 	for (int formatIdx = 0; formatIdx < DE_LENGTH_OF_ARRAY(kDepthStencilFormats); ++formatIdx)
404 	{
405 		const auto dsProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kDepthStencilFormats[formatIdx]);
406 		if ((dsProperties.optimalTilingFeatures & kDSFeatures) == kDSFeatures)
407 		{
408 			dsFormat = kDepthStencilFormats[formatIdx];
409 			break;
410 		}
411 	}
412 
413 	// Note: Not Supported insted of Fail because the transfer feature is not mandatory.
414 	if (dsFormat == vk::VK_FORMAT_UNDEFINED)
415 		TCU_THROW(NotSupportedError, "Required depth/stencil image features not supported");
416 	log << tcu::TestLog::Message << "Chosen depth/stencil format: " << dsFormat << tcu::TestLog::EndMessage;
417 
418 	// Swap static and dynamic values in the test configuration so the static pipeline ends up with the expected values for cases
419 	// where we will bind the static pipeline last before drawing.
420 	if (kReversed)
421 		m_testConfig.swapValues();
422 
423 	// Create color and depth/stencil images.
424 	ImageWithMemoryVec colorImages;
425 	ImageWithMemoryVec dsImages;
426 
427 	const vk::VkImageCreateInfo colorImageInfo =
428 	{
429 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
430 		nullptr,									//	const void*				pNext;
431 		0u,											//	VkImageCreateFlags		flags;
432 		vk::VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
433 		kColorFormat,								//	VkFormat				format;
434 		kFramebufferExtent,							//	VkExtent3D				extent;
435 		1u,											//	deUint32				mipLevels;
436 		1u,											//	deUint32				arrayLayers;
437 		vk::VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
438 		vk::VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
439 		kColorUsage,								//	VkImageUsageFlags		usage;
440 		vk::VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
441 		1u,											//	deUint32				queueFamilyIndexCount;
442 		&queueIndex,								//	const deUint32*			pQueueFamilyIndices;
443 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
444 	};
445 	for (deUint32 i = 0u; i < kNumIterations * kNumColorAttachments; ++i)
446 		colorImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, colorImageInfo, vk::MemoryRequirement::Any));
447 
448 	const vk::VkImageCreateInfo dsImageInfo =
449 	{
450 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
451 		nullptr,									//	const void*				pNext;
452 		0u,											//	VkImageCreateFlags		flags;
453 		vk::VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
454 		dsFormat,									//	VkFormat				format;
455 		kFramebufferExtent,							//	VkExtent3D				extent;
456 		1u,											//	deUint32				mipLevels;
457 		1u,											//	deUint32				arrayLayers;
458 		vk::VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
459 		vk::VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
460 		kDSUsage,									//	VkImageUsageFlags		usage;
461 		vk::VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
462 		1u,											//	deUint32				queueFamilyIndexCount;
463 		&queueIndex,								//	const deUint32*			pQueueFamilyIndices;
464 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
465 	};
466 	for (deUint32 i = 0u; i < kNumIterations; ++i)
467 		dsImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, dsImageInfo, vk::MemoryRequirement::Any));
468 
469 	const auto colorSubresourceRange	= vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
470 	const auto dsSubresourceRange		= vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
471 
472 	ImageViewVec colorImageViews;
473 	ImageViewVec dsImageViews;
474 
475 	for (const auto& img : colorImages)
476 		colorImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, kColorFormat, colorSubresourceRange));
477 
478 	for (const auto& img : dsImages)
479 		dsImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, dsFormat, dsSubresourceRange));
480 
481 	// Vertex buffer.
482 	// Full-screen triangle fan with 6 vertices.
483 	//
484 	// 4        3        2
485 	//  +-------+-------+
486 	//  |X      X      X|
487 	//  | X     X     X |
488 	//  |  X    X    X  |
489 	//  |   X   X   X   |
490 	//  |    X  X  X    |
491 	//  |     X X X     |
492 	//  |      XXX      |
493 	//  +-------+-------+
494 	// 5        0        1
495 	std::vector<float> vertices = {
496 		 0.0f,  1.0f,
497 		 1.0f,  1.0f,
498 		 1.0f, -1.0f,
499 		 0.0f, -1.0f,
500 		-1.0f, -1.0f,
501 		-1.0f,  1.0f,
502 	};
503 
504 	const auto vertDataSize				= vertices.size() * sizeof(float);
505 	const auto vertBufferInfo			= vk::makeBufferCreateInfo(static_cast<vk::VkDeviceSize>(vertDataSize), vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
506 	vk::BufferWithMemory vertBuffer		(vkd, device, allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible);
507 	auto& alloc							= vertBuffer.getAllocation();
508 
509 	deMemcpy(reinterpret_cast<char*>(alloc.getHostPtr()), vertices.data(), vertDataSize);
510 	vk::flushAlloc(vkd, device, alloc);
511 
512 	// Descriptor set layout.
513 	vk::DescriptorSetLayoutBuilder layoutBuilder;
514 	const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
515 
516 	// Pipeline layout.
517 	vk::VkShaderStageFlags pushConstantStageFlags = (vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT);
518 
519 	const vk::VkPushConstantRange pushConstantRange =
520 	{
521 		pushConstantStageFlags,							//	VkShaderStageFlags	stageFlags;
522 		0u,												//	deUint32			offset;
523 		static_cast<deUint32>(sizeof(PushConstants)),	//	deUint32			size;
524 	};
525 
526 	const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
527 	{
528 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	//	VkStructureType					sType;
529 		nullptr,											//	const void*						pNext;
530 		0u,													//	VkPipelineLayoutCreateFlags		flags;
531 		1u,													//	deUint32						setLayoutCount;
532 		&descriptorSetLayout.get(),							//	const VkDescriptorSetLayout*	pSetLayouts;
533 		1u,													//	deUint32						pushConstantRangeCount;
534 		&pushConstantRange,									//	const VkPushConstantRange*		pPushConstantRanges;
535 	};
536 	const auto pipelineLayout = vk::createPipelineLayout(vkd, device, &pipelineLayoutCreateInfo);
537 
538 	// Render pass with single subpass.
539 	std::vector<vk::VkAttachmentReference> colorAttachmentReference;
540 	for (deUint32 i = 0u; i < kNumColorAttachments; ++i)
541 	{
542 		colorAttachmentReference.push_back(vk::VkAttachmentReference
543 			{
544 				i,												//	deUint32		attachment;
545 				vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	//	VkImageLayout	layout;
546 			}
547 		);
548 	}
549 
550 	const vk::VkAttachmentReference dsAttachmentReference =
551 	{
552 		kNumColorAttachments,									//	deUint32		attachment;
553 		vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	//	VkImageLayout	layout;
554 	};
555 
556 	const vk::VkSubpassDescription subpassDescription =
557 	{
558 		0u,										//	VkSubpassDescriptionFlags		flags;
559 		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,	//	VkPipelineBindPoint				pipelineBindPoint;
560 		0u,										//	deUint32						inputAttachmentCount;
561 		nullptr,								//	const VkAttachmentReference*	pInputAttachments;
562 		kNumColorAttachments,					//	deUint32						colorAttachmentCount;
563 		colorAttachmentReference.data(),		//	const VkAttachmentReference*	pColorAttachments;
564 		nullptr,								//	const VkAttachmentReference*	pResolveAttachments;
565 		&dsAttachmentReference,					//	const VkAttachmentReference*	pDepthStencilAttachment;
566 		0u,										//	deUint32						preserveAttachmentCount;
567 		nullptr,								//	const deUint32*					pPreserveAttachments;
568 	};
569 
570 	std::vector<vk::VkAttachmentDescription> attachmentDescriptions(
571 		kNumColorAttachments,
572 		vk::VkAttachmentDescription
573 		{
574 			0u,												//	VkAttachmentDescriptionFlags	flags;
575 			kColorFormat,									//	VkFormat						format;
576 			vk::VK_SAMPLE_COUNT_1_BIT,						//	VkSampleCountFlagBits			samples;
577 			vk::VK_ATTACHMENT_LOAD_OP_CLEAR,				//	VkAttachmentLoadOp				loadOp;
578 			vk::VK_ATTACHMENT_STORE_OP_STORE,				//	VkAttachmentStoreOp				storeOp;
579 			vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				stencilLoadOp;
580 			vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,			//	VkAttachmentStoreOp				stencilStoreOp;
581 			vk::VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout					initialLayout;
582 			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
583 		}
584 	);
585 
586 	attachmentDescriptions.push_back(vk::VkAttachmentDescription
587 	{
588 		0u,														//	VkAttachmentDescriptionFlags	flags;
589 		dsFormat,												//	VkFormat						format;
590 		vk::VK_SAMPLE_COUNT_1_BIT,								//	VkSampleCountFlagBits			samples;
591 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						//	VkAttachmentLoadOp				loadOp;
592 		vk::VK_ATTACHMENT_STORE_OP_STORE,						//	VkAttachmentStoreOp				storeOp;
593 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						//	VkAttachmentLoadOp				stencilLoadOp;
594 		vk::VK_ATTACHMENT_STORE_OP_STORE,						//	VkAttachmentStoreOp				stencilStoreOp;
595 		vk::VK_IMAGE_LAYOUT_UNDEFINED,							//	VkImageLayout					initialLayout;
596 		vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
597 	});
598 
599 	const vk::VkRenderPassCreateInfo renderPassCreateInfo =
600 	{
601 		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			//	VkStructureType					sType;
602 		nullptr,												//	const void*						pNext;
603 		0u,														//	VkRenderPassCreateFlags			flags;
604 		static_cast<deUint32>(attachmentDescriptions.size()),	//	deUint32						attachmentCount;
605 		attachmentDescriptions.data(),							//	const VkAttachmentDescription*	pAttachments;
606 		1u,														//	deUint32						subpassCount;
607 		&subpassDescription,									//	const VkSubpassDescription*		pSubpasses;
608 		0u,														//	deUint32						dependencyCount;
609 		nullptr,												//	const VkSubpassDependency*		pDependencies;
610 	};
611 	const auto renderPass = vk::createRenderPass(vkd, device, &renderPassCreateInfo);
612 
613 	// Framebuffers.
614 	FramebufferVec framebuffers;
615 
616 	DE_ASSERT(colorImageViews.size() == dsImageViews.size() * kNumColorAttachments);
617 	for (size_t imgIdx = 0; imgIdx < dsImageViews.size(); ++imgIdx)
618 	{
619 		std::vector<vk::VkImageView> attachments;
620 		for (deUint32 i = 0u; i < kNumColorAttachments; ++i)
621 			attachments.push_back(colorImageViews[imgIdx * kNumColorAttachments + i].get());
622 
623 		attachments.push_back(dsImageViews[imgIdx].get());
624 
625 		const vk::VkFramebufferCreateInfo framebufferCreateInfo =
626 		{
627 			vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,	//	VkStructureType				sType;
628 			nullptr,										//	const void*					pNext;
629 			0u,												//	VkFramebufferCreateFlags	flags;
630 			renderPass.get(),								//	VkRenderPass				renderPass;
631 			static_cast<deUint32>(attachments.size()),		//	deUint32					attachmentCount;
632 			attachments.data(),								//	const VkImageView*			pAttachments;
633 			kFramebufferWidth,								//	deUint32					width;
634 			kFramebufferHeight,								//	deUint32					height;
635 			1u,												//	deUint32					layers;
636 		};
637 
638 		framebuffers.emplace_back(vk::createFramebuffer(vkd, device, &framebufferCreateInfo));
639 	}
640 
641 	// Shader modules.
642 	const auto	vertModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
643 	const auto	fragModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
644 
645 	// Input state.
646 	const auto vertexBinding = vk::makeVertexInputBindingDescription(0u, kCoordsSize, vk::VK_VERTEX_INPUT_RATE_VERTEX);
647 	const std::vector<vk::VkVertexInputAttributeDescription> vertexAttributes = {
648 		vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u)
649 	};
650 
651 	const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
652 	{
653 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
654 		nullptr,														//	const void*									pNext;
655 		0u,																//	VkPipelineVertexInputStateCreateFlags		flags;
656 		1u,																//	deUint32									vertexBindingDescriptionCount;
657 		&vertexBinding,													//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
658 		static_cast<deUint32>(vertexAttributes.size()),					//	deUint32									vertexAttributeDescriptionCount;
659 		vertexAttributes.data(),										//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
660 	};
661 
662 	// Input assembly.
663 	const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
664 	{
665 		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType							sType;
666 		nullptr,															//	const void*								pNext;
667 		0u,																	//	VkPipelineInputAssemblyStateCreateFlags	flags;
668 		vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,								//	VkPrimitiveTopology						topology;
669 		VK_FALSE,															//	VkBool32								primitiveRestartEnable;
670 	};
671 
672 	// Viewport state.
673 	const std::vector<vk::VkViewport>	viewport	{ vk::makeViewport(kFramebufferWidth, kFramebufferHeight) };
674 	const std::vector<vk::VkRect2D>		scissor		{ vk::makeRect2D(kFramebufferWidth, kFramebufferHeight) };
675 
676 	// Rasterization state.
677 	const vk::VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
678 	{
679 		vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	//	VkStructureType							sType;
680 		nullptr,														//	const void*								pNext;
681 		0u,																//	VkPipelineRasterizationStateCreateFlags	flags;
682 		VK_FALSE,														//	VkBool32								depthClampEnable;
683 		VK_FALSE,														//	VkBool32								rasterizerDiscardEnable;
684 		vk::VK_POLYGON_MODE_FILL,										//	VkPolygonMode							polygonMode;
685 		vk::VK_CULL_MODE_NONE,											//	VkCullModeFlags							cullMode;
686 		vk::VK_FRONT_FACE_COUNTER_CLOCKWISE,							//	VkFrontFace								frontFace;
687 		VK_FALSE,														//	VkBool32								depthBiasEnable;
688 		0.0f,															//	float									depthBiasConstantFactor;
689 		0.0f,															//	float									depthBiasClamp;
690 		0.0f,															//	float									depthBiasSlopeFactor;
691 		1.0f,															//	float									lineWidth;
692 	};
693 
694 	// Multisample state.
695 	const vk::VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo =
696 	{
697 		vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	//	VkStructureType							sType;
698 		nullptr,														//	const void*								pNext;
699 		0u,																//	VkPipelineMultisampleStateCreateFlags	flags;
700 		vk::VK_SAMPLE_COUNT_1_BIT,										//	VkSampleCountFlagBits					rasterizationSamples;
701 		VK_FALSE,														//	VkBool32								sampleShadingEnable;
702 		0.0f,															//	float									minSampleShading;
703 		nullptr,														//	const VkSampleMask*						pSampleMask;
704 		VK_FALSE,														//	VkBool32								alphaToCoverageEnable;
705 		VK_FALSE,														//	VkBool32								alphaToOneEnable;
706 	};
707 
708 	// Depth/stencil state.
709 	const vk::VkStencilOpState stencil =
710 	{
711 		vk::VK_STENCIL_OP_KEEP,		// VkStencilOp	failOp;
712 		vk::VK_STENCIL_OP_KEEP,		// VkStencilOp	passOp;
713 		vk::VK_STENCIL_OP_KEEP,		// VkStencilOp	depthFailOp;
714 		vk::VK_COMPARE_OP_ALWAYS,	// VkCompareOp	compareOp;
715 		0xFFu,						// deUint32		compareMask;
716 		0xFFu,						// deUint32		writeMask;
717 		0u,							// deUint32		reference;
718 	};
719 
720 	const vk::VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
721 	{
722 		vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		//	VkStructureType							sType;
723 		nullptr,															//	const void*								pNext;
724 		0u,																	//	VkPipelineDepthStencilStateCreateFlags	flags;
725 		VK_TRUE,															//	VkBool32								depthTestEnable;
726 		VK_TRUE,															//	VkBool32								depthWriteEnable;
727 		vk::VK_COMPARE_OP_LESS,												//	VkCompareOp								depthCompareOp;
728 		VK_FALSE,															//	VkBool32								depthBoundsTestEnable;
729 		VK_FALSE,															//	VkBool32								stencilTestEnable;
730 		stencil,															//	VkStencilOpState						front;
731 		stencil,															//	VkStencilOpState						back;
732 		0.0f,																//	float									minDepthBounds;
733 		1.0f,																//	float									maxDepthBounds;
734 	};
735 
736 	// Dynamic state. Here we will set all states which have a dynamic value.
737 	std::vector<vk::VkDynamicState> dynamicStates;
738 
739 	if (m_testConfig.colorWriteEnableConfig.dynamicValue)
740 		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT);
741 
742 	const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
743 	{
744 		vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
745 		nullptr,													//	const void*							pNext;
746 		0u,															//	VkPipelineDynamicStateCreateFlags	flags;
747 		static_cast<deUint32>(dynamicStates.size()),				//	deUint32							dynamicStateCount;
748 		dynamicStates.data(),										//	const VkDynamicState*				pDynamicStates;
749 	};
750 
751 	std::vector<vk::VkPipelineColorBlendAttachmentState> colorBlendAttachmentState(
752 		kNumColorAttachments,
753 		vk::VkPipelineColorBlendAttachmentState
754 		{
755 			VK_FALSE,								// VkBool32                 blendEnable
756 			vk::VK_BLEND_FACTOR_ZERO,				// VkBlendFactor            srcColorBlendFactor
757 			vk::VK_BLEND_FACTOR_ZERO,				// VkBlendFactor            dstColorBlendFactor
758 			vk::VK_BLEND_OP_ADD,					// VkBlendOp                colorBlendOp
759 			vk::VK_BLEND_FACTOR_ZERO,				// VkBlendFactor            srcAlphaBlendFactor
760 			vk::VK_BLEND_FACTOR_ZERO,				// VkBlendFactor            dstAlphaBlendFactor
761 			vk::VK_BLEND_OP_ADD,					// VkBlendOp                alphaBlendOp
762 			static_cast<vk::VkColorComponentFlags>(	// VkColorComponentFlags    colorWriteMask
763 				(m_testConfig.channelMask.x() ? vk::VK_COLOR_COMPONENT_R_BIT : 0)
764 				| (m_testConfig.channelMask.y() ? vk::VK_COLOR_COMPONENT_G_BIT : 0)
765 				| (m_testConfig.channelMask.z() ? vk::VK_COLOR_COMPONENT_B_BIT : 0)
766 				| (m_testConfig.channelMask.w() ? vk::VK_COLOR_COMPONENT_A_BIT : 0)
767 			)
768 		}
769 	);
770 
771 	const vk::VkPipelineColorWriteCreateInfoEXT colorWriteCreateInfo =
772 	{
773 		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT,		// VkStructureType	sType;
774 		nullptr,														// const void*		pNext;
775 		kNumColorAttachments,											// deUint32			attachmentCount;
776 		m_testConfig.colorWriteEnableConfig.staticValue.data()			// const VkBool32*	pColorWriteEnables;
777 	};
778 
779 	const vk::VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo =
780 	{
781 		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType                               sType
782 		&colorWriteCreateInfo,											// const void*                                   pNext
783 		0u,																// VkPipelineColorBlendStateCreateFlags          flags
784 		VK_FALSE,														// VkBool32                                      logicOpEnable
785 		vk::VK_LOGIC_OP_CLEAR,											// VkLogicOp                                     logicOp
786 		kNumColorAttachments,											// deUint32                                      attachmentCount
787 		colorBlendAttachmentState.data(),								// const VkPipelineColorBlendAttachmentState*    pAttachments
788 		{ 0.0f, 0.0f, 0.0f, 0.0f }										// float                                         blendConstants[4]
789 	};
790 
791 	vk::GraphicsPipelineWrapper	staticPipeline		(vkd, device, m_testConfig.pipelineConstructionType);
792 	const bool					bindStaticFirst		= (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES	||
793 													   kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES	||
794 													   kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC);
795 	const bool					useStaticPipeline	= (bindStaticFirst || kReversed);
796 
797 	// Create static pipeline when needed.
798 	if (useStaticPipeline)
799 	{
800 		staticPipeline.setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
801 					  .setupPreRasterizationShaderState(viewport,
802 								scissor,
803 								*pipelineLayout,
804 								*renderPass,
805 								0u,
806 								*vertModule,
807 								&rasterizationStateCreateInfo)
808 					  .setupFragmentShaderState(*pipelineLayout,
809 								*renderPass,
810 								0u,
811 								*fragModule,
812 								&depthStencilStateCreateInfo,
813 								&multisampleStateCreateInfo)
814 					  .setupFragmentOutputState(*renderPass, 0u, &colorBlendStateCreateInfo, &multisampleStateCreateInfo)
815 					  .setMonolithicPipelineLayout(*pipelineLayout)
816 					  .buildPipeline();
817 	}
818 
819 	// Create dynamic pipeline.
820 	vk::GraphicsPipelineWrapper graphicsPipeline(vkd, device, m_testConfig.pipelineConstructionType);;
821 	graphicsPipeline.setDynamicState(&dynamicStateCreateInfo)
822 					.setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
823 					.setupPreRasterizationShaderState(viewport,
824 								scissor,
825 								*pipelineLayout,
826 								*renderPass,
827 								0u,
828 								*vertModule,
829 								&rasterizationStateCreateInfo)
830 					.setupFragmentShaderState(*pipelineLayout,
831 								*renderPass,
832 								0u,
833 								*fragModule,
834 								&depthStencilStateCreateInfo,
835 								&multisampleStateCreateInfo)
836 					.setupFragmentOutputState(*renderPass, 0u, &colorBlendStateCreateInfo, &multisampleStateCreateInfo)
837 					.setMonolithicPipelineLayout(*pipelineLayout)
838 					.buildPipeline();
839 
840 	// Command buffer.
841 	const auto cmdPool		= vk::makeCommandPool(vkd, device, queueIndex);
842 	const auto cmdBufferPtr	= vk::allocateCommandBuffer(vkd , device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
843 	const auto cmdBuffer	= cmdBufferPtr.get();
844 
845 	// Clear values.
846 	std::vector<vk::VkClearValue> clearValues;
847 	auto colorClearValue = vk::makeClearValueColor(m_testConfig.clearColorValue);
848 	for (deUint32 i = 0u; i < kNumColorAttachments; ++i)
849 		clearValues.push_back(colorClearValue);
850 	clearValues.push_back(vk::makeClearValueDepthStencil(m_testConfig.clearDepthValue, 0u));
851 
852 	// Record command buffer.
853 	vk::beginCommandBuffer(vkd, cmdBuffer);
854 
855 	for (deUint32 iteration = 0u; iteration < kNumIterations; ++iteration)
856 	{
857 		// Maybe set dynamic state here.
858 		if (kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START)
859 		{
860 			setDynamicStates(m_testConfig, vkd, cmdBuffer);
861 		}
862 
863 		// Begin render pass.
864 		vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffers[iteration].get(), vk::makeRect2D(kFramebufferWidth, kFramebufferHeight), static_cast<deUint32>(clearValues.size()), clearValues.data());
865 
866 			// Bind a static pipeline first if needed.
867 			if (bindStaticFirst && iteration == 0u)
868 			{
869 				vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.getPipeline());
870 			}
871 
872 			// Maybe set dynamic state here.
873 			if (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES)
874 			{
875 				setDynamicStates(m_testConfig, vkd, cmdBuffer);
876 			}
877 
878 			// Bind dynamic pipeline.
879 			if ((kSequenceOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC &&
880 				 kSequenceOrdering != SequenceOrdering::TWO_DRAWS_STATIC) ||
881 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
882 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
883 			{
884 				vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.getPipeline());
885 			}
886 
887 			if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
888 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
889 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
890 			{
891 				setDynamicStates(m_testConfig, vkd, cmdBuffer);
892 			}
893 
894 			// Bind a static pipeline last if needed.
895 			if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
896 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration > 0u))
897 			{
898 				vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.getPipeline());
899 			}
900 
901 			// Push constants.
902 			PushConstants pushConstants =
903 			{
904 				m_testConfig.meshParams.color,		//	tcu::Vec4	triangleColor;
905 				m_testConfig.meshParams.depth,		//	float		meshDepth;
906 				m_testConfig.meshParams.scaleX,		//	float		scaleX;
907 				m_testConfig.meshParams.scaleY,		//	float		scaleY;
908 				m_testConfig.meshParams.offsetX,	//	float		offsetX;
909 				m_testConfig.meshParams.offsetY,	//	float		offsetY;
910 			};
911 			vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pushConstantStageFlags, 0u, static_cast<deUint32>(sizeof(pushConstants)), &pushConstants);
912 
913 			// Maybe set dynamic state here.
914 			if (kSequenceOrdering == SequenceOrdering::BEFORE_DRAW || kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES)
915 			{
916 				setDynamicStates(m_testConfig, vkd, cmdBuffer);
917 			}
918 
919 			// Bind vertex buffer and draw.
920 			vk::VkDeviceSize offset = 0ull;
921 			vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertBuffer.get(), &offset);
922 			vkd.cmdDraw(cmdBuffer, 6u, 1u, 0u, 0u);
923 
924 		vk::endRenderPass(vkd, cmdBuffer);
925 	}
926 
927 	vk::endCommandBuffer(vkd, cmdBuffer);
928 
929 	// Submit commands.
930 	vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
931 
932 	// Read result image aspects from the last used framebuffer.
933 	const tcu::UVec2	renderSize(kFramebufferWidth, kFramebufferHeight);
934 
935 	const int kWidth	= static_cast<int>(kFramebufferWidth);
936 	const int kHeight	= static_cast<int>(kFramebufferHeight);
937 
938 	const tcu::Vec4		kGood(0.0f, 1.0f, 0.0f, 1.0f);
939 	const tcu::Vec4		kBad(1.0f, 0.0f, 0.0f, 1.0f);
940 
941 	const tcu::TextureFormat errorFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
942 
943 	bool colorMatchAll = true;
944 
945 	// Check expected values.
946 	auto nextAttachmentImage = colorImages.end() - kNumColorAttachments;
947 	for (deUint32 attachmentIndex = 0u; attachmentIndex < kNumColorAttachments; ++attachmentIndex, ++nextAttachmentImage)
948 	{
949 		const auto			colorBuffer = readColorAttachment(vkd, device, queue, queueIndex, allocator, (*nextAttachmentImage)->get(), kColorFormat, renderSize);
950 		const auto			colorAccess = colorBuffer->getAccess();
951 
952 		tcu::TextureLevel	colorError			(errorFormat, kWidth, kHeight);
953 		const auto			colorErrorAccess	= colorError.getAccess();
954 
955 		bool colorMatch = true;
956 
957 		for (int y = 0; y < kHeight; ++y)
958 		for (int x = 0; x < kWidth; ++x)
959 		{
960 			const auto colorPixel = colorAccess.getPixel(x, y);
961 
962 			bool match = tcu::boolAll(tcu::lessThan(tcu::absDiff(colorPixel, m_testConfig.expectedColor[attachmentIndex]), kColorThreshold));
963 			colorErrorAccess.setPixel((match ? kGood : kBad), x, y);
964 			if (!match)
965 				colorMatch = false;
966 		}
967 
968 		if (!colorMatch)
969 		{
970 			std::ostringstream desc;
971 			desc << "Result color image and error mask for attachment #" << attachmentIndex;
972 			logErrors(log, "Color", desc.str(), colorAccess, colorErrorAccess);
973 			colorMatchAll = false;
974 		}
975 	}
976 
977 	const auto			depthBuffer = readDepthAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormat, renderSize);
978 	const auto			depthAccess = depthBuffer->getAccess();
979 	tcu::TextureLevel	depthError(errorFormat, kWidth, kHeight);
980 	const auto			depthErrorAccess = depthError.getAccess();
981 
982 	const auto	minDepth	= m_testConfig.expectedDepth - 1.0e-07f;
983 	const auto	maxDepth	= m_testConfig.expectedDepth + 1.0e-07f;
984 	bool		depthMatch	= true;
985 
986 	for (int y = 0; y < kHeight; ++y)
987 	for (int x = 0; x < kWidth; ++x)
988 	{
989 		const auto depthPixel = depthAccess.getPixDepth(x, y);
990 		bool match = de::inRange(depthPixel, minDepth, maxDepth);
991 		depthErrorAccess.setPixel((match ? kGood : kBad), x, y);
992 		if (!match)
993 			depthMatch = false;
994 	}
995 
996 	if (!depthMatch)
997 	{
998 		logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
999 	}
1000 
1001 	if (!(colorMatchAll && depthMatch))
1002 	{
1003 		return tcu::TestStatus::fail("Incorrect value found in attachments; please check logged images");
1004 	}
1005 
1006 	return tcu::TestStatus::pass("Pass");
1007 }
1008 
1009 template <typename VectorType>
MaskVector(const VectorType & valueIfMaskIsFalse,const VectorType & valueIfMaskIsTrue,const std::vector<bool> & mask,bool inverse=false)1010 VectorType MaskVector(const VectorType& valueIfMaskIsFalse, const VectorType& valueIfMaskIsTrue, const std::vector<bool>& mask, bool inverse = false)
1011 {
1012 	DE_ASSERT(valueIfMaskIsFalse.size() == valueIfMaskIsTrue.size() && valueIfMaskIsFalse.size() == mask.size());
1013 
1014 	VectorType ret(mask.size());
1015 
1016 	for (size_t i = 0; i < mask.size(); ++i)
1017 	{
1018 		bool m = mask[i];
1019 		if (inverse)
1020 			m = !m;
1021 		ret[i] = m ? valueIfMaskIsTrue[i] : valueIfMaskIsFalse[i];
1022 	}
1023 
1024 	return ret;
1025 }
1026 
ApplyChannelMask(std::vector<tcu::Vec4> & meshColors,const tcu::BVec4 & channelMask,const tcu::Vec4 & clearColor)1027 void ApplyChannelMask(std::vector<tcu::Vec4>& meshColors, const tcu::BVec4& channelMask, const tcu::Vec4& clearColor)
1028 {
1029 	for (auto&& attachmentColor : meshColors)
1030 		attachmentColor = tcu::Vec4(
1031 			channelMask.x() ? attachmentColor.x() : clearColor.x(),
1032 			channelMask.y() ? attachmentColor.y() : clearColor.y(),
1033 			channelMask.z() ? attachmentColor.z() : clearColor.z(),
1034 			channelMask.w() ? attachmentColor.w() : clearColor.w()
1035 		);
1036 }
1037 
AddSingleTestCaseStatic(const std::string & name,const std::string & description,vk::PipelineConstructionType pipelineConstructionType,const std::vector<bool> mask,const tcu::BVec4 channelMask,bool inverse,tcu::TestCaseGroup * orderingGroup,tcu::TestContext & testCtx)1038 void AddSingleTestCaseStatic(const std::string&				name,
1039 							 const std::string&				description,
1040 							 vk::PipelineConstructionType	pipelineConstructionType,
1041 							 const std::vector<bool>		mask,
1042 							 const tcu::BVec4				channelMask,
1043 							 bool							inverse,
1044 							 tcu::TestCaseGroup*			orderingGroup,
1045 							 tcu::TestContext&				testCtx)
1046 {
1047 	TestConfig config(pipelineConstructionType, SequenceOrdering::CMD_BUFFER_START);
1048 
1049 	// Enable writes and expect the mesh color, or disable writes and expect the clear color.
1050 
1051 	config.clearColorValue						= tcu::Vec4(0.25f, 0.5f, 0.75f, 0.5f);
1052 	config.meshParams.color						= tcu::Vec4(1.0f, 0.75f, 0.5f, 0.25f);
1053 
1054 	const auto allVkFalse						= Bool32Vec(kNumColorAttachments, VK_FALSE);
1055 	const auto allVkTrue						= Bool32Vec(kNumColorAttachments, VK_TRUE);
1056 
1057 	config.channelMask = channelMask;
1058 
1059 	config.colorWriteEnableConfig.staticValue	= MaskVector(allVkFalse, allVkTrue, mask, inverse);
1060 
1061 	// Note colorWriteEnableConfig.dynamicValue is unset, defaults to an empty Maybe<T>
1062 
1063 	std::vector<tcu::Vec4> meshColorsPerAttachment(kNumColorAttachments);
1064 	meshColorsPerAttachment[0] = config.meshParams.color;
1065 	for (deUint32 i = 1u; i < kNumColorAttachments; ++i)
1066 		meshColorsPerAttachment[i] = meshColorsPerAttachment[i - 1] * 0.5f;
1067 
1068 	std::vector<tcu::Vec4> clearColorsPerAttachment(kNumColorAttachments, config.clearColorValue);
1069 
1070 	ApplyChannelMask(meshColorsPerAttachment, channelMask, config.clearColorValue);
1071 
1072 	config.expectedColor = MaskVector(clearColorsPerAttachment, meshColorsPerAttachment, mask, inverse);
1073 
1074 	// Depth should always be written even when color is not
1075 	config.clearDepthValue	= 0.5f;
1076 	config.meshParams.depth	= 0.25f;
1077 	config.expectedDepth	= 0.25f;
1078 
1079 	orderingGroup->addChild(new ColorWriteEnableTest(testCtx, name, description, config));
1080 }
1081 
AddSingleTestCaseDynamic(const std::string & name,const std::string & description,vk::PipelineConstructionType pipelineConstructionType,const std::vector<bool> mask,const tcu::BVec4 channelMask,bool inverse,tcu::TestCaseGroup * orderingGroup,tcu::TestContext & testCtx,SequenceOrdering ordering)1082 void AddSingleTestCaseDynamic(const std::string&			name,
1083 							  const std::string&			description,
1084 							  vk::PipelineConstructionType	pipelineConstructionType,
1085 							  const std::vector<bool>		mask,
1086 							  const tcu::BVec4				channelMask,
1087 							  bool							inverse,
1088 							  tcu::TestCaseGroup*			orderingGroup,
1089 							  tcu::TestContext&				testCtx,
1090 							  SequenceOrdering				ordering)
1091 {
1092 	TestConfig config(pipelineConstructionType, ordering);
1093 
1094 	// Enable writes and expect the mesh color, or disable writes and expect the clear color.
1095 
1096 	config.clearColorValue						= tcu::Vec4(0.25f, 0.5f, 0.75f, 0.5f);
1097 	config.meshParams.color						= tcu::Vec4(1.0f, 0.75f, 0.5f, 0.25f);
1098 
1099 	const auto allVkFalse						= Bool32Vec(kNumColorAttachments, VK_FALSE);
1100 	const auto allVkTrue						= Bool32Vec(kNumColorAttachments, VK_TRUE);
1101 
1102 	config.channelMask = channelMask;
1103 
1104 	config.colorWriteEnableConfig.staticValue	= inverse ? allVkTrue : allVkFalse;
1105 	config.colorWriteEnableConfig.dynamicValue	= MaskVector(allVkFalse, allVkTrue, mask, inverse);
1106 
1107 	std::vector<tcu::Vec4> meshColorsPerAttachment(kNumColorAttachments);
1108 	meshColorsPerAttachment[0] = config.meshParams.color;
1109 	for (deUint32 i = 1u; i < kNumColorAttachments; ++i)
1110 		meshColorsPerAttachment[i] = meshColorsPerAttachment[i - 1] * 0.5f;
1111 
1112 	std::vector<tcu::Vec4> clearColorsPerAttachment(kNumColorAttachments, config.clearColorValue);
1113 
1114 	ApplyChannelMask(meshColorsPerAttachment, channelMask, config.clearColorValue);
1115 
1116 	config.expectedColor = MaskVector(clearColorsPerAttachment, meshColorsPerAttachment, mask, inverse);
1117 
1118 	// Depth should always be written even when color is not
1119 	config.clearDepthValue	= 0.5f;
1120 	config.meshParams.depth	= 0.25f;
1121 	config.expectedDepth	= 0.25f;
1122 
1123 	orderingGroup->addChild(new ColorWriteEnableTest(testCtx, name, description, config));
1124 }
1125 
1126 } // anonymous namespace
1127 
1128 namespace
1129 {
1130 using namespace vk;
1131 using namespace tcu;
1132 
1133 struct TestParams
1134 {
1135 	deUint32	width;
1136 	deUint32	height;
1137 	VkFormat	format;
1138 	deUint32	attachmentCount;
1139 	deUint32	attachmentMore;
1140 	bool		setCweBeforePlBind;
1141 	bool		colorWriteEnables;
1142 	PipelineConstructionType pct;
1143 	bool selectOptimalBlendableFormat (const InstanceInterface&, VkPhysicalDevice);
1144 };
1145 
1146 class ColorWriteEnable2Test : public vkt::TestCase
1147 {
1148 public:
ColorWriteEnable2Test(TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & testParams)1149 								ColorWriteEnable2Test	(TestContext&		testCtx,
1150 														 const std::string&	name,
1151 														 const std::string& description,
1152 														 const TestParams&	testParams)
1153 									: vkt::TestCase		(testCtx, name, description)
1154 									, m_params		(testParams) { }
1155 
1156 	virtual						~ColorWriteEnable2Test	() = default;
1157 
1158 	virtual void				checkSupport			(Context&			context) const override;
1159 	virtual void				initPrograms			(SourceCollections&	programCollection) const override;
1160 	virtual vkt::TestInstance*	createInstance			(Context&			context) const override;
1161 
1162 private:
1163 	mutable TestParams			m_params;
1164 
1165 };
1166 
1167 class ColorWriteEnable2Instance : public vkt::TestInstance
1168 {
1169 public:
1170 	typedef std::vector<VkBool32>	ColorWriteEnables;
1171 	struct Attachment
1172 	{
1173 		de::MovePtr<ImageWithMemory>	image;
1174 		Move<VkImageView>				view;
1175 		Attachment () = default;
1176 		DE_UNUSED_FUNCTION Attachment (Attachment&& other);
1177 	};
1178 	struct Framebuffer
1179 	{
1180 		std::vector<Attachment>	attachments;
1181 		Move<VkFramebuffer>		framebuffer;
1182 		Framebuffer	() = default;
1183 		Framebuffer	(Framebuffer&& other);
1184 	};
1185 	struct GraphicsPipelineWrapperEx : public GraphicsPipelineWrapper
1186 	{
GraphicsPipelineWrapperExvkt::pipeline::__anon117cea180211::ColorWriteEnable2Instance::GraphicsPipelineWrapperEx1187 		GraphicsPipelineWrapperEx			(const DeviceInterface&			vkd,
1188 											 const VkDevice					dev,
1189 											 const PipelineConstructionType	pct)
1190 			: GraphicsPipelineWrapper		(vkd, dev, pct)
1191 			, m_isDynamicColorWriteEnable	(false) {}
isDynamicColorWriteEnablevkt::pipeline::__anon117cea180211::ColorWriteEnable2Instance::GraphicsPipelineWrapperEx1192 		bool isDynamicColorWriteEnable		() const { return m_isDynamicColorWriteEnable; }
1193 	private:
1194 		friend class ColorWriteEnable2Instance;
1195 		bool m_isDynamicColorWriteEnable;
1196 	};
1197 									ColorWriteEnable2Instance	(Context&						context,
1198 																 const TestParams&				testParams);
1199 	virtual							~ColorWriteEnable2Instance	() = default;
1200 
1201 	de::MovePtr<BufferWithMemory>	createVerrtexBuffer			() const;
1202 	Move<VkRenderPass>				createRenderPass			(deUint32						colorAttachmentCount) const;
1203 	Framebuffer						createFramebuffer			(VkRenderPass					renderPass,
1204 																 deUint32						colorAttachmentCount) const;
1205 	void							setupAndBuildPipeline		(GraphicsPipelineWrapperEx&		owner,
1206 																 VkPipelineLayout				pipelineLayout,
1207 																 VkRenderPass					renderPass,
1208 																 deUint32						colorAttachmentCount,
1209 																 const ColorWriteEnables&		colorWriteEnables,
1210 																 float							blendComp,
1211 																 bool							dynamic) const;
1212 	virtual TestStatus				iterate						() override;
1213 	bool							verifyAttachment			(const deUint32					attachmentIndex,
1214 																 const deUint32					attachmentCount,
1215 																 const ConstPixelBufferAccess&	attachmentContent,
1216 																 const ColorWriteEnables&		colorWriteEnables,
1217 																 const Vec4&					background,
1218 																 const float					blendComp) const;
1219 private:
1220 	const TestParams			m_params;
1221 	const DeviceInterface&		m_vkd;
1222 	const VkDevice				m_device;
1223 	Allocator&					m_allocator;
1224 	const Move<VkShaderModule>	m_vertex;
1225 	const Move<VkShaderModule>	m_fragment;
1226 };
1227 
Attachment(Attachment && other)1228 ColorWriteEnable2Instance::Attachment::Attachment (Attachment&& other)
1229 	: image			(std::move(other.image))
1230 	, view			(std::move(other.view))
1231 {
1232 }
Framebuffer(Framebuffer && other)1233 ColorWriteEnable2Instance::Framebuffer::Framebuffer (Framebuffer&& other)
1234 	: attachments	(std::move(other.attachments))
1235 	, framebuffer	(std::move(other.framebuffer))
1236 {
1237 }
1238 
selectOptimalBlendableFormat(const InstanceInterface & vk,VkPhysicalDevice dev)1239 bool TestParams::selectOptimalBlendableFormat (const InstanceInterface& vk, VkPhysicalDevice dev)
1240 {
1241 	auto doesFormatMatch = [](const VkFormat fmt) -> bool
1242 	{
1243 		const auto tcuFmt = mapVkFormat(fmt);
1244 		return tcuFmt.order == TextureFormat::ChannelOrder::RGBA
1245 				|| tcuFmt.order == TextureFormat::ChannelOrder::sRGBA;
1246 	};
1247 
1248 	VkFormatProperties2 props{};
1249 	const VkFormatFeatureFlags flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT
1250 										| VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT
1251 										| VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
1252 	for (int f = VK_FORMAT_R64G64B64A64_SFLOAT; f > 0; --f)
1253 	{
1254 		props.sType				= VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
1255 		props.pNext				= nullptr;
1256 		props.formatProperties	= {};
1257 		const VkFormat			fmt = static_cast<VkFormat>(f);
1258 		vk.getPhysicalDeviceFormatProperties2(dev, fmt, &props);
1259 		if (doesFormatMatch(fmt) && ((props.formatProperties.optimalTilingFeatures & flags) == flags))
1260 		{
1261 			this->format = fmt;
1262 			return true;
1263 		}
1264 	}
1265 	return false;
1266 }
1267 
checkSupport(Context & context) const1268 void ColorWriteEnable2Test::checkSupport (Context& context) const
1269 {
1270 	const auto&	vki				= context.getInstanceInterface();
1271 	const auto	physicalDevice	= context.getPhysicalDevice();
1272 
1273 	if (m_params.colorWriteEnables)
1274 	{
1275 		context.requireDeviceFunctionality("VK_EXT_color_write_enable");
1276 	}
1277 
1278 	DE_ASSERT(m_params.attachmentCount >= 1);
1279 	auto maxColorAttachments = context.getDeviceProperties().limits.maxColorAttachments;
1280 	if ((m_params.attachmentCount + m_params.attachmentMore) > maxColorAttachments)
1281 	{
1282 		std::stringstream ss;
1283 		if (m_params.attachmentMore)
1284 		{
1285 			ss << "Sum of color attachments (" << m_params.attachmentCount << " + " << m_params.attachmentMore << ")";
1286 		}
1287 		else
1288 		{
1289 			ss << "Color attachment count of " << m_params.attachmentCount;
1290 		}
1291 		ss << " exceeds maximum number of color attachments supported by device which is " << maxColorAttachments;
1292 		ss.flush();
1293 		TCU_THROW(NotSupportedError, ss.str());
1294 	}
1295 
1296 	if ( ! m_params.selectOptimalBlendableFormat(vki, physicalDevice))
1297 		TCU_THROW(NotSupportedError, "Required color image features not supported");
1298 
1299 	checkPipelineLibraryRequirements(vki, physicalDevice, m_params.pct);
1300 }
1301 
initPrograms(SourceCollections & programCollection) const1302 void ColorWriteEnable2Test::initPrograms (SourceCollections& programCollection) const
1303 {
1304 	const char			nl = '\n';
1305 	const deUint32		ac = m_params.attachmentCount;
1306 	std::ostringstream	vs;
1307 	std::ostringstream	fs;
1308 
1309 	vs	<< "#version 450"									<<	nl
1310 		<< "layout(location = 0) in vec4 position;"			<<	nl
1311 		<< "layout(location = 0) out flat int instance;"	<<	nl
1312 		<< "void main() {"									<<	nl
1313 		<< "    gl_Position = vec4(position.xy, 0.0, 1.0);"	<<	nl
1314 		<< "	instance = gl_InstanceIndex;"				<<	nl
1315 		<< "}"												<<	nl;
1316 	programCollection.glslSources.add("vert") << glu::VertexSource(vs.str());
1317 
1318 	fs	<< "#version 450"											<<	nl
1319 		<< "layout(location = 0) in flat int attachments;"			<<	nl
1320 		<< "layout(location = 0) out vec4 colors[" << ac << "];"	<<	nl
1321 		<< "void main() {"											<<	nl
1322 		<< "    for (int a = 0; a < attachments; ++a) {"			<<	nl
1323 		<< "		float c = float(attachments - a);"				<<	nl
1324 		<< "		colors[a] = vec4(pow(0.5, c));"					<<	nl
1325 		<< "}}"														<<	nl;
1326 	programCollection.glslSources.add("frag") << glu::FragmentSource(fs.str());
1327 }
1328 
createInstance(Context & context) const1329 TestInstance* ColorWriteEnable2Test::createInstance (Context& context) const
1330 {
1331 	return new ColorWriteEnable2Instance(context, m_params);
1332 }
1333 
ColorWriteEnable2Instance(Context & context,const TestParams & testParams)1334 ColorWriteEnable2Instance::ColorWriteEnable2Instance (Context& context, const TestParams& testParams)
1335 	: vkt::TestInstance	(context)
1336 	, m_params		(testParams)
1337 	, m_vkd				(context.getDeviceInterface())
1338 	, m_device			(context.getDevice())
1339 	, m_allocator		(context.getDefaultAllocator())
1340 	, m_vertex			(createShaderModule(m_vkd, m_device, context.getBinaryCollection().get("vert")))
1341 	, m_fragment		(createShaderModule(m_vkd, m_device, context.getBinaryCollection().get("frag")))
1342 {
1343 }
1344 
createRenderPass(deUint32 colorAttachmentCount) const1345 Move<VkRenderPass> ColorWriteEnable2Instance::createRenderPass (deUint32 colorAttachmentCount) const
1346 {
1347 	const std::vector<VkAttachmentDescription> attachmentDescriptions(
1348 		colorAttachmentCount,
1349 		VkAttachmentDescription
1350 		{
1351 			0u,											//	VkAttachmentDescriptionFlags	flags;
1352 			m_params.format,							//	VkFormat						format;
1353 			VK_SAMPLE_COUNT_1_BIT,						//	VkSampleCountFlagBits			samples;
1354 			VK_ATTACHMENT_LOAD_OP_CLEAR,				//	VkAttachmentLoadOp				loadOp;
1355 			VK_ATTACHMENT_STORE_OP_STORE,				//	VkAttachmentStoreOp				storeOp;
1356 			VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				stencilLoadOp;
1357 			VK_ATTACHMENT_STORE_OP_DONT_CARE,			//	VkAttachmentStoreOp				stencilStoreOp;
1358 			VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout					initialLayout;
1359 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
1360 		}
1361 	);
1362 
1363 	std::vector<VkAttachmentReference> colorAttachmentReference;
1364 	for (deUint32 i = 0u; i < colorAttachmentCount; ++i)
1365 	{
1366 		colorAttachmentReference.push_back(VkAttachmentReference
1367 			{
1368 				i,											//	deUint32		attachment;
1369 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	//	VkImageLayout	layout;
1370 			}
1371 		);
1372 	}
1373 
1374 	const VkSubpassDescription subpassDescription
1375 	{
1376 		0u,												//	VkSubpassDescriptionFlags		flags;
1377 		VK_PIPELINE_BIND_POINT_GRAPHICS,				//	VkPipelineBindPoint				pipelineBindPoint;
1378 		0u,												//	deUint32						inputAttachmentCount;
1379 		nullptr,										//	const VkAttachmentReference*	pInputAttachments;
1380 		colorAttachmentCount,							//	deUint32						colorAttachmentCount;
1381 		colorAttachmentReference.data(),				//	const VkAttachmentReference*	pColorAttachments;
1382 		nullptr,										//	const VkAttachmentReference*	pResolveAttachments;
1383 		nullptr,										//	const VkAttachmentReference*	pDepthStencilAttachment;
1384 		0u,												//	deUint32						preserveAttachmentCount;
1385 		nullptr,										//	const deUint32*					pPreserveAttachments;
1386 	};
1387 
1388 	const VkRenderPassCreateInfo renderPassCreateInfo
1389 	{
1390 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,		//	VkStructureType					sType;
1391 		nullptr,										//	const void*						pNext;
1392 		0u,												//	VkRenderPassCreateFlags			flags;
1393 		colorAttachmentCount,							//	deUint32						attachmentCount;
1394 		attachmentDescriptions.data(),					//	const VkAttachmentDescription*	pAttachments;
1395 		1u,												//	deUint32						subpassCount;
1396 		&subpassDescription,							//	const VkSubpassDescription*		pSubpasses;
1397 		0u,												//	deUint32						dependencyCount;
1398 		nullptr,										//	const VkSubpassDependency*		pDependencies;
1399 	};
1400 
1401 	return vk::createRenderPass(m_vkd, m_device, &renderPassCreateInfo);
1402 }
1403 
createVerrtexBuffer() const1404 de::MovePtr<BufferWithMemory> ColorWriteEnable2Instance::createVerrtexBuffer () const
1405 {
1406 	const std::vector<float> quad
1407 	{
1408 		-1.0f, -1.0f, 0.0f, 0.0f,
1409 		+1.0f, -1.0f, 0.0f, 0.0f,
1410 		-1.0f, +1.0f, 0.0f, 0.0f,
1411 		-1.0f, +1.0f, 0.0f, 0.0f,
1412 		+1.0f, -1.0f, 0.0f, 0.0f,
1413 		+1.0f, +1.0f, 0.0f, 0.0f
1414 	};
1415 
1416 	const auto						vertDataSize	= quad.size() * sizeof(float);
1417 	const auto						vertBufferInfo	= makeBufferCreateInfo(static_cast<VkDeviceSize>(vertDataSize), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1418 	de::MovePtr<BufferWithMemory>	vertBuffer		(new BufferWithMemory(m_vkd, m_device, m_allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible));
1419 	auto&							alloc			= vertBuffer->getAllocation();
1420 
1421 	deMemcpy(reinterpret_cast<char*>(alloc.getHostPtr()), quad.data(), vertDataSize);
1422 	flushAlloc(m_vkd, m_device, alloc);
1423 
1424 	return vertBuffer;
1425 }
1426 
createFramebuffer(VkRenderPass renderPass,deUint32 colorAttachmentCount) const1427 ColorWriteEnable2Instance::Framebuffer ColorWriteEnable2Instance::createFramebuffer (VkRenderPass renderPass, deUint32 colorAttachmentCount) const
1428 {
1429 	const VkExtent3D			extent				{ m_params.width, m_params.height, 1u };
1430 	const VkImageUsageFlags		imageUsage			= (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1431 	const auto					imageSubresource	= vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1432 	const deUint32				queueIndex			= m_context.getUniversalQueueFamilyIndex();
1433 	Allocator&					allocator			= m_context.getDefaultAllocator();
1434 
1435 	std::vector<Attachment>		attachments			(colorAttachmentCount);
1436 	std::vector<VkImageView>	views				(colorAttachmentCount);
1437 
1438 	for (deUint32 i = 0; i < colorAttachmentCount; ++i)
1439 	{
1440 		auto& attachment = attachments[i];
1441 
1442 		const VkImageCreateInfo imageCreateInfo
1443 		{
1444 			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		//	VkStructureType			sType;
1445 			nullptr,									//	const void*				pNext;
1446 			0u,											//	VkImageCreateFlags		flags;
1447 			VK_IMAGE_TYPE_2D,							//	VkImageType				imageType;
1448 			m_params.format,							//	VkFormat				format;
1449 			extent,										//	VkExtent3D				extent;
1450 			1u,											//	deUint32				mipLevels;
1451 			1u,											//	deUint32				arrayLayers;
1452 			VK_SAMPLE_COUNT_1_BIT,						//	VkSampleCountFlagBits	samples;
1453 			VK_IMAGE_TILING_OPTIMAL,					//	VkImageTiling			tiling;
1454 			imageUsage,									//	VkImageUsageFlags		usage;
1455 			VK_SHARING_MODE_EXCLUSIVE,					//	VkSharingMode			sharingMode;
1456 			1u,											//	deUint32				queueFamilyIndexCount;
1457 			&queueIndex,								//	const deUint32*			pQueueFamilyIndices;
1458 			VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout			initialLayout;
1459 		};
1460 		attachment.image = de::MovePtr<ImageWithMemory>(new ImageWithMemory(m_vkd, m_device, allocator, imageCreateInfo, MemoryRequirement::Any));
1461 
1462 		attachment.view	= makeImageView(m_vkd, m_device, **attachment.image, VK_IMAGE_VIEW_TYPE_2D, m_params.format, imageSubresource);
1463 
1464 		views[i] = *attachment.view;
1465 	}
1466 
1467 	const VkFramebufferCreateInfo framebufferCreateInfo
1468 	{
1469 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		//	VkStructureType				sType;
1470 		nullptr,										//	const void*					pNext;
1471 		0u,												//	VkFramebufferCreateFlags	flags;
1472 		renderPass,										//	VkRenderPass				renderPass;
1473 		colorAttachmentCount,							//	deUint32					attachmentCount;
1474 		views.data(),									//	const VkImageView*			pAttachments;
1475 		m_params.width,									//	deUint32					width;
1476 		m_params.height,								//	deUint32					height;
1477 		1u,												//	deUint32					layers;
1478 	};
1479 
1480 	Framebuffer result;
1481 	result.attachments = std::move(attachments);
1482 	result.framebuffer = ::vk::createFramebuffer(m_vkd, m_device, &framebufferCreateInfo);
1483 
1484 	return result;
1485 }
1486 
setupAndBuildPipeline(GraphicsPipelineWrapperEx & owner,VkPipelineLayout pipelineLayout,VkRenderPass renderPass,deUint32 colorAttachmentCount,const ColorWriteEnables & colorWriteEnables,float blendComp,bool dynamic) const1487 void ColorWriteEnable2Instance::setupAndBuildPipeline (GraphicsPipelineWrapperEx&	owner,
1488 													   VkPipelineLayout				pipelineLayout,
1489 													   VkRenderPass					renderPass,
1490 													   deUint32						colorAttachmentCount,
1491 													   const ColorWriteEnables&		colorWriteEnables,
1492 													   float						blendComp,
1493 													   bool							dynamic) const
1494 {
1495 	const std::vector<VkViewport>	viewports		{ makeViewport(m_params.width, m_params.height) };
1496 	const std::vector<VkRect2D>		scissors		{ makeRect2D(m_params.width, m_params.height) };
1497 
1498 	const auto						vertexBinding	= makeVertexInputBindingDescription(0u, static_cast<deUint32>(4 * sizeof(float)), VK_VERTEX_INPUT_RATE_VERTEX);
1499 	const auto						vertexAttrib	= makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u);
1500 
1501 	const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo
1502 	{
1503 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
1504 		nullptr,														//	const void*									pNext;
1505 		0u,																//	VkPipelineVertexInputStateCreateFlags		flags;
1506 		1u,																//	deUint32									vertexBindingDescriptionCount;
1507 		&vertexBinding,													//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
1508 		1u,																//	deUint32									vertexAttributeDescriptionCount;
1509 		&vertexAttrib													//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
1510 	};
1511 
1512 	const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo
1513 	{
1514 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType							sType;
1515 		nullptr,														//	const void*								pNext;
1516 		0u,																//	VkPipelineInputAssemblyStateCreateFlags	flags;
1517 		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							//	VkPrimitiveTopology						topology;
1518 		VK_FALSE,														//	VkBool32								primitiveRestartEnable;
1519 	};
1520 
1521 	const VkDynamicState cweDynamicStates[1] { VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT };
1522 	const VkPipelineDynamicStateCreateInfo	dynamicStateCreateInfo
1523 	{
1524 		VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
1525 		nullptr,												//	const void*							pNext;
1526 		0u,														//	VkPipelineDynamicStateCreateFlags	flags;
1527 		1u,														//	deUint32							dynamicStateCount;
1528 		cweDynamicStates										//	const VkDynamicState*				pDynamicStates;
1529 	};
1530 
1531 	DE_ASSERT(colorAttachmentCount <= colorWriteEnables.size());
1532 
1533 	std::vector<vk::VkPipelineColorBlendAttachmentState> colorBlendAttachmentStates(
1534 		colorAttachmentCount,
1535 		VkPipelineColorBlendAttachmentState
1536 		{
1537 			VK_TRUE,											// VkBool32                 blendEnable
1538 			VK_BLEND_FACTOR_CONSTANT_COLOR,						// VkBlendFactor            srcColorBlendFactor
1539 			VK_BLEND_FACTOR_ZERO,								// VkBlendFactor            dstColorBlendFactor
1540 			VK_BLEND_OP_ADD,									// VkBlendOp                colorBlendOp
1541 			VK_BLEND_FACTOR_CONSTANT_ALPHA,						// VkBlendFactor            srcAlphaBlendFactor
1542 			VK_BLEND_FACTOR_ZERO,								// VkBlendFactor            dstAlphaBlendFactor
1543 			VK_BLEND_OP_ADD,									// VkBlendOp                alphaBlendOp
1544 			VkColorComponentFlags(0)							// VkColorComponentFlags    colorWriteMask
1545 		}
1546 	);
1547 	for (deUint32 i = 0; i < colorAttachmentCount; ++i)
1548 	{
1549 		VkColorComponentFlags colorWriteMask(  VK_COLOR_COMPONENT_R_BIT
1550 											 | VK_COLOR_COMPONENT_G_BIT
1551 											 | VK_COLOR_COMPONENT_B_BIT
1552 											 | VK_COLOR_COMPONENT_A_BIT);
1553 		switch (i % 4)
1554 		{
1555 			case 0: colorWriteMask &= (~(VK_COLOR_COMPONENT_R_BIT)); break;
1556 			case 1: colorWriteMask &= (~(VK_COLOR_COMPONENT_G_BIT)); break;
1557 			case 2: colorWriteMask &= (~(VK_COLOR_COMPONENT_B_BIT)); break;
1558 			case 3: colorWriteMask &= (~(VK_COLOR_COMPONENT_A_BIT)); break;
1559 		}
1560 		colorBlendAttachmentStates[i].colorWriteMask = colorWriteMask;
1561 		colorBlendAttachmentStates[i].blendEnable = colorWriteEnables[i];
1562 	}
1563 
1564 	const VkPipelineColorWriteCreateInfoEXT colorWriteCreateInfo
1565 	{
1566 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT,			// VkStructureType	sType;
1567 		nullptr,														// const void*		pNext;
1568 		colorAttachmentCount,											// deUint32			attachmentCount;
1569 		colorWriteEnables.data()										// const VkBool32*	pColorWriteEnables;
1570 	};
1571 
1572 	const bool cweAllowed = (dynamic && m_params.colorWriteEnables);
1573 	owner.m_isDynamicColorWriteEnable = cweAllowed;
1574 
1575 	const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo
1576 	{
1577 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType                               sType
1578 		cweAllowed ? nullptr : &colorWriteCreateInfo,					// const void*                                   pNext
1579 		0u,																// VkPipelineColorBlendStateCreateFlags          flags
1580 		VK_FALSE,														// VkBool32                                      logicOpEnable
1581 		VK_LOGIC_OP_CLEAR,												// VkLogicOp                                     logicOp
1582 		colorAttachmentCount,											// deUint32                                      attachmentCount
1583 		colorBlendAttachmentStates.data(),								// const VkPipelineColorBlendAttachmentState*    pAttachments
1584 		{ blendComp, blendComp, blendComp, blendComp }					// float                                         blendConstants[4]
1585 	};
1586 
1587 	owner
1588 		.setDefaultRasterizationState()
1589 		.setDefaultDepthStencilState()
1590 		.setDefaultMultisampleState()
1591 		.setDynamicState(cweAllowed ? &dynamicStateCreateInfo : nullptr)
1592 		.setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
1593 		.setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, renderPass, 0u, *m_vertex)
1594 		.setupFragmentShaderState(pipelineLayout, renderPass, 0u, *m_fragment)
1595 		.setupFragmentOutputState(renderPass, 0u, &colorBlendStateCreateInfo)
1596 		.setMonolithicPipelineLayout(pipelineLayout)
1597 		.buildPipeline();
1598 }
1599 
verifyAttachment(const deUint32 attachmentIndex,const deUint32 attachmentCount,const ConstPixelBufferAccess & attachmentContent,const ColorWriteEnables & colorWriteEnables,const Vec4 & background,const float blendComp) const1600 bool ColorWriteEnable2Instance::verifyAttachment (const deUint32				attachmentIndex,
1601 												  const deUint32				attachmentCount,
1602 												  const ConstPixelBufferAccess&	attachmentContent,
1603 												  const ColorWriteEnables&		colorWriteEnables,
1604 												  const Vec4&					background,
1605 												  const float					blendComp) const
1606 {
1607 	const auto	maskColor	= [&](Vec4 color) -> Vec4 {
1608 		color[attachmentIndex % 4] = background[attachmentIndex % 4];
1609 		return color;
1610 	};
1611 	const Vec4	source		(powf(0.5f, static_cast<float>(attachmentCount - attachmentIndex)));
1612 	const Vec4	expected	= colorWriteEnables[attachmentIndex] ? maskColor(source * blendComp) : background;
1613 	deUint32	failures	= 0;
1614 
1615 	for (deUint32 y = 0; y < m_params.height; ++y)
1616 	{
1617 		for (deUint32 x = 0; x < m_params.width; ++x)
1618 		{
1619 			const auto result = attachmentContent.getPixel(x, y);
1620 			const float er = expected.x(); const float rr = result.x();
1621 			const float eg = expected.y(); const float rg = result.y();
1622 			const float eb = expected.z(); const float rb = result.z();
1623 			const float ea = expected.w(); const float ra = result.w();
1624 			if (rr != er || rg != eg || rb != eb || ra != ea) ++failures;
1625 		}
1626 	}
1627 
1628 	return (0 == failures);
1629 }
1630 
iterate(void)1631 TestStatus ColorWriteEnable2Instance::iterate (void)
1632 {
1633 	const VkQueue							queue				= m_context.getUniversalQueue();
1634 	const deUint32							queueIndex			= m_context.getUniversalQueueFamilyIndex();
1635 	const VkRect2D							renderArea			= makeRect2D(m_params.width, m_params.height);
1636 	const deUint32							attachmentCount		= m_params.attachmentCount;
1637 
1638 	const float								blendComp			= 0.5f;
1639 	const Vec4								background			(0.75f, 0.75f, 0.75f, 0.75f);
1640 	std::vector<VkClearValue>				clearValues			(attachmentCount, makeClearValueColor(background));
1641 	de::MovePtr<BufferWithMemory>			vertexBuffer		= createVerrtexBuffer();
1642 	ColorWriteEnables						writeEnables		(attachmentCount + m_params.attachmentMore, VK_TRUE);
1643 	for (deUint32 i = 0; i < attachmentCount; ++i)	writeEnables[i] = (i % 2) ? VK_TRUE : VK_FALSE;
1644 
1645 	Move<VkPipelineLayout>					pipelineLayout		= makePipelineLayout(m_vkd, m_device, 0u, nullptr, 0u, nullptr);
1646 	std::vector<Move<VkRenderPass>>			renderPasses;
1647 	std::vector<Framebuffer>				framebuffers;
1648 	std::vector<GraphicsPipelineWrapperEx>	pipelines;
1649 	for (deUint32 i = 0; i < attachmentCount; ++i)
1650 	{
1651 		renderPasses.emplace_back(createRenderPass(i+1));
1652 		framebuffers.emplace_back(createFramebuffer(*renderPasses.back(), (i+1)));
1653 
1654 		const bool dynamicColorWriteEnable = (((attachmentCount - i) % 2) == 1);
1655 
1656 		// build dynamics and statics pipelines alternately in reverse order
1657 		pipelines.emplace_back(m_vkd, m_device, m_params.pct);
1658 		setupAndBuildPipeline(pipelines.back(), *pipelineLayout, *renderPasses[i], (i+1), writeEnables, blendComp, dynamicColorWriteEnable);
1659 	}
1660 
1661 	Move<VkCommandPool>						cmdPool				= makeCommandPool(m_vkd, m_device, queueIndex);
1662 	Move<VkCommandBuffer>					cmdBuff				= allocateCommandBuffer(m_vkd, m_device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1663 
1664 	beginCommandBuffer(m_vkd, *cmdBuff);
1665 		m_vkd.cmdBindVertexBuffers(*cmdBuff, 0u, 1u, &vertexBuffer->get(), &static_cast<const VkDeviceSize&>(0));
1666 
1667 		for (deUint32 a = 0; a < attachmentCount; ++a)
1668 		{
1669 			if (m_params.setCweBeforePlBind)
1670 			{
1671 				if (pipelines[a].isDynamicColorWriteEnable())
1672 					m_vkd.cmdSetColorWriteEnableEXT(*cmdBuff, static_cast<deUint32>(writeEnables.size()), writeEnables.data());
1673 				m_vkd.cmdBindPipeline(*cmdBuff, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[a].getPipeline());
1674 			}
1675 			else
1676 			{
1677 				m_vkd.cmdBindPipeline(*cmdBuff, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[a].getPipeline());
1678 				if (pipelines[a].isDynamicColorWriteEnable())
1679 					m_vkd.cmdSetColorWriteEnableEXT(*cmdBuff, static_cast<deUint32>(writeEnables.size()), writeEnables.data());
1680 			}
1681 
1682 			beginRenderPass(m_vkd, *cmdBuff, *renderPasses[a], *framebuffers[a].framebuffer, renderArea, attachmentCount, clearValues.data());
1683 				m_vkd.cmdDraw(*cmdBuff, 6u, 1u, 0u, (a + 1));
1684 			endRenderPass(m_vkd, *cmdBuff);
1685 		}
1686 
1687 	endCommandBuffer(m_vkd, *cmdBuff);
1688 	submitCommandsAndWait(m_vkd, m_device, queue, *cmdBuff);
1689 
1690 	deUint32 failureCount = 0;
1691 	for (deUint32 i = 0; i < attachmentCount; ++i)
1692 	for (deUint32 a = 0; a < (i+1); ++a)
1693 	{
1694 		const auto	colorBuffer = readColorAttachment(m_vkd, m_device, queue, queueIndex, m_allocator,
1695 													  **framebuffers.at(i).attachments.at(a).image, m_params.format,
1696 													  UVec2(m_params.width, m_params.height));
1697 		failureCount += verifyAttachment(a, (i+1), colorBuffer->getAccess(), writeEnables, background, blendComp) ? 0u : 1u;
1698 	}
1699 
1700 	return (0u == failureCount) ? TestStatus::pass("") : TestStatus::fail("");
1701 }
1702 
1703 } // unnamed namespace
1704 
createColorWriteEnableTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pct)1705 tcu::TestCaseGroup* createColorWriteEnableTests (tcu::TestContext& testCtx, vk::PipelineConstructionType pct)
1706 {
1707 	de::MovePtr<tcu::TestCaseGroup> colorWriteEnableGroup(new tcu::TestCaseGroup(testCtx, "color_write_enable", "Tests for VK_EXT_color_write_enable"));
1708 
1709 	DE_ASSERT(kNumColorAttachments >= 2);
1710 
1711 	std::vector<bool> mask_all				(kNumColorAttachments, true);
1712 	std::vector<bool> mask_first			(kNumColorAttachments, false);	mask_first[0]												= true;
1713 	std::vector<bool> mask_second			(kNumColorAttachments, false);	mask_second[1]												= true;
1714 	std::vector<bool> mask_last				(kNumColorAttachments, false);	mask_last.back()											= true;
1715 	std::vector<bool> mask_first_and_second	(kNumColorAttachments, false);	mask_first_and_second[0]	= mask_first_and_second[1]		= true;
1716 	std::vector<bool> mask_second_and_last	(kNumColorAttachments, false);	mask_second_and_last[1]		= mask_second_and_last.back()	= true;
1717 
1718 	// Test cases for channel enables
1719 	static const struct
1720 	{
1721 		tcu::BVec4		enabledChannels;
1722 		std::string		name;
1723 		std::string		desc;
1724 	} kChannelCases[] =
1725 	{
1726 		{ tcu::BVec4(true, true, true, true), "all_channels", "Enable all channels in colorWriteMask"},
1727 		{ tcu::BVec4(true, false, false, false), "red_channel", "Red channel enabled in colorWriteMask"},
1728 		{ tcu::BVec4(false, true, false, false), "green_channel", "Green channel enabled in colorWriteMask"},
1729 		{ tcu::BVec4(false, false, true, false), "blue_channel", "Blue channel enabled in colorWriteMask"},
1730 		{ tcu::BVec4(false, false, false, true), "alpha_channel", "Alpha channel enabled in colorWriteMask"},
1731 		{ tcu::BVec4(false, false, false, false), "no_channels", "Disable all channels in colorWriteMask"},
1732 	};
1733 
1734 	// Test cases for the dynamic state
1735 	static const struct
1736 	{
1737 		SequenceOrdering	ordering;
1738 		std::string			name;
1739 		std::string			desc;
1740 	} kOrderingCases[] =
1741 	{
1742 		{ SequenceOrdering::CMD_BUFFER_START,	"cmd_buffer_start",		"Dynamic state set after command buffer start"																								},
1743 		{ SequenceOrdering::BEFORE_DRAW,		"before_draw",			"Dynamic state set just before drawing"																										},
1744 		{ SequenceOrdering::BETWEEN_PIPELINES,	"between_pipelines",	"Dynamic after a pipeline with static states has been bound and before a pipeline with dynamic states has been bound"						},
1745 		{ SequenceOrdering::AFTER_PIPELINES,	"after_pipelines",		"Dynamic state set after both a static-state pipeline and a second dynamic-state pipeline have been bound"									},
1746 		{ SequenceOrdering::BEFORE_GOOD_STATIC,	"before_good_static",	"Dynamic state set after a dynamic pipeline has been bound and before a second static-state pipeline with the right values has been bound"	},
1747 		{ SequenceOrdering::TWO_DRAWS_DYNAMIC,	"two_draws_dynamic",	"Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again"											},
1748 		{ SequenceOrdering::TWO_DRAWS_STATIC,	"two_draws_static",		"Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again"											},
1749 	};
1750 
1751 	for (int channelCaseIdx = 0; channelCaseIdx < DE_LENGTH_OF_ARRAY(kChannelCases); ++channelCaseIdx)
1752 	{
1753 		const auto& kChannelCase	 = kChannelCases[channelCaseIdx];
1754 		de::MovePtr<tcu::TestCaseGroup> channelGroup(new tcu::TestCaseGroup(testCtx, kChannelCase.name.c_str(), kChannelCase.desc.c_str()));
1755 
1756 		for (int orderingIdx = 0; orderingIdx < DE_LENGTH_OF_ARRAY(kOrderingCases); ++orderingIdx)
1757 		{
1758 			const auto& kOrderingCase	= kOrderingCases[orderingIdx];
1759 			const auto& kOrdering		= kOrderingCase.ordering;
1760 
1761 			de::MovePtr<tcu::TestCaseGroup> orderingGroup(new tcu::TestCaseGroup(testCtx, kOrderingCase.name.c_str(), kOrderingCase.desc.c_str()));
1762 
1763 			AddSingleTestCaseDynamic("enable_all",					"Dynamically enable writes to all color attachments",							pct,	mask_all,				kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1764 			AddSingleTestCaseDynamic("enable_first",				"Dynamically enable writes to the first color attachment",						pct,	mask_first,				kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1765 			AddSingleTestCaseDynamic("enable_second",				"Dynamically enable writes to the second color attachment",						pct,	mask_second,			kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1766 			AddSingleTestCaseDynamic("enable_last",					"Dynamically enable writes to the last color attachment",						pct,	mask_last,				kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1767 			AddSingleTestCaseDynamic("enable_first_and_second",		"Dynamically enable writes to the first two color attachments",					pct,	mask_first_and_second,	kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1768 			AddSingleTestCaseDynamic("enable_second_and_last",		"Dynamically enable writes to the second and last color attachments",			pct,	mask_second_and_last,	kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1769 
1770 			AddSingleTestCaseDynamic("disable_all",					"Dynamically disable writes to all color attachments",							pct,	mask_all,				kChannelCase.enabledChannels, true,  orderingGroup.get(), testCtx, kOrdering);
1771 			AddSingleTestCaseDynamic("disable_first",				"Dynamically disable writes to the first color attachment",						pct,	mask_first,				kChannelCase.enabledChannels, true,  orderingGroup.get(), testCtx, kOrdering);
1772 			AddSingleTestCaseDynamic("disable_second",				"Dynamically disable writes to the second color attachment",					pct,	mask_second,			kChannelCase.enabledChannels, true,  orderingGroup.get(), testCtx, kOrdering);
1773 			AddSingleTestCaseDynamic("disable_last",				"Dynamically disable writes to the last color attachment",						pct,	mask_last,				kChannelCase.enabledChannels, true,  orderingGroup.get(), testCtx, kOrdering);
1774 			AddSingleTestCaseDynamic("disable_first_and_second",	"Dynamically disable writes to the first two color attachments",				pct,	mask_first_and_second,	kChannelCase.enabledChannels, true,  orderingGroup.get(), testCtx, kOrdering);
1775 			AddSingleTestCaseDynamic("disable_second_and_last",		"Dynamically disable writes to the second and last color attachments",			pct,	mask_second_and_last,	kChannelCase.enabledChannels, true,  orderingGroup.get(), testCtx, kOrdering);
1776 
1777 			channelGroup->addChild(orderingGroup.release());
1778 		}
1779 
1780 		// Test cases for the static state
1781 		// Note that the dynamic state test cases above also test pipelines with static state (when ordering is BEFORE_GOOD_STATIC and TWO_DRAWS_STATIC).
1782 		// However they all bind a pipeline with the static state AFTER binding a pipeline with the dynamic state.
1783 		// The only case missing, then, is static state alone without any dynamic pipelines in the same render pass or command buffer.
1784 		de::MovePtr<tcu::TestCaseGroup> staticOrderingGroup(new tcu::TestCaseGroup(testCtx, "static", "Static state set"));
1785 
1786 		AddSingleTestCaseStatic("enable_all",				"Statically enable writes to all color attachments",							pct,	mask_all,				kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1787 		AddSingleTestCaseStatic("enable_first",				"Statically enable writes to the first color attachment",						pct,	mask_first,				kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1788 		AddSingleTestCaseStatic("enable_second",			"Statically enable writes to the second color attachment",						pct,	mask_second,			kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1789 		AddSingleTestCaseStatic("enable_last",				"Statically enable writes to the last color attachment",						pct,	mask_last,				kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1790 		AddSingleTestCaseStatic("enable_first_and_second",	"Statically enable writes to the first two color attachments",					pct,	mask_first_and_second,	kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1791 		AddSingleTestCaseStatic("enable_second_and_last",	"Statically enable writes to the second and last color attachments",			pct,	mask_second_and_last,	kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1792 
1793 		AddSingleTestCaseStatic("disable_all",				"Statically disable writes to all color attachments",							pct,	mask_all,				kChannelCase.enabledChannels, true,  staticOrderingGroup.get(), testCtx);
1794 		AddSingleTestCaseStatic("disable_first",			"Statically disable writes to the first color attachment",						pct,	mask_first,				kChannelCase.enabledChannels, true,  staticOrderingGroup.get(), testCtx);
1795 		AddSingleTestCaseStatic("disable_second",			"Statically disable writes to the second color attachment",						pct,	mask_second,			kChannelCase.enabledChannels, true,  staticOrderingGroup.get(), testCtx);
1796 		AddSingleTestCaseStatic("disable_last",				"Statically disable writes to the last color attachment",						pct,	mask_last,				kChannelCase.enabledChannels, true,  staticOrderingGroup.get(), testCtx);
1797 		AddSingleTestCaseStatic("disable_first_and_second",	"Statically disable writes to the first two color attachments",					pct,	mask_first_and_second,	kChannelCase.enabledChannels, true,  staticOrderingGroup.get(), testCtx);
1798 		AddSingleTestCaseStatic("disable_second_and_last",	"Statically disable writes to the second and last color attachments",			pct,	mask_second_and_last,	kChannelCase.enabledChannels, true,  staticOrderingGroup.get(), testCtx);
1799 
1800 		channelGroup->addChild(staticOrderingGroup.release());
1801 
1802 		colorWriteEnableGroup->addChild(channelGroup.release());
1803 	}
1804 
1805 	return colorWriteEnableGroup.release();
1806 }
1807 
createColorWriteEnable2Tests(tcu::TestContext & testCtx,vk::PipelineConstructionType pct)1808 tcu::TestCaseGroup* createColorWriteEnable2Tests (tcu::TestContext& testCtx, vk::PipelineConstructionType pct)
1809 {
1810 	const deUint32		attachmentCounts[]	{ 3,4,5 };
1811 	const deUint32		attachentMores[]	{ 0,1,2,3 };
1812 
1813 	std::pair<bool, const char*>
1814 		static const	setCweMoments[]
1815 	{
1816 		{ true,		"cwe_before_bind" },
1817 		{ false,	"cwe_after_bind" }
1818 	};
1819 
1820 
1821 	tcu::TestCaseGroup* rootGroup = new tcu::TestCaseGroup(testCtx, "color_write_enable_maxa", "Tests for VK_EXT_color_write_enable");
1822 
1823 	for (const auto& setCweMoment : setCweMoments)
1824 	{
1825 		tcu::TestCaseGroup* setCweGroup = new tcu::TestCaseGroup(testCtx, setCweMoment.second, "A moment when cmdSetColorWriteEnableEXT() is called");
1826 
1827 		for (auto attachmentCount : attachmentCounts)
1828 		{
1829 			for (auto attachentMore : attachentMores)
1830 			{
1831 				const std::string title = "attachments" + std::to_string(attachmentCount) + "_more" + std::to_string(attachentMore);
1832 
1833 				TestParams p;
1834 				p.format				= VK_FORMAT_UNDEFINED;
1835 				p.width					= 32;
1836 				p.height				= 32;
1837 				p.setCweBeforePlBind	= setCweMoment.first;
1838 				p.colorWriteEnables		= true;
1839 				p.attachmentCount		= attachmentCount;
1840 				p.attachmentMore		= attachentMore;
1841 				p.pct					= pct;
1842 				setCweGroup->addChild(new ColorWriteEnable2Test(testCtx, title, "", p));
1843 			}
1844 		}
1845 		rootGroup->addChild(setCweGroup);
1846 	}
1847 	return rootGroup;
1848 }
1849 
1850 } // pipeline
1851 } // vkt
1852