• 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 	PipelineConstructionType	pipelineConstructionType;	// Use monolithic pipeline or pipeline_library
70 	tcu::UVec4					fbColor;					// Framebuffer color.
71 	tcu::UVec4					quadColor;					// Geometry color.
72 	VkFormat					format;						// Framebuffer format.
73 	std::string					name;						// Logic operator test name.
74 };
75 
calcOpResult(VkLogicOp op,deUint32 src,deUint32 dst)76 deUint32 calcOpResult(VkLogicOp op, deUint32 src, deUint32 dst)
77 {
78 	// See section 29.2 "Logical Operations" in the spec.
79 	//
80 	//	AND:			SRC & DST		= 1010 & 1100		= 1000 = 0x8
81 	//	AND_REVERSE:	SRC & ~DST		= 0011 & 1010		= 0010 = 0x2
82 	//	COPY:			SRC				= 1010				= 1010 = 0xa
83 	//	AND_INVERTED:	~SRC & DST		= 0101 & 1100		= 0100 = 0x4
84 	//	NO_OP:			DST				= 1010				= 1010 = 0xa
85 	//	XOR:			SRC ^ DST		= 1010 ^ 1100		= 0110 = 0x6
86 	//	OR:				SRC | DST		= 1010 | 1100		= 1110 = 0xe
87 	//	NOR:			~(SRC | DST)	= ~(1010 | 1100)	= 0001 = 0x1
88 	//	EQUIVALENT:		~(SRC ^ DST)	= ~(1010 ^ 1100)	= 1001 = 0x9
89 	//	INVERT:			~DST			= ~1100				= 0011 = 0x3
90 	//	OR_REVERSE:		SRC | ~DST		= 1010 | 0011		= 1011 = 0xb
91 	//	COPY_INVERTED:	~SRC			= 0101				= 0101 = 0x5
92 	//	OR_INVERTED:	~SRC | DST		= 0101 | 1100		= 1101 = 0xd
93 	//	NAND:			~(SRC & DST)	= ~(1010 &1100)		= 0111 = 0x7
94 	//	SET:							= 1111				= 1111 = 0xf (sets all bits)
95 
96 	switch (op)
97 	{
98 	case VK_LOGIC_OP_CLEAR:				return (0u);
99 	case VK_LOGIC_OP_AND:				return (src & dst);
100 	case VK_LOGIC_OP_AND_REVERSE:		return (src & ~dst);
101 	case VK_LOGIC_OP_COPY:				return (src);
102 	case VK_LOGIC_OP_AND_INVERTED:		return (~src & dst);
103 	case VK_LOGIC_OP_NO_OP:				return (dst);
104 	case VK_LOGIC_OP_XOR:				return (src ^ dst);
105 	case VK_LOGIC_OP_OR:				return (src | dst);
106 	case VK_LOGIC_OP_NOR:				return (~(src | dst));
107 	case VK_LOGIC_OP_EQUIVALENT:		return (~(src ^ dst));
108 	case VK_LOGIC_OP_INVERT:			return (~dst);
109 	case VK_LOGIC_OP_OR_REVERSE:		return (src | ~dst);
110 	case VK_LOGIC_OP_COPY_INVERTED:		return (~src);
111 	case VK_LOGIC_OP_OR_INVERTED:		return (~src | dst);
112 	case VK_LOGIC_OP_NAND:				return (~(src & dst));
113 	case VK_LOGIC_OP_SET:				return (std::numeric_limits<deUint32>::max());
114 	default: DE_ASSERT(false); break;
115 	}
116 
117 	DE_ASSERT(false);
118 	return 0u;
119 }
120 
121 // Gets a bitmask to filter out unused bits according to the channel size (e.g. 0xFFu for 8-bit channels).
122 // channelSize in bytes.
getChannelMask(int channelSize)123 deUint32 getChannelMask (int channelSize)
124 {
125 	DE_ASSERT(channelSize >= 1 && channelSize <= 4);
126 
127 	deUint64 mask = 1u;
128 	mask <<= (channelSize * 8);
129 	--mask;
130 
131 	return static_cast<deUint32>(mask);
132 }
133 
134 class LogicOpTest : public vkt::TestCase
135 {
136 public:
137 									LogicOpTest			(tcu::TestContext&  testCtx,
138 														 const std::string& name,
139 														 const std::string& description,
140 														 const TestParams &testParams);
141 	virtual							~LogicOpTest		(void);
142 	virtual		  void				initPrograms		(SourceCollections& sourceCollections) const;
143 	virtual		  void				checkSupport		(Context& context) const;
144 	virtual		  TestInstance*		createInstance		(Context& context) const;
145 
146 private:
147 	TestParams m_params;
148 };
149 
LogicOpTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & testParams)150 LogicOpTest::LogicOpTest (tcu::TestContext& testCtx,
151 						  const std::string& name,
152 						  const std::string& description,
153 						  const TestParams& testParams)
154 	: vkt::TestCase	(testCtx, name, description)
155 	, m_params		(testParams)
156 {
157 	DE_ASSERT(m_params.format != VK_FORMAT_UNDEFINED);
158 }
159 
~LogicOpTest(void)160 LogicOpTest::~LogicOpTest (void)
161 {
162 }
163 
checkSupport(Context & ctx) const164 void 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 	checkPipelineLibraryRequirements(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 
initPrograms(SourceCollections & sourceCollections) const177 void 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 
203 class LogicOpTestInstance : public vkt::TestInstance
204 {
205 public:
206 										LogicOpTestInstance(Context& context,
207 															const TestParams& params);
208 										~LogicOpTestInstance(void);
209 	virtual		tcu::TestStatus			iterate(void);
210 
211 private:
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 	Move<VkRenderPass>					m_renderPass;
229 	Move<VkFramebuffer>					m_framebuffer;
230 
231 	Move<VkShaderModule>				m_vertexShaderModule;
232 	Move<VkShaderModule>				m_fragmentShaderModule;
233 
234 	Move<VkPipelineLayout>				m_preRasterizationStatePipelineLayout;
235 	Move<VkPipelineLayout>				m_fragmentStatePipelineLayout;
236 	GraphicsPipelineWrapper				m_graphicsPipeline;
237 
238 	Move<VkCommandPool>					m_cmdPool;
239 	Move<VkCommandBuffer>				m_cmdBuffer;
240 };
241 
LogicOpTestInstance(Context & ctx,const TestParams & testParams)242 LogicOpTestInstance::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.getDeviceInterface(), m_context.getDevice(), 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	= makeRenderPass(vk, vkDevice, m_params.format);
304 	m_framebuffer	= makeFramebuffer(vk, vkDevice, *m_renderPass, m_colorAttachmentView.get(), 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		= createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
333 		pipelineLayoutParams.pushConstantRangeCount = 1u;
334 		pipelineLayoutParams.pPushConstantRanges	= &pcRange;
335 		m_fragmentStatePipelineLayout				= createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
336 	}
337 
338 	m_vertexShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
339 	m_fragmentShaderModule	= createShaderModule(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 		beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, 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 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline.getPipeline());
419 		vk.cmdDraw(*m_cmdBuffer, 4u, 1u, 0u, 0u);
420 		endRenderPass(vk, *m_cmdBuffer);
421 		endCommandBuffer(vk, *m_cmdBuffer);
422 	}
423 }
424 
~LogicOpTestInstance(void)425 LogicOpTestInstance::~LogicOpTestInstance (void)
426 {
427 }
428 
iterate(void)429 tcu::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 
verifyImage(void)439 tcu::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 
createInstance(Context & context) const477 TestInstance *LogicOpTest::createInstance (Context& context) const
478 {
479 	return new LogicOpTestInstance(context, m_params);
480 }
481 
getSimpleFormatName(VkFormat format)482 std::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 
createLogicOpTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineType)489 tcu::TestCaseGroup* createLogicOpTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineType)
490 {
491 	de::MovePtr<tcu::TestCaseGroup>	logicOpTests (new tcu::TestCaseGroup(testCtx, "logic_op", "Logical Operations tests"));
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(), formatDesc.c_str()));
557 
558 		for (auto& params : logicOpTestParams)
559 		{
560 			params.format = format;
561 			formatGroup->addChild(new LogicOpTest(testCtx, params.name, "Tests the " + params.name + " logical operator", params));
562 		}
563 
564 		logicOpTests->addChild(formatGroup.release());
565 	}
566 
567 	return logicOpTests.release();
568 }
569 
570 } // pipeline namespace
571 } // vkt namespace
572