1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Imagination Technologies Ltd.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Blend Tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktPipelineBlendTests.hpp"
26#include "vktPipelineClearUtil.hpp"
27#include "vktPipelineImageUtil.hpp"
28#include "vktPipelineVertexUtil.hpp"
29#include "vktPipelineUniqueRandomIterator.hpp"
30#include "vktPipelineReferenceRenderer.hpp"
31#include "vktTestCase.hpp"
32#include "vkImageUtil.hpp"
33#include "vkMemUtil.hpp"
34#include "vkPlatform.hpp"
35#include "vkPrograms.hpp"
36#include "vkQueryUtil.hpp"
37#include "vkRef.hpp"
38#include "vkRefUtil.hpp"
39#include "tcuImageCompare.hpp"
40#include "tcuPlatform.hpp"
41#include "tcuTextureUtil.hpp"
42#include "deRandom.hpp"
43#include "deStringUtil.hpp"
44#include "deUniquePtr.hpp"
45#include <cstring>
46#include <set>
47#include <sstream>
48#include <vector>
49
50namespace vkt
51{
52namespace pipeline
53{
54
55using namespace vk;
56
57namespace
58{
59
60bool isSupportedBlendFormat (const InstanceInterface& instanceInterface, VkPhysicalDevice device, VkFormat format)
61{
62	VkFormatProperties formatProps;
63
64	instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps);
65
66	return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) &&
67		   (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT);
68}
69
70class BlendStateUniqueRandomIterator : public UniqueRandomIterator<VkPipelineColorBlendAttachmentState>
71{
72public:
73											BlendStateUniqueRandomIterator		(deUint32 numberOfCombinations, int seed);
74	virtual									~BlendStateUniqueRandomIterator		(void) {}
75	VkPipelineColorBlendAttachmentState		getIndexedValue	(deUint32 index);
76
77private:
78	const static VkBlendFactor				m_blendFactors[];
79	const static VkBlendOp					m_blendOps[];
80
81	// Pre-calculated constants
82	const static deUint32					m_blendFactorsLength;
83	const static deUint32					m_blendFactorsLength2;
84	const static deUint32					m_blendFactorsLength3;
85	const static deUint32					m_blendFactorsLength4;
86	const static deUint32					m_blendOpsLength;
87
88	// Total number of cross-combinations of (srcBlendColor x destBlendColor x blendOpColor x srcBlendAlpha x destBlendAlpha x blendOpAlpha)
89	const static deUint32					m_totalBlendStates;
90};
91
92class BlendTest : public vkt::TestCase
93{
94public:
95	enum
96	{
97		QUAD_COUNT = 4
98	};
99
100	const static VkColorComponentFlags	s_colorWriteMasks[QUAD_COUNT];
101	const static tcu::Vec4				s_blendConst;
102
103										BlendTest				(tcu::TestContext&							testContext,
104																 const std::string&							name,
105																 const std::string&							description,
106																 const VkFormat								colorFormat,
107																 const VkPipelineColorBlendAttachmentState	blendStates[QUAD_COUNT]);
108	virtual								~BlendTest				(void);
109	virtual void						initPrograms			(SourceCollections& sourceCollections) const;
110	virtual TestInstance*				createInstance			(Context& context) const;
111
112private:
113	const VkFormat						m_colorFormat;
114	VkPipelineColorBlendAttachmentState	m_blendStates[QUAD_COUNT];
115};
116
117class BlendTestInstance : public vkt::TestInstance
118{
119public:
120										BlendTestInstance		(Context& context, const VkFormat colorFormat, const VkPipelineColorBlendAttachmentState blendStates[BlendTest::QUAD_COUNT]);
121	virtual								~BlendTestInstance		(void);
122	virtual tcu::TestStatus				iterate					(void);
123
124private:
125	static float						getNormChannelThreshold	(const tcu::TextureFormat& format, int numBits);
126	static tcu::Vec4					getFormatThreshold		(const tcu::TextureFormat& format);
127	tcu::TestStatus						verifyImage				(void);
128
129	VkPipelineColorBlendAttachmentState	m_blendStates[BlendTest::QUAD_COUNT];
130
131	const tcu::UVec2					m_renderSize;
132	const VkFormat						m_colorFormat;
133
134	VkImageCreateInfo					m_colorImageCreateInfo;
135	Move<VkImage>						m_colorImage;
136	de::MovePtr<Allocation>				m_colorImageAlloc;
137	Move<VkImageView>					m_colorAttachmentView;
138	Move<VkRenderPass>					m_renderPass;
139	Move<VkFramebuffer>					m_framebuffer;
140
141	Move<VkShaderModule>				m_vertexShaderModule;
142	Move<VkShaderModule>				m_fragmentShaderModule;
143
144	Move<VkBuffer>						m_vertexBuffer;
145	std::vector<Vertex4RGBA>			m_vertices;
146	de::MovePtr<Allocation>				m_vertexBufferAlloc;
147
148	Move<VkPipelineLayout>				m_pipelineLayout;
149	Move<VkPipeline>					m_graphicsPipelines[BlendTest::QUAD_COUNT];
150
151	Move<VkCommandPool>					m_cmdPool;
152	Move<VkCommandBuffer>				m_cmdBuffer;
153
154	Move<VkFence>						m_fence;
155};
156
157
158// BlendStateUniqueRandomIterator
159
160const VkBlendFactor BlendStateUniqueRandomIterator::m_blendFactors[] =
161{
162	VK_BLEND_FACTOR_ZERO,
163	VK_BLEND_FACTOR_ONE,
164	VK_BLEND_FACTOR_SRC_COLOR,
165	VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
166	VK_BLEND_FACTOR_DST_COLOR,
167	VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
168	VK_BLEND_FACTOR_SRC_ALPHA,
169	VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
170	VK_BLEND_FACTOR_DST_ALPHA,
171	VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
172	VK_BLEND_FACTOR_CONSTANT_COLOR,
173	VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
174	VK_BLEND_FACTOR_CONSTANT_ALPHA,
175	VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
176	VK_BLEND_FACTOR_SRC_ALPHA_SATURATE
177};
178
179const VkBlendOp BlendStateUniqueRandomIterator::m_blendOps[] =
180{
181	VK_BLEND_OP_ADD,
182	VK_BLEND_OP_SUBTRACT,
183	VK_BLEND_OP_REVERSE_SUBTRACT,
184	VK_BLEND_OP_MIN,
185	VK_BLEND_OP_MAX
186};
187
188const deUint32 BlendStateUniqueRandomIterator::m_blendFactorsLength		= DE_LENGTH_OF_ARRAY(m_blendFactors);
189const deUint32 BlendStateUniqueRandomIterator::m_blendFactorsLength2	= m_blendFactorsLength * m_blendFactorsLength;
190const deUint32 BlendStateUniqueRandomIterator::m_blendFactorsLength3	= m_blendFactorsLength2 * m_blendFactorsLength;
191const deUint32 BlendStateUniqueRandomIterator::m_blendFactorsLength4	= m_blendFactorsLength3 * m_blendFactorsLength;
192const deUint32 BlendStateUniqueRandomIterator::m_blendOpsLength			= DE_LENGTH_OF_ARRAY(m_blendOps);
193const deUint32 BlendStateUniqueRandomIterator::m_totalBlendStates		= m_blendFactorsLength4 * m_blendOpsLength * m_blendOpsLength;
194
195
196BlendStateUniqueRandomIterator::BlendStateUniqueRandomIterator (deUint32 numberOfCombinations, int seed)
197	: UniqueRandomIterator<VkPipelineColorBlendAttachmentState>(numberOfCombinations, m_totalBlendStates, seed)
198{
199}
200
201VkPipelineColorBlendAttachmentState BlendStateUniqueRandomIterator::getIndexedValue (deUint32 index)
202{
203	const deUint32		blendOpAlphaIndex			= index / (m_blendFactorsLength4 * m_blendOpsLength);
204	const deUint32		blendOpAlphaSeqIndex		= blendOpAlphaIndex * (m_blendFactorsLength4 * m_blendOpsLength);
205
206	const deUint32		destBlendAlphaIndex			= (index - blendOpAlphaSeqIndex) / (m_blendFactorsLength3 * m_blendOpsLength);
207	const deUint32		destBlendAlphaSeqIndex		= destBlendAlphaIndex * (m_blendFactorsLength3 * m_blendOpsLength);
208
209	const deUint32		srcBlendAlphaIndex			= (index - blendOpAlphaSeqIndex - destBlendAlphaSeqIndex) / (m_blendFactorsLength2 * m_blendOpsLength);
210	const deUint32		srcBlendAlphaSeqIndex		= srcBlendAlphaIndex * (m_blendFactorsLength2 * m_blendOpsLength);
211
212	const deUint32		blendOpColorIndex			= (index - blendOpAlphaSeqIndex - destBlendAlphaSeqIndex - srcBlendAlphaSeqIndex) / m_blendFactorsLength2;
213	const deUint32		blendOpColorSeqIndex		= blendOpColorIndex * m_blendFactorsLength2;
214
215	const deUint32		destBlendColorIndex			= (index - blendOpAlphaSeqIndex - destBlendAlphaSeqIndex - srcBlendAlphaSeqIndex - blendOpColorSeqIndex) / m_blendFactorsLength;
216	const deUint32		destBlendColorSeqIndex		= destBlendColorIndex * m_blendFactorsLength;
217
218	const deUint32		srcBlendColorIndex			= index - blendOpAlphaSeqIndex - destBlendAlphaSeqIndex - srcBlendAlphaSeqIndex - blendOpColorSeqIndex - destBlendColorSeqIndex;
219
220	const VkPipelineColorBlendAttachmentState blendAttachmentState =
221	{
222		true,														// VkBool32					blendEnable;
223		m_blendFactors[srcBlendColorIndex],							// VkBlendFactor			srcColorBlendFactor;
224		m_blendFactors[destBlendColorIndex],						// VkBlendFactor			dstColorBlendFactor;
225		m_blendOps[blendOpColorIndex],								// VkBlendOp				colorBlendOp;
226		m_blendFactors[srcBlendAlphaIndex],							// VkBlendFactor			srcAlphaBlendFactor;
227		m_blendFactors[destBlendAlphaIndex],						// VkBlendFactor			dstAlphaBlendFactor;
228		m_blendOps[blendOpAlphaIndex],								// VkBlendOp				alphaBlendOp;
229		VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |		// VkColorComponentFlags	colorWriteMask;
230			VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
231	};
232
233	return blendAttachmentState;
234}
235
236
237// BlendTest
238
239const VkColorComponentFlags BlendTest::s_colorWriteMasks[BlendTest::QUAD_COUNT] = { VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT,	// Pair of channels: R & G
240																					VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT,	// Pair of channels: G & B
241																					VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,	// Pair of channels: B & A
242																					VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT };	// All channels
243
244const tcu::Vec4 BlendTest::s_blendConst = tcu::Vec4(0.1f, 0.2f, 0.3f, 0.4f);
245
246BlendTest::BlendTest (tcu::TestContext&								testContext,
247					  const std::string&							name,
248					  const std::string&							description,
249					  const VkFormat								colorFormat,
250					  const VkPipelineColorBlendAttachmentState		blendStates[QUAD_COUNT])
251	: vkt::TestCase	(testContext, name, description)
252	, m_colorFormat(colorFormat)
253{
254	deMemcpy(m_blendStates, blendStates, sizeof(VkPipelineColorBlendAttachmentState) * QUAD_COUNT);
255}
256
257BlendTest::~BlendTest (void)
258{
259}
260
261TestInstance* BlendTest::createInstance(Context& context) const
262{
263	return new BlendTestInstance(context, m_colorFormat, m_blendStates);
264}
265
266void BlendTest::initPrograms (SourceCollections& sourceCollections) const
267{
268	std::ostringstream fragmentSource;
269
270	sourceCollections.glslSources.add("color_vert") << glu::VertexSource(
271		"#version 310 es\n"
272		"layout(location = 0) in highp vec4 position;\n"
273		"layout(location = 1) in highp vec4 color;\n"
274		"layout(location = 0) out highp vec4 vtxColor;\n"
275		"void main (void)\n"
276		"{\n"
277		"	gl_Position = position;\n"
278		"	vtxColor = color;\n"
279		"}\n");
280
281	fragmentSource << "#version 310 es\n"
282		"layout(location = 0) in highp vec4 vtxColor;\n"
283		"layout(location = 0) out highp vec4 fragColor;\n"
284		"void main (void)\n"
285		"{\n"
286		"	fragColor = vtxColor;\n"
287		"}\n";
288
289	sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(fragmentSource.str());
290}
291
292
293// BlendTestInstance
294
295BlendTestInstance::BlendTestInstance (Context&									context,
296									  const VkFormat							colorFormat,
297									  const VkPipelineColorBlendAttachmentState	blendStates[BlendTest::QUAD_COUNT])
298	: vkt::TestInstance	(context)
299	, m_renderSize		(32, 32)
300	, m_colorFormat		(colorFormat)
301{
302	const DeviceInterface&		vk					= m_context.getDeviceInterface();
303	const VkDevice				vkDevice			= m_context.getDevice();
304	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
305	SimpleAllocator				memAlloc			(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
306
307	// Copy depth operators
308	deMemcpy(m_blendStates, blendStates, sizeof(VkPipelineColorBlendAttachmentState) * BlendTest::QUAD_COUNT);
309
310	// Create color image
311	{
312		if (!isSupportedBlendFormat(context.getInstanceInterface(), context.getPhysicalDevice(), m_colorFormat))
313			throw tcu::NotSupportedError(std::string("Unsupported color blending format: ") + getFormatName(m_colorFormat));
314
315		const VkImageCreateInfo	colorImageParams =
316		{
317			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										// VkStructureType			sType;
318			DE_NULL,																	// const void*				pNext;
319			0u,																			// VkImageCreateFlags		flags;
320			VK_IMAGE_TYPE_2D,															// VkImageType				imageType;
321			m_colorFormat,																// VkFormat					format;
322			{ m_renderSize.x(), m_renderSize.y(), 1u },									// VkExtent3D				extent;
323			1u,																			// deUint32					mipLevels;
324			1u,																			// deUint32					arrayLayers;
325			VK_SAMPLE_COUNT_1_BIT,														// VkSampleCountFlagBits	samples;
326			VK_IMAGE_TILING_OPTIMAL,													// VkImageTiling			tiling;
327			VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,		// VkImageUsageFlags		usage;
328			VK_SHARING_MODE_EXCLUSIVE,													// VkSharingMode			sharingMode;
329			1u,																			// deUint32					queueFamilyIndexCount;
330			&queueFamilyIndex,															// const deUint32*			pQueueFamilyIndices;
331			VK_IMAGE_LAYOUT_UNDEFINED													// VkImageLayout			initialLayout;
332		};
333
334		m_colorImageCreateInfo	= colorImageParams;
335		m_colorImage			= createImage(vk, vkDevice, &m_colorImageCreateInfo);
336
337		// Allocate and bind color image memory
338		m_colorImageAlloc		= memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
339		VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
340	}
341
342	// Create color attachment view
343	{
344		const VkImageViewCreateInfo colorAttachmentViewParams =
345		{
346			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,			// VkStructureType			sType;
347			DE_NULL,											// const void*				pNext;
348			0u,													// VkImageViewCreateFlags	flags;
349			*m_colorImage,										// VkImage					image;
350			VK_IMAGE_VIEW_TYPE_2D,								// VkImageViewType			viewType;
351			m_colorFormat,										// VkFormat					format;
352			{VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY},
353			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }		// VkImageSubresourceRange	subresourceRange;
354		};
355
356		m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
357	}
358
359	// Create render pass
360	{
361		const VkAttachmentDescription colorAttachmentDescription =
362		{
363			0u,													// VkAttachmentDescriptionFlags		flags;
364			m_colorFormat,										// VkFormat							format;
365			VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
366			VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
367			VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
368			VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
369			VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
370			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					initialLayout;
371			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
372		};
373
374		const VkAttachmentReference colorAttachmentReference =
375		{
376			0u,													// deUint32			attachment;
377			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
378		};
379
380		const VkSubpassDescription subpassDescription =
381		{
382			0u,													// VkSubpassDescriptionFlag		flags;
383			VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint			pipelineBindPoint;
384			0u,													// deUint32						inputAttachmentCount;
385			DE_NULL,											// const VkAttachmentReference*	pInputAttachments;
386			1u,													// deUint32						colorAttachmentCount;
387			&colorAttachmentReference,							// const VkAttachmentReference*	pColorAttachments;
388			DE_NULL,											// const VkAttachmentReference*	pResolveAttachments;
389			DE_NULL,											// const VkAttachmentReference*	pDepthStencilAttachment;
390			0u,													// deUint32						preserveAttachmentCount;
391			DE_NULL												// const VkAttachmentReference*	pPreserveAttachments;
392		};
393
394		const VkRenderPassCreateInfo renderPassParams =
395		{
396			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
397			DE_NULL,											// const void*						pNext;
398			0u,													// VkRenderPassCreateFlags			flags;
399			1u,													// deUint32							attachmentCount;
400			&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
401			1u,													// deUint32							subpassCount;
402			&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
403			0u,													// deUint32							dependencyCount;
404			DE_NULL												// const VkSubpassDependency*		pDependencies;
405		};
406
407		m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
408	}
409
410	// Create framebuffer
411	{
412		const VkFramebufferCreateInfo framebufferParams =
413		{
414			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,			// VkStructureType			sType;
415			DE_NULL,											// const void*				pNext;
416			0u,													// VkFramebufferCreateFlags	flags;
417			*m_renderPass,										// VkRenderPass				renderPass;
418			1u,													// deUint32					attachmentCount;
419			&m_colorAttachmentView.get(),						// const VkImageView*		pAttachments;
420			(deUint32)m_renderSize.x(),							// deUint32					width;
421			(deUint32)m_renderSize.y(),							// deUint32					height;
422			1u													// deUint32					layers;
423		};
424
425		m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
426	}
427
428	// Create pipeline layout
429	{
430		const VkPipelineLayoutCreateInfo pipelineLayoutParams =
431		{
432			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType					sType;
433			DE_NULL,											// const void*						pNext;
434			0u,													// VkPipelineLayoutCreateFlags		flags;
435			0u,													// deUint32							setLayoutCount;
436			DE_NULL,											// const VkDescriptorSetLayout*		pSetLayouts;
437			0u,													// deUint32							pushConstantRangeCount;
438			DE_NULL												// const VkPushConstantRange*		pPushConstantRanges;
439		};
440
441		m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
442	}
443
444	m_vertexShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
445	m_fragmentShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
446
447	// Create pipeline
448	{
449		const VkPipelineShaderStageCreateInfo shaderStages[2] =
450		{
451			{
452				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType					sType;
453				DE_NULL,												// const void*						pNext;
454				0u,														// VkPipelineShaderStageCreateFlags	flags;
455				VK_SHADER_STAGE_VERTEX_BIT,								// VkShaderStageFlagBits			stage;
456				*m_vertexShaderModule,									// VkShaderModule					module;
457				"main",													// const char*						pName;
458				DE_NULL													// const VkSpecializationInfo*		pSpecializationInfo;
459			},
460			{
461				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType					sType;
462				DE_NULL,												// const void*						pNext;
463				0u,														// VkPipelineShaderStageCreateFlags	flags;
464				VK_SHADER_STAGE_FRAGMENT_BIT,							// VkShaderStageFlagBits			stage;
465				*m_fragmentShaderModule,								// VkShaderModule					module;
466				"main",													// const char*						pName;
467				DE_NULL													// const VkSpecializationInfo*		pSpecializationInfo;
468			}
469		};
470
471		const VkVertexInputBindingDescription vertexInputBindingDescription =
472		{
473			0u,									// deUint32					binding;
474			sizeof(Vertex4RGBA),				// deUint32					strideInBytes;
475			VK_VERTEX_INPUT_RATE_VERTEX			// VkVertexInputStepRate	inputRate;
476		};
477
478		const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
479		{
480			{
481				0u,								// deUint32	location;
482				0u,								// deUint32	binding;
483				VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat	format;
484				0u								// deUint32	offset;
485			},
486			{
487				1u,								// deUint32	location;
488				0u,								// deUint32	binding;
489				VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat	format;
490				(deUint32)(sizeof(float) * 4),	// deUint32	offset;
491			}
492		};
493
494		const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
495		{
496			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType							sType;
497			DE_NULL,														// const void*								pNext;
498			0u,																// VkPipelineVertexInputStateCreateFlags	flags;
499			1u,																// deUint32									vertexBindingDescriptionCount;
500			&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
501			2u,																// deUint32									vertexAttributeDescriptionCount;
502			vertexInputAttributeDescriptions								// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
503		};
504
505		const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
506		{
507			VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType							sType;
508			DE_NULL,														// const void*								pNext;
509			0u,																// VkPipelineInputAssemblyStateCreateFlags	flags;
510			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							// VkPrimitiveTopology						topology;
511			false															// VkBool32									primitiveRestartEnable;
512		};
513
514		const VkViewport viewport =
515		{
516			0.0f,						// float	x;
517			0.0f,						// float	y;
518			(float)m_renderSize.x(),	// float	width;
519			(float)m_renderSize.y(),	// float	height;
520			0.0f,						// float	minDepth;
521			1.0f						// float	maxDepth;
522		};
523
524		const VkRect2D scissor = { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } };
525
526		const VkPipelineViewportStateCreateInfo viewportStateParams =
527		{
528			VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType						sType;
529			DE_NULL,														// const void*							pNext;
530			0u,																// VkPipelineViewportStateCreateFlags	flags;
531			1u,																// deUint32								viewportCount;
532			&viewport,														// const VkViewport*					pViewports;
533			1u,																// deUint32								scissorCount;
534			&scissor														// const VkRect2D*						pScissors;
535		};
536
537		const VkPipelineRasterizationStateCreateInfo rasterStateParams =
538		{
539			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType							sType;
540			DE_NULL,														// const void*								pNext;
541			0u,																// VkPipelineRasterizationStateCreateFlags	flags;
542			false,															// VkBool32									depthClampEnable;
543			false,															// VkBool32									rasterizerDiscardEnable;
544			VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
545			VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
546			VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
547			false,															// VkBool32									depthBiasEnable;
548			0.0f,															// float									depthBiasConstantFactor;
549			0.0f,															// float									depthBiasClamp;
550			0.0f,															// float									depthBiasSlopeFactor;
551			1.0f															// float									lineWidth;
552		};
553
554		const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
555		{
556			VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType							sType;
557			DE_NULL,													// const void*								pNext;
558			0u,															// VkPipelineMultisampleStateCreateFlags	flags;
559			VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits					rasterizationSamples;
560			false,														// VkBool32									sampleShadingEnable;
561			0.0f,														// float									minSampleShading;
562			DE_NULL,													// const VkSampleMask*						pSampleMask;
563			false,														// VkBool32									alphaToCoverageEnable;
564			false														// VkBool32									alphaToOneEnable;
565		};
566
567		const VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
568		{
569			VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType							sType;
570			DE_NULL,													// const void*								pNext;
571			0u,															// VkPipelineDepthStencilStateCreateFlags	flags;
572			false,														// VkBool32									depthTestEnable;
573			false,														// VkBool32									depthWriteEnable;
574			VK_COMPARE_OP_LESS,											// VkCompareOp								depthCompareOp;
575			false,														// VkBool32									depthBoundsTestEnable;
576			false,														// VkBool32									stencilTestEnable;
577			// VkStencilOpState	front;
578			{
579				VK_STENCIL_OP_KEEP,		// VkStencilOp	failOp;
580				VK_STENCIL_OP_KEEP,		// VkStencilOp	passOp;
581				VK_STENCIL_OP_KEEP,		// VkStencilOp	depthFailOp;
582				VK_COMPARE_OP_NEVER,	// VkCompareOp	compareOp;
583				0u,						// deUint32		compareMask;
584				0u,						// deUint32		writeMask;
585				0u						// deUint32		reference;
586			},
587			// VkStencilOpState	back;
588			{
589				VK_STENCIL_OP_KEEP,		// VkStencilOp	failOp;
590				VK_STENCIL_OP_KEEP,		// VkStencilOp	passOp;
591				VK_STENCIL_OP_KEEP,		// VkStencilOp	depthFailOp;
592				VK_COMPARE_OP_NEVER,	// VkCompareOp	compareOp;
593				0u,						// deUint32		compareMask;
594				0u,						// deUint32		writeMask;
595				0u						// deUint32		reference;
596			},
597			0.0f,														// float			minDepthBounds;
598			1.0f														// float			maxDepthBounds;
599		};
600
601		// The color blend attachment will be set up before creating the graphics pipeline.
602		VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
603		{
604			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
605			DE_NULL,													// const void*									pNext;
606			0u,															// VkPipelineColorBlendStateCreateFlags			flags;
607			false,														// VkBool32										logicOpEnable;
608			VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
609			0u,															// deUint32										attachmentCount;
610			DE_NULL,													// const VkPipelineColorBlendAttachmentState*	pAttachments;
611			{															// float										blendConstants[4];
612				BlendTest::s_blendConst.x(),
613				BlendTest::s_blendConst.y(),
614				BlendTest::s_blendConst.z(),
615				BlendTest::s_blendConst.w()
616			}
617		};
618
619		const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
620		{
621			VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
622			DE_NULL,											// const void*										pNext;
623			0u,													// VkPipelineCreateFlags							flags;
624			2u,													// deUint32											stageCount;
625			shaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
626			&vertexInputStateParams,							// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
627			&inputAssemblyStateParams,							// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
628			DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
629			&viewportStateParams,								// const VkPipelineViewportStateCreateInfo*			pViewportState;
630			&rasterStateParams,									// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
631			&multisampleStateParams,							// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
632			&depthStencilStateParams,							// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
633			&colorBlendStateParams,								// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
634			(const VkPipelineDynamicStateCreateInfo*)DE_NULL,	// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
635			*m_pipelineLayout,									// VkPipelineLayout									layout;
636			*m_renderPass,										// VkRenderPass										renderPass;
637			0u,													// deUint32											subpass;
638			0u,													// VkPipeline										basePipelineHandle;
639			0u													// deInt32											basePipelineIndex;
640		};
641
642		for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
643		{
644			colorBlendStateParams.attachmentCount	= 1u;
645			colorBlendStateParams.pAttachments		= &m_blendStates[quadNdx];
646			m_graphicsPipelines[quadNdx]			= createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
647		}
648	}
649
650	// Create vertex buffer
651	{
652		const VkBufferCreateInfo vertexBufferParams =
653		{
654			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
655			DE_NULL,									// const void*			pNext;
656			0u,											// VkBufferCreateFlags	flags;
657			1024u,										// VkDeviceSize			size;
658			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
659			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
660			1u,											// deUint32				queueFamilyIndexCount;
661			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
662		};
663
664		m_vertices			= createOverlappingQuads();
665		m_vertexBuffer		= createBuffer(vk, vkDevice, &vertexBufferParams);
666		m_vertexBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
667
668		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
669
670		// Adjust vertex colors
671		if (!isFloatFormat(m_colorFormat))
672		{
673			const tcu::TextureFormatInfo formatInfo = tcu::getTextureFormatInfo(mapVkFormat(m_colorFormat));
674			for (size_t vertexNdx = 0; vertexNdx < m_vertices.size(); vertexNdx++)
675				m_vertices[vertexNdx].color = (m_vertices[vertexNdx].color - formatInfo.lookupBias) / formatInfo.lookupScale;
676		}
677
678		// Upload vertex data
679		deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
680
681		const VkMappedMemoryRange flushRange =
682		{
683			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	// VkStructureType	sType;
684			DE_NULL,								// const void*		pNext;
685			m_vertexBufferAlloc->getMemory(),		// VkDeviceMemory	memory;
686			m_vertexBufferAlloc->getOffset(),		// VkDeviceSize		offset;
687			vertexBufferParams.size					// VkDeviceSize		size;
688		};
689
690		vk.flushMappedMemoryRanges(vkDevice, 1, &flushRange);
691	}
692
693	// Create command pool
694	{
695		const VkCommandPoolCreateInfo cmdPoolParams =
696		{
697			VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,		// VkStructureType			sType;
698			DE_NULL,										// const void*				pNext;
699			VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,			// VkCommandPoolCreateFlags	flags;
700			queueFamilyIndex								// deUint32					queueFamilyIndex;
701		};
702
703		m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
704	}
705
706	// Create command buffer
707	{
708		const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
709		{
710			VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// VkStructureType			sType;
711			DE_NULL,										// const void*				pNext;
712			*m_cmdPool,										// VkCommandPool			commandPool;
713			VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// VkCommandBufferLevel		level;
714			1u,												// deUint32				bufferCount;
715		};
716
717		const VkCommandBufferBeginInfo cmdBufferBeginInfo =
718		{
719			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	// VkStructureType					sType;
720			DE_NULL,										// const void*						pNext;
721			0u,												// VkCommandBufferUsageFlags		flags;
722			(const VkCommandBufferInheritanceInfo*)DE_NULL,
723		};
724
725		const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
726
727		const VkRenderPassBeginInfo renderPassBeginInfo =
728		{
729			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,				// VkStructureType		sType;
730			DE_NULL,												// const void*			pNext;
731			*m_renderPass,											// VkRenderPass			renderPass;
732			*m_framebuffer,											// VkFramebuffer		framebuffer;
733			{ { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } },	// VkRect2D				renderArea;
734			1,														// deUint32				clearValueCount;
735			&attachmentClearValue									// const VkClearValue*	pClearValues;
736		};
737
738		// Color image layout transition
739		const VkImageMemoryBarrier imageLayoutBarrier =
740		{
741			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,									// VkStructureType            sType;
742			DE_NULL,																// const void*                pNext;
743			(VkAccessFlags)0,														// VkAccessFlags              srcAccessMask;
744			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,									// VkAccessFlags              dstAccessMask;
745			VK_IMAGE_LAYOUT_UNDEFINED,												// VkImageLayout              oldLayout;
746			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,								// VkImageLayout              newLayout;
747			VK_QUEUE_FAMILY_IGNORED,												// uint32_t                   srcQueueFamilyIndex;
748			VK_QUEUE_FAMILY_IGNORED,												// uint32_t                   dstQueueFamilyIndex;
749			*m_colorImage,															// VkImage                    image;
750			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }							// VkImageSubresourceRange    subresourceRange;
751		};
752
753		m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
754
755		VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
756
757		vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, (VkDependencyFlags)0,
758			0u, DE_NULL, 0u, DE_NULL, 1u, &imageLayoutBarrier);
759
760		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
761
762		const VkDeviceSize quadOffset = (m_vertices.size() / BlendTest::QUAD_COUNT) * sizeof(Vertex4RGBA);
763
764		for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
765		{
766			VkDeviceSize vertexBufferOffset = quadOffset * quadNdx;
767
768			vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelines[quadNdx]);
769			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
770			vk.cmdDraw(*m_cmdBuffer, (deUint32)(m_vertices.size() / BlendTest::QUAD_COUNT), 1, 0, 0);
771		}
772
773		vk.cmdEndRenderPass(*m_cmdBuffer);
774		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
775	}
776
777	// Create fence
778	{
779		const VkFenceCreateInfo fenceParams =
780		{
781			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
782			DE_NULL,								// const void*			pNext;
783			0u										// VkFenceCreateFlags	flags;
784		};
785
786		m_fence = createFence(vk, vkDevice, &fenceParams);
787	}
788}
789
790BlendTestInstance::~BlendTestInstance (void)
791{
792}
793
794tcu::TestStatus BlendTestInstance::iterate (void)
795{
796	const DeviceInterface&		vk			= m_context.getDeviceInterface();
797	const VkDevice				vkDevice	= m_context.getDevice();
798	const VkQueue				queue		= m_context.getUniversalQueue();
799	const VkSubmitInfo			submitInfo	=
800	{
801		VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
802		DE_NULL,						// const void*				pNext;
803		0u,								// deUint32					waitSemaphoreCount;
804		DE_NULL,						// const VkSemaphore*		pWaitSemaphores;
805		(const VkPipelineStageFlags*)DE_NULL,
806		1u,								// deUint32					commandBufferCount;
807		&m_cmdBuffer.get(),				// const VkCommandBuffer*	pCommandBuffers;
808		0u,								// deUint32					signalSemaphoreCount;
809		DE_NULL							// const VkSemaphore*		pSignalSemaphores;
810	};
811
812	VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
813	VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
814	VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
815
816	return verifyImage();
817}
818
819float BlendTestInstance::getNormChannelThreshold (const tcu::TextureFormat& format, int numBits)
820{
821	switch (tcu::getTextureChannelClass(format.type))
822	{
823		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:	return BlendTest::QUAD_COUNT / static_cast<float>((1 << numBits) - 1);
824		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:	return BlendTest::QUAD_COUNT / static_cast<float>((1 << (numBits - 1)) - 1);
825		default:
826			break;
827	}
828
829	DE_ASSERT(false);
830	return 0.0f;
831}
832
833tcu::Vec4 BlendTestInstance::getFormatThreshold (const tcu::TextureFormat& format)
834{
835	using tcu::Vec4;
836	using tcu::TextureFormat;
837
838	Vec4 threshold(0.01f);
839
840	switch (format.type)
841	{
842		case TextureFormat::UNORM_BYTE_44:
843			threshold = Vec4(getNormChannelThreshold(format, 4), getNormChannelThreshold(format, 4), 1.0f, 1.0f);
844			break;
845
846		case TextureFormat::UNORM_SHORT_565:
847			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 6), getNormChannelThreshold(format, 5), 1.0f);
848			break;
849
850		case TextureFormat::UNORM_SHORT_555:
851			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), 1.0f);
852			break;
853
854		case TextureFormat::UNORM_SHORT_4444:
855			threshold = Vec4(getNormChannelThreshold(format, 4));
856			break;
857
858		case TextureFormat::UNORM_SHORT_5551:
859			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), 0.1f);
860			break;
861
862		case TextureFormat::UNORM_INT_1010102_REV:
863		case TextureFormat::SNORM_INT_1010102_REV:
864			threshold = Vec4(getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), 0.34f);
865			break;
866
867		case TextureFormat::UNORM_INT8:
868		case TextureFormat::SNORM_INT8:
869			threshold = Vec4(getNormChannelThreshold(format, 8));
870			break;
871
872		case TextureFormat::UNORM_INT16:
873		case TextureFormat::SNORM_INT16:
874			threshold = Vec4(getNormChannelThreshold(format, 16));
875			break;
876
877		case TextureFormat::UNORM_INT32:
878		case TextureFormat::SNORM_INT32:
879			threshold = Vec4(getNormChannelThreshold(format, 32));
880			break;
881
882		case TextureFormat::HALF_FLOAT:
883			threshold = Vec4(0.005f);
884			break;
885
886		case TextureFormat::FLOAT:
887			threshold = Vec4(0.00001f);
888			break;
889
890		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
891			threshold = Vec4(0.02f, 0.02f, 0.0625f, 1.0f);
892			break;
893
894		case TextureFormat::UNSIGNED_INT_999_E5_REV:
895			threshold = Vec4(0.05f, 0.05f, 0.05f, 1.0f);
896			break;
897
898		default:
899			DE_ASSERT(false);
900	}
901
902	// Return value matching the channel order specified by the format
903	if (format.order == tcu::TextureFormat::BGR || format.order == tcu::TextureFormat::BGRA)
904		return threshold.swizzle(2, 1, 0, 3);
905	else
906		return threshold;
907}
908
909tcu::TestStatus BlendTestInstance::verifyImage (void)
910{
911	const tcu::TextureFormat	tcuColorFormat	= mapVkFormat(m_colorFormat);
912	const tcu::TextureFormat	tcuDepthFormat	= tcu::TextureFormat(); // Undefined depth/stencil format
913	const ColorVertexShader		vertexShader;
914	const ColorFragmentShader	fragmentShader	(tcuColorFormat, tcuDepthFormat);
915	const rr::Program			program			(&vertexShader, &fragmentShader);
916	ReferenceRenderer			refRenderer		(m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
917	bool						compareOk		= false;
918
919	// Render reference image
920	{
921		for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
922		{
923			const VkPipelineColorBlendAttachmentState& blendState = m_blendStates[quadNdx];
924
925			// Set blend state
926			rr::RenderState renderState					(refRenderer.getViewportState());
927			renderState.fragOps.blendMode				= rr::BLENDMODE_STANDARD;
928			renderState.fragOps.blendRGBState.srcFunc	= mapVkBlendFactor(blendState.srcColorBlendFactor);
929			renderState.fragOps.blendRGBState.dstFunc	= mapVkBlendFactor(blendState.dstColorBlendFactor);
930			renderState.fragOps.blendRGBState.equation	= mapVkBlendOp(blendState.colorBlendOp);
931			renderState.fragOps.blendAState.srcFunc		= mapVkBlendFactor(blendState.srcAlphaBlendFactor);
932			renderState.fragOps.blendAState.dstFunc		= mapVkBlendFactor(blendState.dstAlphaBlendFactor);
933			renderState.fragOps.blendAState.equation	= mapVkBlendOp(blendState.alphaBlendOp);
934			renderState.fragOps.blendColor				= BlendTest::s_blendConst;
935			renderState.fragOps.colorMask				= mapVkColorComponentFlags(BlendTest::s_colorWriteMasks[quadNdx]);
936
937			refRenderer.draw(renderState,
938							 rr::PRIMITIVETYPE_TRIANGLES,
939							 std::vector<Vertex4RGBA>(m_vertices.begin() + quadNdx * 6,
940													  m_vertices.begin() + (quadNdx + 1) * 6));
941		}
942	}
943
944
945	// Compare result with reference image
946	{
947		const DeviceInterface&				vk							= m_context.getDeviceInterface();
948		const VkDevice						vkDevice					= m_context.getDevice();
949		const VkQueue						queue						= m_context.getUniversalQueue();
950		const deUint32						queueFamilyIndex			= m_context.getUniversalQueueFamilyIndex();
951		SimpleAllocator						allocator					(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
952		de::UniquePtr<tcu::TextureLevel>	result						(readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize).release());
953		const tcu::Vec4						threshold					(getFormatThreshold(tcuColorFormat));
954
955		compareOk = tcu::floatThresholdCompare(m_context.getTestContext().getLog(),
956											   "FloatImageCompare",
957											   "Image comparison",
958											   refRenderer.getAccess(),
959											   result->getAccess(),
960											   threshold,
961											   tcu::COMPARE_LOG_RESULT);
962	}
963
964	if (compareOk)
965		return tcu::TestStatus::pass("Result image matches reference");
966	else
967		return tcu::TestStatus::fail("Image mismatch");
968}
969
970} // anonymous
971
972std::string getBlendStateName (const VkPipelineColorBlendAttachmentState& blendState)
973{
974	const char* shortBlendFactorNames[] =
975	{
976		"z",		// VK_BLEND_ZERO
977		"o",		// VK_BLEND_ONE
978		"sc",		// VK_BLEND_SRC_COLOR
979		"1msc",		// VK_BLEND_ONE_MINUS_SRC_COLOR
980		"dc",		// VK_BLEND_DEST_COLOR
981		"1mdc",		// VK_BLEND_ONE_MINUS_DEST_COLOR
982		"sa",		// VK_BLEND_SRC_ALPHA
983		"1msa",		// VK_BLEND_ONE_MINUS_SRC_ALPHA
984		"da",		// VK_BLEND_DEST_ALPHA
985		"1mda",		// VK_BLEND_ONE_MINUS_DEST_ALPHA
986		"cc",		// VK_BLEND_CONSTANT_COLOR
987		"1mcc",		// VK_BLEND_ONE_MINUS_CONSTANT_COLOR
988		"ca",		// VK_BLEND_CONSTANT_ALPHA
989		"1mca",		// VK_BLEND_ONE_MINUS_CONSTANT_ALPHA
990		"sas"		// VK_BLEND_SRC_ALPHA_SATURATE
991	};
992
993	const char* blendOpNames[] =
994	{
995		"add",		// VK_BLEND_OP_ADD
996		"sub",		// VK_BLEND_OP_SUBTRACT
997		"rsub",		// VK_BLEND_OP_REVERSE_SUBTRACT
998		"min",		// VK_BLEND_OP_MIN
999		"max",		// VK_BLEND_OP_MAX
1000	};
1001
1002	std::ostringstream shortName;
1003
1004	shortName << "color_" << shortBlendFactorNames[blendState.srcColorBlendFactor] << "_" << shortBlendFactorNames[blendState.dstColorBlendFactor] << "_" << blendOpNames[blendState.colorBlendOp];
1005	shortName << "_alpha_" << shortBlendFactorNames[blendState.srcAlphaBlendFactor] << "_" << shortBlendFactorNames[blendState.dstAlphaBlendFactor] << "_" << blendOpNames[blendState.alphaBlendOp];
1006
1007	return shortName.str();
1008}
1009
1010std::string getBlendStateSetName (const VkPipelineColorBlendAttachmentState blendStates[BlendTest::QUAD_COUNT])
1011{
1012	std::ostringstream name;
1013
1014	for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
1015	{
1016		name << getBlendStateName(blendStates[quadNdx]);
1017
1018		if (quadNdx < BlendTest::QUAD_COUNT - 1)
1019			name << "-";
1020	}
1021
1022	return name.str();
1023}
1024
1025std::string getBlendStateSetDescription (const VkPipelineColorBlendAttachmentState blendStates[BlendTest::QUAD_COUNT])
1026{
1027	std::ostringstream description;
1028
1029	description << "Draws " << BlendTest::QUAD_COUNT << " quads with the following blend states:\n";
1030
1031	for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
1032		description << blendStates[quadNdx] << "\n";
1033
1034	return description.str();
1035}
1036
1037std::string getFormatCaseName (VkFormat format)
1038{
1039	const std::string fullName = getFormatName(format);
1040
1041	DE_ASSERT(de::beginsWith(fullName, "VK_FORMAT_"));
1042
1043	return de::toLower(fullName.substr(10));
1044}
1045
1046tcu::TestCaseGroup* createBlendTests (tcu::TestContext& testCtx)
1047{
1048	const deUint32 blendStatesPerFormat = 100 * BlendTest::QUAD_COUNT;
1049
1050	// Formats that are dEQP-compatible, non-integer and uncompressed
1051	const VkFormat blendFormats[] =
1052	{
1053		VK_FORMAT_R4G4_UNORM_PACK8,
1054		VK_FORMAT_R4G4B4A4_UNORM_PACK16,
1055		VK_FORMAT_R5G6B5_UNORM_PACK16,
1056		VK_FORMAT_R5G5B5A1_UNORM_PACK16,
1057		VK_FORMAT_R8_UNORM,
1058		VK_FORMAT_R8_SNORM,
1059		VK_FORMAT_R8_SRGB,
1060		VK_FORMAT_R8G8_UNORM,
1061		VK_FORMAT_R8G8_SNORM,
1062		VK_FORMAT_R8G8_SRGB,
1063		VK_FORMAT_R8G8B8_UNORM,
1064		VK_FORMAT_R8G8B8_SNORM,
1065		VK_FORMAT_R8G8B8_SRGB,
1066		VK_FORMAT_R8G8B8A8_UNORM,
1067		VK_FORMAT_R8G8B8A8_SNORM,
1068		VK_FORMAT_R8G8B8A8_SRGB,
1069		VK_FORMAT_A2R10G10B10_UNORM_PACK32,
1070		VK_FORMAT_R16_UNORM,
1071		VK_FORMAT_R16_SNORM,
1072		VK_FORMAT_R16_SFLOAT,
1073		VK_FORMAT_R16G16_UNORM,
1074		VK_FORMAT_R16G16_SNORM,
1075		VK_FORMAT_R16G16_SFLOAT,
1076		VK_FORMAT_R16G16B16_UNORM,
1077		VK_FORMAT_R16G16B16_SNORM,
1078		VK_FORMAT_R16G16B16_SFLOAT,
1079		VK_FORMAT_R16G16B16A16_UNORM,
1080		VK_FORMAT_R16G16B16A16_SNORM,
1081		VK_FORMAT_R16G16B16A16_SFLOAT,
1082		VK_FORMAT_R32_SFLOAT,
1083		VK_FORMAT_R32G32_SFLOAT,
1084		VK_FORMAT_R32G32B32_SFLOAT,
1085		VK_FORMAT_R32G32B32A32_SFLOAT,
1086		VK_FORMAT_B10G11R11_UFLOAT_PACK32,
1087		VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
1088		VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1089		VK_FORMAT_B5G5R5A1_UNORM_PACK16,
1090	};
1091
1092	de::MovePtr<tcu::TestCaseGroup>		blendTests		(new tcu::TestCaseGroup(testCtx, "blend", "Blend tests"));
1093	de::MovePtr<tcu::TestCaseGroup>		formatTests		(new tcu::TestCaseGroup(testCtx, "format", "Uses different blend formats"));
1094	BlendStateUniqueRandomIterator		blendStateItr	(blendStatesPerFormat, 123);
1095
1096	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(blendFormats); formatNdx++)
1097	{
1098		const VkFormat					format			= blendFormats[formatNdx];
1099		de::MovePtr<tcu::TestCaseGroup>	formatTest		(new tcu::TestCaseGroup(testCtx,
1100																				getFormatCaseName(format).c_str(),
1101																				(std::string("Uses format ") + getFormatName(format)).c_str()));
1102		de::MovePtr<tcu::TestCaseGroup>	blendStateTests;
1103		{
1104			std::ostringstream blendStateDescription;
1105			blendStateDescription << "Combines blend factors, operators and channel write masks. The constant color used in all tests is " << BlendTest::s_blendConst;
1106			blendStateTests = de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, "states", blendStateDescription.str().c_str()));
1107		}
1108
1109		blendStateItr.reset();
1110
1111		while (blendStateItr.hasNext())
1112		{
1113			VkPipelineColorBlendAttachmentState quadBlendConfigs[BlendTest::QUAD_COUNT];
1114
1115			for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
1116			{
1117				quadBlendConfigs[quadNdx]					= blendStateItr.next();
1118				quadBlendConfigs[quadNdx].colorWriteMask	= BlendTest::s_colorWriteMasks[quadNdx];
1119			}
1120
1121			blendStateTests->addChild(new BlendTest(testCtx,
1122													getBlendStateSetName(quadBlendConfigs),
1123													getBlendStateSetDescription(quadBlendConfigs),
1124													format,
1125													quadBlendConfigs));
1126		}
1127		formatTest->addChild(blendStateTests.release());
1128		formatTests->addChild(formatTest.release());
1129	}
1130	blendTests->addChild(formatTests.release());
1131
1132	return blendTests.release();
1133}
1134
1135} // pipeline
1136} // vkt
1137