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