1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 Google LLC.
6  *
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Verify Depth/Stencil Write conditions
23  *//*--------------------------------------------------------------------*/
24 
25 #include "deUniquePtr.hpp"
26 
27 #include "../pipeline/vktPipelineImageUtil.hpp"
28 #include "vktDrawImageObjectUtil.hpp"
29 
30 #include "vkImageUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vktTestCaseUtil.hpp"
36 
37 #include <string>
38 
39 using namespace vk;
40 
41 namespace vkt
42 {
43 namespace renderpass
44 {
45 namespace
46 {
47 
48 using de::MovePtr;
49 using std::vector;
50 using tcu::TextureLevel;
51 using tcu::Vec4;
52 
53 const int WIDTH  = 64;
54 const int HEIGHT = 64;
55 
56 enum DiscardType
57 {
58     KILL = 0,
59     TERMINATE,
60     DEMOTE
61 };
62 
63 enum BufferType
64 {
65     DEPTH = 0,
66     STENCIL
67 };
68 
69 enum MutationMode
70 {
71     WRITE = 0,
72     INITIALIZE,
73     INITIALIZE_WRITE
74 };
75 
makeVertexBuffer(const DeviceInterface & vk,const VkDevice device,const uint32_t queueFamilyIndex)76 Move<VkBuffer> makeVertexBuffer(const DeviceInterface &vk, const VkDevice device, const uint32_t queueFamilyIndex)
77 {
78     const VkBufferCreateInfo vertexBufferParams = {
79         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType      sType;
80         DE_NULL,                              // const void*          pNext;
81         0u,                                   // VkBufferCreateFlags  flags;
82         1024u,                                // VkDeviceSize         size;
83         VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags   usage;
84         VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode        sharingMode;
85         1u,                                   // uint32_t             queueFamilyIndexCount;
86         &queueFamilyIndex                     // const uint32_t*      pQueueFamilyIndices;
87     };
88 
89     Move<VkBuffer> vertexBuffer = createBuffer(vk, device, &vertexBufferParams);
90     ;
91     return vertexBuffer;
92 }
93 
94 class DepthStencilWriteConditionsInstance : public TestInstance
95 {
96 public:
97     DepthStencilWriteConditionsInstance(Context &context, const BufferType &bufferType, const VkFormat &m_bufferFormat);
98     tcu::TestStatus iterate(void);
99 
100 private:
101     BufferType m_bufferType;
102     VkFormat m_bufferFormat;
103 };
104 
DepthStencilWriteConditionsInstance(Context & context,const BufferType & bufferType,const VkFormat & bufferFormat)105 DepthStencilWriteConditionsInstance::DepthStencilWriteConditionsInstance(Context &context, const BufferType &bufferType,
106                                                                          const VkFormat &bufferFormat)
107     : TestInstance(context)
108     , m_bufferType(bufferType)
109     , m_bufferFormat(bufferFormat)
110 {
111 }
112 
113 template <typename T>
sizeInBytes(const vector<T> & vec)114 inline size_t sizeInBytes(const vector<T> &vec)
115 {
116     return vec.size() * sizeof(vec[0]);
117 }
118 
119 // A quad covering the whole framebuffer
genFullQuadVertices(void)120 vector<Vec4> genFullQuadVertices(void)
121 {
122     vector<Vec4> vertices;
123     vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
124     vertices.push_back(Vec4(1.0f, -1.0f, 0.0f, 1.0f));
125     vertices.push_back(Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
126     vertices.push_back(Vec4(1.0f, -1.0f, 1.0f, 1.0f));
127     vertices.push_back(Vec4(1.0f, 1.0f, 1.0f, 1.0f));
128     vertices.push_back(Vec4(-1.0f, 1.0f, 1.0f, 1.0f));
129 
130     return vertices;
131 }
132 
133 struct Vertex
134 {
Vertexvkt::renderpass::__anone03cf1860111::Vertex135     Vertex(Vec4 vertices_) : vertices(vertices_)
136     {
137     }
138     Vec4 vertices;
139 
140     static VkVertexInputBindingDescription getBindingDescription(void);
141     static vector<VkVertexInputAttributeDescription> getAttributeDescriptions(void);
142 };
143 
getBindingDescription(void)144 VkVertexInputBindingDescription Vertex::getBindingDescription(void)
145 {
146     static const VkVertexInputBindingDescription desc = {
147         0u,                                    // uint32_t             binding;
148         static_cast<uint32_t>(sizeof(Vertex)), // uint32_t             stride;
149         VK_VERTEX_INPUT_RATE_VERTEX,           // VkVertexInputRate    inputRate;
150     };
151 
152     return desc;
153 }
154 
getAttributeDescriptions(void)155 vector<VkVertexInputAttributeDescription> Vertex::getAttributeDescriptions(void)
156 {
157     static const vector<VkVertexInputAttributeDescription> desc = {
158         {
159             0u,                                                // uint32_t    location;
160             0u,                                                // uint32_t    binding;
161             VK_FORMAT_R32G32B32A32_SFLOAT,                     // VkFormat    format;
162             static_cast<uint32_t>(offsetof(Vertex, vertices)), // uint32_t    offset;
163         },
164     };
165 
166     return desc;
167 }
168 
iterate(void)169 tcu::TestStatus DepthStencilWriteConditionsInstance::iterate(void)
170 {
171     const DeviceInterface &vk       = m_context.getDeviceInterface();
172     const VkDevice device           = m_context.getDevice();
173     Allocator &allocator            = m_context.getDefaultAllocator();
174     const VkQueue queue             = m_context.getUniversalQueue();
175     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
176     const VkDeviceSize bufferSize   = 16 * 1024;
177 
178     const VkExtent2D renderSize = {uint32_t(WIDTH), uint32_t(HEIGHT)};
179     const VkRect2D renderArea   = makeRect2D(makeExtent3D(WIDTH, HEIGHT, 1u));
180     const vector<VkRect2D> scissors(1u, renderArea);
181     const vector<VkViewport> viewports(1u, makeViewport(makeExtent3D(WIDTH, HEIGHT, 1u)));
182 
183     const vector<Vec4> vertices = genFullQuadVertices();
184     Move<VkBuffer> vertexBuffer = makeVertexBuffer(vk, device, queueFamilyIndex);
185     MovePtr<Allocation> vertexBufferAlloc =
186         bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible);
187     const VkDeviceSize vertexBufferOffset = 0ull;
188 
189     deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], sizeInBytes(vertices));
190     flushAlloc(vk, device, *vertexBufferAlloc);
191 
192     const VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
193     const VkImageCreateInfo colorImageCreateInfo = {
194         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, //  VkStructureType         sType;
195         DE_NULL,                             //  const void*             pNext;
196         0,                                   //  VkImageCreateFlags      flags;
197         VK_IMAGE_TYPE_2D,                    //  VkImageType             imageType;
198         VK_FORMAT_R8G8B8A8_UNORM,            //  VkFormat                format;
199         makeExtent3D(WIDTH, HEIGHT, 1u),     //  VkExtent3D              extent;
200         1u,                                  //  uint32_t                mipLevels;
201         1u,                                  //  uint32_t                arrayLayers;
202         VK_SAMPLE_COUNT_1_BIT,               //  VkSampleCountFlagBits   samples;
203         VK_IMAGE_TILING_OPTIMAL,             //  VkImageTiling           tiling;
204         colorImageUsage,                     //  VkImageUsageFlags       usage;
205         VK_SHARING_MODE_EXCLUSIVE,           //  VkSharingMode           sharingMode;
206         0u,                                  //  uint32_t                queueFamilyIndexCount;
207         DE_NULL,                             //  const uint32_t*         pQueueFamilyIndices;
208         VK_IMAGE_LAYOUT_UNDEFINED,           //  VkImageLayout           initialLayout;
209     };
210     const VkImageSubresourceRange colorSubresourceRange =
211         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1, 0, 1);
212     const ImageWithMemory colorImage(vk, device, m_context.getDefaultAllocator(), colorImageCreateInfo,
213                                      MemoryRequirement::Any);
214     Move<VkImageView> colorImageView =
215         makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, colorSubresourceRange);
216 
217     // Depending on the type of the buffer, create a depth buffer or a stencil buffer.
218     const VkImageUsageFlags depthStencilUsage =
219         VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
220 
221     const VkImageCreateInfo depthStencilBufferInfo = {
222         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType          sType;
223         nullptr,                             // const void*              pNext;
224         0u,                                  // VkImageCreateFlags       flags;
225         VK_IMAGE_TYPE_2D,                    // VkImageType              imageType;
226         m_bufferFormat,                      // VkFormat                 format;
227         makeExtent3D(WIDTH, HEIGHT, 1u),     // VkExtent3D               extent;
228         1u,                                  // uint32_t                 mipLevels;
229         1u,                                  // uint32_t                 arrayLayers;
230         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits    samples;
231         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling            tiling;
232         depthStencilUsage,                   // VkImageUsageFlags        usage;
233         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode            sharingMode;
234         0u,                                  // uint32_t                 queueFamilyIndexCount;
235         nullptr,                             // const uint32_t*          pQueueFamilyIndices;
236         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout            initialLayout;
237     };
238 
239     const de::SharedPtr<Draw::Image> depthStencilImage =
240         Draw::Image::createAndAlloc(vk, device, depthStencilBufferInfo, m_context.getDefaultAllocator(),
241                                     m_context.getUniversalQueueFamilyIndex(), MemoryRequirement::Any);
242     const VkImageAspectFlagBits imageAspectFlagBits =
243         m_bufferType == BufferType::DEPTH ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT;
244     const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(imageAspectFlagBits, 0u, 1u, 0u, 1u);
245     Move<VkImageView> depthStencilImageView =
246         makeImageView(vk, device, depthStencilImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_bufferFormat, subresourceRange);
247 
248     const Move<VkCommandPool> cmdPool =
249         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
250     const Move<VkCommandBuffer> cmdBuffer =
251         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
252 
253     const auto renderPass =
254         makeRenderPass(vk, device, VK_FORMAT_R8G8B8A8_UNORM, m_bufferFormat, VK_ATTACHMENT_LOAD_OP_CLEAR,
255                        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
256     const vector<VkImageView> attachments = {colorImageView.get(), depthStencilImageView.get()};
257     const auto framebuffer = makeFramebuffer(vk, device, renderPass.get(), static_cast<uint32_t>(attachments.size()),
258                                              de::dataOrNull(attachments), renderSize.width, renderSize.height);
259 
260     const Move<VkShaderModule> vertexModule =
261         createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
262     const Move<VkShaderModule> fragmentModule =
263         createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
264 
265     const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vk, device, DE_NULL);
266 
267     const VkVertexInputBindingDescription vtxBindingDescription = Vertex::getBindingDescription();
268     const auto vtxAttrDescriptions                              = Vertex::getAttributeDescriptions();
269 
270     const VkPipelineVertexInputStateCreateInfo vtxInputStateCreateInfo = {
271         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                             sType;
272         DE_NULL,                                                   // const void*                                 pNext;
273         (VkPipelineVertexInputStateCreateFlags)0,                  // VkPipelineVertexInputStateCreateFlags       flags;
274         1u,                     // uint32_t                                    vertexBindingDescriptionCount;
275         &vtxBindingDescription, // const VkVertexInputBindingDescription*      pVertexBindingDescriptions
276         static_cast<uint32_t>(
277             vtxAttrDescriptions.size()), // uint32_t                                    vertexAttributeDescriptionCount
278         vtxAttrDescriptions.data(),      // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions
279     };
280 
281     // The value in the stencil buffer is replaced if the new value is greater than the previous value.
282     const VkStencilOpState stencilOp = makeStencilOpState(
283         VK_STENCIL_OP_KEEP, VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE, VK_COMPARE_OP_GREATER, 0xffu, 0xffu, 0u);
284 
285     const VkPipelineDepthStencilStateCreateInfo depthStencilCreateInfo = {
286         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType                          sType
287         nullptr,                                                    // const void*                              pNext
288         0u,                                                         // VkPipelineDepthStencilStateCreateFlags   flags
289         m_bufferType == BufferType::DEPTH ? VK_TRUE :
290                                             VK_FALSE, // VkBool32                                 depthTestEnable
291         VK_TRUE,                                      // VkBool32                                 depthWriteEnable
292         VK_COMPARE_OP_GREATER,                        // VkCompareOp                              depthCompareOp
293         VK_FALSE,                                     // VkBool32                                 depthBoundsTestEnable
294         m_bufferType == BufferType::STENCIL ? VK_TRUE :
295                                               VK_FALSE, // VkBool32                                 stencilTestEnable
296         stencilOp,                                      // VkStencilOpState                         front
297         stencilOp,                                      // VkStencilOpState                         back
298         0.0f,                                           // float                                    minDepthBounds
299         1.0f,                                           // float                                    maxDepthBounds
300     };
301 
302     const Move<VkPipeline> graphicsPipeline = makeGraphicsPipeline(
303         vk, device, pipelineLayout.get(), vertexModule.get(), DE_NULL, DE_NULL, DE_NULL, fragmentModule.get(),
304         renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u, &vtxInputStateCreateInfo,
305         DE_NULL, DE_NULL, &depthStencilCreateInfo, DE_NULL, DE_NULL);
306 
307     const VkBufferCreateInfo resultBufferCreateInfo =
308         makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
309     Move<VkBuffer> resultBuffer = createBuffer(vk, device, &resultBufferCreateInfo);
310     MovePtr<Allocation> resultBufferMemory =
311         allocator.allocate(getBufferMemoryRequirements(vk, device, *resultBuffer), MemoryRequirement::HostVisible);
312 
313     VK_CHECK(
314         vk.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(), resultBufferMemory->getOffset()));
315 
316     const vector<VkClearValue> clearColors = {
317         makeClearValueColorF32(0.0f, 0.0f, 0.0f, 0.0f),
318         makeClearValueDepthStencil(.1f, 0u),
319     };
320 
321     beginCommandBuffer(vk, *cmdBuffer);
322 
323     vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
324     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
325 
326     beginRenderPass(vk, *cmdBuffer, renderPass.get(), framebuffer.get(), makeRect2D(0, 0, WIDTH, HEIGHT),
327                     static_cast<uint32_t>(clearColors.size()), de::dataOrNull(clearColors), VK_SUBPASS_CONTENTS_INLINE,
328                     DE_NULL);
329     vk.cmdDraw(*cmdBuffer, static_cast<uint32_t>(vertices.size()), 1u, 0u, 0u);
330     endRenderPass(vk, *cmdBuffer);
331 
332     endCommandBuffer(vk, *cmdBuffer);
333     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
334 
335     invalidateAlloc(vk, device, *resultBufferMemory);
336 
337     de::MovePtr<tcu::TextureLevel> attachment;
338 
339     if (m_bufferType == BufferType::DEPTH)
340         attachment = pipeline::readDepthAttachment(vk, device, queue, queueFamilyIndex, allocator,
341                                                    depthStencilImage->object(), m_bufferFormat,
342                                                    tcu::UVec2(WIDTH, HEIGHT), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
343     else
344         attachment = pipeline::readStencilAttachment(vk, device, queue, queueFamilyIndex, allocator,
345                                                      depthStencilImage->object(), m_bufferFormat,
346                                                      tcu::UVec2(WIDTH, HEIGHT), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
347 
348     bool result = true;
349     for (uint32_t y = 0; y < HEIGHT; y++)
350     {
351         for (uint32_t x = 0; x < WIDTH; x++)
352         {
353             if (m_bufferType == BufferType::STENCIL)
354             {
355                 const auto stencilPixel = attachment->getAccess().getPixStencil(x, y, 0);
356                 if (static_cast<uint32_t>(stencilPixel) != x % 2)
357                     result = false;
358             }
359             else
360             {
361                 const auto depthPixel = attachment->getAccess().getPixDepth(x, y);
362                 if ((depthPixel < 0.09 || depthPixel > 0.11) && x % 2 == 0)
363                     result = false;
364                 if ((depthPixel < 0.19 || depthPixel > 0.21) && x % 2 == 1)
365                     result = false;
366             }
367         }
368     }
369 
370     return result ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
371 }
372 
373 class DepthStencilWriteConditionsTest : public TestCase
374 {
375 public:
376     DepthStencilWriteConditionsTest(tcu::TestContext &testCtx, const std::string &name, const BufferType bufferType,
377                                     const DiscardType discardType, const MutationMode mutationMode,
378                                     const VkFormat bufferFormat);
379 
380     virtual void checkSupport(Context &context) const;
381     void initPrograms(SourceCollections &programCollection) const;
382     TestInstance *createInstance(Context &context) const;
383 
384 private:
385     BufferType m_bufferType;
386     DiscardType m_discardType;
387     MutationMode m_mutationMode;
388     VkFormat m_bufferFormat;
389 };
390 
DepthStencilWriteConditionsTest(tcu::TestContext & testCtx,const std::string & name,const BufferType bufferType,const DiscardType discardType,const MutationMode mutationMode,const VkFormat bufferFormat)391 DepthStencilWriteConditionsTest::DepthStencilWriteConditionsTest(tcu::TestContext &testCtx, const std::string &name,
392                                                                  const BufferType bufferType,
393                                                                  const DiscardType discardType,
394                                                                  const MutationMode mutationMode,
395                                                                  const VkFormat bufferFormat)
396     : TestCase(testCtx, name)
397     , m_bufferType(bufferType)
398     , m_discardType(discardType)
399     , m_mutationMode(mutationMode)
400     , m_bufferFormat(bufferFormat)
401 {
402 }
403 
initPrograms(SourceCollections & programCollection) const404 void DepthStencilWriteConditionsTest::initPrograms(SourceCollections &programCollection) const
405 {
406     /*
407      * The fragment shader has been compiled from the following GLSL shader:
408      *
409      * layout(location = 0) out vec4 outColor;
410      * void main() {
411      *     if (int(gl_FragCoord.x) % 2 == 0)
412      *         discard;
413      *     outColor = vec4(1., 1., 1., 1.);
414      *     gl_FragDepth = 0.2;
415      * }
416      *
417      * If a stencil buffer is enabled, the shader writes to gl_FragStencilRefARB
418      * instead of gl_FragDepth.
419      *
420      * If the mutation mode is INITIALIZE or INITIALIZE_WRITE, the object that
421      * is written to the buffer is allocated with an initial value.
422      *
423      * Demote and terminate commands are used instead of discard if a corresponding
424      * DiscardType has been given.
425      */
426 
427     std::ostringstream vertexSrc;
428     vertexSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
429               << "layout(location = 0) in highp vec4 a_position;\n"
430               << "void main (void) {\n"
431               << "    gl_Position = a_position;\n"
432               << "}\n";
433 
434     std::string discardCommand = "OpKill\n";
435     std::string extensions     = "";
436     std::string capabilities   = "";
437 
438     if (m_discardType == DiscardType::TERMINATE)
439     {
440         extensions     = "OpExtension \"SPV_KHR_terminate_invocation\"\n";
441         discardCommand = "OpTerminateInvocation\n";
442     }
443     else if (m_discardType == DiscardType::DEMOTE)
444     {
445         capabilities   = "OpCapability DemoteToHelperInvocationEXT\n";
446         extensions     = "OpExtension \"SPV_EXT_demote_to_helper_invocation\"\n";
447         discardCommand = "OpDemoteToHelperInvocationEXT\n";
448     }
449 
450     if (m_bufferType == BufferType::STENCIL)
451     {
452         capabilities += "OpCapability StencilExportEXT\n";
453         extensions += "OpExtension \"SPV_EXT_shader_stencil_export\"\n";
454     }
455 
456     std::ostringstream fragmentSrc;
457     fragmentSrc << "OpCapability Shader\n"
458                 << capabilities << extensions << "%1 = OpExtInstImport \"GLSL.std.450\"\n"
459                 << "OpMemoryModel Logical GLSL450\n";
460 
461     fragmentSrc << "OpEntryPoint Fragment %4 \"main\" %9 %26 %30\n"
462                 << "OpExecutionMode %4 OriginUpperLeft\n";
463 
464     if (m_bufferType == BufferType::DEPTH)
465         fragmentSrc << "OpExecutionMode %4 DepthReplacing\n";
466 
467     fragmentSrc << "OpDecorate %9 BuiltIn FragCoord\n"
468                 << "OpDecorate %26 Location 0\n";
469 
470     if (m_bufferType == BufferType::DEPTH)
471         fragmentSrc << "OpDecorate %30 BuiltIn FragDepth\n";
472     else
473         fragmentSrc << "OpDecorate %30 BuiltIn FragStencilRefEXT\n";
474 
475     fragmentSrc << "%2 = OpTypeVoid\n"
476                 << "%3 = OpTypeFunction %2\n"
477                 << "%6 = OpTypeFloat 32\n"
478                 << "%7 = OpTypeVector %6 4\n"
479                 << "%8 = OpTypePointer Input %7\n"
480                 << "%9 = OpVariable %8 Input\n"
481                 << "%10 = OpTypeInt 32 0\n"
482                 << "%11 = OpConstant %10 0\n"
483                 << "%12 = OpTypePointer Input %6\n"
484                 << "%15 = OpTypeInt 32 1\n"
485                 << "%17 = OpConstant %15 2\n"
486                 << "%19 = OpConstant %15 0\n"
487                 << "%20 = OpTypeBool\n"
488                 << "%25 = OpTypePointer Output %7\n"
489                 << "%26 = OpVariable %25 Output\n"
490                 << "%27 = OpConstant %6 1\n"
491                 << "%28 = OpConstantComposite %7 %27 %27 %27 %27\n";
492     if (m_bufferType == BufferType::DEPTH)
493     {
494         fragmentSrc << "%29 = OpTypePointer Output %6\n";
495 
496         if (m_mutationMode == MutationMode::INITIALIZE || m_mutationMode == MutationMode::INITIALIZE_WRITE)
497         {
498             // The value the depth buffer is initialized with.
499             fragmentSrc << "%const_f32_02 = OpConstant %6 0.2\n";
500             fragmentSrc << "%30 = OpVariable %29 Output %const_f32_02\n";
501         }
502         else
503             fragmentSrc << "%30 = OpVariable %29 Output\n";
504 
505         // The value written to the depth buffer.
506         fragmentSrc << "%31 = OpConstant %6 0.2\n";
507     }
508     else
509     {
510         fragmentSrc << "%29 = OpTypePointer Output %15\n";
511 
512         if (m_mutationMode == MutationMode::INITIALIZE || m_mutationMode == MutationMode::INITIALIZE_WRITE)
513         {
514             // The value the stencil buffer is initialized with.
515             fragmentSrc << "%const_int_1 = OpConstant %15 1\n";
516             fragmentSrc << "%30 = OpVariable %29 Output %const_int_1\n";
517         }
518         else
519             fragmentSrc << "%30 = OpVariable %29 Output\n";
520 
521         // The value written to the stencil buffer.
522         fragmentSrc << "%31 = OpConstant %15 1\n";
523     }
524 
525     fragmentSrc << "%4 = OpFunction %2 None %3\n"
526                 << "%5 = OpLabel\n"
527                 << "%13 = OpAccessChain %12 %9 %11\n"
528                 << "%14 = OpLoad %6 %13\n"
529                 << "%16 = OpConvertFToS %15 %14\n"
530                 << "%18 = OpSMod %15 %16 %17\n"
531                 << "%21 = OpIEqual %20 %18 %19\n"
532                 << "OpSelectionMerge %23 None\n"
533                 << "OpBranchConditional %21 %22 %23\n"
534                 << "%22 = OpLabel\n"
535                 << discardCommand;
536     if (m_discardType == DiscardType::DEMOTE)
537         fragmentSrc << "OpBranch %23\n";
538     fragmentSrc << "%23 = OpLabel\n"
539                 << "OpStore %26 %28\n";
540 
541     if (m_mutationMode == MutationMode::WRITE || m_mutationMode == MutationMode::INITIALIZE_WRITE)
542         fragmentSrc << "OpStore %30 %31\n";
543 
544     fragmentSrc << "OpReturn\n"
545                 << "OpFunctionEnd\n";
546 
547     programCollection.spirvAsmSources.add("frag") << fragmentSrc.str().c_str();
548     programCollection.glslSources.add("vert") << glu::VertexSource(vertexSrc.str());
549 }
550 
checkSupport(Context & context) const551 void DepthStencilWriteConditionsTest::checkSupport(Context &context) const
552 {
553     if (m_discardType == DiscardType::DEMOTE)
554         context.requireDeviceFunctionality("VK_EXT_shader_demote_to_helper_invocation");
555     if (m_discardType == DiscardType::TERMINATE)
556         context.requireDeviceFunctionality("VK_KHR_shader_terminate_invocation");
557     if (m_bufferType == BufferType::STENCIL)
558         context.requireDeviceFunctionality("VK_EXT_shader_stencil_export");
559 
560     std::string formatName = "VK_FORMAT_D32_SFLOAT_S8_UINT";
561     if (m_bufferFormat == VK_FORMAT_D24_UNORM_S8_UINT)
562         formatName = "VK_FORMAT_D24_UNORM_S8_UINT";
563     if (m_bufferFormat == VK_FORMAT_X8_D24_UNORM_PACK32)
564         formatName = "VK_FORMAT_X8_D24_UNORM_PACK32";
565     if (m_bufferFormat == VK_FORMAT_D32_SFLOAT)
566         formatName = "VK_FORMAT_D32_SFLOAT";
567 
568     const auto &vki           = context.getInstanceInterface();
569     const auto physicalDevice = context.getPhysicalDevice();
570     const VkImageUsageFlags depthStencilUsage =
571         VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
572 
573     VkImageFormatProperties imageFormatProperties;
574     if (vki.getPhysicalDeviceImageFormatProperties(physicalDevice, m_bufferFormat, VK_IMAGE_TYPE_2D,
575                                                    VK_IMAGE_TILING_OPTIMAL, depthStencilUsage, (VkImageCreateFlags)0,
576                                                    &imageFormatProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
577         TCU_THROW(NotSupportedError, formatName + " not supported.");
578 }
579 
createInstance(Context & context) const580 TestInstance *DepthStencilWriteConditionsTest::createInstance(Context &context) const
581 {
582     return new DepthStencilWriteConditionsInstance(context, m_bufferType, m_bufferFormat);
583 }
584 
585 } // namespace
586 
createDepthStencilWriteConditionsTests(tcu::TestContext & testCtx)587 tcu::TestCaseGroup *createDepthStencilWriteConditionsTests(tcu::TestContext &testCtx)
588 {
589     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "depth_stencil_write_conditions"));
590 
591     const VkFormat depthFormats[4]   = {VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT,
592                                         VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_D32_SFLOAT};
593     const VkFormat stencilFormats[2] = {VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT};
594 
595     for (int i = 0; i < 4; i++)
596     {
597         VkFormat format     = depthFormats[i];
598         std::string postfix = "_d32sf_s8ui";
599         if (format == VK_FORMAT_D24_UNORM_S8_UINT)
600             postfix = "_d24unorm_s8ui";
601         if (format == VK_FORMAT_X8_D24_UNORM_PACK32)
602             postfix = "_d24_unorm";
603         if (format == VK_FORMAT_D32_SFLOAT)
604             postfix = "_d32sf";
605 
606         testGroup->addChild(new DepthStencilWriteConditionsTest(
607             testCtx, "depth_kill_write" + postfix, BufferType::DEPTH, DiscardType::KILL, MutationMode::WRITE, format));
608         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_kill_initialize" + postfix,
609                                                                 BufferType::DEPTH, DiscardType::KILL,
610                                                                 MutationMode::INITIALIZE, format));
611         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_kill_write_initialize" + postfix,
612                                                                 BufferType::DEPTH, DiscardType::KILL,
613                                                                 MutationMode::INITIALIZE_WRITE, format));
614         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_terminate_write" + postfix,
615                                                                 BufferType::DEPTH, DiscardType::TERMINATE,
616                                                                 MutationMode::WRITE, format));
617         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_terminate_initialize" + postfix,
618                                                                 BufferType::DEPTH, DiscardType::TERMINATE,
619                                                                 MutationMode::INITIALIZE, format));
620         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_terminate_write_initialize" + postfix,
621                                                                 BufferType::DEPTH, DiscardType::TERMINATE,
622                                                                 MutationMode::INITIALIZE_WRITE, format));
623         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_demote_write" + postfix,
624                                                                 BufferType::DEPTH, DiscardType::DEMOTE,
625                                                                 MutationMode::WRITE, format));
626         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_demote_initialize" + postfix,
627                                                                 BufferType::DEPTH, DiscardType::DEMOTE,
628                                                                 MutationMode::INITIALIZE, format));
629         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_demote_write_initialize" + postfix,
630                                                                 BufferType::DEPTH, DiscardType::DEMOTE,
631                                                                 MutationMode::INITIALIZE_WRITE, format));
632     }
633 
634     for (int i = 0; i < 2; i++)
635     {
636         VkFormat format     = stencilFormats[i];
637         std::string postfix = "_d32sf_s8ui";
638         if (format == VK_FORMAT_D24_UNORM_S8_UINT)
639             postfix = "_d24unorm_s8ui";
640 
641         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_kill_write" + postfix,
642                                                                 BufferType::STENCIL, DiscardType::KILL,
643                                                                 MutationMode::WRITE, format));
644         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_kill_initialize" + postfix,
645                                                                 BufferType::STENCIL, DiscardType::KILL,
646                                                                 MutationMode::INITIALIZE, format));
647         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_kill_write_initialize" + postfix,
648                                                                 BufferType::STENCIL, DiscardType::KILL,
649                                                                 MutationMode::INITIALIZE_WRITE, format));
650         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_terminate_write" + postfix,
651                                                                 BufferType::STENCIL, DiscardType::TERMINATE,
652                                                                 MutationMode::WRITE, format));
653         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_terminate_initialize" + postfix,
654                                                                 BufferType::STENCIL, DiscardType::TERMINATE,
655                                                                 MutationMode::INITIALIZE, format));
656         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_terminate_write_initialize" + postfix,
657                                                                 BufferType::STENCIL, DiscardType::TERMINATE,
658                                                                 MutationMode::INITIALIZE_WRITE, format));
659         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_demote_write" + postfix,
660                                                                 BufferType::STENCIL, DiscardType::DEMOTE,
661                                                                 MutationMode::WRITE, format));
662         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_demote_initialize" + postfix,
663                                                                 BufferType::STENCIL, DiscardType::DEMOTE,
664                                                                 MutationMode::INITIALIZE, format));
665         testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_demote_write_initialize" + postfix,
666                                                                 BufferType::STENCIL, DiscardType::DEMOTE,
667                                                                 MutationMode::INITIALIZE_WRITE, format));
668     }
669 
670     return testGroup.release();
671 }
672 
673 } // namespace renderpass
674 } // namespace vkt
675