1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 LunarG, Inc.
6  * Copyright (c) 2022 The Khronos Group Inc.
7  * Copyright (c) 2022 Google LLC
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 Discard Tests
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktDynamicStateDiscardTests.hpp"
28 
29 #include "vktDynamicStateBaseClass.hpp"
30 #include "vktDynamicStateTestCaseUtil.hpp"
31 
32 #include "vkImageUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 
35 #include "tcuImageCompare.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuRGBA.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkObjUtil.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkBufferWithMemory.hpp"
42 
43 namespace vkt
44 {
45 namespace DynamicState
46 {
47 using namespace Draw;
48 using namespace vk;
49 
50 enum TestDynamicStateDiscard
51 {
52     TEST_STENCIL,
53     TEST_VIEWPORT,
54     TEST_SCISSOR,
55     TEST_DEPTH,
56     TEST_BLEND_CONSTANTS,
57     TEST_LINE_WIDTH,
58 };
59 
pickSupportedStencilFormat(const InstanceInterface & instanceInterface,const VkPhysicalDevice device)60 VkFormat pickSupportedStencilFormat(const InstanceInterface &instanceInterface, const VkPhysicalDevice device)
61 {
62     static const VkFormat stencilFormats[] = {
63         VK_FORMAT_S8_UINT,
64         VK_FORMAT_D16_UNORM_S8_UINT,
65         VK_FORMAT_D24_UNORM_S8_UINT,
66         VK_FORMAT_D32_SFLOAT_S8_UINT,
67     };
68 
69     for (uint32_t i = 0; i < DE_LENGTH_OF_ARRAY(stencilFormats); ++i)
70     {
71         VkFormatProperties formatProps;
72         instanceInterface.getPhysicalDeviceFormatProperties(device, stencilFormats[i], &formatProps);
73 
74         if ((formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0)
75         {
76             return stencilFormats[i];
77         }
78     }
79     TCU_FAIL("Cannot find supported stencil format");
80 }
81 
isFormatStencil(VkFormat format)82 bool isFormatStencil(VkFormat format)
83 {
84     const auto textureFormat = vk::mapVkFormat(format);
85     return (textureFormat.order == tcu::TextureFormat::DS || textureFormat.order == tcu::TextureFormat::S);
86 }
87 
88 class DiscardTestInstance : public DynamicStateBaseClass
89 {
90 public:
91     DiscardTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
92                         const char *vertexShaderName, const char *fragmentShaderName, vk::VkFormat depthStencilFormat);
93 
94     virtual void initRenderPass(const vk::VkDevice device);
95     virtual void initFramebuffer(const vk::VkDevice device);
96     virtual void initPipeline(const vk::VkDevice device);
97 
98     void beginRenderPass(const vk::VkClearColorValue &clearColor);
99 
100     virtual tcu::TestStatus iterate(void);
101 
102 protected:
setDynamicState(void)103     virtual void setDynamicState(void)
104     {
105         DE_ASSERT(false);
106     }
verifyResults(void)107     virtual tcu::TestStatus verifyResults(void)
108     {
109         DE_ASSERT(false);
110         return tcu::TestStatus(QP_TEST_RESULT_PASS, "");
111     }
112     const vk::VkFormat m_depthStencilAttachmentFormat;
113 
114     de::SharedPtr<Draw::Image> m_depthStencilImage;
115     vk::Move<vk::VkImageView> m_depthStencilView;
116     std::vector<vk::VkDynamicState> m_dynamicStates;
117     VkBool32 m_depthBounds;
118 };
119 
DiscardTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName,vk::VkFormat depthStencilFormat)120 DiscardTestInstance::DiscardTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
121                                          const char *vertexShaderName, const char *fragmentShaderName,
122                                          vk::VkFormat depthStencilFormat)
123     : DynamicStateBaseClass(context, pipelineConstructionType, vertexShaderName, fragmentShaderName)
124     , m_depthStencilAttachmentFormat(depthStencilFormat)
125     , m_depthBounds(VK_FALSE)
126 {
127     const vk::VkDevice device = m_context.getDevice();
128 
129     const vk::VkExtent3D stencilImageExtent = {WIDTH, HEIGHT, 1};
130     const ImageCreateInfo stencilImageCreateInfo(
131         vk::VK_IMAGE_TYPE_2D, m_depthStencilAttachmentFormat, stencilImageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT,
132         vk::VK_IMAGE_TILING_OPTIMAL,
133         vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
134             vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
135 
136     m_depthStencilImage = Image::createAndAlloc(m_vk, device, stencilImageCreateInfo, m_context.getDefaultAllocator(),
137                                                 m_context.getUniversalQueueFamilyIndex());
138 
139     const ImageViewCreateInfo stencilViewInfo(m_depthStencilImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D,
140                                               m_depthStencilAttachmentFormat);
141     m_depthStencilView = vk::createImageView(m_vk, device, &stencilViewInfo);
142 
143     m_topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
144 
145     m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
146     m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
147     m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
148     m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
149 
150     const vk::VkDescriptorSetLayoutBinding binding = {0u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
151                                                       vk::VK_SHADER_STAGE_FRAGMENT_BIT, DE_NULL};
152 
153     DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo(1, &binding);
154     m_otherSetLayout = vk::createDescriptorSetLayout(m_vk, device, &descriptorSetLayoutCreateInfo);
155 }
156 
initRenderPass(const vk::VkDevice device)157 void DiscardTestInstance::initRenderPass(const vk::VkDevice device)
158 {
159     RenderPassCreateInfo renderPassCreateInfo;
160     renderPassCreateInfo.addAttachment(AttachmentDescription(
161         m_colorAttachmentFormat, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_ATTACHMENT_LOAD_OP_LOAD,
162         vk::VK_ATTACHMENT_STORE_OP_STORE, vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, vk::VK_ATTACHMENT_STORE_OP_STORE,
163         vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_GENERAL));
164     renderPassCreateInfo.addAttachment(AttachmentDescription(
165         m_depthStencilAttachmentFormat, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_ATTACHMENT_LOAD_OP_LOAD,
166         vk::VK_ATTACHMENT_STORE_OP_STORE, vk::VK_ATTACHMENT_LOAD_OP_LOAD, vk::VK_ATTACHMENT_STORE_OP_STORE,
167         vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_GENERAL));
168 
169     const vk::VkAttachmentReference colorAttachmentReference = {0, vk::VK_IMAGE_LAYOUT_GENERAL};
170 
171     const vk::VkAttachmentReference stencilAttachmentReference = {1, vk::VK_IMAGE_LAYOUT_GENERAL};
172 
173     renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, 1,
174                                                        &colorAttachmentReference, DE_NULL, stencilAttachmentReference,
175                                                        0, DE_NULL));
176 
177     m_renderPass = vk::RenderPassWrapper(m_pipelineConstructionType, m_vk, device, &renderPassCreateInfo);
178 }
179 
initFramebuffer(const vk::VkDevice device)180 void DiscardTestInstance::initFramebuffer(const vk::VkDevice device)
181 {
182     std::vector<vk::VkImageView> attachments(2);
183     attachments[0] = *m_colorTargetView;
184     attachments[1] = *m_depthStencilView;
185 
186     const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
187 
188     m_renderPass.createFramebuffer(m_vk, device, &framebufferCreateInfo,
189                                    {m_colorTargetImage->object(), m_depthStencilImage->object()});
190 }
191 
initPipeline(const vk::VkDevice device)192 void DiscardTestInstance::initPipeline(const vk::VkDevice device)
193 {
194     const vk::ShaderWrapper vs(
195         vk::ShaderWrapper(m_vk, device, m_context.getBinaryCollection().get(m_vertexShaderName), 0));
196     const vk::ShaderWrapper fs(
197         vk::ShaderWrapper(m_vk, device, m_context.getBinaryCollection().get(m_fragmentShaderName), 0));
198     std::vector<vk::VkViewport> viewports{{0.0f, 0.0f, (float)WIDTH, (float)HEIGHT, 0.0f, 1.0f}};
199     std::vector<vk::VkRect2D> scissors{{{0u, 0u}, {WIDTH, HEIGHT}}};
200 
201     const PipelineCreateInfo::ColorBlendState::Attachment attachmentState;
202     const PipelineCreateInfo::ColorBlendState colorBlendState(
203         1u, static_cast<const vk::VkPipelineColorBlendAttachmentState *>(&attachmentState));
204     const PipelineCreateInfo::RasterizerState rasterizerState;
205     PipelineCreateInfo::DepthStencilState depthStencilState;
206     const PipelineCreateInfo::DynamicState dynamicState(m_dynamicStates);
207 
208     depthStencilState.depthTestEnable       = VK_TRUE;
209     depthStencilState.depthWriteEnable      = VK_TRUE;
210     depthStencilState.depthCompareOp        = VK_COMPARE_OP_ALWAYS;
211     depthStencilState.depthBoundsTestEnable = m_depthBounds;
212     depthStencilState.minDepthBounds        = 0.0f;
213     depthStencilState.maxDepthBounds        = 1.0f;
214     depthStencilState.stencilTestEnable     = VK_TRUE;
215     depthStencilState.front.failOp          = VK_STENCIL_OP_KEEP;
216     depthStencilState.front.passOp          = VK_STENCIL_OP_REPLACE;
217     depthStencilState.front.depthFailOp     = VK_STENCIL_OP_KEEP;
218     depthStencilState.front.compareOp       = VK_COMPARE_OP_ALWAYS;
219     depthStencilState.front.compareMask     = 0u;
220     depthStencilState.front.writeMask       = 0u;
221     depthStencilState.front.reference       = 0u;
222     depthStencilState.back.failOp           = VK_STENCIL_OP_KEEP;
223     depthStencilState.back.passOp           = VK_STENCIL_OP_REPLACE;
224     depthStencilState.back.depthFailOp      = VK_STENCIL_OP_KEEP;
225     depthStencilState.back.compareOp        = VK_COMPARE_OP_ALWAYS;
226     depthStencilState.back.compareMask      = 0u;
227     depthStencilState.back.writeMask        = 0u;
228     depthStencilState.back.reference        = 0u;
229 
230     m_pipeline.setDefaultTopology(m_topology)
231         .setDynamicState(static_cast<const vk::VkPipelineDynamicStateCreateInfo *>(&dynamicState))
232         .setDefaultMultisampleState()
233         .setupVertexInputState(&m_vertexInputState)
234         .setupPreRasterizationShaderState(
235             viewports, scissors, m_pipelineLayout, *m_renderPass, 0u, vs,
236             static_cast<const vk::VkPipelineRasterizationStateCreateInfo *>(&rasterizerState))
237         .setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, fs,
238                                   static_cast<const vk::VkPipelineDepthStencilStateCreateInfo *>(&depthStencilState))
239         .setupFragmentOutputState(*m_renderPass, 0u,
240                                   static_cast<const vk::VkPipelineColorBlendStateCreateInfo *>(&colorBlendState))
241         .setMonolithicPipelineLayout(m_pipelineLayout)
242         .buildPipeline();
243 }
244 
beginRenderPass(const vk::VkClearColorValue & clearColor)245 void DiscardTestInstance::beginRenderPass(const vk::VkClearColorValue &clearColor)
246 {
247     beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
248 
249     initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
250                                   vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
251 
252     const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
253     m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1,
254                             &subresourceRange);
255 
256     const vk::VkMemoryBarrier memBarrier = {
257         vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, vk::VK_ACCESS_TRANSFER_WRITE_BIT,
258         vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT};
259 
260     m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
261                             vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0,
262                             DE_NULL);
263 
264     if (isFormatStencil(m_depthStencilAttachmentFormat))
265     {
266         initialTransitionStencil2DImage(m_vk, *m_cmdBuffer, m_depthStencilImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
267                                         vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
268     }
269     else
270     {
271         initialTransitionDepth2DImage(m_vk, *m_cmdBuffer, m_depthStencilImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
272                                       vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
273     }
274 
275     const vk::VkClearDepthStencilValue depthStencilClearValue = {0.0f, 0};
276     const ImageSubresourceRange subresourceRangeStencil = m_depthStencilAttachmentFormat == vk::VK_FORMAT_S8_UINT ?
277                                                               vk::VK_IMAGE_ASPECT_STENCIL_BIT :
278                                                               vk::VK_IMAGE_ASPECT_DEPTH_BIT;
279     m_vk.cmdClearDepthStencilImage(*m_cmdBuffer, m_depthStencilImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
280                                    &depthStencilClearValue, 1, &subresourceRangeStencil);
281 
282     vk::VkMemoryBarrier dsMemBarrier;
283     dsMemBarrier.sType         = vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER;
284     dsMemBarrier.pNext         = NULL;
285     dsMemBarrier.srcAccessMask = vk::VK_ACCESS_TRANSFER_WRITE_BIT;
286     dsMemBarrier.dstAccessMask = vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
287                                  vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
288                                  vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
289 
290     m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
291                             vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
292                                 vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
293                                 vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
294                             0, 1, &dsMemBarrier, 0, NULL, 0, NULL);
295 
296     m_renderPass.begin(m_vk, *m_cmdBuffer, vk::makeRect2D(0, 0, WIDTH, HEIGHT));
297 }
iterate(void)298 tcu::TestStatus DiscardTestInstance::iterate(void)
299 {
300     const vk::VkQueue queue   = m_context.getUniversalQueue();
301     const vk::VkDevice device = m_context.getDevice();
302     Allocator &allocator      = m_context.getDefaultAllocator();
303 
304     const VkDescriptorPoolSize poolSizes[] = {
305         {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u},
306     };
307     const VkDescriptorPoolCreateInfo poolInfo = {
308         VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
309         DE_NULL,
310         vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
311         1u, // maxSets
312         DE_LENGTH_OF_ARRAY(poolSizes),
313         poolSizes,
314     };
315 
316     vk::Move<vk::VkDescriptorPool> descriptorPool = createDescriptorPool(m_vk, device, &poolInfo);
317     vk::Move<vk::VkDescriptorSet> descriptorSet   = makeDescriptorSet(m_vk, device, *descriptorPool, *m_otherSetLayout);
318 
319     const vk::VkDeviceSize size = sizeof(int);
320 
321     const BufferWithMemory buffer(m_vk, device, allocator,
322                                   makeBufferCreateInfo(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT),
323                                   MemoryRequirement::HostVisible);
324 
325     uint32_t *ptr = (uint32_t *)buffer.getAllocation().getHostPtr();
326     deMemset(ptr, 0u, static_cast<std::size_t>(size));
327 
328     {
329         const vk::VkDescriptorBufferInfo bufferInfo    = makeDescriptorBufferInfo(*buffer, 0, size);
330         const vk::VkWriteDescriptorSet descriptorWrite = {
331             VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
332             DE_NULL,
333             *descriptorSet,
334             0u, // dstBinding
335             0u, // dstArrayElement
336             1u, // descriptorCount
337             VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
338             DE_NULL,
339             &bufferInfo,
340             DE_NULL,
341         };
342 
343         m_vk.updateDescriptorSets(device, 1, &descriptorWrite, 0u, DE_NULL);
344     }
345 
346     const vk::VkClearColorValue clearColor = {{0.0f, 0.0f, 0.0f, 1.0f}};
347     beginRenderPass(clearColor);
348     m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0, 1,
349                                &*descriptorSet, 0, nullptr);
350     m_pipeline.bind(*m_cmdBuffer);
351     const vk::VkDeviceSize vertexBufferOffset = 0;
352     const vk::VkBuffer vertexBuffer           = m_vertexBuffer->object();
353     m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
354 
355     setDynamicState();
356 
357     m_vk.cmdDraw(*m_cmdBuffer, 4, 1, 0, 0);
358     m_renderPass.end(m_vk, *m_cmdBuffer);
359     endCommandBuffer(m_vk, *m_cmdBuffer);
360 
361     submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
362 
363     return verifyResults();
364 }
365 
366 class StencilTestInstance : public DiscardTestInstance
367 {
368 public:
StencilTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)369     StencilTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
370                         const char *vertexShaderName, const char *fragmentShaderName)
371         : DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName,
372                               pickSupportedStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice()))
373     {
374         m_dynamicStates     = {vk::VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, vk::VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
375                                vk::VK_DYNAMIC_STATE_STENCIL_REFERENCE};
376         const auto features = context.getDeviceFeatures();
377         m_depthBounds       = features.depthBounds;
378 
379         DynamicStateBaseClass::initialize();
380     }
381 
setDynamicState(void)382     virtual void setDynamicState(void)
383     {
384         uint32_t value = 0x80;
385         m_vk.cmdSetStencilCompareMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, value);
386         m_vk.cmdSetStencilWriteMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, value);
387         m_vk.cmdSetStencilReference(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, value);
388         m_vk.cmdSetStencilCompareMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, value);
389         m_vk.cmdSetStencilWriteMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, value);
390         m_vk.cmdSetStencilReference(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, value);
391     }
392 
verifyResults(void)393     virtual tcu::TestStatus verifyResults(void)
394     {
395         const vk::VkQueue queue         = m_context.getUniversalQueue();
396         const vk::VkOffset3D zeroOffset = {0, 0, 0};
397         tcu::ConstPixelBufferAccess renderedFrame =
398             m_depthStencilImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
399                                              zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_STENCIL_BIT);
400         de::SharedPtr<tcu::TextureLevel> stencilFrame;
401 
402         if (tcu::isCombinedDepthStencilType(renderedFrame.getFormat().type))
403         {
404             stencilFrame = de::SharedPtr<tcu::TextureLevel>(new tcu::TextureLevel(
405                 tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8), WIDTH, HEIGHT, 1u));
406 
407             tcu::copy(stencilFrame->getAccess(),
408                       tcu::getEffectiveDepthStencilAccess(renderedFrame, tcu::Sampler::MODE_STENCIL));
409             renderedFrame = stencilFrame->getAccess();
410         }
411 
412         for (int i = 0; i < WIDTH; ++i)
413         {
414             for (int j = 0; j < HEIGHT; ++j)
415             {
416                 const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
417                 if (pixel[0] != 0.0f)
418                 {
419                     return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
420                 }
421             }
422         }
423         return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
424     }
425 };
426 
427 class ViewportTestInstance : public DiscardTestInstance
428 {
429 public:
ViewportTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)430     ViewportTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
431                          const char *vertexShaderName, const char *fragmentShaderName)
432         : DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName,
433                               pickSupportedStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice()))
434     {
435         m_dynamicStates = {vk::VK_DYNAMIC_STATE_VIEWPORT};
436         DynamicStateBaseClass::initialize();
437     }
438 
setDynamicState(void)439     virtual void setDynamicState(void)
440     {
441         vk::VkViewport viewport = vk::makeViewport(tcu::UVec2(WIDTH, HEIGHT));
442         if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
443         {
444 #ifndef CTS_USES_VULKANSC
445             m_vk.cmdSetViewportWithCount(*m_cmdBuffer, 1, &viewport);
446 #else
447             m_vk.cmdSetViewportWithCountEXT(*m_cmdBuffer, 1, &viewport);
448 #endif
449         }
450         else
451         {
452             m_vk.cmdSetViewport(*m_cmdBuffer, 0, 1, &viewport);
453         }
454     }
455 
verifyResults(void)456     virtual tcu::TestStatus verifyResults(void)
457     {
458         const vk::VkQueue queue = m_context.getUniversalQueue();
459         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_depthStencilAttachmentFormat), WIDTH, HEIGHT);
460         referenceFrame.allocLevel(0);
461 
462         const vk::VkOffset3D zeroOffset = {0, 0, 0};
463         const tcu::ConstPixelBufferAccess renderedFrame =
464             m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
465                                             zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
466 
467         for (int i = 0; i < WIDTH; ++i)
468         {
469             for (int j = 0; j < HEIGHT; ++j)
470             {
471                 const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
472                 if (pixel != tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f))
473                 {
474                     return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
475                 }
476             }
477         }
478         return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
479     }
480 };
481 
482 class ScissorTestInstance : public DiscardTestInstance
483 {
484 public:
ScissorTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)485     ScissorTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
486                         const char *vertexShaderName, const char *fragmentShaderName)
487         : DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName,
488                               pickSupportedStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice()))
489     {
490         m_dynamicStates = {vk::VK_DYNAMIC_STATE_SCISSOR};
491         DynamicStateBaseClass::initialize();
492     }
493 
setDynamicState(void)494     virtual void setDynamicState(void)
495     {
496         vk::VkRect2D scissor = vk::makeRect2D(tcu::UVec2(WIDTH, HEIGHT));
497         if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
498         {
499 #ifndef CTS_USES_VULKANSC
500             m_vk.cmdSetScissorWithCount(*m_cmdBuffer, 1, &scissor);
501 #else
502             m_vk.cmdSetScissorWithCountEXT(*m_cmdBuffer, 1, &scissor);
503 #endif
504         }
505         else
506         {
507             m_vk.cmdSetScissor(*m_cmdBuffer, 0, 1, &scissor);
508         }
509     }
510 
verifyResults(void)511     virtual tcu::TestStatus verifyResults(void)
512     {
513         const vk::VkQueue queue = m_context.getUniversalQueue();
514         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_depthStencilAttachmentFormat), WIDTH, HEIGHT);
515         referenceFrame.allocLevel(0);
516 
517         const vk::VkOffset3D zeroOffset = {0, 0, 0};
518         const tcu::ConstPixelBufferAccess renderedFrame =
519             m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
520                                             zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
521 
522         for (int i = 0; i < WIDTH; ++i)
523         {
524             for (int j = 0; j < HEIGHT; ++j)
525             {
526                 const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
527                 if (pixel != tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f))
528                 {
529                     return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
530                 }
531             }
532         }
533         return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
534     }
535 };
536 
537 class DepthTestInstance : public DiscardTestInstance
538 {
539 public:
DepthTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)540     DepthTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
541                       const char *vertexShaderName, const char *fragmentShaderName)
542         : DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName,
543                               vk::VK_FORMAT_D32_SFLOAT)
544     {
545         m_dynamicStates = {vk::VK_DYNAMIC_STATE_DEPTH_BIAS, vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS};
546         DynamicStateBaseClass::initialize();
547     }
548 
setDynamicState(void)549     virtual void setDynamicState(void)
550     {
551         m_vk.cmdSetDepthBounds(*m_cmdBuffer, 0.0f, 1.0f);
552         m_vk.cmdSetDepthBias(*m_cmdBuffer, 1.0f, 1.0f, 1.0f);
553     }
554 
verifyResults(void)555     virtual tcu::TestStatus verifyResults(void)
556     {
557         const vk::VkQueue queue         = m_context.getUniversalQueue();
558         const vk::VkOffset3D zeroOffset = {0, 0, 0};
559         const tcu::ConstPixelBufferAccess renderedFrame =
560             m_depthStencilImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
561                                              zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_DEPTH_BIT);
562 
563         for (int i = 0; i < WIDTH; ++i)
564         {
565             for (int j = 0; j < HEIGHT; ++j)
566             {
567                 const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
568                 if (pixel[0] != 0.0f)
569                 {
570                     return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
571                 }
572             }
573         }
574         return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
575     }
576 };
577 
578 class BlendTestInstance : public DiscardTestInstance
579 {
580 public:
BlendTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)581     BlendTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
582                       const char *vertexShaderName, const char *fragmentShaderName)
583         : DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName,
584                               pickSupportedStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice()))
585     {
586         m_dynamicStates = {vk::VK_DYNAMIC_STATE_BLEND_CONSTANTS};
587         DynamicStateBaseClass::initialize();
588     }
589 
setDynamicState(void)590     virtual void setDynamicState(void)
591     {
592         float blendConstantsants[4] = {0.0f, 0.0f, 0.0f, 0.0f};
593         m_vk.cmdSetBlendConstants(*m_cmdBuffer, blendConstantsants);
594     }
595 
verifyResults(void)596     virtual tcu::TestStatus verifyResults(void)
597     {
598         const vk::VkQueue queue = m_context.getUniversalQueue();
599         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_depthStencilAttachmentFormat), WIDTH, HEIGHT);
600         referenceFrame.allocLevel(0);
601 
602         const vk::VkOffset3D zeroOffset = {0, 0, 0};
603         const tcu::ConstPixelBufferAccess renderedFrame =
604             m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
605                                             zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
606 
607         for (int i = 0; i < WIDTH; ++i)
608         {
609             for (int j = 0; j < HEIGHT; ++j)
610             {
611                 const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
612                 if (pixel != tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f))
613                 {
614                     return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
615                 }
616             }
617         }
618         return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
619     }
620 };
621 
622 class LineTestInstance : public DiscardTestInstance
623 {
624 public:
LineTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)625     LineTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
626                      const char *vertexShaderName, const char *fragmentShaderName)
627         : DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName,
628                               pickSupportedStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice()))
629     {
630         m_dynamicStates = {vk::VK_DYNAMIC_STATE_LINE_WIDTH};
631         DynamicStateBaseClass::initialize();
632     }
633 
setDynamicState(void)634     virtual void setDynamicState(void)
635     {
636         m_vk.cmdSetLineWidth(*m_cmdBuffer, 1.0f);
637     }
638 
verifyResults(void)639     virtual tcu::TestStatus verifyResults(void)
640     {
641         const vk::VkQueue queue = m_context.getUniversalQueue();
642         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_depthStencilAttachmentFormat), WIDTH, HEIGHT);
643         referenceFrame.allocLevel(0);
644 
645         const vk::VkOffset3D zeroOffset = {0, 0, 0};
646         const tcu::ConstPixelBufferAccess renderedFrame =
647             m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
648                                             zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
649 
650         for (int i = 0; i < WIDTH; ++i)
651         {
652             for (int j = 0; j < HEIGHT; ++j)
653             {
654                 const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
655                 if (pixel != tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f))
656                 {
657                     return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
658                 }
659             }
660         }
661         return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
662     }
663 };
664 
665 class DiscardTestCase : public vkt::TestCase
666 {
667 public:
DiscardTestCase(tcu::TestContext & context,const char * name,vk::PipelineConstructionType pipelineConstructionType,TestDynamicStateDiscard testCase)668     DiscardTestCase(tcu::TestContext &context, const char *name, vk::PipelineConstructionType pipelineConstructionType,
669                     TestDynamicStateDiscard testCase)
670         : TestCase(context, name)
671         , m_pipelineConstructionType(pipelineConstructionType)
672         , m_testCase(testCase)
673         , m_depthBounds(false)
674     {
675     }
676 
checkSupport(Context & context) const677     virtual void checkSupport(Context &context) const
678     {
679         checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
680                                               m_pipelineConstructionType);
681     }
682 
createInstance(Context & context) const683     TestInstance *createInstance(Context &context) const
684     {
685         switch (m_testCase)
686         {
687         case TEST_STENCIL:
688             return new StencilTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
689         case TEST_VIEWPORT:
690             return new ViewportTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
691         case TEST_SCISSOR:
692             return new ScissorTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
693         case TEST_DEPTH:
694             return new DepthTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
695         case TEST_BLEND_CONSTANTS:
696             return new BlendTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
697         case TEST_LINE_WIDTH:
698             return new LineTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
699         default:
700             break;
701         }
702         DE_ASSERT(false);
703         return nullptr;
704     }
705 
initPrograms(vk::SourceCollections & programCollection) const706     virtual void initPrograms(vk::SourceCollections &programCollection) const
707     {
708         std::ostringstream vert;
709         vert << "#version 450\n"
710              << "\n"
711              << "layout(location = 0) in vec4 in_position;"
712              << "layout(location = 1) in vec4 in_color;"
713              << "\n"
714              << "layout(location = 0) out vec4 out_color;"
715              << "out gl_PerVertex { vec4 gl_Position; };"
716              << "\n"
717              << "void main ()\n"
718              << "{\n"
719              << "    gl_Position = in_position;\n"
720              << "    out_color = in_color;\n"
721              << "}\n";
722 
723         programCollection.glslSources.add("discard.vert") << glu::VertexSource(vert.str());
724 
725         std::ostringstream frag;
726         frag << "#version 450\n"
727              << "\n"
728              << "layout (set=0, binding=0, std140) uniform InputBlock {\n"
729              << "    int discard_all;\n"
730              << "} unif;\n"
731              << "\n"
732              << "layout (location = 0) in vec4 in_color;"
733              << "\n"
734              << "layout (location = 0) out vec4 color;"
735              << "\n"
736              << "void main ()\n"
737              << "{\n"
738              << "    if (unif.discard_all == 0) {\n"
739              << "        discard;\n"
740              << "    }\n"
741              << "    color = in_color;\n"
742              << "}\n";
743 
744         programCollection.glslSources.add("discard.frag") << glu::FragmentSource(frag.str());
745     }
746 
747 protected:
748     vk::PipelineConstructionType m_pipelineConstructionType;
749     TestDynamicStateDiscard m_testCase;
750     VkBool32 m_depthBounds;
751 };
752 
DynamicStateDiscardTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)753 DynamicStateDiscardTests::DynamicStateDiscardTests(tcu::TestContext &testCtx,
754                                                    vk::PipelineConstructionType pipelineConstructionType)
755     : TestCaseGroup(testCtx, "discard")
756     , m_pipelineConstructionType(pipelineConstructionType)
757 {
758     /* Left blank on purpose */
759 }
760 
~DynamicStateDiscardTests()761 DynamicStateDiscardTests::~DynamicStateDiscardTests()
762 {
763 }
764 
init(void)765 void DynamicStateDiscardTests::init(void)
766 {
767     // Use dynamic stencil with discard
768     addChild(
769         new DiscardTestCase(m_testCtx, "stencil", m_pipelineConstructionType, TestDynamicStateDiscard::TEST_STENCIL));
770     // Use dynamic viewport with discard
771     addChild(
772         new DiscardTestCase(m_testCtx, "viewport", m_pipelineConstructionType, TestDynamicStateDiscard::TEST_VIEWPORT));
773     // Use dynamic scissor with discard
774     addChild(
775         new DiscardTestCase(m_testCtx, "scissor", m_pipelineConstructionType, TestDynamicStateDiscard::TEST_SCISSOR));
776     // Use dynamic depth with discard
777     addChild(new DiscardTestCase(m_testCtx, "depth", m_pipelineConstructionType, TestDynamicStateDiscard::TEST_DEPTH));
778     // Use dynamic blend constants with discard
779     addChild(new DiscardTestCase(m_testCtx, "blend", m_pipelineConstructionType,
780                                  TestDynamicStateDiscard::TEST_BLEND_CONSTANTS));
781     // Use dynamic line width with discard
782     addChild(
783         new DiscardTestCase(m_testCtx, "line", m_pipelineConstructionType, TestDynamicStateDiscard::TEST_LINE_WIDTH));
784 }
785 
786 } // namespace DynamicState
787 } // namespace vkt
788