vktPipelineBlendTests.cpp revision 978d3d585aa549eb1e729b51e9d85fc6477240f9
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			-1.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 VkPipelineDynamicStateCreateInfo dynamicStateParams =
620		{
621			VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,		// VkStructureType						sType;
622			DE_NULL,													// const void*							pNext;
623			0u,															// VkPipelineDynamicStateCreateFlags	flags;
624			0u,															// deUint32								dynamicStateCount;
625			DE_NULL														// const VkDynamicState*				pDynamicStates;
626		};
627
628		const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
629		{
630			VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
631			DE_NULL,											// const void*										pNext;
632			0u,													// VkPipelineCreateFlags							flags;
633			2u,													// deUint32											stageCount;
634			shaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
635			&vertexInputStateParams,							// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
636			&inputAssemblyStateParams,							// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
637			DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
638			&viewportStateParams,								// const VkPipelineViewportStateCreateInfo*			pViewportState;
639			&rasterStateParams,									// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
640			&multisampleStateParams,							// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
641			&depthStencilStateParams,							// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
642			&colorBlendStateParams,								// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
643			&dynamicStateParams,								// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
644			*m_pipelineLayout,									// VkPipelineLayout									layout;
645			*m_renderPass,										// VkRenderPass										renderPass;
646			0u,													// deUint32											subpass;
647			0u,													// VkPipeline										basePipelineHandle;
648			0u													// deInt32											basePipelineIndex;
649		};
650
651		for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
652		{
653			colorBlendStateParams.attachmentCount	= 1u;
654			colorBlendStateParams.pAttachments		= &m_blendStates[quadNdx];
655			m_graphicsPipelines[quadNdx]			= createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
656		}
657	}
658
659	// Create vertex buffer
660	{
661		const VkBufferCreateInfo vertexBufferParams =
662		{
663			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
664			DE_NULL,									// const void*			pNext;
665			0u,											// VkBufferCreateFlags	flags;
666			1024u,										// VkDeviceSize			size;
667			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
668			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
669			1u,											// deUint32				queueFamilyIndexCount;
670			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
671		};
672
673		m_vertices			= createOverlappingQuads();
674		m_vertexBuffer		= createBuffer(vk, vkDevice, &vertexBufferParams);
675		m_vertexBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
676
677		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
678
679		// Adjust vertex colors
680		if (!isFloatFormat(m_colorFormat))
681		{
682			const tcu::TextureFormatInfo formatInfo = tcu::getTextureFormatInfo(mapVkFormat(m_colorFormat));
683			for (size_t vertexNdx = 0; vertexNdx < m_vertices.size(); vertexNdx++)
684				m_vertices[vertexNdx].color = (m_vertices[vertexNdx].color - formatInfo.lookupBias) / formatInfo.lookupScale;
685		}
686
687		// Upload vertex data
688		deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
689
690		const VkMappedMemoryRange flushRange =
691		{
692			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	// VkStructureType	sType;
693			DE_NULL,								// const void*		pNext;
694			m_vertexBufferAlloc->getMemory(),		// VkDeviceMemory	memory;
695			m_vertexBufferAlloc->getOffset(),		// VkDeviceSize		offset;
696			vertexBufferParams.size					// VkDeviceSize		size;
697		};
698
699		vk.flushMappedMemoryRanges(vkDevice, 1, &flushRange);
700	}
701
702	// Create command pool
703	{
704		const VkCommandPoolCreateInfo cmdPoolParams =
705		{
706			VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,		// VkStructureType			sType;
707			DE_NULL,										// const void*				pNext;
708			VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,			// VkCommandPoolCreateFlags	flags;
709			queueFamilyIndex								// deUint32					queueFamilyIndex;
710		};
711
712		m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
713	}
714
715	// Create command buffer
716	{
717		const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
718		{
719			VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// VkStructureType			sType;
720			DE_NULL,										// const void*				pNext;
721			*m_cmdPool,										// VkCommandPool			commandPool;
722			VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// VkCommandBufferLevel		level;
723			1u,												// deUint32				bufferCount;
724		};
725
726		const VkCommandBufferBeginInfo cmdBufferBeginInfo =
727		{
728			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	// VkStructureType					sType;
729			DE_NULL,										// const void*						pNext;
730			0u,												// VkCommandBufferUsageFlags		flags;
731			(const VkCommandBufferInheritanceInfo*)DE_NULL,
732		};
733
734		const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
735
736		const VkRenderPassBeginInfo renderPassBeginInfo =
737		{
738			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,				// VkStructureType		sType;
739			DE_NULL,												// const void*			pNext;
740			*m_renderPass,											// VkRenderPass			renderPass;
741			*m_framebuffer,											// VkFramebuffer		framebuffer;
742			{ { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } },	// VkRect2D				renderArea;
743			1,														// deUint32				clearValueCount;
744			&attachmentClearValue									// const VkClearValue*	pClearValues;
745		};
746
747		m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
748
749		VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
750		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
751
752		const VkDeviceSize quadOffset = (m_vertices.size() / BlendTest::QUAD_COUNT) * sizeof(Vertex4RGBA);
753
754		for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
755		{
756			VkDeviceSize vertexBufferOffset = quadOffset * quadNdx;
757
758			vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelines[quadNdx]);
759			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
760			vk.cmdDraw(*m_cmdBuffer, (deUint32)(m_vertices.size() / BlendTest::QUAD_COUNT), 1, 0, 0);
761		}
762
763		vk.cmdEndRenderPass(*m_cmdBuffer);
764		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
765	}
766
767	// Create fence
768	{
769		const VkFenceCreateInfo fenceParams =
770		{
771			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
772			DE_NULL,								// const void*			pNext;
773			0u										// VkFenceCreateFlags	flags;
774		};
775
776		m_fence = createFence(vk, vkDevice, &fenceParams);
777	}
778}
779
780BlendTestInstance::~BlendTestInstance (void)
781{
782}
783
784tcu::TestStatus BlendTestInstance::iterate (void)
785{
786	const DeviceInterface&		vk			= m_context.getDeviceInterface();
787	const VkDevice				vkDevice	= m_context.getDevice();
788	const VkQueue				queue		= m_context.getUniversalQueue();
789	const VkSubmitInfo			submitInfo	=
790	{
791		VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
792		DE_NULL,						// const void*				pNext;
793		0u,								// deUint32					waitSemaphoreCount;
794		DE_NULL,						// const VkSemaphore*		pWaitSemaphores;
795		(const VkPipelineStageFlags*)DE_NULL,
796		1u,								// deUint32					commandBufferCount;
797		&m_cmdBuffer.get(),				// const VkCommandBuffer*	pCommandBuffers;
798		0u,								// deUint32					signalSemaphoreCount;
799		DE_NULL							// const VkSemaphore*		pSignalSemaphores;
800	};
801
802	VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
803	VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
804	VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
805
806	return verifyImage();
807}
808
809float BlendTestInstance::getNormChannelThreshold (const tcu::TextureFormat& format, int numBits)
810{
811	switch (tcu::getTextureChannelClass(format.type))
812	{
813		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:	return BlendTest::QUAD_COUNT / static_cast<float>((1 << numBits) - 1);
814		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:	return BlendTest::QUAD_COUNT / static_cast<float>((1 << (numBits - 1)) - 1);
815		default:
816			break;
817	}
818
819	DE_ASSERT(false);
820	return 0.0f;
821}
822
823tcu::Vec4 BlendTestInstance::getFormatThreshold (const tcu::TextureFormat& format)
824{
825	using tcu::Vec4;
826	using tcu::TextureFormat;
827
828	Vec4 threshold(0.01f);
829
830	switch (format.type)
831	{
832		case TextureFormat::UNORM_BYTE_44:
833			threshold = Vec4(getNormChannelThreshold(format, 4), getNormChannelThreshold(format, 4), 1.0f, 1.0f);
834			break;
835
836		case TextureFormat::UNORM_SHORT_565:
837			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 6), getNormChannelThreshold(format, 5), 1.0f);
838			break;
839
840		case TextureFormat::UNORM_SHORT_555:
841			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), 1.0f);
842			break;
843
844		case TextureFormat::UNORM_SHORT_4444:
845			threshold = Vec4(getNormChannelThreshold(format, 4));
846			break;
847
848		case TextureFormat::UNORM_SHORT_5551:
849			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), 0.1f);
850			break;
851
852		case TextureFormat::UNORM_INT_1010102_REV:
853		case TextureFormat::SNORM_INT_1010102_REV:
854			threshold = Vec4(getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), 0.34f);
855			break;
856
857		case TextureFormat::UNORM_INT8:
858		case TextureFormat::SNORM_INT8:
859			threshold = Vec4(getNormChannelThreshold(format, 8));
860			break;
861
862		case TextureFormat::UNORM_INT16:
863		case TextureFormat::SNORM_INT16:
864			threshold = Vec4(getNormChannelThreshold(format, 16));
865			break;
866
867		case TextureFormat::UNORM_INT32:
868		case TextureFormat::SNORM_INT32:
869			threshold = Vec4(getNormChannelThreshold(format, 32));
870			break;
871
872		case TextureFormat::HALF_FLOAT:
873			threshold = Vec4(0.005f);
874			break;
875
876		case TextureFormat::FLOAT:
877			threshold = Vec4(0.00001f);
878			break;
879
880		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
881			threshold = Vec4(0.02f, 0.02f, 0.0625f, 1.0f);
882			break;
883
884		case TextureFormat::UNSIGNED_INT_999_E5_REV:
885			threshold = Vec4(0.05f, 0.05f, 0.05f, 1.0f);
886			break;
887
888		default:
889			DE_ASSERT(false);
890	}
891
892	// Return value matching the channel order specified by the format
893	if (format.order == tcu::TextureFormat::BGR || format.order == tcu::TextureFormat::BGRA)
894		return threshold.swizzle(2, 1, 0, 3);
895	else
896		return threshold;
897}
898
899tcu::TestStatus BlendTestInstance::verifyImage (void)
900{
901	const tcu::TextureFormat	tcuColorFormat	= mapVkFormat(m_colorFormat);
902	const tcu::TextureFormat	tcuDepthFormat	= tcu::TextureFormat(); // Undefined depth/stencil format
903	const ColorVertexShader		vertexShader;
904	const ColorFragmentShader	fragmentShader	(tcuColorFormat, tcuDepthFormat);
905	const rr::Program			program			(&vertexShader, &fragmentShader);
906	ReferenceRenderer			refRenderer		(m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
907	bool						compareOk		= false;
908
909	// Render reference image
910	{
911		for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
912		{
913			const VkPipelineColorBlendAttachmentState& blendState = m_blendStates[quadNdx];
914
915			// Set blend state
916			rr::RenderState renderState					(refRenderer.getViewportState());
917			renderState.fragOps.blendMode				= rr::BLENDMODE_STANDARD;
918			renderState.fragOps.blendRGBState.srcFunc	= mapVkBlendFactor(blendState.srcColorBlendFactor);
919			renderState.fragOps.blendRGBState.dstFunc	= mapVkBlendFactor(blendState.dstColorBlendFactor);
920			renderState.fragOps.blendRGBState.equation	= mapVkBlendOp(blendState.colorBlendOp);
921			renderState.fragOps.blendAState.srcFunc		= mapVkBlendFactor(blendState.srcAlphaBlendFactor);
922			renderState.fragOps.blendAState.dstFunc		= mapVkBlendFactor(blendState.dstAlphaBlendFactor);
923			renderState.fragOps.blendAState.equation	= mapVkBlendOp(blendState.alphaBlendOp);
924			renderState.fragOps.blendColor				= BlendTest::s_blendConst;
925			renderState.fragOps.colorMask				= mapVkColorComponentFlags(BlendTest::s_colorWriteMasks[quadNdx]);
926
927			refRenderer.draw(renderState,
928							 rr::PRIMITIVETYPE_TRIANGLES,
929							 std::vector<Vertex4RGBA>(m_vertices.begin() + quadNdx * 6,
930													  m_vertices.begin() + (quadNdx + 1) * 6));
931		}
932	}
933
934
935	// Compare result with reference image
936	{
937		const DeviceInterface&				vk							= m_context.getDeviceInterface();
938		const VkDevice						vkDevice					= m_context.getDevice();
939		const VkQueue						queue						= m_context.getUniversalQueue();
940		const deUint32						queueFamilyIndex			= m_context.getUniversalQueueFamilyIndex();
941		SimpleAllocator						allocator					(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
942		de::UniquePtr<tcu::TextureLevel>	result						(readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize).release());
943		const tcu::Vec4						threshold					(getFormatThreshold(tcuColorFormat));
944
945		compareOk = tcu::floatThresholdCompare(m_context.getTestContext().getLog(),
946											   "FloatImageCompare",
947											   "Image comparison",
948											   refRenderer.getAccess(),
949											   result->getAccess(),
950											   threshold,
951											   tcu::COMPARE_LOG_RESULT);
952	}
953
954	if (compareOk)
955		return tcu::TestStatus::pass("Result image matches reference");
956	else
957		return tcu::TestStatus::fail("Image mismatch");
958}
959
960} // anonymous
961
962std::string getBlendStateName (const VkPipelineColorBlendAttachmentState& blendState)
963{
964	const char* shortBlendFactorNames[] =
965	{
966		"z",		// VK_BLEND_ZERO
967		"o",		// VK_BLEND_ONE
968		"sc",		// VK_BLEND_SRC_COLOR
969		"1msc",		// VK_BLEND_ONE_MINUS_SRC_COLOR
970		"dc",		// VK_BLEND_DEST_COLOR
971		"1mdc",		// VK_BLEND_ONE_MINUS_DEST_COLOR
972		"sa",		// VK_BLEND_SRC_ALPHA
973		"1msa",		// VK_BLEND_ONE_MINUS_SRC_ALPHA
974		"da",		// VK_BLEND_DEST_ALPHA
975		"1mda",		// VK_BLEND_ONE_MINUS_DEST_ALPHA
976		"cc",		// VK_BLEND_CONSTANT_COLOR
977		"1mcc",		// VK_BLEND_ONE_MINUS_CONSTANT_COLOR
978		"ca",		// VK_BLEND_CONSTANT_ALPHA
979		"1mca",		// VK_BLEND_ONE_MINUS_CONSTANT_ALPHA
980		"sas"		// VK_BLEND_SRC_ALPHA_SATURATE
981	};
982
983	const char* blendOpNames[] =
984	{
985		"add",		// VK_BLEND_OP_ADD
986		"sub",		// VK_BLEND_OP_SUBTRACT
987		"rsub",		// VK_BLEND_OP_REVERSE_SUBTRACT
988		"min",		// VK_BLEND_OP_MIN
989		"max",		// VK_BLEND_OP_MAX
990	};
991
992	std::ostringstream shortName;
993
994	shortName << "color_" << shortBlendFactorNames[blendState.srcColorBlendFactor] << "_" << shortBlendFactorNames[blendState.dstColorBlendFactor] << "_" << blendOpNames[blendState.colorBlendOp];
995	shortName << "_alpha_" << shortBlendFactorNames[blendState.srcAlphaBlendFactor] << "_" << shortBlendFactorNames[blendState.dstAlphaBlendFactor] << "_" << blendOpNames[blendState.alphaBlendOp];
996
997	return shortName.str();
998}
999
1000std::string getBlendStateSetName (const VkPipelineColorBlendAttachmentState blendStates[BlendTest::QUAD_COUNT])
1001{
1002	std::ostringstream name;
1003
1004	for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
1005	{
1006		name << getBlendStateName(blendStates[quadNdx]);
1007
1008		if (quadNdx < BlendTest::QUAD_COUNT - 1)
1009			name << "-";
1010	}
1011
1012	return name.str();
1013}
1014
1015std::string getBlendStateSetDescription (const VkPipelineColorBlendAttachmentState blendStates[BlendTest::QUAD_COUNT])
1016{
1017	std::ostringstream description;
1018
1019	description << "Draws " << BlendTest::QUAD_COUNT << " quads with the following blend states:\n";
1020
1021	for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
1022		description << blendStates[quadNdx] << "\n";
1023
1024	return description.str();
1025}
1026
1027std::string getFormatCaseName (VkFormat format)
1028{
1029	const std::string fullName = getFormatName(format);
1030
1031	DE_ASSERT(de::beginsWith(fullName, "VK_FORMAT_"));
1032
1033	return de::toLower(fullName.substr(10));
1034}
1035
1036tcu::TestCaseGroup* createBlendTests (tcu::TestContext& testCtx)
1037{
1038	const deUint32 blendStatesPerFormat = 100 * BlendTest::QUAD_COUNT;
1039
1040	// Formats that are dEQP-compatible, non-integer and uncompressed
1041	const VkFormat blendFormats[] =
1042	{
1043		VK_FORMAT_R4G4_UNORM_PACK8,
1044		VK_FORMAT_R4G4B4A4_UNORM_PACK16,
1045		VK_FORMAT_R5G6B5_UNORM_PACK16,
1046		VK_FORMAT_R5G5B5A1_UNORM_PACK16,
1047		VK_FORMAT_R8_UNORM,
1048		VK_FORMAT_R8_SNORM,
1049		VK_FORMAT_R8_SRGB,
1050		VK_FORMAT_R8G8_UNORM,
1051		VK_FORMAT_R8G8_SNORM,
1052		VK_FORMAT_R8G8_SRGB,
1053		VK_FORMAT_R8G8B8_UNORM,
1054		VK_FORMAT_R8G8B8_SNORM,
1055		VK_FORMAT_R8G8B8_SRGB,
1056		VK_FORMAT_R8G8B8A8_UNORM,
1057		VK_FORMAT_R8G8B8A8_SNORM,
1058		VK_FORMAT_R8G8B8A8_SRGB,
1059		VK_FORMAT_A2R10G10B10_UNORM_PACK32,
1060		VK_FORMAT_R16_UNORM,
1061		VK_FORMAT_R16_SNORM,
1062		VK_FORMAT_R16_SFLOAT,
1063		VK_FORMAT_R16G16_UNORM,
1064		VK_FORMAT_R16G16_SNORM,
1065		VK_FORMAT_R16G16_SFLOAT,
1066		VK_FORMAT_R16G16B16_UNORM,
1067		VK_FORMAT_R16G16B16_SNORM,
1068		VK_FORMAT_R16G16B16_SFLOAT,
1069		VK_FORMAT_R16G16B16A16_UNORM,
1070		VK_FORMAT_R16G16B16A16_SNORM,
1071		VK_FORMAT_R16G16B16A16_SFLOAT,
1072		VK_FORMAT_R32_SFLOAT,
1073		VK_FORMAT_R32G32_SFLOAT,
1074		VK_FORMAT_R32G32B32_SFLOAT,
1075		VK_FORMAT_R32G32B32A32_SFLOAT,
1076		VK_FORMAT_B10G11R11_UFLOAT_PACK32,
1077		VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
1078		VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1079		VK_FORMAT_B5G5R5A1_UNORM_PACK16,
1080	};
1081
1082	de::MovePtr<tcu::TestCaseGroup>		blendTests		(new tcu::TestCaseGroup(testCtx, "blend", "Blend tests"));
1083	de::MovePtr<tcu::TestCaseGroup>		formatTests		(new tcu::TestCaseGroup(testCtx, "format", "Uses different blend formats"));
1084	BlendStateUniqueRandomIterator		blendStateItr	(blendStatesPerFormat, 123);
1085
1086	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(blendFormats); formatNdx++)
1087	{
1088		const VkFormat					format			= blendFormats[formatNdx];
1089		de::MovePtr<tcu::TestCaseGroup>	formatTest		(new tcu::TestCaseGroup(testCtx,
1090																				getFormatCaseName(format).c_str(),
1091																				(std::string("Uses format ") + getFormatName(format)).c_str()));
1092		de::MovePtr<tcu::TestCaseGroup>	blendStateTests;
1093		{
1094			std::ostringstream blendStateDescription;
1095			blendStateDescription << "Combines blend factors, operators and channel write masks. The constant color used in all tests is " << BlendTest::s_blendConst;
1096			blendStateTests = de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, "states", blendStateDescription.str().c_str()));
1097		}
1098
1099		blendStateItr.reset();
1100
1101		while (blendStateItr.hasNext())
1102		{
1103			VkPipelineColorBlendAttachmentState quadBlendConfigs[BlendTest::QUAD_COUNT];
1104
1105			for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
1106			{
1107				quadBlendConfigs[quadNdx]					= blendStateItr.next();
1108				quadBlendConfigs[quadNdx].colorWriteMask	= BlendTest::s_colorWriteMasks[quadNdx];
1109			}
1110
1111			blendStateTests->addChild(new BlendTest(testCtx,
1112													getBlendStateSetName(quadBlendConfigs),
1113													getBlendStateSetDescription(quadBlendConfigs),
1114													format,
1115													quadBlendConfigs));
1116		}
1117		formatTest->addChild(blendStateTests.release());
1118		formatTests->addChild(formatTest.release());
1119	}
1120	blendTests->addChild(formatTests.release());
1121
1122	return blendTests.release();
1123}
1124
1125} // pipeline
1126} // vkt
1127