1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 The Khronos Group Inc.
6 * Copyright (c) 2020 Valve Corporation.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 *		http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Logic Operators Tests
25 *//*--------------------------------------------------------------------*/
26
27#include "vktPipelineLogicOpTests.hpp"
28#include "vktPipelineImageUtil.hpp"
29
30#include "vkQueryUtil.hpp"
31#include "vkCmdUtil.hpp"
32#include "vkObjUtil.hpp"
33#include "vkTypeUtil.hpp"
34#include "vkMemUtil.hpp"
35#include "vkImageUtil.hpp"
36#include "vkImageWithMemory.hpp"
37
38#include "tcuVectorUtil.hpp"
39#include "tcuImageCompare.hpp"
40#include "tcuTestLog.hpp"
41
42#include <string>
43#include <limits>
44
45namespace vkt
46{
47namespace pipeline
48{
49
50using namespace vk;
51
52namespace
53{
54
55bool isSupportedColorAttachmentFormat (const InstanceInterface& instanceInterface,
56									   VkPhysicalDevice device,
57									   VkFormat format)
58{
59	VkFormatProperties formatProps;
60	instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps);
61
62	// Format also needs to be INT, UINT, or SINT but as we are the ones setting the
63	// color attachment format we only need to check that it is a valid color attachment
64	// format here.
65	return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
66}
67
68struct TestParams
69{
70	VkLogicOp					logicOp;					// Operation.
71	PipelineConstructionType	pipelineConstructionType;	// Use monolithic pipeline or pipeline_library
72	tcu::UVec4					fbColor;					// Framebuffer color.
73	tcu::UVec4					quadColor;					// Geometry color.
74	VkFormat					format;						// Framebuffer format.
75	std::string					name;						// Logic operator test name.
76};
77
78deUint32 calcOpResult(VkLogicOp op, deUint32 src, deUint32 dst)
79{
80	// See section 29.2 "Logical Operations" in the spec.
81	//
82	//	AND:			SRC & DST		= 1010 & 1100		= 1000 = 0x8
83	//	AND_REVERSE:	SRC & ~DST		= 0011 & 1010		= 0010 = 0x2
84	//	COPY:			SRC				= 1010				= 1010 = 0xa
85	//	AND_INVERTED:	~SRC & DST		= 0101 & 1100		= 0100 = 0x4
86	//	NO_OP:			DST				= 1010				= 1010 = 0xa
87	//	XOR:			SRC ^ DST		= 1010 ^ 1100		= 0110 = 0x6
88	//	OR:				SRC | DST		= 1010 | 1100		= 1110 = 0xe
89	//	NOR:			~(SRC | DST)	= ~(1010 | 1100)	= 0001 = 0x1
90	//	EQUIVALENT:		~(SRC ^ DST)	= ~(1010 ^ 1100)	= 1001 = 0x9
91	//	INVERT:			~DST			= ~1100				= 0011 = 0x3
92	//	OR_REVERSE:		SRC | ~DST		= 1010 | 0011		= 1011 = 0xb
93	//	COPY_INVERTED:	~SRC			= 0101				= 0101 = 0x5
94	//	OR_INVERTED:	~SRC | DST		= 0101 | 1100		= 1101 = 0xd
95	//	NAND:			~(SRC & DST)	= ~(1010 &1100)		= 0111 = 0x7
96	//	SET:							= 1111				= 1111 = 0xf (sets all bits)
97
98	switch (op)
99	{
100	case VK_LOGIC_OP_CLEAR:				return (0u);
101	case VK_LOGIC_OP_AND:				return (src & dst);
102	case VK_LOGIC_OP_AND_REVERSE:		return (src & ~dst);
103	case VK_LOGIC_OP_COPY:				return (src);
104	case VK_LOGIC_OP_AND_INVERTED:		return (~src & dst);
105	case VK_LOGIC_OP_NO_OP:				return (dst);
106	case VK_LOGIC_OP_XOR:				return (src ^ dst);
107	case VK_LOGIC_OP_OR:				return (src | dst);
108	case VK_LOGIC_OP_NOR:				return (~(src | dst));
109	case VK_LOGIC_OP_EQUIVALENT:		return (~(src ^ dst));
110	case VK_LOGIC_OP_INVERT:			return (~dst);
111	case VK_LOGIC_OP_OR_REVERSE:		return (src | ~dst);
112	case VK_LOGIC_OP_COPY_INVERTED:		return (~src);
113	case VK_LOGIC_OP_OR_INVERTED:		return (~src | dst);
114	case VK_LOGIC_OP_NAND:				return (~(src & dst));
115	case VK_LOGIC_OP_SET:				return (std::numeric_limits<deUint32>::max());
116	default: DE_ASSERT(false); break;
117	}
118
119	DE_ASSERT(false);
120	return 0u;
121}
122
123// Gets a bitmask to filter out unused bits according to the channel size (e.g. 0xFFu for 8-bit channels).
124// channelSize in bytes.
125deUint32 getChannelMask (int channelSize)
126{
127	DE_ASSERT(channelSize >= 1 && channelSize <= 4);
128
129	deUint64 mask = 1u;
130	mask <<= (channelSize * 8);
131	--mask;
132
133	return static_cast<deUint32>(mask);
134}
135
136class LogicOpTest : public vkt::TestCase
137{
138public:
139									LogicOpTest			(tcu::TestContext&  testCtx,
140														 const std::string& name,
141														 const TestParams &testParams);
142	virtual							~LogicOpTest		(void);
143	virtual		  void				initPrograms		(SourceCollections& sourceCollections) const;
144	virtual		  void				checkSupport		(Context& context) const;
145	virtual		  TestInstance*		createInstance		(Context& context) const;
146
147private:
148	TestParams m_params;
149};
150
151LogicOpTest::LogicOpTest (tcu::TestContext& testCtx,
152						  const std::string& name,
153						  const TestParams& testParams)
154	: vkt::TestCase	(testCtx, name)
155	, m_params		(testParams)
156{
157	DE_ASSERT(m_params.format != VK_FORMAT_UNDEFINED);
158}
159
160LogicOpTest::~LogicOpTest (void)
161{
162}
163
164void LogicOpTest::checkSupport (Context &ctx) const
165{
166	const auto& features = ctx.getDeviceFeatures();
167
168	if (!features.logicOp)
169		TCU_THROW(NotSupportedError, "Logic operations not supported");
170
171	checkPipelineConstructionRequirements(ctx.getInstanceInterface(), ctx.getPhysicalDevice(), m_params.pipelineConstructionType);
172
173	if (!isSupportedColorAttachmentFormat(ctx.getInstanceInterface(), ctx.getPhysicalDevice(), m_params.format))
174		TCU_THROW(NotSupportedError, "Unsupported color attachment format: " + std::string(getFormatName(m_params.format)));
175}
176
177void LogicOpTest::initPrograms (SourceCollections& sourceCollections) const
178{
179	sourceCollections.glslSources.add("color_vert") << glu::VertexSource(
180		"#version 430\n"
181		"vec2 vdata[] = vec2[] (\n"
182		"vec2(-1.0, -1.0),\n"
183		"vec2(1.0, -1.0),\n"
184		"vec2(-1.0, 1.0),\n"
185		"vec2(1.0, 1.0));\n"
186		"void main (void)\n"
187		"{\n"
188		"	gl_Position = vec4(vdata[gl_VertexIndex], 0.0, 1.0);\n"
189		"}\n");
190
191	sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(
192		"#version 430\n"
193		"layout(push_constant) uniform quadColor {\n"
194		"	uvec4 val;\n"
195		"} QUAD_COLOR;\n"
196		"layout(location = 0) out uvec4 fragColor;\n"
197		"void main (void)\n"
198		"{\n"
199		"	fragColor = QUAD_COLOR.val;\n"
200		"}\n");
201}
202
203class LogicOpTestInstance : public vkt::TestInstance
204{
205public:
206										LogicOpTestInstance(Context& context,
207															const TestParams& params);
208										~LogicOpTestInstance(void);
209	virtual		tcu::TestStatus			iterate(void);
210
211private:
212	tcu::TestStatus						verifyImage(void);
213
214	TestParams							m_params;
215
216	// Derived from m_params.
217	const tcu::TextureFormat			m_tcuFormat;
218	const int							m_numChannels;
219	const int							m_channelSize;
220	const deUint32						m_channelMask;
221
222	const tcu::UVec2					m_renderSize;
223
224	VkImageCreateInfo					m_colorImageCreateInfo;
225	de::MovePtr<ImageWithMemory>		m_colorImage;
226	Move<VkImageView>					m_colorAttachmentView;
227
228	RenderPassWrapper					m_renderPass;
229	Move<VkFramebuffer>					m_framebuffer;
230
231	ShaderWrapper						m_vertexShaderModule;
232	ShaderWrapper						m_fragmentShaderModule;
233
234	PipelineLayoutWrapper				m_preRasterizationStatePipelineLayout;
235	PipelineLayoutWrapper				m_fragmentStatePipelineLayout;
236	GraphicsPipelineWrapper				m_graphicsPipeline;
237
238	Move<VkCommandPool>					m_cmdPool;
239	Move<VkCommandBuffer>				m_cmdBuffer;
240};
241
242LogicOpTestInstance::LogicOpTestInstance (Context &ctx, const TestParams &testParams)
243	: vkt::TestInstance		(ctx)
244	, m_params				(testParams)
245	, m_tcuFormat			(mapVkFormat(m_params.format))
246	, m_numChannels			(tcu::getNumUsedChannels(m_tcuFormat.order))
247	, m_channelSize			(tcu::getChannelSize(m_tcuFormat.type))
248	, m_channelMask			(getChannelMask(m_channelSize))
249	, m_renderSize			(32u, 32u)
250	, m_graphicsPipeline	(m_context.getInstanceInterface(), m_context.getDeviceInterface(), m_context.getPhysicalDevice(), m_context.getDevice(), m_context.getDeviceExtensions(), testParams.pipelineConstructionType)
251{
252	DE_ASSERT(isUintFormat(m_params.format));
253
254	const DeviceInterface&		vk					= m_context.getDeviceInterface();
255	const VkDevice				vkDevice			= m_context.getDevice();
256	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
257	Allocator&					memAlloc			= m_context.getDefaultAllocator();
258	constexpr auto				kPushConstantSize	= static_cast<deUint32>(sizeof(m_params.quadColor));
259
260	// create color image
261	{
262		const VkImageCreateInfo	colorImageParams =
263		{
264			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										// VkStructureType			sType;
265			DE_NULL,																	// const void*				pNext;
266			0u,																			// VkImageCreateFlags		flags;
267			VK_IMAGE_TYPE_2D,															// VkImageType				imageType;
268			m_params.format,															// VkFormat					format;
269			{ m_renderSize.x(), m_renderSize.y(), 1u },									// VkExtent3D				extent;
270			1u,																			// deUint32					mipLevels;
271			1u,																			// deUint32					arrayLayers;
272			VK_SAMPLE_COUNT_1_BIT,														// VkSampleCountFlagBits	samples;
273			VK_IMAGE_TILING_OPTIMAL,													// VkImageTiling			tiling;
274			VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,		// VkImageUsageFlags		usage;
275			VK_SHARING_MODE_EXCLUSIVE,													// VkSharingMode			sharingMode;
276			1u,																			// deUint32					queueFamilyIndexCount;
277			&queueFamilyIndex,															// const deUint32*			pQueueFamilyIndices;
278			VK_IMAGE_LAYOUT_UNDEFINED													// VkImageLayout			initialLayout;
279		};
280
281		m_colorImageCreateInfo	= colorImageParams;
282		m_colorImage			= de::MovePtr<ImageWithMemory>(new ImageWithMemory(vk, vkDevice, memAlloc, m_colorImageCreateInfo, MemoryRequirement::Any));
283
284		// create color attachment view
285		const VkImageViewCreateInfo colorAttachmentViewParams =
286		{
287			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,			// VkStructureType			sType;
288			DE_NULL,											// const void*				pNext;
289			0u,													// VkImageViewCreateFlags	flags;
290			m_colorImage->get(),								// VkImage					image;
291			VK_IMAGE_VIEW_TYPE_2D,								// VkImageViewType			viewType;
292			m_params.format,									// VkFormat					format;
293			{	VK_COMPONENT_SWIZZLE_IDENTITY,
294				VK_COMPONENT_SWIZZLE_IDENTITY,
295				VK_COMPONENT_SWIZZLE_IDENTITY,
296				VK_COMPONENT_SWIZZLE_IDENTITY	},
297			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }		// VkImageSubresourceRange	subresourceRange;
298		};
299
300		m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
301	}
302
303	m_renderPass	= RenderPassWrapper(m_params.pipelineConstructionType, vk, vkDevice, m_params.format);
304	m_renderPass.createFramebuffer(vk, vkDevice, **m_colorImage, *m_colorAttachmentView, m_renderSize.x(), m_renderSize.y());
305
306	// create pipeline layout
307	{
308		const VkPushConstantRange pcRange =
309		{
310			VK_SHADER_STAGE_FRAGMENT_BIT,		// VkShaderStageFlags				stageFlags;
311			0u,									// deUint32							offset;
312			kPushConstantSize,					// deUint32							size;
313		};
314
315#ifndef CTS_USES_VULKANSC
316		VkPipelineLayoutCreateFlags pipelineLayoutFlags = (m_params.pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC) ? 0u : deUint32(VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT);
317#else
318		VkPipelineLayoutCreateFlags pipelineLayoutFlags = 0u;
319#endif // CTS_USES_VULKANSC
320
321		VkPipelineLayoutCreateInfo pipelineLayoutParams
322		{
323			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType					sType;
324			DE_NULL,											// const void*						pNext;
325			pipelineLayoutFlags,								// VkPipelineLayoutCreateFlags		flags;
326			0u,													// deUint32							setLayoutCount;
327			DE_NULL,											// const VkDescriptorSetLayout*		pSetLayouts;
328			0u,													// deUint32							pushConstantRangeCount;
329			DE_NULL,											// const VkPushConstantRange*		pPushConstantRanges;
330		};
331
332		m_preRasterizationStatePipelineLayout		= PipelineLayoutWrapper(m_params.pipelineConstructionType, vk, vkDevice, &pipelineLayoutParams);
333		pipelineLayoutParams.pushConstantRangeCount = 1u;
334		pipelineLayoutParams.pPushConstantRanges	= &pcRange;
335		m_fragmentStatePipelineLayout				= PipelineLayoutWrapper(m_params.pipelineConstructionType, vk, vkDevice, &pipelineLayoutParams);
336	}
337
338	m_vertexShaderModule	= ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
339	m_fragmentShaderModule	= ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
340
341	// create pipeline
342	{
343		const VkPipelineVertexInputStateCreateInfo	vertexInputStateParams	= initVulkanStructure();
344
345		const std::vector<VkViewport>				viewports				{ makeViewport(m_renderSize) };
346		const std::vector<VkRect2D>					scissors				{ makeRect2D(m_renderSize) };
347
348		VkColorComponentFlags						colorWriteMask		=	VK_COLOR_COMPONENT_R_BIT |
349																			VK_COLOR_COMPONENT_G_BIT |
350																			VK_COLOR_COMPONENT_B_BIT |
351																			VK_COLOR_COMPONENT_A_BIT;
352
353		const VkPipelineColorBlendAttachmentState blendAttachmentState =
354		{
355			VK_FALSE,					//	VkBool32				blendEnable;
356			(VkBlendFactor) 0,			//	VkBlendFactor			srcColorBlendFactor;
357			(VkBlendFactor) 0,			//	VkBlendFactor			dstColorBlendFactor;
358			(VkBlendOp)		0,			//	VkBlendOp				colorBlendOp;
359			(VkBlendFactor) 0,			//	VkBlendFactor			srcAlphaBlendFactor;
360			(VkBlendFactor) 0,			//	VkBlendFactor			dstAlphaBlendFactor;
361			(VkBlendOp)		0,			//	VkBlendOp				alphaBlendOp;
362			colorWriteMask,				//	VkColorComponentFlags	colorWriteMask;
363		};
364
365		const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
366		{
367			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	//	VkStructureType								sType;
368			DE_NULL,													//	const void*									pNext;
369			DE_NULL,													//	VkPipelineColorBlendStateCreateFlags		flags;
370			VK_TRUE,													//	VkBool32									logicOpEnable;
371			m_params.logicOp,											//	VkLogicOp									logicOp;
372			1u,															//	uint32_t									attachmentCount;
373			&blendAttachmentState,										//	const VkPipelineColorBlendAttachmentState*	pAttachments;
374			{ 0.0f, 0.0f, 0.0f, 0.0f },									//	float										blendConstants[4];
375		};
376
377		m_graphicsPipeline.setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
378						  .setDefaultDepthStencilState()
379						  .setDefaultRasterizationState()
380						  .setDefaultMultisampleState()
381						  .setMonolithicPipelineLayout(m_fragmentStatePipelineLayout)
382						  .setupVertexInputState(&vertexInputStateParams)
383						  .setupPreRasterizationShaderState(viewports,
384															scissors,
385															m_preRasterizationStatePipelineLayout,
386															*m_renderPass,
387															0u,
388															m_vertexShaderModule)
389						  .setupFragmentShaderState(m_fragmentStatePipelineLayout, *m_renderPass, 0u, m_fragmentShaderModule)
390						  .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams)
391						  .buildPipeline();
392	}
393
394	// create command pool
395	m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
396
397	// allocate and record command buffer
398	{
399		// Prepare clear color value and quad color taking into account the channel mask.
400		VkClearValue	attachmentClearValue;
401		tcu::UVec4		quadColor(0u, 0u, 0u, 0u);
402
403		deMemset(&attachmentClearValue.color, 0, sizeof(attachmentClearValue.color));
404		for (int c = 0; c < m_numChannels; ++c)
405			attachmentClearValue.color.uint32[c] = (m_params.fbColor[c] & m_channelMask);
406
407		for (int c = 0; c < m_numChannels; ++c)
408			quadColor[c] = (m_params.quadColor[c] & m_channelMask);
409
410		m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
411
412		beginCommandBuffer(vk, *m_cmdBuffer, 0u);
413		m_renderPass.begin(vk, *m_cmdBuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), attachmentClearValue);
414
415		// Update push constant values
416		vk.cmdPushConstants(*m_cmdBuffer, *m_fragmentStatePipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, kPushConstantSize, &quadColor);
417
418		m_graphicsPipeline.bind(*m_cmdBuffer);
419		vk.cmdDraw(*m_cmdBuffer, 4u, 1u, 0u, 0u);
420		m_renderPass.end(vk, *m_cmdBuffer);
421		endCommandBuffer(vk, *m_cmdBuffer);
422	}
423}
424
425LogicOpTestInstance::~LogicOpTestInstance (void)
426{
427}
428
429tcu::TestStatus LogicOpTestInstance::iterate (void)
430{
431	const DeviceInterface&		vk			= m_context.getDeviceInterface();
432	const VkDevice				vkDevice	= m_context.getDevice();
433	const VkQueue				queue		= m_context.getUniversalQueue();
434
435	submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
436	return verifyImage();
437}
438
439tcu::TestStatus LogicOpTestInstance::verifyImage (void)
440{
441	const DeviceInterface&		vk					= m_context.getDeviceInterface();
442	const VkDevice				vkDevice			= m_context.getDevice();
443	const VkQueue				queue				= m_context.getUniversalQueue();
444	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
445	Allocator&					allocator			= m_context.getDefaultAllocator();
446	auto&						log					= m_context.getTestContext().getLog();
447
448	const auto					result				= readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, m_colorImage->get(), m_params.format, m_renderSize).release();
449	const auto					resultAccess		= result->getAccess();
450	const int					iWidth				= static_cast<int>(m_renderSize.x());
451	const int					iHeight				= static_cast<int>(m_renderSize.y());
452	tcu::UVec4					expectedColor		(0u, 0u, 0u, 0u);	// Overwritten below.
453	tcu::TextureLevel			referenceTexture	(m_tcuFormat, iWidth, iHeight);
454	auto						referenceAccess		= referenceTexture.getAccess();
455	tcu::UVec4					threshold			(0u, 0u, 0u, 0u);	// Exact results.
456
457	// Calculate proper expected color values.
458	for (int c = 0; c < m_numChannels; ++c)
459	{
460		expectedColor[c] = calcOpResult(m_params.logicOp, m_params.quadColor[c], m_params.fbColor[c]);
461		expectedColor[c] &= m_channelMask;
462	}
463
464	for (int y = 0; y < iHeight; ++y)
465	for (int x = 0; x < iWidth; ++x)
466		referenceAccess.setPixel(expectedColor, x, y);
467
468	// Check result.
469	bool resultOk = tcu::intThresholdCompare(log, "TestResults", "Test Result Images", referenceAccess, resultAccess, threshold, tcu::COMPARE_LOG_ON_ERROR);
470
471	if (!resultOk)
472		TCU_FAIL("Result does not match expected values; check log for details");
473
474	return tcu::TestStatus::pass("Pass");
475}
476
477TestInstance *LogicOpTest::createInstance (Context& context) const
478{
479	return new LogicOpTestInstance(context, m_params);
480}
481
482std::string getSimpleFormatName (VkFormat format)
483{
484	return de::toLower(std::string(getFormatName(format)).substr(std::string("VK_FORMAT_").size()));
485}
486
487} // anonymous namespace
488
489tcu::TestCaseGroup* createLogicOpTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineType)
490{
491	de::MovePtr<tcu::TestCaseGroup>	logicOpTests (new tcu::TestCaseGroup(testCtx, "logic_op"));
492
493	// 4 bits are enough to check all possible combinations of logical operation inputs at once, for example s AND d:
494	//
495	//		1 0 1 0
496	//	AND	1 1 0 0
497	//	------------
498	//		1 0 0 0
499	//
500	// However, we will choose color values such that both higher bits and lower bits are used, and the implementation will not be
501	// able to mix channels by mistake.
502	//
503	//	0011 0101 1010 1100
504	//	3    5    a    c
505	//	0101 0011 1100 1010
506	//	5    3    c    a
507
508	const tcu::UVec4 kQuadColor	= { 0x35acU, 0x5ac3U, 0xac35U, 0xc35aU };
509	const tcu::UVec4 kFbColor	= { 0x53caU, 0x3ca5U, 0xca53U, 0xa53cU };
510
511	// Note: the format will be chosen and changed later.
512	std::vector<TestParams> logicOpTestParams
513	{
514		{ VK_LOGIC_OP_CLEAR,			pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"clear"			},
515		{ VK_LOGIC_OP_AND,				pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"and"			},
516		{ VK_LOGIC_OP_AND_REVERSE,		pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"and_reverse"	},
517		{ VK_LOGIC_OP_COPY,				pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"copy"			},
518		{ VK_LOGIC_OP_AND_INVERTED,		pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"and_inverted"	},
519		{ VK_LOGIC_OP_NO_OP,			pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"no_op"			},
520		{ VK_LOGIC_OP_XOR,				pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"xor"			},
521		{ VK_LOGIC_OP_OR,				pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"or"			},
522		{ VK_LOGIC_OP_NOR,				pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"nor"			},
523		{ VK_LOGIC_OP_EQUIVALENT,		pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"equivalent"	},
524		{ VK_LOGIC_OP_INVERT,			pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"invert"		},
525		{ VK_LOGIC_OP_OR_REVERSE,		pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"or_reverse"	},
526		{ VK_LOGIC_OP_COPY_INVERTED,	pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"copy_inverted"	},
527		{ VK_LOGIC_OP_OR_INVERTED,		pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"or_inverted"	},
528		{ VK_LOGIC_OP_NAND,				pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"nand"			},
529		{ VK_LOGIC_OP_SET,				pipelineType,	kFbColor,	kQuadColor,		VK_FORMAT_UNDEFINED,	"set"			},
530	};
531
532	const VkFormat formatList[] =
533	{
534		VK_FORMAT_R8_UINT,
535		VK_FORMAT_R8G8_UINT,
536		VK_FORMAT_R8G8B8_UINT,
537		VK_FORMAT_B8G8R8_UINT,
538		VK_FORMAT_R8G8B8A8_UINT,
539		VK_FORMAT_B8G8R8A8_UINT,
540		VK_FORMAT_R16_UINT,
541		VK_FORMAT_R16G16_UINT,
542		VK_FORMAT_R16G16B16_UINT,
543		VK_FORMAT_R16G16B16A16_UINT,
544		VK_FORMAT_R32_UINT,
545		VK_FORMAT_R32G32_UINT,
546		VK_FORMAT_R32G32B32_UINT,
547		VK_FORMAT_R32G32B32A32_UINT,
548	};
549
550	for (int formatIdx = 0; formatIdx < DE_LENGTH_OF_ARRAY(formatList); ++formatIdx)
551	{
552		const auto&	format		= formatList[formatIdx];
553		const auto	formatName	= getSimpleFormatName(format);
554		const auto	formatDesc	= "Logical operator tests with format " + formatName;
555
556		de::MovePtr<tcu::TestCaseGroup> formatGroup (new tcu::TestCaseGroup(testCtx, formatName.c_str()));
557
558		for (auto& params : logicOpTestParams)
559		{
560			params.format = format;
561			formatGroup->addChild(new LogicOpTest(testCtx, params.name, params));
562		}
563
564		logicOpTests->addChild(formatGroup.release());
565	}
566
567	return logicOpTests.release();
568}
569
570} // pipeline namespace
571} // vkt namespace
572