xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/pipeline/vktPipelineLogicOpTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 &params);
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 &params : 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