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	m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
695
696	// Create command buffer
697	{
698		const VkCommandBufferBeginInfo cmdBufferBeginInfo =
699		{
700			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	// VkStructureType					sType;
701			DE_NULL,										// const void*						pNext;
702			0u,												// VkCommandBufferUsageFlags		flags;
703			(const VkCommandBufferInheritanceInfo*)DE_NULL,
704		};
705
706		const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
707
708		const VkRenderPassBeginInfo renderPassBeginInfo =
709		{
710			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,				// VkStructureType		sType;
711			DE_NULL,												// const void*			pNext;
712			*m_renderPass,											// VkRenderPass			renderPass;
713			*m_framebuffer,											// VkFramebuffer		framebuffer;
714			{ { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } },	// VkRect2D				renderArea;
715			1,														// deUint32				clearValueCount;
716			&attachmentClearValue									// const VkClearValue*	pClearValues;
717		};
718
719		// Color image layout transition
720		const VkImageMemoryBarrier imageLayoutBarrier =
721		{
722			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,									// VkStructureType            sType;
723			DE_NULL,																// const void*                pNext;
724			(VkAccessFlags)0,														// VkAccessFlags              srcAccessMask;
725			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,									// VkAccessFlags              dstAccessMask;
726			VK_IMAGE_LAYOUT_UNDEFINED,												// VkImageLayout              oldLayout;
727			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,								// VkImageLayout              newLayout;
728			VK_QUEUE_FAMILY_IGNORED,												// uint32_t                   srcQueueFamilyIndex;
729			VK_QUEUE_FAMILY_IGNORED,												// uint32_t                   dstQueueFamilyIndex;
730			*m_colorImage,															// VkImage                    image;
731			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }							// VkImageSubresourceRange    subresourceRange;
732		};
733
734		m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
735
736		VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
737
738		vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, (VkDependencyFlags)0,
739			0u, DE_NULL, 0u, DE_NULL, 1u, &imageLayoutBarrier);
740
741		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
742
743		const VkDeviceSize quadOffset = (m_vertices.size() / BlendTest::QUAD_COUNT) * sizeof(Vertex4RGBA);
744
745		for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
746		{
747			VkDeviceSize vertexBufferOffset = quadOffset * quadNdx;
748
749			vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelines[quadNdx]);
750			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
751			vk.cmdDraw(*m_cmdBuffer, (deUint32)(m_vertices.size() / BlendTest::QUAD_COUNT), 1, 0, 0);
752		}
753
754		vk.cmdEndRenderPass(*m_cmdBuffer);
755		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
756	}
757
758	// Create fence
759	m_fence = createFence(vk, vkDevice);
760}
761
762BlendTestInstance::~BlendTestInstance (void)
763{
764}
765
766tcu::TestStatus BlendTestInstance::iterate (void)
767{
768	const DeviceInterface&		vk			= m_context.getDeviceInterface();
769	const VkDevice				vkDevice	= m_context.getDevice();
770	const VkQueue				queue		= m_context.getUniversalQueue();
771	const VkSubmitInfo			submitInfo	=
772	{
773		VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
774		DE_NULL,						// const void*				pNext;
775		0u,								// deUint32					waitSemaphoreCount;
776		DE_NULL,						// const VkSemaphore*		pWaitSemaphores;
777		(const VkPipelineStageFlags*)DE_NULL,
778		1u,								// deUint32					commandBufferCount;
779		&m_cmdBuffer.get(),				// const VkCommandBuffer*	pCommandBuffers;
780		0u,								// deUint32					signalSemaphoreCount;
781		DE_NULL							// const VkSemaphore*		pSignalSemaphores;
782	};
783
784	VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
785	VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
786	VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
787
788	return verifyImage();
789}
790
791float BlendTestInstance::getNormChannelThreshold (const tcu::TextureFormat& format, int numBits)
792{
793	switch (tcu::getTextureChannelClass(format.type))
794	{
795		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:	return BlendTest::QUAD_COUNT / static_cast<float>((1 << numBits) - 1);
796		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:	return BlendTest::QUAD_COUNT / static_cast<float>((1 << (numBits - 1)) - 1);
797		default:
798			break;
799	}
800
801	DE_ASSERT(false);
802	return 0.0f;
803}
804
805tcu::Vec4 BlendTestInstance::getFormatThreshold (const tcu::TextureFormat& format)
806{
807	using tcu::Vec4;
808	using tcu::TextureFormat;
809
810	Vec4 threshold(0.01f);
811
812	switch (format.type)
813	{
814		case TextureFormat::UNORM_BYTE_44:
815			threshold = Vec4(getNormChannelThreshold(format, 4), getNormChannelThreshold(format, 4), 1.0f, 1.0f);
816			break;
817
818		case TextureFormat::UNORM_SHORT_565:
819			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 6), getNormChannelThreshold(format, 5), 1.0f);
820			break;
821
822		case TextureFormat::UNORM_SHORT_555:
823			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), 1.0f);
824			break;
825
826		case TextureFormat::UNORM_SHORT_4444:
827			threshold = Vec4(getNormChannelThreshold(format, 4));
828			break;
829
830		case TextureFormat::UNORM_SHORT_5551:
831			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), 0.1f);
832			break;
833
834		case TextureFormat::UNORM_INT_1010102_REV:
835		case TextureFormat::SNORM_INT_1010102_REV:
836			threshold = Vec4(getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), 0.34f);
837			break;
838
839		case TextureFormat::UNORM_INT8:
840		case TextureFormat::SNORM_INT8:
841			threshold = Vec4(getNormChannelThreshold(format, 8));
842			break;
843
844		case TextureFormat::UNORM_INT16:
845		case TextureFormat::SNORM_INT16:
846			threshold = Vec4(getNormChannelThreshold(format, 16));
847			break;
848
849		case TextureFormat::UNORM_INT32:
850		case TextureFormat::SNORM_INT32:
851			threshold = Vec4(getNormChannelThreshold(format, 32));
852			break;
853
854		case TextureFormat::HALF_FLOAT:
855			threshold = Vec4(0.005f);
856			break;
857
858		case TextureFormat::FLOAT:
859			threshold = Vec4(0.00001f);
860			break;
861
862		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
863			threshold = Vec4(0.02f, 0.02f, 0.0625f, 1.0f);
864			break;
865
866		case TextureFormat::UNSIGNED_INT_999_E5_REV:
867			threshold = Vec4(0.05f, 0.05f, 0.05f, 1.0f);
868			break;
869
870		default:
871			DE_ASSERT(false);
872	}
873
874	// Return value matching the channel order specified by the format
875	if (format.order == tcu::TextureFormat::BGR || format.order == tcu::TextureFormat::BGRA)
876		return threshold.swizzle(2, 1, 0, 3);
877	else
878		return threshold;
879}
880
881tcu::TestStatus BlendTestInstance::verifyImage (void)
882{
883	const tcu::TextureFormat	tcuColorFormat	= mapVkFormat(m_colorFormat);
884	const tcu::TextureFormat	tcuDepthFormat	= tcu::TextureFormat(); // Undefined depth/stencil format
885	const ColorVertexShader		vertexShader;
886	const ColorFragmentShader	fragmentShader	(tcuColorFormat, tcuDepthFormat);
887	const rr::Program			program			(&vertexShader, &fragmentShader);
888	ReferenceRenderer			refRenderer		(m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
889	bool						compareOk		= false;
890
891	// Render reference image
892	{
893		for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
894		{
895			const VkPipelineColorBlendAttachmentState& blendState = m_blendStates[quadNdx];
896
897			// Set blend state
898			rr::RenderState renderState					(refRenderer.getViewportState());
899			renderState.fragOps.blendMode				= rr::BLENDMODE_STANDARD;
900			renderState.fragOps.blendRGBState.srcFunc	= mapVkBlendFactor(blendState.srcColorBlendFactor);
901			renderState.fragOps.blendRGBState.dstFunc	= mapVkBlendFactor(blendState.dstColorBlendFactor);
902			renderState.fragOps.blendRGBState.equation	= mapVkBlendOp(blendState.colorBlendOp);
903			renderState.fragOps.blendAState.srcFunc		= mapVkBlendFactor(blendState.srcAlphaBlendFactor);
904			renderState.fragOps.blendAState.dstFunc		= mapVkBlendFactor(blendState.dstAlphaBlendFactor);
905			renderState.fragOps.blendAState.equation	= mapVkBlendOp(blendState.alphaBlendOp);
906			renderState.fragOps.blendColor				= BlendTest::s_blendConst;
907			renderState.fragOps.colorMask				= mapVkColorComponentFlags(BlendTest::s_colorWriteMasks[quadNdx]);
908
909			refRenderer.draw(renderState,
910							 rr::PRIMITIVETYPE_TRIANGLES,
911							 std::vector<Vertex4RGBA>(m_vertices.begin() + quadNdx * 6,
912													  m_vertices.begin() + (quadNdx + 1) * 6));
913		}
914	}
915
916
917	// Compare result with reference image
918	{
919		const DeviceInterface&				vk							= m_context.getDeviceInterface();
920		const VkDevice						vkDevice					= m_context.getDevice();
921		const VkQueue						queue						= m_context.getUniversalQueue();
922		const deUint32						queueFamilyIndex			= m_context.getUniversalQueueFamilyIndex();
923		SimpleAllocator						allocator					(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
924		de::UniquePtr<tcu::TextureLevel>	result						(readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize).release());
925		const tcu::Vec4						threshold					(getFormatThreshold(tcuColorFormat));
926
927		compareOk = tcu::floatThresholdCompare(m_context.getTestContext().getLog(),
928											   "FloatImageCompare",
929											   "Image comparison",
930											   refRenderer.getAccess(),
931											   result->getAccess(),
932											   threshold,
933											   tcu::COMPARE_LOG_RESULT);
934	}
935
936	if (compareOk)
937		return tcu::TestStatus::pass("Result image matches reference");
938	else
939		return tcu::TestStatus::fail("Image mismatch");
940}
941
942} // anonymous
943
944std::string getBlendStateName (const VkPipelineColorBlendAttachmentState& blendState)
945{
946	const char* shortBlendFactorNames[] =
947	{
948		"z",		// VK_BLEND_ZERO
949		"o",		// VK_BLEND_ONE
950		"sc",		// VK_BLEND_SRC_COLOR
951		"1msc",		// VK_BLEND_ONE_MINUS_SRC_COLOR
952		"dc",		// VK_BLEND_DEST_COLOR
953		"1mdc",		// VK_BLEND_ONE_MINUS_DEST_COLOR
954		"sa",		// VK_BLEND_SRC_ALPHA
955		"1msa",		// VK_BLEND_ONE_MINUS_SRC_ALPHA
956		"da",		// VK_BLEND_DEST_ALPHA
957		"1mda",		// VK_BLEND_ONE_MINUS_DEST_ALPHA
958		"cc",		// VK_BLEND_CONSTANT_COLOR
959		"1mcc",		// VK_BLEND_ONE_MINUS_CONSTANT_COLOR
960		"ca",		// VK_BLEND_CONSTANT_ALPHA
961		"1mca",		// VK_BLEND_ONE_MINUS_CONSTANT_ALPHA
962		"sas"		// VK_BLEND_SRC_ALPHA_SATURATE
963	};
964
965	const char* blendOpNames[] =
966	{
967		"add",		// VK_BLEND_OP_ADD
968		"sub",		// VK_BLEND_OP_SUBTRACT
969		"rsub",		// VK_BLEND_OP_REVERSE_SUBTRACT
970		"min",		// VK_BLEND_OP_MIN
971		"max",		// VK_BLEND_OP_MAX
972	};
973
974	std::ostringstream shortName;
975
976	shortName << "color_" << shortBlendFactorNames[blendState.srcColorBlendFactor] << "_" << shortBlendFactorNames[blendState.dstColorBlendFactor] << "_" << blendOpNames[blendState.colorBlendOp];
977	shortName << "_alpha_" << shortBlendFactorNames[blendState.srcAlphaBlendFactor] << "_" << shortBlendFactorNames[blendState.dstAlphaBlendFactor] << "_" << blendOpNames[blendState.alphaBlendOp];
978
979	return shortName.str();
980}
981
982std::string getBlendStateSetName (const VkPipelineColorBlendAttachmentState blendStates[BlendTest::QUAD_COUNT])
983{
984	std::ostringstream name;
985
986	for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
987	{
988		name << getBlendStateName(blendStates[quadNdx]);
989
990		if (quadNdx < BlendTest::QUAD_COUNT - 1)
991			name << "-";
992	}
993
994	return name.str();
995}
996
997std::string getBlendStateSetDescription (const VkPipelineColorBlendAttachmentState blendStates[BlendTest::QUAD_COUNT])
998{
999	std::ostringstream description;
1000
1001	description << "Draws " << BlendTest::QUAD_COUNT << " quads with the following blend states:\n";
1002
1003	for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
1004		description << blendStates[quadNdx] << "\n";
1005
1006	return description.str();
1007}
1008
1009std::string getFormatCaseName (VkFormat format)
1010{
1011	const std::string fullName = getFormatName(format);
1012
1013	DE_ASSERT(de::beginsWith(fullName, "VK_FORMAT_"));
1014
1015	return de::toLower(fullName.substr(10));
1016}
1017
1018tcu::TestCaseGroup* createBlendTests (tcu::TestContext& testCtx)
1019{
1020	const deUint32 blendStatesPerFormat = 100 * BlendTest::QUAD_COUNT;
1021
1022	// Formats that are dEQP-compatible, non-integer and uncompressed
1023	const VkFormat blendFormats[] =
1024	{
1025		VK_FORMAT_R4G4_UNORM_PACK8,
1026		VK_FORMAT_R4G4B4A4_UNORM_PACK16,
1027		VK_FORMAT_R5G6B5_UNORM_PACK16,
1028		VK_FORMAT_R5G5B5A1_UNORM_PACK16,
1029		VK_FORMAT_R8_UNORM,
1030		VK_FORMAT_R8_SNORM,
1031		VK_FORMAT_R8_SRGB,
1032		VK_FORMAT_R8G8_UNORM,
1033		VK_FORMAT_R8G8_SNORM,
1034		VK_FORMAT_R8G8_SRGB,
1035		VK_FORMAT_R8G8B8_UNORM,
1036		VK_FORMAT_R8G8B8_SNORM,
1037		VK_FORMAT_R8G8B8_SRGB,
1038		VK_FORMAT_R8G8B8A8_UNORM,
1039		VK_FORMAT_R8G8B8A8_SNORM,
1040		VK_FORMAT_R8G8B8A8_SRGB,
1041		VK_FORMAT_A2R10G10B10_UNORM_PACK32,
1042		VK_FORMAT_R16_UNORM,
1043		VK_FORMAT_R16_SNORM,
1044		VK_FORMAT_R16_SFLOAT,
1045		VK_FORMAT_R16G16_UNORM,
1046		VK_FORMAT_R16G16_SNORM,
1047		VK_FORMAT_R16G16_SFLOAT,
1048		VK_FORMAT_R16G16B16_UNORM,
1049		VK_FORMAT_R16G16B16_SNORM,
1050		VK_FORMAT_R16G16B16_SFLOAT,
1051		VK_FORMAT_R16G16B16A16_UNORM,
1052		VK_FORMAT_R16G16B16A16_SNORM,
1053		VK_FORMAT_R16G16B16A16_SFLOAT,
1054		VK_FORMAT_R32_SFLOAT,
1055		VK_FORMAT_R32G32_SFLOAT,
1056		VK_FORMAT_R32G32B32_SFLOAT,
1057		VK_FORMAT_R32G32B32A32_SFLOAT,
1058		VK_FORMAT_B10G11R11_UFLOAT_PACK32,
1059		VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
1060		VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1061		VK_FORMAT_B5G5R5A1_UNORM_PACK16,
1062	};
1063
1064	de::MovePtr<tcu::TestCaseGroup>		blendTests		(new tcu::TestCaseGroup(testCtx, "blend", "Blend tests"));
1065	de::MovePtr<tcu::TestCaseGroup>		formatTests		(new tcu::TestCaseGroup(testCtx, "format", "Uses different blend formats"));
1066	BlendStateUniqueRandomIterator		blendStateItr	(blendStatesPerFormat, 123);
1067
1068	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(blendFormats); formatNdx++)
1069	{
1070		const VkFormat					format			= blendFormats[formatNdx];
1071		de::MovePtr<tcu::TestCaseGroup>	formatTest		(new tcu::TestCaseGroup(testCtx,
1072																				getFormatCaseName(format).c_str(),
1073																				(std::string("Uses format ") + getFormatName(format)).c_str()));
1074		de::MovePtr<tcu::TestCaseGroup>	blendStateTests;
1075		{
1076			std::ostringstream blendStateDescription;
1077			blendStateDescription << "Combines blend factors, operators and channel write masks. The constant color used in all tests is " << BlendTest::s_blendConst;
1078			blendStateTests = de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, "states", blendStateDescription.str().c_str()));
1079		}
1080
1081		blendStateItr.reset();
1082
1083		while (blendStateItr.hasNext())
1084		{
1085			VkPipelineColorBlendAttachmentState quadBlendConfigs[BlendTest::QUAD_COUNT];
1086
1087			for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
1088			{
1089				quadBlendConfigs[quadNdx]					= blendStateItr.next();
1090				quadBlendConfigs[quadNdx].colorWriteMask	= BlendTest::s_colorWriteMasks[quadNdx];
1091			}
1092
1093			blendStateTests->addChild(new BlendTest(testCtx,
1094													getBlendStateSetName(quadBlendConfigs),
1095													getBlendStateSetDescription(quadBlendConfigs),
1096													format,
1097													quadBlendConfigs));
1098		}
1099		formatTest->addChild(blendStateTests.release());
1100		formatTests->addChild(formatTest.release());
1101	}
1102	blendTests->addChild(formatTests.release());
1103
1104	return blendTests.release();
1105}
1106
1107} // pipeline
1108} // vkt
1109