1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Intel 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 Dynamic State Tests - General
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktDynamicStateGeneralTests.hpp"
28 
29 #include "vktTestCaseUtil.hpp"
30 #include "vktDynamicStateTestCaseUtil.hpp"
31 #include "vktDynamicStateBaseClass.hpp"
32 #include "vktDrawCreateInfoUtil.hpp"
33 #include "vktDrawImageObjectUtil.hpp"
34 #include "vktDrawBufferObjectUtil.hpp"
35 
36 #include "vkImageUtil.hpp"
37 #include "vkCmdUtil.hpp"
38 
39 #include "tcuTestLog.hpp"
40 #include "tcuResource.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "tcuTextureUtil.hpp"
43 #include "tcuRGBA.hpp"
44 
45 #include "vkDefs.hpp"
46 #include "vkCmdUtil.hpp"
47 #include "vkObjUtil.hpp"
48 #include "vkBarrierUtil.hpp"
49 
50 namespace vkt
51 {
52 namespace DynamicState
53 {
54 
55 using namespace Draw;
56 
57 namespace
58 {
59 
60 class StateSwitchTestInstance : public DynamicStateBaseClass
61 {
62 public:
StateSwitchTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const ShaderMap & shaders)63     StateSwitchTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
64                             const ShaderMap &shaders)
65         : DynamicStateBaseClass(context, pipelineConstructionType, shaders.at(glu::SHADERTYPE_VERTEX),
66                                 shaders.at(glu::SHADERTYPE_FRAGMENT), shaders.at(glu::SHADERTYPE_MESH))
67     {
68         m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
69         m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
70         m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
71         m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
72 
73         DynamicStateBaseClass::initialize();
74     }
75 
iterate(void)76     virtual tcu::TestStatus iterate(void)
77     {
78         tcu::TestLog &log         = m_context.getTestContext().getLog();
79         const vk::VkQueue queue   = m_context.getUniversalQueue();
80         const vk::VkDevice device = m_context.getDevice();
81 
82         beginRenderPass();
83 
84         // bind states here
85         vk::VkViewport viewport = {0, 0, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f};
86         vk::VkRect2D scissor_1  = {{0, 0}, {WIDTH / 2, HEIGHT / 2}};
87         vk::VkRect2D scissor_2  = {{WIDTH / 2, HEIGHT / 2}, {WIDTH / 2, HEIGHT / 2}};
88 
89         setDynamicRasterizationState();
90         setDynamicBlendState();
91         setDynamicDepthStencilState();
92 
93         m_pipeline.bind(*m_cmdBuffer);
94 
95 #ifndef CTS_USES_VULKANSC
96         if (m_isMesh)
97         {
98             const auto numVert = static_cast<uint32_t>(m_data.size());
99             DE_ASSERT(numVert >= 2u);
100 
101             m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout.get(), 0u,
102                                        1u, &m_descriptorSet.get(), 0u, nullptr);
103             pushVertexOffset(0u, *m_pipelineLayout);
104 
105             // bind first state
106             setDynamicViewportState(1, &viewport, &scissor_1);
107             m_vk.cmdDrawMeshTasksEXT(*m_cmdBuffer, numVert - 2u, 1u, 1u);
108 
109             // bind second state
110             setDynamicViewportState(1, &viewport, &scissor_2);
111             m_vk.cmdDrawMeshTasksEXT(*m_cmdBuffer, numVert - 2u, 1u, 1u);
112         }
113         else
114 #endif // CTS_USES_VULKANSC
115         {
116             const vk::VkDeviceSize vertexBufferOffset = 0;
117             const vk::VkBuffer vertexBuffer           = m_vertexBuffer->object();
118             m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
119 
120             // bind first state
121             setDynamicViewportState(1, &viewport, &scissor_1);
122             m_vk.cmdDraw(*m_cmdBuffer, static_cast<uint32_t>(m_data.size()), 1, 0, 0);
123 
124             // bind second state
125             setDynamicViewportState(1, &viewport, &scissor_2);
126             m_vk.cmdDraw(*m_cmdBuffer, static_cast<uint32_t>(m_data.size()), 1, 0, 0);
127         }
128 
129         m_renderPass.end(m_vk, *m_cmdBuffer);
130         endCommandBuffer(m_vk, *m_cmdBuffer);
131 
132         submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
133 
134         //validation
135         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
136                                       (int)(0.5f + static_cast<float>(HEIGHT)));
137         referenceFrame.allocLevel(0);
138 
139         const int32_t frameWidth  = referenceFrame.getWidth();
140         const int32_t frameHeight = referenceFrame.getHeight();
141 
142         tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
143 
144         for (int y = 0; y < frameHeight; y++)
145         {
146             const float yCoord = (float)(y / (0.5 * frameHeight)) - 1.0f;
147 
148             for (int x = 0; x < frameWidth; x++)
149             {
150                 const float xCoord = (float)(x / (0.5 * frameWidth)) - 1.0f;
151 
152                 if ((yCoord >= -1.0f && yCoord <= 0.0f && xCoord >= -1.0f && xCoord <= 0.0f) ||
153                     (yCoord > 0.0f && yCoord <= 1.0f && xCoord > 0.0f && xCoord < 1.0f))
154                     referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
155             }
156         }
157 
158         const vk::VkOffset3D zeroOffset = {0, 0, 0};
159         const tcu::ConstPixelBufferAccess renderedFrame =
160             m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
161                                             zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
162 
163         if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame.getLevel(0), renderedFrame,
164                                0.05f, tcu::COMPARE_LOG_RESULT))
165         {
166 
167             return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
168         }
169 
170         return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
171     }
172 };
173 
174 class BindOrderTestInstance : public DynamicStateBaseClass
175 {
176 public:
BindOrderTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const ShaderMap & shaders)177     BindOrderTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
178                           const ShaderMap &shaders)
179         : DynamicStateBaseClass(context, pipelineConstructionType, shaders.at(glu::SHADERTYPE_VERTEX),
180                                 shaders.at(glu::SHADERTYPE_FRAGMENT), shaders.at(glu::SHADERTYPE_MESH))
181     {
182         m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
183         m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
184         m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
185         m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
186 
187         DynamicStateBaseClass::initialize();
188     }
189 
iterate(void)190     virtual tcu::TestStatus iterate(void)
191     {
192         tcu::TestLog &log         = m_context.getTestContext().getLog();
193         const vk::VkQueue queue   = m_context.getUniversalQueue();
194         const vk::VkDevice device = m_context.getDevice();
195 
196         beginRenderPass();
197 
198         // bind states here
199         vk::VkViewport viewport = {0.0f, 0.0f, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f};
200         vk::VkRect2D scissor_1  = {{0, 0}, {WIDTH / 2, HEIGHT / 2}};
201         vk::VkRect2D scissor_2  = {{WIDTH / 2, HEIGHT / 2}, {WIDTH / 2, HEIGHT / 2}};
202 
203         setDynamicRasterizationState();
204         setDynamicBlendState();
205         setDynamicDepthStencilState();
206         setDynamicViewportState(1, &viewport, &scissor_1);
207 
208         m_pipeline.bind(*m_cmdBuffer);
209 
210 #ifndef CTS_USES_VULKANSC
211         if (m_isMesh)
212         {
213             const auto numVert = static_cast<uint32_t>(m_data.size());
214             DE_ASSERT(numVert >= 2u);
215 
216             m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout.get(), 0u,
217                                        1u, &m_descriptorSet.get(), 0u, nullptr);
218             pushVertexOffset(0u, *m_pipelineLayout);
219 
220             // rebind in different order
221             setDynamicBlendState();
222             setDynamicRasterizationState();
223             setDynamicDepthStencilState();
224 
225             // bind first state
226             setDynamicViewportState(1, &viewport, &scissor_1);
227             m_vk.cmdDrawMeshTasksEXT(*m_cmdBuffer, numVert - 2u, 1u, 1u);
228 
229             setDynamicViewportState(1, &viewport, &scissor_2);
230             m_vk.cmdDrawMeshTasksEXT(*m_cmdBuffer, numVert - 2u, 1u, 1u);
231         }
232         else
233 #endif // CTS_USES_VULKANSC
234         {
235             const vk::VkDeviceSize vertexBufferOffset = 0;
236             const vk::VkBuffer vertexBuffer           = m_vertexBuffer->object();
237             m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
238 
239             // rebind in different order
240             setDynamicBlendState();
241             setDynamicRasterizationState();
242             setDynamicDepthStencilState();
243 
244             // bind first state
245             setDynamicViewportState(1, &viewport, &scissor_1);
246             m_vk.cmdDraw(*m_cmdBuffer, static_cast<uint32_t>(m_data.size()), 1, 0, 0);
247 
248             setDynamicViewportState(1, &viewport, &scissor_2);
249             m_vk.cmdDraw(*m_cmdBuffer, static_cast<uint32_t>(m_data.size()), 1, 0, 0);
250         }
251 
252         m_renderPass.end(m_vk, *m_cmdBuffer);
253         endCommandBuffer(m_vk, *m_cmdBuffer);
254 
255         submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
256 
257         //validation
258         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
259                                       (int)(0.5f + static_cast<float>(HEIGHT)));
260         referenceFrame.allocLevel(0);
261 
262         const int32_t frameWidth  = referenceFrame.getWidth();
263         const int32_t frameHeight = referenceFrame.getHeight();
264 
265         tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
266 
267         for (int y = 0; y < frameHeight; y++)
268         {
269             const float yCoord = (float)(y / (0.5 * frameHeight)) - 1.0f;
270 
271             for (int x = 0; x < frameWidth; x++)
272             {
273                 const float xCoord = (float)(x / (0.5 * frameWidth)) - 1.0f;
274 
275                 if ((yCoord >= -1.0f && yCoord <= 0.0f && xCoord >= -1.0f && xCoord <= 0.0f) ||
276                     (yCoord > 0.0f && yCoord <= 1.0f && xCoord > 0.0f && xCoord < 1.0f))
277                     referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
278             }
279         }
280 
281         const vk::VkOffset3D zeroOffset = {0, 0, 0};
282         const tcu::ConstPixelBufferAccess renderedFrame =
283             m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
284                                             zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
285 
286         if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame.getLevel(0), renderedFrame,
287                                0.05f, tcu::COMPARE_LOG_RESULT))
288         {
289             return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
290         }
291 
292         return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
293     }
294 };
295 
296 class StatePersistenceTestInstance : public DynamicStateBaseClass
297 {
298 protected:
299     vk::GraphicsPipelineWrapper m_pipelineAdditional;
300 
301 public:
StatePersistenceTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const ShaderMap & shaders)302     StatePersistenceTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
303                                  const ShaderMap &shaders)
304         : DynamicStateBaseClass(context, pipelineConstructionType, shaders.at(glu::SHADERTYPE_VERTEX),
305                                 shaders.at(glu::SHADERTYPE_FRAGMENT), shaders.at(glu::SHADERTYPE_MESH))
306         , m_pipelineAdditional(context.getInstanceInterface(), context.getDeviceInterface(),
307                                context.getPhysicalDevice(), context.getDevice(), context.getDeviceExtensions(),
308                                pipelineConstructionType)
309     {
310         // This test does not make sense for mesh shader variants.
311         DE_ASSERT(!m_isMesh);
312 
313         m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
314         m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
315         m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
316         m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
317 
318         m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
319         m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
320         m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
321         m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
322         m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
323         m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
324 
325         DynamicStateBaseClass::initialize();
326     }
initPipeline(const vk::VkDevice device)327     virtual void initPipeline(const vk::VkDevice device)
328     {
329         const vk::ShaderWrapper vs(
330             vk::ShaderWrapper(m_vk, device, m_context.getBinaryCollection().get(m_vertexShaderName), 0));
331         const vk::ShaderWrapper fs(
332             vk::ShaderWrapper(m_vk, device, m_context.getBinaryCollection().get(m_fragmentShaderName), 0));
333         std::vector<vk::VkViewport> viewports{{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}};
334         std::vector<vk::VkRect2D> scissors{{{0u, 0u}, {0u, 0u}}};
335 
336         const PipelineCreateInfo::ColorBlendState::Attachment attachmentState;
337         const PipelineCreateInfo::ColorBlendState colorBlendState(
338             1, static_cast<const vk::VkPipelineColorBlendAttachmentState *>(&attachmentState));
339         const PipelineCreateInfo::RasterizerState rasterizerState;
340         const PipelineCreateInfo::DepthStencilState depthStencilState;
341         const PipelineCreateInfo::DynamicState dynamicState;
342 
343         m_pipeline.setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
344             .setDynamicState(static_cast<const vk::VkPipelineDynamicStateCreateInfo *>(&dynamicState))
345             .setDefaultMultisampleState()
346             .setupVertexInputState(&m_vertexInputState)
347             .setupPreRasterizationShaderState(
348                 viewports, scissors, m_pipelineLayout, *m_renderPass, 0u, vs,
349                 static_cast<const vk::VkPipelineRasterizationStateCreateInfo *>(&rasterizerState))
350             .setupFragmentShaderState(
351                 m_pipelineLayout, *m_renderPass, 0u, fs,
352                 static_cast<const vk::VkPipelineDepthStencilStateCreateInfo *>(&depthStencilState))
353             .setupFragmentOutputState(*m_renderPass, 0u,
354                                       static_cast<const vk::VkPipelineColorBlendStateCreateInfo *>(&colorBlendState))
355             .setMonolithicPipelineLayout(m_pipelineLayout)
356             .buildPipeline();
357 
358         m_pipelineAdditional.setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
359             .setDynamicState(static_cast<const vk::VkPipelineDynamicStateCreateInfo *>(&dynamicState))
360             .setDefaultMultisampleState()
361             .setupVertexInputState(&m_vertexInputState)
362             .setupPreRasterizationShaderState(
363                 viewports, scissors, m_pipelineLayout, *m_renderPass, 0u, vs,
364                 static_cast<const vk::VkPipelineRasterizationStateCreateInfo *>(&rasterizerState))
365             .setupFragmentShaderState(
366                 m_pipelineLayout, *m_renderPass, 0u, fs,
367                 static_cast<const vk::VkPipelineDepthStencilStateCreateInfo *>(&depthStencilState))
368             .setupFragmentOutputState(*m_renderPass, 0u,
369                                       static_cast<const vk::VkPipelineColorBlendStateCreateInfo *>(&colorBlendState))
370             .setMonolithicPipelineLayout(m_pipelineLayout)
371             .buildPipeline();
372     }
373 
iterate(void)374     virtual tcu::TestStatus iterate(void)
375     {
376         tcu::TestLog &log         = m_context.getTestContext().getLog();
377         const vk::VkQueue queue   = m_context.getUniversalQueue();
378         const vk::VkDevice device = m_context.getDevice();
379 
380         beginRenderPass();
381 
382         // bind states here
383         const vk::VkViewport viewport = {0.0f, 0.0f, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f};
384         const vk::VkRect2D scissor_1  = {{0, 0}, {WIDTH / 2, HEIGHT / 2}};
385         const vk::VkRect2D scissor_2  = {{WIDTH / 2, HEIGHT / 2}, {WIDTH / 2, HEIGHT / 2}};
386 
387         setDynamicRasterizationState();
388         setDynamicBlendState();
389         setDynamicDepthStencilState();
390 
391         m_pipeline.bind(*m_cmdBuffer);
392 
393         const vk::VkDeviceSize vertexBufferOffset = 0;
394         const vk::VkBuffer vertexBuffer           = m_vertexBuffer->object();
395         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
396 
397         // bind first state
398         setDynamicViewportState(1, &viewport, &scissor_1);
399         // draw quad using vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
400         m_vk.cmdDraw(*m_cmdBuffer, 4, 1, 0, 0);
401 
402         m_pipelineAdditional.bind(*m_cmdBuffer);
403 
404         // bind second state
405         setDynamicViewportState(1, &viewport, &scissor_2);
406         // draw quad using vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
407         m_vk.cmdDraw(*m_cmdBuffer, 6, 1, 4, 0);
408 
409         m_renderPass.end(m_vk, *m_cmdBuffer);
410         endCommandBuffer(m_vk, *m_cmdBuffer);
411 
412         submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
413 
414         //validation
415         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
416                                       (int)(0.5f + static_cast<float>(HEIGHT)));
417         referenceFrame.allocLevel(0);
418 
419         const int32_t frameWidth  = referenceFrame.getWidth();
420         const int32_t frameHeight = referenceFrame.getHeight();
421 
422         tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
423 
424         for (int y = 0; y < frameHeight; y++)
425         {
426             const float yCoord = (float)(y / (0.5 * frameHeight)) - 1.0f;
427 
428             for (int x = 0; x < frameWidth; x++)
429             {
430                 const float xCoord = (float)(x / (0.5 * frameWidth)) - 1.0f;
431 
432                 if (yCoord >= -1.0f && yCoord <= 0.0f && xCoord >= -1.0f && xCoord <= 0.0f)
433                     referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
434                 else if (yCoord > 0.0f && yCoord <= 1.0f && xCoord > 0.0f && xCoord < 1.0f)
435                     referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
436             }
437         }
438 
439         const vk::VkOffset3D zeroOffset = {0, 0, 0};
440         const tcu::ConstPixelBufferAccess renderedFrame =
441             m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
442                                             zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
443 
444         if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame.getLevel(0), renderedFrame,
445                                0.05f, tcu::COMPARE_LOG_RESULT))
446         {
447             return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
448         }
449 
450         return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
451     }
452 };
453 
454 #ifndef CTS_USES_VULKANSC
checkMeshShaderSupport(Context & context)455 void checkMeshShaderSupport(Context &context)
456 {
457     context.requireDeviceFunctionality("VK_EXT_mesh_shader");
458 }
459 #endif // CTS_USES_VULKANSC
460 
checkNothing(Context &)461 void checkNothing(Context &)
462 {
463 }
464 
initStaticStencilMaskZeroPrograms(vk::SourceCollections & dst,vk::PipelineConstructionType)465 void initStaticStencilMaskZeroPrograms(vk::SourceCollections &dst, vk::PipelineConstructionType)
466 {
467     std::ostringstream vert;
468     vert << "#version 460\n"
469          << "layout (location=0) in vec4 inPos;\n"
470          << "layout (location=1) in vec4 inColor;\n"
471          << "layout (location=0) out vec4 outColor;\n"
472          << "void main (void) {\n"
473          << "    gl_Position = inPos;\n"
474          << "    outColor = inColor;\n"
475          << "}\n";
476     dst.glslSources.add("vert") << glu::VertexSource(vert.str());
477 
478     // Fragment shader such that it will actually discard all fragments.
479     std::ostringstream frag;
480     frag << "#version 460\n"
481          << "layout (location=0) in vec4 inColor;\n"
482          << "layout (location=0) out vec4 outColor;\n"
483          << "void main (void) {\n"
484          << "    if (inColor == vec4(0.0, 0.0, 1.0, 1.0)) {\n"
485          << "        discard;\n"
486          << "    }\n"
487          << "    outColor = inColor;\n"
488          << "}\n";
489     dst.glslSources.add("frag") << glu::FragmentSource(frag.str());
490 }
491 
checkStaticStencilMaskZeroSupport(vkt::Context & context,vk::PipelineConstructionType pipelineConstructionType)492 void checkStaticStencilMaskZeroSupport(vkt::Context &context, vk::PipelineConstructionType pipelineConstructionType)
493 {
494     const auto &vki           = context.getInstanceInterface();
495     const auto physicalDevice = context.getPhysicalDevice();
496 
497     checkPipelineConstructionRequirements(vki, physicalDevice, pipelineConstructionType);
498 }
499 
500 // Find a suitable format for the depth/stencil buffer.
chooseDepthStencilFormat(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physDev)501 vk::VkFormat chooseDepthStencilFormat(const vk::InstanceInterface &vki, vk::VkPhysicalDevice physDev)
502 {
503     // The spec mandates support for one of these two formats.
504     const vk::VkFormat candidates[] = {vk::VK_FORMAT_D32_SFLOAT_S8_UINT, vk::VK_FORMAT_D24_UNORM_S8_UINT};
505 
506     for (const auto &format : candidates)
507     {
508         const auto properties = getPhysicalDeviceFormatProperties(vki, physDev, format);
509         if ((properties.optimalTilingFeatures & vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0u)
510             return format;
511     }
512 
513     TCU_FAIL("No suitable depth/stencil format found");
514     return vk::VK_FORMAT_UNDEFINED; // Unreachable.
515 }
516 
517 // On some implementations, when the static state is 0, the pipeline is created
518 // such that it is unable to avoid writing to stencil when a pixel is discarded.
staticStencilMaskZeroProgramsTest(Context & context,vk::PipelineConstructionType pipelineConstructionType)519 tcu::TestStatus staticStencilMaskZeroProgramsTest(Context &context,
520                                                   vk::PipelineConstructionType pipelineConstructionType)
521 {
522     const auto &ctx = context.getContextCommonData();
523     const tcu::IVec3 fbExtent(1, 1, 1);
524     const auto pixelCount  = fbExtent.x() * fbExtent.y() * fbExtent.z();
525     const auto vkExtent    = vk::makeExtent3D(fbExtent);
526     const auto fbFormat    = vk::VK_FORMAT_R8G8B8A8_UNORM;
527     const auto tcuFormat   = mapVkFormat(fbFormat);
528     const auto fbUsage     = (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
529     const auto dsFormat    = chooseDepthStencilFormat(ctx.vki, ctx.physicalDevice);
530     const auto depthFormat = vk::getDepthCopyFormat(dsFormat);
531     const auto stencilFmt  = vk::getStencilCopyFormat(dsFormat);
532     const auto dsUsage     = (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
533     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
534     const float clearDepth    = 1.0f;
535     const uint32_t clearStenc = 0u;
536     const tcu::Vec4 geomColor(0.0f, 0.0f, 1.0f, 1.0f); // Must match frag shader discard color.
537     const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f); // When using 0 and 1 only, we expect exact results.
538     const auto colorSRR = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
539     const auto dsSRR = vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT),
540                                                      0u, 1u, 0u, 1u);
541     const auto colorSRL   = vk::makeImageSubresourceLayers(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
542     const auto depthSRL   = vk::makeImageSubresourceLayers(vk::VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 0u, 1u);
543     const auto stencilSRL = vk::makeImageSubresourceLayers(vk::VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 0u, 1u);
544 
545     // Color buffer with verification buffer.
546     vk::ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, fbFormat, fbUsage,
547                                     vk::VK_IMAGE_TYPE_2D);
548 
549     // Depth/stencil buffer.
550     const vk::VkImageCreateInfo dsCreateInfo = {
551         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
552         nullptr,                                 // const void* pNext;
553         0u,                                      // VkImageCreateFlags flags;
554         vk::VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
555         dsFormat,                                // VkFormat format;
556         vkExtent,                                // VkExtent3D extent;
557         1u,                                      // uint32_t mipLevels;
558         1u,                                      // uint32_t arrayLayers;
559         vk::VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
560         vk::VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
561         dsUsage,                                 // VkImageUsageFlags usage;
562         vk::VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
563         0u,                                      // uint32_t queueFamilyIndexCount;
564         nullptr,                                 // const uint32_t* pQueueFamilyIndices;
565         vk::VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
566     };
567     vk::ImageWithMemory dsBuffer(ctx.vkd, ctx.device, ctx.allocator, dsCreateInfo, vk::MemoryRequirement::Any);
568     const auto dsImageView =
569         vk::makeImageView(ctx.vkd, ctx.device, dsBuffer.get(), vk::VK_IMAGE_VIEW_TYPE_2D, dsFormat, dsSRR);
570 
571     // Verification buffers for depth and stencil.
572     const auto depthVerifBufferSize = static_cast<vk::VkDeviceSize>(tcu::getPixelSize(depthFormat) * pixelCount);
573     const auto depthVerifBufferInfo =
574         vk::makeBufferCreateInfo(depthVerifBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
575     vk::BufferWithMemory depthVerifBuffer(ctx.vkd, ctx.device, ctx.allocator, depthVerifBufferInfo,
576                                           vk::MemoryRequirement::HostVisible);
577 
578     const auto stencilVerifBufferSize = static_cast<vk::VkDeviceSize>(tcu::getPixelSize(stencilFmt) * pixelCount);
579     const auto stencilVerifBufferInfo =
580         vk::makeBufferCreateInfo(stencilVerifBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
581     vk::BufferWithMemory stencilVerifBuffer(ctx.vkd, ctx.device, ctx.allocator, stencilVerifBufferInfo,
582                                             vk::MemoryRequirement::HostVisible);
583 
584     // Vertices.
585     const std::vector<PositionColorVertex> vertices{
586         PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), geomColor),
587         PositionColorVertex(tcu::Vec4(-1.0f, 3.0f, 0.0f, 1.0f), geomColor),
588         PositionColorVertex(tcu::Vec4(3.0f, -1.0f, 0.0f, 1.0f), geomColor),
589     };
590 
591     // Vertex buffer
592     const auto vbSize = static_cast<vk::VkDeviceSize>(de::dataSize(vertices));
593     const auto vbInfo = vk::makeBufferCreateInfo(vbSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
594     vk::BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vbInfo, vk::MemoryRequirement::HostVisible);
595     const auto vbAlloc  = vertexBuffer.getAllocation();
596     void *vbData        = vbAlloc.getHostPtr();
597     const auto vbOffset = static_cast<vk::VkDeviceSize>(0);
598 
599     deMemcpy(vbData, de::dataOrNull(vertices), de::dataSize(vertices));
600     flushAlloc(ctx.vkd, ctx.device, vbAlloc); // strictly speaking, not needed.
601 
602     const std::vector<vk::VkImage> framebufferImages{
603         colorBuffer.getImage(),
604         dsBuffer.get(),
605     };
606 
607     const std::vector<vk::VkImageView> framebufferViews{
608         colorBuffer.getImageView(),
609         dsImageView.get(),
610     };
611 
612     const auto pipelineLayout = vk::PipelineLayoutWrapper(pipelineConstructionType, ctx.vkd, ctx.device);
613     auto renderPass = vk::RenderPassWrapper(pipelineConstructionType, ctx.vkd, ctx.device, fbFormat, dsFormat);
614 
615     DE_ASSERT(framebufferImages.size() == framebufferViews.size());
616     renderPass.createFramebuffer(ctx.vkd, ctx.device, de::sizeU32(framebufferViews), de::dataOrNull(framebufferImages),
617                                  de::dataOrNull(framebufferViews), vkExtent.width, vkExtent.height);
618 
619     // Modules.
620     const auto &binaries  = context.getBinaryCollection();
621     const auto vertModule = vk::ShaderWrapper(ctx.vkd, ctx.device, binaries.get("vert"));
622     const auto fragModule = vk::ShaderWrapper(ctx.vkd, ctx.device, binaries.get("frag"));
623 
624     const std::vector<vk::VkViewport> viewports(1u, makeViewport(vkExtent));
625     const std::vector<vk::VkRect2D> scissors(1u, makeRect2D(vkExtent));
626 
627     const auto stencilStaticWriteMask =
628         0u; // This is key for this test and what was causing issues in some implementations.
629     const auto stencilDynamicWriteMask = 0xFFu;
630 
631     const std::vector<vk::VkDynamicState> dynamicStates{vk::VK_DYNAMIC_STATE_STENCIL_WRITE_MASK};
632 
633     // The stencil op state is such that it will overwrite the stencil value for all non-discarded fragments.
634     // However, the fragment shader should discard all fragments.
635     const auto stencilOpState =
636         vk::makeStencilOpState(vk::VK_STENCIL_OP_REPLACE, vk::VK_STENCIL_OP_REPLACE, vk::VK_STENCIL_OP_REPLACE,
637                                vk::VK_COMPARE_OP_ALWAYS, 0xFFu, stencilStaticWriteMask, 0xFFu);
638 
639     const auto vtxBindingDesc = vk::makeVertexInputBindingDescription(
640         0u, static_cast<uint32_t>(sizeof(PositionColorVertex)), vk::VK_VERTEX_INPUT_RATE_VERTEX);
641 
642     const std::vector<vk::VkVertexInputAttributeDescription> vtxAttributes{
643         vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT,
644                                                 static_cast<uint32_t>(offsetof(PositionColorVertex, position))),
645         vk::makeVertexInputAttributeDescription(1u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT,
646                                                 static_cast<uint32_t>(offsetof(PositionColorVertex, color))),
647     };
648 
649     const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
650         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
651         nullptr,                                                       // const void* pNext;
652         0u,                                                            // VkPipelineVertexInputStateCreateFlags flags;
653         1u,                                                            // uint32_t vertexBindingDescriptionCount;
654         &vtxBindingDesc,               // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
655         de::sizeU32(vtxAttributes),    // uint32_t vertexAttributeDescriptionCount;
656         de::dataOrNull(vtxAttributes), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
657     };
658 
659     const vk::VkPipelineDepthStencilStateCreateInfo depthStencilState = {
660         vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
661         nullptr,                                                        // const void* pNext;
662         0u,                                                             // VkPipelineDepthStencilStateCreateFlags flags;
663         VK_FALSE,                                                       // VkBool32 depthTestEnable;
664         VK_TRUE,                                                        // VkBool32 depthWriteEnable;
665         vk::VK_COMPARE_OP_LESS,                                         // VkCompareOp depthCompareOp;
666         VK_FALSE,                                                       // VkBool32 depthBoundsTestEnable;
667         VK_TRUE,                                                        // VkBool32 stencilTestEnable;
668         stencilOpState,                                                 // VkStencilOpState front;
669         stencilOpState,                                                 // VkStencilOpState back;
670         0.0f,                                                           // float minDepthBounds;
671         1.0f,                                                           // float maxDepthBounds;
672     };
673 
674     const vk::VkPipelineDynamicStateCreateInfo dynamicStateInfo = {
675         vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
676         nullptr,                                                  // const void* pNext;
677         0u,                                                       // VkPipelineDynamicStateCreateFlags flags;
678         de::sizeU32(dynamicStates),                               // uint32_t dynamicStateCount;
679         de::dataOrNull(dynamicStates),                            // const VkDynamicState* pDynamicStates;
680     };
681 
682     vk::GraphicsPipelineWrapper pipeline(ctx.vki, ctx.vkd, ctx.physicalDevice, ctx.device,
683                                          context.getDeviceExtensions(), pipelineConstructionType);
684     pipeline.setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
685         .setDefaultMultisampleState()
686         .setDefaultRasterizationState()
687         .setDefaultColorBlendState()
688         .setDynamicState(&dynamicStateInfo)
689         .setupVertexInputState(&vertexInputStateCreateInfo)
690         .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPass, 0u, vertModule)
691         .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragModule, &depthStencilState)
692         .setupFragmentOutputState(*renderPass)
693         .setMonolithicPipelineLayout(pipelineLayout)
694         .buildPipeline();
695 
696     vk::CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
697     const auto cmdBuffer = *cmd.cmdBuffer;
698 
699     const std::vector<vk::VkClearValue> clearValues{
700         vk::makeClearValueColor(clearColor),
701         vk::makeClearValueDepthStencil(clearDepth, clearStenc),
702     };
703 
704     beginCommandBuffer(ctx.vkd, cmdBuffer);
705     renderPass.begin(ctx.vkd, cmdBuffer, scissors.at(0u), de::sizeU32(clearValues), de::dataOrNull(clearValues));
706     ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vbOffset);
707     pipeline.bind(cmdBuffer);
708     ctx.vkd.cmdSetStencilWriteMask(cmdBuffer, vk::VK_STENCIL_FACE_FRONT_AND_BACK,
709                                    stencilDynamicWriteMask); // Write every value.
710     ctx.vkd.cmdDraw(cmdBuffer, de::sizeU32(vertices), 1u, 0u, 0u);
711     renderPass.end(ctx.vkd, cmdBuffer);
712     {
713         // Insert barriers and copy images to the different verification buffers.
714         const std::vector<vk::VkImageMemoryBarrier> imageBarriers{
715             // Color barrier.
716             vk::makeImageMemoryBarrier(vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT,
717                                        vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
718                                        vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.getImage(), colorSRR),
719             // Depth/stencil barrier.
720             vk::makeImageMemoryBarrier(vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
721                                        vk::VK_ACCESS_TRANSFER_READ_BIT,
722                                        vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
723                                        vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dsBuffer.get(), dsSRR),
724         };
725         const auto srcPipelineStages =
726             (vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
727              vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
728 
729         ctx.vkd.cmdPipelineBarrier(cmdBuffer, srcPipelineStages, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr,
730                                    0u, nullptr, de::sizeU32(imageBarriers), de::dataOrNull(imageBarriers));
731 
732         const auto colorRegion = vk::makeBufferImageCopy(vkExtent, colorSRL);
733         ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.getImage(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
734                                      colorBuffer.getBuffer(), 1u, &colorRegion);
735 
736         const auto depthRegion = vk::makeBufferImageCopy(vkExtent, depthSRL);
737         ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, dsBuffer.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
738                                      depthVerifBuffer.get(), 1u, &depthRegion);
739 
740         const auto stencilRegion = vk::makeBufferImageCopy(vkExtent, stencilSRL);
741         ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, dsBuffer.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
742                                      stencilVerifBuffer.get(), 1u, &stencilRegion);
743     }
744     {
745         // Transfer to host sync barrier.
746         const auto transfer2Host = vk::makeMemoryBarrier(vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT);
747         ctx.vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, 0u,
748                                    1u, &transfer2Host, 0u, nullptr, 0u, nullptr);
749     }
750     endCommandBuffer(ctx.vkd, cmdBuffer);
751     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
752 
753     auto &log = context.getTestContext().getLog();
754 
755     // Verify color output.
756     vk::invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
757     tcu::PixelBufferAccess resColorAccess(tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
758 
759     tcu::TextureLevel refColorLevel(tcuFormat, fbExtent.x(), fbExtent.y());
760     auto refColorAccess = refColorLevel.getAccess();
761     tcu::clear(refColorAccess, clearColor); // All fragments should have been discarded.
762 
763     if (!tcu::floatThresholdCompare(log, "ColorResult", "", refColorAccess, resColorAccess, threshold,
764                                     tcu::COMPARE_LOG_ON_ERROR))
765         return tcu::TestStatus::fail("Unexpected color in result buffer; check log for details");
766 
767     // Verify depth.
768     vk::invalidateAlloc(ctx.vkd, ctx.device, depthVerifBuffer.getAllocation());
769     tcu::PixelBufferAccess resDepthAccess(depthFormat, fbExtent, depthVerifBuffer.getAllocation().getHostPtr());
770 
771     tcu::TextureLevel refDepthLevel(depthFormat, fbExtent.x(), fbExtent.y());
772     auto refDepthAccess = refDepthLevel.getAccess();
773     tcu::clearDepth(refDepthAccess, clearDepth); // All fragments should have been discarded.
774 
775     if (!tcu::dsThresholdCompare(log, "DepthResult", "", refDepthAccess, resDepthAccess, 0.0f,
776                                  tcu::COMPARE_LOG_ON_ERROR))
777         return tcu::TestStatus::fail("Unexpected depth in result buffer; check log for details");
778 
779     // Verify stencil.
780     vk::invalidateAlloc(ctx.vkd, ctx.device, stencilVerifBuffer.getAllocation());
781     tcu::PixelBufferAccess resStencilAccess(stencilFmt, fbExtent, stencilVerifBuffer.getAllocation().getHostPtr());
782 
783     tcu::TextureLevel refStencilLevel(stencilFmt, fbExtent.x(), fbExtent.y());
784     auto refStencilAccess = refStencilLevel.getAccess();
785     tcu::clearStencil(refStencilAccess, static_cast<int>(clearStenc)); // All fragments should have been discarded.
786 
787     if (!tcu::dsThresholdCompare(log, "StencilResult", "", refStencilAccess, resStencilAccess, 0.0f,
788                                  tcu::COMPARE_LOG_ON_ERROR))
789         return tcu::TestStatus::fail("Unexpected stencil value in result buffer; check log for details");
790 
791     return tcu::TestStatus::pass("Pass");
792 }
793 
initDoubleBindPrograms(vk::SourceCollections & dst)794 void initDoubleBindPrograms(vk::SourceCollections &dst)
795 {
796     std::ostringstream vert;
797     vert << "#version 460\n"
798          << "const vec4 vertices[] = vec4[](\n"
799          << "    vec4(-1.0, -1.0, 0.0, 1.0),\n"
800          << "    vec4(-1.0,  3.0, 0.0, 1.0),\n"
801          << "    vec4( 3.0, -1.0, 0.0, 1.0)\n"
802          << ");\n"
803          << "void main (void) {\n"
804          << "    gl_Position = vertices[gl_VertexIndex % 3];\n"
805          << "}\n";
806     dst.glslSources.add("vert") << glu::VertexSource(vert.str());
807 
808     std::ostringstream frag;
809     frag << "#version 460\n"
810          << "layout (location=0) out vec4 outColor;\n"
811          << "void main (void) {\n"
812          << "    outColor = vec4(0.0f, 0.0f, 1.0f, 1.0f);\n"
813          << "}\n";
814     dst.glslSources.add("frag") << glu::FragmentSource(frag.str());
815 }
816 
817 // The test does:
818 // - bind pipeline with some static state.
819 // - set state command for that static state (to a bad value).
820 // - bind the same pipeline again.
821 // - draw.
822 // - verify the good value has been used.
823 // In this case, the bad state and value will be the scissor, but the pipeline will also have a dynamic viewport.
doubleBindTest(Context & context)824 tcu::TestStatus doubleBindTest(Context &context)
825 {
826     const auto &ctx = context.getContextCommonData();
827     const tcu::IVec3 fbExtent(2, 2, 1);
828     const auto vkExtent  = vk::makeExtent3D(fbExtent);
829     const auto fbFormat  = vk::VK_FORMAT_R8G8B8A8_UNORM;
830     const auto tcuFormat = mapVkFormat(fbFormat);
831     const auto fbUsage   = (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
832     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
833     const tcu::Vec4 geomColor(0.0f, 0.0f, 1.0f, 1.0f); // Must match frag shader.
834     const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f); // When using 0 and 1 only, we expect exact results.
835     const auto bindPoint = vk::VK_PIPELINE_BIND_POINT_GRAPHICS;
836 
837     // Color buffer with verification buffer.
838     vk::ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, fbFormat, fbUsage,
839                                     vk::VK_IMAGE_TYPE_2D);
840 
841     const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device);
842     const auto renderPass     = makeRenderPass(ctx.vkd, ctx.device, fbFormat);
843     const auto framebuffer =
844         makeFramebuffer(ctx.vkd, ctx.device, *renderPass, colorBuffer.getImageView(), vkExtent.width, vkExtent.height);
845 
846     // Modules.
847     const auto &binaries  = context.getBinaryCollection();
848     const auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
849     const auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
850 
851     const std::vector<vk::VkDynamicState> dynamicStates{
852         vk::VK_DYNAMIC_STATE_VIEWPORT,
853     };
854 
855     const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
856         vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
857         nullptr,                                                  // const void* pNext;
858         0u,                                                       // VkPipelineDynamicStateCreateFlags flags;
859         de::sizeU32(dynamicStates),                               // uint32_t dynamicStateCount;
860         de::dataOrNull(dynamicStates),                            // const VkDynamicState* pDynamicStates;
861     };
862 
863     const auto goodViewport = makeViewport(vkExtent);
864     const auto goodScissor  = vk::makeRect2D(vkExtent);
865     const auto badViewport  = vk::makeViewport(1u, 1u); // Needs to be smaller than the framebuffer.
866     const auto badScissor   = vk::makeRect2D(1u, 1u);   // Needs to be smaller than the framebuffer.
867 
868     const std::vector<vk::VkViewport> staticViewports(1u, badViewport);
869     const std::vector<vk::VkRect2D> staticScissors(1u, goodScissor);
870 
871     const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = vk::initVulkanStructure();
872 
873     const auto pipeline = makeGraphicsPipeline(
874         ctx.vkd, ctx.device, *pipelineLayout, *vertModule, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, *fragModule,
875         *renderPass, staticViewports, staticScissors, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u,
876         &vertexInputStateCreateInfo, nullptr, nullptr, nullptr, nullptr, &dynamicStateCreateInfo);
877 
878     vk::CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
879     const auto cmdBuffer = *cmd.cmdBuffer;
880 
881     beginCommandBuffer(ctx.vkd, cmdBuffer);
882     beginRenderPass(ctx.vkd, cmdBuffer, *renderPass, *framebuffer, goodScissor, clearColor);
883     ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, *pipeline);
884     ctx.vkd.cmdSetScissor(cmdBuffer, 0u, 1u, &badScissor); // This should not be taken into account.
885     ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, *pipeline);
886     ctx.vkd.cmdSetViewport(cmdBuffer, 0u, 1u, &goodViewport); // The static one was bad too.
887     ctx.vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
888     endRenderPass(ctx.vkd, cmdBuffer);
889     copyImageToBuffer(ctx.vkd, cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(), fbExtent.swizzle(0, 1),
890                       vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
891                       vk::VK_IMAGE_ASPECT_COLOR_BIT, vk::VK_IMAGE_ASPECT_COLOR_BIT,
892                       vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
893     endCommandBuffer(ctx.vkd, cmdBuffer);
894     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
895 
896     // Verify color output.
897     invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
898     tcu::PixelBufferAccess resultAccess(tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
899 
900     tcu::TextureLevel referenceLevel(tcuFormat, fbExtent.x(), fbExtent.y());
901     auto referenceAccess = referenceLevel.getAccess();
902     tcu::clear(referenceAccess, geomColor);
903 
904     auto &log = context.getTestContext().getLog();
905     if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, threshold,
906                                     tcu::COMPARE_LOG_ON_ERROR))
907         return tcu::TestStatus::fail("Unexpected color in result buffer; check log for details");
908 
909     return tcu::TestStatus::pass("Pass");
910 }
911 
912 } // namespace
913 
914 // General tests for dynamic states
DynamicStateGeneralTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)915 DynamicStateGeneralTests::DynamicStateGeneralTests(tcu::TestContext &testCtx,
916                                                    vk::PipelineConstructionType pipelineConstructionType)
917     : TestCaseGroup(testCtx, "general_state")
918     , m_pipelineConstructionType(pipelineConstructionType)
919 {
920     /* Left blank on purpose */
921 }
922 
~DynamicStateGeneralTests(void)923 DynamicStateGeneralTests::~DynamicStateGeneralTests(void)
924 {
925 }
926 
init(void)927 void DynamicStateGeneralTests::init(void)
928 {
929     ShaderMap basePaths;
930     basePaths[glu::SHADERTYPE_FRAGMENT] = "vulkan/dynamic_state/VertexFetch.frag";
931     basePaths[glu::SHADERTYPE_MESH]     = nullptr;
932     basePaths[glu::SHADERTYPE_VERTEX]   = nullptr;
933 
934     for (int i = 0; i < 2; ++i)
935     {
936         const bool isMesh = (i > 0);
937         ShaderMap shaderPaths(basePaths);
938         std::string nameSuffix;
939         FunctionSupport0::Function checkSupportFunc;
940 
941         if (isMesh)
942         {
943 #ifndef CTS_USES_VULKANSC
944             shaderPaths[glu::SHADERTYPE_MESH] = "vulkan/dynamic_state/VertexFetch.mesh";
945             nameSuffix                        = "_mesh";
946             checkSupportFunc                  = checkMeshShaderSupport;
947 #else
948             continue;
949 #endif // CTS_USES_VULKANSC
950         }
951         else
952         {
953             shaderPaths[glu::SHADERTYPE_VERTEX] = "vulkan/dynamic_state/VertexFetch.vert";
954             checkSupportFunc                    = checkNothing;
955         }
956 
957         // Perform multiple draws with different VP states (scissor test)
958         addChild(new InstanceFactory<StateSwitchTestInstance, FunctionSupport0>(
959             m_testCtx, "state_switch" + nameSuffix, m_pipelineConstructionType, shaderPaths, checkSupportFunc));
960         // Check if binding order is not important for pipeline configuration
961         addChild(new InstanceFactory<BindOrderTestInstance, FunctionSupport0>(
962             m_testCtx, "bind_order" + nameSuffix, m_pipelineConstructionType, shaderPaths, checkSupportFunc));
963         if (!isMesh)
964         {
965             // Check if bound states are persistent across pipelines
966             addChild(new InstanceFactory<StatePersistenceTestInstance>(m_testCtx, "state_persistence" + nameSuffix,
967                                                                        m_pipelineConstructionType, shaderPaths));
968         }
969     }
970 
971     addFunctionCaseWithPrograms(this, "static_stencil_mask_zero", checkStaticStencilMaskZeroSupport,
972                                 initStaticStencilMaskZeroPrograms, staticStencilMaskZeroProgramsTest,
973                                 m_pipelineConstructionType);
974 
975     if (!vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
976     {
977         addFunctionCaseWithPrograms(this, "double_static_bind", initDoubleBindPrograms, doubleBindTest);
978     }
979 }
980 
981 } // namespace DynamicState
982 } // namespace vkt
983