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