1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 The Khronos Group Inc.
6  * Copyright (c) 2018 Danylo Piliaiev <[email protected]>
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 Test for conditional rendering of vkCmdClearAttachments
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktConditionalClearAttachmentTests.hpp"
26 #include "vktConditionalRenderingTestUtil.hpp"
27 
28 #include "vktTestCaseUtil.hpp"
29 #include "vktDrawTestCaseUtil.hpp"
30 
31 #include "vktDrawBaseClass.hpp"
32 
33 #include "tcuTestLog.hpp"
34 #include "tcuResource.hpp"
35 #include "tcuImageCompare.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuRGBA.hpp"
38 
39 #include "vkDefs.hpp"
40 #include "vkCmdUtil.hpp"
41 #include "vkTypeUtil.hpp"
42 
43 namespace vkt
44 {
45 namespace conditional
46 {
47 namespace
48 {
49 
50 struct ConditionalTestSpec : public Draw::TestSpecBase
51 {
52     ConditionalData conditionalData;
53 };
54 
55 class ConditionalClearAttachmentTest : public Draw::DrawTestsBaseClass
56 {
57 public:
58     typedef ConditionalTestSpec TestSpec;
59 
60     ConditionalClearAttachmentTest(Context &context, ConditionalTestSpec testSpec);
61 
62     virtual tcu::TestStatus iterate(void);
63 
64 protected:
65     const ConditionalData m_conditionalData;
66     de::SharedPtr<Draw::Buffer> m_conditionalBuffer;
67 
68     vk::Move<vk::VkCommandBuffer> m_secondaryCmdBuffer;
69     vk::Move<vk::VkCommandBuffer> m_nestedCmdBuffer;
70 };
71 
ConditionalClearAttachmentTest(Context & context,ConditionalTestSpec testSpec)72 ConditionalClearAttachmentTest::ConditionalClearAttachmentTest(Context &context, ConditionalTestSpec testSpec)
73     : Draw::DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX],
74                                testSpec.shaders[glu::SHADERTYPE_FRAGMENT],
75                                Draw::SharedGroupParams(new Draw::GroupParams{false, false, false, false}),
76                                vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
77     , m_conditionalData(testSpec.conditionalData)
78 {
79     checkConditionalRenderingCapabilities(context, m_conditionalData);
80     checkNestedRenderPassCapabilities(context);
81 
82     m_data.push_back(Draw::VertexElementData(tcu::Vec4(0.0f), tcu::Vec4(0.0f), 0));
83 
84     initialize();
85 
86     m_secondaryCmdBuffer =
87         vk::allocateCommandBuffer(m_vk, m_context.getDevice(), *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
88     m_nestedCmdBuffer =
89         vk::allocateCommandBuffer(m_vk, m_context.getDevice(), *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
90 }
91 
iterate(void)92 tcu::TestStatus ConditionalClearAttachmentTest::iterate(void)
93 {
94     tcu::TestLog &log         = m_context.getTestContext().getLog();
95     const vk::VkQueue queue   = m_context.getUniversalQueue();
96     const vk::VkDevice device = m_context.getDevice();
97 
98     const tcu::Vec4 clearColor = tcu::RGBA::black().toVec();
99     const tcu::Vec4 drawColor  = tcu::RGBA::blue().toVec();
100 
101     beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
102     preRenderBarriers();
103     const bool useSecondaryCmdBuffer =
104         m_conditionalData.conditionInherited || m_conditionalData.conditionInSecondaryCommandBuffer;
105     beginLegacyRender(*m_cmdBuffer, useSecondaryCmdBuffer ? vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS :
106                                                             vk::VK_SUBPASS_CONTENTS_INLINE);
107 
108     vk::VkCommandBuffer targetCmdBuffer = *m_cmdBuffer;
109 
110     if (useSecondaryCmdBuffer)
111     {
112         const vk::VkCommandBufferInheritanceConditionalRenderingInfoEXT conditionalRenderingInheritanceInfo = {
113             vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT, DE_NULL,
114             m_conditionalData.conditionInherited ? VK_TRUE : VK_FALSE // conditionalRenderingEnable
115         };
116 
117         const vk::VkCommandBufferInheritanceInfo inheritanceInfo = {
118             vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
119             &conditionalRenderingInheritanceInfo,
120             *m_renderPass,                         // renderPass
121             0u,                                    // subpass
122             *m_framebuffer,                        // framebuffer
123             VK_FALSE,                              // occlusionQueryEnable
124             (vk::VkQueryControlFlags)0u,           // queryFlags
125             (vk::VkQueryPipelineStatisticFlags)0u, // pipelineStatistics
126         };
127 
128         const vk::VkCommandBufferBeginInfo commandBufferBeginInfo = {
129             vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, DE_NULL,
130             vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inheritanceInfo};
131 
132         if (m_conditionalData.secondaryCommandBufferNested)
133         {
134             VK_CHECK(m_vk.beginCommandBuffer(*m_nestedCmdBuffer, &commandBufferBeginInfo));
135         }
136 
137         VK_CHECK(m_vk.beginCommandBuffer(*m_secondaryCmdBuffer, &commandBufferBeginInfo));
138 
139         targetCmdBuffer = *m_secondaryCmdBuffer;
140     }
141 
142     m_vk.cmdBindPipeline(targetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
143 
144     const vk::VkClearAttachment clearAttachment = {
145         vk::VK_IMAGE_ASPECT_COLOR_BIT,     // VkImageAspectFlags aspectMask;
146         0u,                                // uint32_t colorAttachment;
147         vk::makeClearValueColor(drawColor) // VkClearValue clearValue;
148     };
149 
150     const vk::VkClearRect rect = {
151         vk::makeRect2D(WIDTH, HEIGHT), // VkRect2D    rect;
152         0u,                            // uint32_t    baseArrayLayer;
153         1u,                            // uint32_t    layerCount;
154     };
155 
156     m_conditionalBuffer = createConditionalRenderingBuffer(m_context, m_conditionalData);
157 
158     if (m_conditionalData.conditionInSecondaryCommandBuffer)
159     {
160         beginConditionalRendering(m_vk, *m_secondaryCmdBuffer, *m_conditionalBuffer, m_conditionalData);
161         m_vk.cmdClearAttachments(*m_secondaryCmdBuffer, 1, &clearAttachment, 1, &rect);
162         m_vk.cmdEndConditionalRenderingEXT(*m_secondaryCmdBuffer);
163         m_vk.endCommandBuffer(*m_secondaryCmdBuffer);
164     }
165     else if (m_conditionalData.conditionInherited)
166     {
167         m_vk.cmdClearAttachments(*m_secondaryCmdBuffer, 1, &clearAttachment, 1, &rect);
168         m_vk.endCommandBuffer(*m_secondaryCmdBuffer);
169     }
170 
171     if (useSecondaryCmdBuffer && m_conditionalData.secondaryCommandBufferNested)
172     {
173         m_vk.cmdExecuteCommands(*m_nestedCmdBuffer, 1, &m_secondaryCmdBuffer.get());
174         m_vk.endCommandBuffer(*m_nestedCmdBuffer);
175     }
176 
177     if (m_conditionalData.conditionInPrimaryCommandBuffer)
178     {
179         beginConditionalRendering(m_vk, *m_cmdBuffer, *m_conditionalBuffer, m_conditionalData);
180 
181         if (m_conditionalData.conditionInherited)
182         {
183             if (m_conditionalData.secondaryCommandBufferNested)
184             {
185                 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_nestedCmdBuffer.get());
186             }
187             else
188             {
189                 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_secondaryCmdBuffer.get());
190             }
191         }
192         else
193         {
194             m_vk.cmdClearAttachments(*m_cmdBuffer, 1, &clearAttachment, 1, &rect);
195         }
196 
197         m_vk.cmdEndConditionalRenderingEXT(*m_cmdBuffer);
198     }
199     else if (useSecondaryCmdBuffer)
200     {
201         if (m_conditionalData.secondaryCommandBufferNested)
202         {
203             m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_nestedCmdBuffer.get());
204         }
205         else
206         {
207             m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_secondaryCmdBuffer.get());
208         }
209     }
210 
211     endLegacyRender(*m_cmdBuffer);
212     endCommandBuffer(m_vk, *m_cmdBuffer);
213 
214     submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
215 
216     // Validation
217     tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
218                                   (int)(0.5f + static_cast<float>(HEIGHT)));
219     referenceFrame.allocLevel(0);
220 
221     const int32_t frameWidth  = referenceFrame.getWidth();
222     const int32_t frameHeight = referenceFrame.getHeight();
223 
224     tcu::clear(referenceFrame.getLevel(0), clearColor);
225 
226     const tcu::Vec4 referenceColor = m_conditionalData.expectCommandExecution ? drawColor : clearColor;
227 
228     for (int y = 0; y < frameHeight; y++)
229     {
230         for (int x = 0; x < frameWidth; x++)
231         {
232             referenceFrame.getLevel(0).setPixel(referenceColor, x, y);
233         }
234     }
235 
236     const vk::VkOffset3D zeroOffset = {0, 0, 0};
237     const tcu::ConstPixelBufferAccess renderedFrame =
238         m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset,
239                                         WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
240 
241     qpTestResult res = QP_TEST_RESULT_PASS;
242 
243     if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame.getLevel(0), renderedFrame, 0.05f,
244                            tcu::COMPARE_LOG_RESULT))
245     {
246         res = QP_TEST_RESULT_FAIL;
247     }
248 
249     return tcu::TestStatus(res, qpGetTestResultName(res));
250 }
251 
252 } // namespace
253 
ConditionalClearAttachmentTests(tcu::TestContext & testCtx)254 ConditionalClearAttachmentTests::ConditionalClearAttachmentTests(tcu::TestContext &testCtx)
255     : TestCaseGroup(testCtx, "clear_attachments")
256 {
257     /* Left blank on purpose */
258 }
259 
~ConditionalClearAttachmentTests(void)260 ConditionalClearAttachmentTests::~ConditionalClearAttachmentTests(void)
261 {
262 }
263 
init(void)264 void ConditionalClearAttachmentTests::init(void)
265 {
266     for (int conditionNdx = 0; conditionNdx < DE_LENGTH_OF_ARRAY(conditional::s_testsData); conditionNdx++)
267     {
268         const ConditionalData &conditionData = conditional::s_testsData[conditionNdx];
269 
270         if (conditionData.clearInRenderPass)
271             continue;
272 
273         tcu::TestCaseGroup *conditionalDrawRootGroup =
274             new tcu::TestCaseGroup(m_testCtx, de::toString(conditionData).c_str());
275 
276         ConditionalTestSpec testSpec;
277         testSpec.conditionalData                   = conditionData;
278         testSpec.shaders[glu::SHADERTYPE_VERTEX]   = "vulkan/dynamic_state/VertexFetch.vert";
279         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/dynamic_state/VertexFetch.frag";
280 
281         conditionalDrawRootGroup->addChild(
282             new Draw::InstanceFactory<ConditionalClearAttachmentTest>(m_testCtx, "clear_attachments", testSpec));
283 
284         addChild(conditionalDrawRootGroup);
285     }
286 }
287 
288 } // namespace conditional
289 } // namespace vkt
290