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