1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 The Khronos Group Inc.
6  * Copyright (c) 2023 LunarG, Inc.
7  * Copyright (c) 2023 Nintendo
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief VK_EXT_shader_stencil_export tests
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineStencilExportTests.hpp"
27 #include "vktPipelineMakeUtil.hpp"
28 #include "vktPipelineClearUtil.hpp"
29 #include "vktPipelineImageUtil.hpp"
30 #include "vktPipelineVertexUtil.hpp"
31 #include "vktPipelineReferenceRenderer.hpp"
32 #include "vktPipelineUniqueRandomIterator.hpp"
33 #include "vktTestCase.hpp"
34 #include "vktTestCaseUtil.hpp"
35 
36 #include "vkImageUtil.hpp"
37 #include "vkMemUtil.hpp"
38 #include "vkPrograms.hpp"
39 #include "vkQueryUtil.hpp"
40 #include "vkRef.hpp"
41 #include "vkRefUtil.hpp"
42 #include "vkTypeUtil.hpp"
43 #include "vkCmdUtil.hpp"
44 #include "vkObjUtil.hpp"
45 
46 #include "tcuTestLog.hpp"
47 #include "tcuImageCompare.hpp"
48 
49 #include "deMemory.h"
50 #include "deRandom.hpp"
51 #include "deStringUtil.hpp"
52 #include "deUniquePtr.hpp"
53 
54 #include <algorithm>
55 #include <sstream>
56 #include <vector>
57 
58 namespace vkt
59 {
60 namespace pipeline
61 {
62 
63 using namespace vk;
64 using de::MovePtr;
65 using de::SharedPtr;
66 using de::UniquePtr;
67 using tcu::UVec2;
68 using tcu::UVec4;
69 using tcu::Vec2;
70 using tcu::Vec4;
71 
72 namespace
73 {
74 
75 struct TestParams
76 {
77     PipelineConstructionType pipelineConstructionType;
78     vk::VkFormat stencilFormat;
79     bool early_and_late;
80 };
81 
82 static const std::string ExecutionModeStencil[] = {
83     "StencilRefGreaterFrontAMD", "StencilRefLessFrontAMD",      "StencilRefGreaterBackAMD",
84     "StencilRefLessBackAMD",     "StencilRefUnchangedFrontAMD", "StencilRefUnchangedBackAMD",
85 };
86 
87 enum ExecutionModeEarlyAndLate
88 {
89     MODE_STENCIL_REF_GREATER_FRONT_AMD = 0,
90     MODE_STENCIL_REF_LESS_FRONT_AMD,
91     MODE_STENCIL_REF_GREATER_BACK_AMD,
92     MODE_STENCIL_REF_LESS_BACK_AMD,
93     MODE_STENCIL_REF_UNCHANGED_FRONT_AMD,
94     MODE_STENCIL_REF_UNCHANGED_BACK_AMD,
95     MODE_COUNT_AMD
96 };
97 
initPrograms(SourceCollections & programCollection,TestParams paramaeters)98 void initPrograms(SourceCollections &programCollection, TestParams paramaeters)
99 {
100     // Vertex shader.
101     {
102         std::ostringstream src;
103         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
104             << "vec2 positions[6] = vec2[](\n"
105             << "    vec2(-1.0, -1.0),\n"
106             << "    vec2(-1.0, +1.0),\n"
107             << "    vec2(+1.0, -1.0),\n"
108             << "    vec2(+1.0, +1.0),\n"
109             << "    vec2(+1.0, -1.0),\n"
110             << "    vec2(-1.0, +1.0)\n"
111             << "\n"
112             << ");\n"
113             << "\n"
114             << "void main(void)\n"
115             << "{\n"
116             << "    gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);\n"
117             << "}\n";
118         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
119     }
120 
121     // Fragment shader that writes to Stencil buffer.
122     if (paramaeters.early_and_late)
123     {
124         for (int stencilModeNdx = 0; stencilModeNdx < 6; stencilModeNdx++)
125         {
126             const std::string src = "; SPIR-V\n"
127                                     "; Version: 1.0\n"
128                                     "; Bound: 36\n"
129                                     "; Schema: 0\n"
130                                     "OpCapability Shader\n"
131                                     "OpCapability StencilExportEXT\n"
132                                     "OpExtension \"SPV_EXT_shader_stencil_export\"\n"
133                                     "OpExtension \"SPV_AMD_shader_early_and_late_fragment_tests\"\n"
134                                     "%1 = OpExtInstImport \"GLSL.std.450\"\n"
135                                     "OpMemoryModel Logical GLSL450\n"
136                                     "OpEntryPoint Fragment %4 \"main\" %12 %31\n"
137                                     "OpExecutionMode %4 StencilRefReplacingEXT\n"
138                                     "OpExecutionMode %4 OriginUpperLeft\n"
139                                     "OpExecutionMode %4 EarlyAndLateFragmentTestsAMD\n"
140                                     "OpExecutionMode %4 " +
141                                     ExecutionModeStencil[stencilModeNdx] +
142                                     "\n"
143                                     "OpDecorate %12 BuiltIn FragCoord\n"
144                                     "OpDecorate %31 BuiltIn FragStencilRefEXT\n"
145                                     "%2 = OpTypeVoid\n"
146                                     "%3 = OpTypeFunction %2\n"
147                                     "%6 = OpTypeInt 32 1\n"
148                                     "%7 = OpTypePointer Function %6\n"
149                                     "%9 = OpTypeFloat 32\n"
150                                     "%10 = OpTypeVector %9 4\n"
151                                     "%11 = OpTypePointer Input %10\n"
152                                     "%12 = OpVariable %11 Input\n"
153                                     "%13 = OpTypeInt 32 0\n"
154                                     "%14 = OpConstant %13 0\n"
155                                     "%15 = OpTypePointer Input %9\n"
156                                     "%19 = OpConstant %6 4\n"
157                                     "%21 = OpConstant %6 2\n"
158                                     "%24 = OpConstant %13 1\n"
159                                     "%30 = OpTypePointer Output %6\n"
160                                     "%31 = OpVariable %30 Output\n"
161                                     "%4 = OpFunction %2 None %3\n"
162                                     "%5 = OpLabel\n"
163                                     "%8 = OpVariable %7 Function\n"
164                                     "%23 = OpVariable %7 Function\n"
165                                     "%16 = OpAccessChain %15 %12 %14\n"
166                                     "%17 = OpLoad %9 %16\n"
167                                     "%18 = OpConvertFToS %6 %17\n"
168                                     "%20 = OpShiftRightArithmetic %6 %18 %19\n"
169                                     "%22 = OpSMod %6 %20 %21\n"
170                                     "OpStore %8 %22\n"
171                                     "%25 = OpAccessChain %15 %12 %24\n"
172                                     "%26 = OpLoad %9 %25\n"
173                                     "%27 = OpConvertFToS %6 %26\n"
174                                     "%28 = OpShiftRightArithmetic %6 %27 %19\n"
175                                     "%29 = OpSMod %6 %28 %21\n"
176                                     "OpStore %23 %29\n"
177                                     "%32 = OpLoad %6 %8\n"
178                                     "%33 = OpLoad %6 %23\n"
179                                     "%34 = OpIAdd %6 %32 %33\n"
180                                     "%35 = OpSMod %6 %34 %21\n"
181                                     "OpStore %31 %35\n"
182                                     "OpReturn\n"
183                                     "OpFunctionEnd\n";
184 
185             std::ostringstream shaderName;
186             shaderName << "frag-stencil" << stencilModeNdx;
187             programCollection.spirvAsmSources.add(shaderName.str())
188                 << src << SpirVAsmBuildOptions(programCollection.usedVulkanVersion, SPIRV_VERSION_1_1);
189         }
190     }
191     else
192     {
193         std::ostringstream src;
194         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
195             << "#extension GL_ARB_shader_stencil_export: enable\n"
196             << "\n"
197             << "void main(void)\n"
198             << "{\n"
199             << "    int refX = (int(gl_FragCoord.x) >> 4) % 2;\n"
200             << "    int refY = (int(gl_FragCoord.y) >> 4) % 2;\n"
201             << "    gl_FragStencilRefARB = (refX + refY) % 2;\n"
202             << "}\n";
203         programCollection.glslSources.add("frag-stencil0") << glu::FragmentSource(src.str());
204     }
205 
206     // Fragment shader that writes to Color buffer.
207     {
208         std::ostringstream src;
209         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
210             << "layout(location = 0) out highp vec4 fragColor;\n"
211             << "\n"
212             << "void main(void)\n"
213             << "{\n"
214             << "    fragColor = vec4(0, 0, 1, 1);\n"
215             << "}\n";
216         programCollection.glslSources.add("frag-color") << glu::FragmentSource(src.str());
217     }
218 }
219 
isSupportedDepthStencilFormat(const InstanceInterface & instanceInterface,VkPhysicalDevice device,VkFormat format)220 bool isSupportedDepthStencilFormat(const InstanceInterface &instanceInterface, VkPhysicalDevice device, VkFormat format)
221 {
222     VkFormatProperties formatProps;
223 
224     instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps);
225 
226     return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
227 }
228 
makeImageCreateInfo(const VkFormat format,const UVec2 & size,VkImageUsageFlags usage)229 VkImageCreateInfo makeImageCreateInfo(const VkFormat format, const UVec2 &size, VkImageUsageFlags usage)
230 {
231     const VkImageCreateInfo imageParams = {
232         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
233         DE_NULL,                             // const void* pNext;
234         (VkImageCreateFlags)0,               // VkImageCreateFlags flags;
235         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
236         format,                              // VkFormat format;
237         makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
238         1u,                                  // uint32_t mipLevels;
239         1u,                                  // uint32_t arrayLayers;
240         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
241         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
242         usage,                               // VkImageUsageFlags usage;
243         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
244         0u,                                  // uint32_t queueFamilyIndexCount;
245         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
246         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
247     };
248     return imageParams;
249 }
250 
makeTestRenderPass(const DeviceInterface & vk,const VkDevice device,const PipelineConstructionType pipelineConstructionType,const VkFormat colorFormat,const VkFormat stencilFormat)251 RenderPassWrapper makeTestRenderPass(const DeviceInterface &vk, const VkDevice device,
252                                      const PipelineConstructionType pipelineConstructionType,
253                                      const VkFormat colorFormat, const VkFormat stencilFormat)
254 {
255     VkAttachmentDescription attachmentDescriptions[] = {
256         {
257             (VkAttachmentDescriptionFlags)0,          // VkAttachmentDescriptionFlags flags;
258             colorFormat,                              // VkFormat format;
259             VK_SAMPLE_COUNT_1_BIT,                    // VkSampleCountFlagBits samples;
260             VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp loadOp;
261             VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
262             VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
263             VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
264             VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout initialLayout;
265             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
266         },
267         {
268             (VkAttachmentDescriptionFlags)0,                  // VkAttachmentDescriptionFlags flags;
269             stencilFormat,                                    // VkFormat format;
270             VK_SAMPLE_COUNT_1_BIT,                            // VkSampleCountFlagBits samples;
271             VK_ATTACHMENT_LOAD_OP_DONT_CARE,                  // VkAttachmentLoadOp loadOp;
272             VK_ATTACHMENT_STORE_OP_DONT_CARE,                 // VkAttachmentStoreOp storeOp;
273             VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp stencilLoadOp;
274             VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp stencilStoreOp;
275             VK_IMAGE_LAYOUT_UNDEFINED,                        // VkImageLayout initialLayout;
276             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
277         },
278     };
279 
280     VkAttachmentReference colorAttachmentReference = {
281         0,                                        // uint32_t attachment;
282         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
283     };
284 
285     VkAttachmentReference stencilAttachmentReference = {
286         1,                                                // uint32_t attachment;
287         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
288     };
289 
290     VkSubpassDescription subpasses[] = {
291         {
292             (VkSubpassDescriptionFlags)0,    // VkSubpassDescriptionFlags flags;
293             VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
294             0u,                              // uint32_t inputAttachmentCount;
295             DE_NULL,                         // const VkAttachmentReference* pInputAttachments;
296             0u,                              // uint32_t colorAttachmentCount;
297             DE_NULL,                         // const VkAttachmentReference* pColorAttachments;
298             DE_NULL,                         // const VkAttachmentReference* pResolveAttachments;
299             &stencilAttachmentReference,     // const VkAttachmentReference* pDepthStencilAttachment;
300             0u,                              // uint32_t preserveAttachmentCount;
301             DE_NULL                          // const uint32_t* pPreserveAttachments;
302         },
303         {
304             (VkSubpassDescriptionFlags)0,    // VkSubpassDescriptionFlags flags;
305             VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
306             0u,                              // uint32_t inputAttachmentCount;
307             DE_NULL,                         // const VkAttachmentReference* pInputAttachments;
308             1u,                              // uint32_t colorAttachmentCount;
309             &colorAttachmentReference,       // const VkAttachmentReference* pColorAttachments;
310             DE_NULL,                         // const VkAttachmentReference* pResolveAttachments;
311             &stencilAttachmentReference,     // const VkAttachmentReference* pDepthStencilAttachment;
312             0u,                              // uint32_t preserveAttachmentCount;
313             DE_NULL                          // const uint32_t* pPreserveAttachments;
314         },
315     };
316 
317     VkSubpassDependency dependency = {
318         0u,                                           // uint32_t                srcSubpass;
319         1u,                                           // uint32_t                dstSubpass;
320         VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,    // VkPipelineStageFlags    srcStageMask;
321         VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,   // VkPipelineStageFlags    dstStageMask;
322         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags           srcAccessMask;
323         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,  // VkAccessFlags           dstAccessMask;
324         0u,                                           // VkDependencyFlags       dependencyFlags;
325     };
326 
327     const VkRenderPassCreateInfo renderPassInfo = {
328         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
329         DE_NULL,                                   // const void* pNext;
330         (VkRenderPassCreateFlags)0,                // VkRenderPassCreateFlags flags;
331         2u,                                        // uint32_t attachmentCount;
332         &attachmentDescriptions[0],                // const VkAttachmentDescription* pAttachments;
333         2u,                                        // uint32_t subpassCount;
334         &subpasses[0],                             // const VkSubpassDescription* pSubpasses;
335         1u,                                        // uint32_t dependencyCount;
336         &dependency,                               // const VkSubpassDependency* pDependencies;
337     };
338 
339     return RenderPassWrapper(pipelineConstructionType, vk, device, &renderPassInfo);
340 }
341 
preparePipelineWrapper(GraphicsPipelineWrapper & gpw,const PipelineLayoutWrapper & pipelineLayout,const VkRenderPass renderPass,const uint32_t subpass,const ShaderWrapper vertexModule,const ShaderWrapper fragmentModule,const UVec2 renderSize,const bool useColor,const bool earlyLate=false)342 void preparePipelineWrapper(GraphicsPipelineWrapper &gpw, const PipelineLayoutWrapper &pipelineLayout,
343                             const VkRenderPass renderPass, const uint32_t subpass, const ShaderWrapper vertexModule,
344                             const ShaderWrapper fragmentModule, const UVec2 renderSize, const bool useColor,
345                             const bool earlyLate = false)
346 {
347     const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {
348         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
349         DE_NULL,                                                   // const void* pNext;
350         (VkPipelineVertexInputStateCreateFlags)0,                  // VkPipelineVertexInputStateCreateFlags flags;
351         0u,                                                        // uint32_t vertexBindingDescriptionCount;
352         DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
353         0u,      // uint32_t vertexAttributeDescriptionCount;
354         DE_NULL, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
355     };
356 
357     const std::vector<VkViewport> viewport{makeViewport(renderSize)};
358     const std::vector<VkRect2D> scissor{makeRect2D(renderSize)};
359 
360     const VkStencilOpState stencilOpState = makeStencilOpState(
361         useColor ? VK_STENCIL_OP_KEEP : VK_STENCIL_OP_REPLACE, // stencil fail
362         useColor ? VK_STENCIL_OP_KEEP :
363                    (earlyLate ? VK_STENCIL_OP_KEEP : VK_STENCIL_OP_REPLACE), // depth & stencil pass
364         useColor ? VK_STENCIL_OP_KEEP : (earlyLate ? VK_STENCIL_OP_KEEP : VK_STENCIL_OP_REPLACE), // depth only fail
365         useColor ? VK_COMPARE_OP_EQUAL :
366                    (earlyLate ? VK_COMPARE_OP_EQUAL : VK_COMPARE_OP_NEVER), // compare op VK_COMPARE_OP_ALWAYS
367         useColor ? 0xffu : 0xffu,                                           // compare mask
368         useColor ? 0u : 0xffu,                                              // write mask
369         useColor ? 0u : 1u);                                                // reference
370 
371     VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo{
372         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
373         DE_NULL,                                                    // const void* pNext;
374         (VkPipelineDepthStencilStateCreateFlags)0,                  // VkPipelineDepthStencilStateCreateFlags flags;
375         VK_FALSE,                                                   // VkBool32 depthTestEnable;
376         VK_FALSE,                                                   // VkBool32 depthWriteEnable;
377         VK_COMPARE_OP_NEVER,                                        // VkCompareOp depthCompareOp;
378         VK_FALSE,                                                   // VkBool32 depthBoundsTestEnable;
379         VK_TRUE,                                                    // VkBool32 stencilTestEnable;
380         stencilOpState,                                             // VkStencilOpState front;
381         stencilOpState,                                             // VkStencilOpState back;
382         0.0f,                                                       // float minDepthBounds;
383         1.0f,                                                       // float maxDepthBounds;
384     };
385 
386     const VkColorComponentFlags colorComponentsAll =
387         VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
388     const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState{
389         VK_FALSE,             // VkBool32 blendEnable;
390         VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor;
391         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
392         VK_BLEND_OP_ADD,      // VkBlendOp colorBlendOp;
393         VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor;
394         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
395         VK_BLEND_OP_ADD,      // VkBlendOp alphaBlendOp;
396         colorComponentsAll,   // VkColorComponentFlags colorWriteMask;
397     };
398 
399     const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo{
400         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
401         DE_NULL,                                                  // const void* pNext;
402         (VkPipelineColorBlendStateCreateFlags)0,                  // VkPipelineColorBlendStateCreateFlags flags;
403         VK_FALSE,                                                 // VkBool32 logicOpEnable;
404         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
405         1u,                                                       // uint32_t attachmentCount;
406         &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
407         {0.0f, 0.0f, 0.0f, 0.0f},           // float blendConstants[4];
408     };
409 
410     gpw.setDefaultRasterizationState()
411         .setDefaultMultisampleState()
412         .setupVertexInputState(&vertexInputStateInfo)
413         .setupPreRasterizationShaderState(viewport, scissor, pipelineLayout, renderPass, subpass, vertexModule)
414         .setupFragmentShaderState(pipelineLayout, renderPass, subpass, fragmentModule, &pipelineDepthStencilStateInfo)
415         .setupFragmentOutputState(renderPass, subpass, &pipelineColorBlendStateInfo)
416         .setMonolithicPipelineLayout(pipelineLayout)
417         .buildPipeline();
418 }
419 
generateReferenceImage(const tcu::TextureFormat format,const UVec2 & renderSize,const uint32_t patternSize,const Vec4 & clearColor,const Vec4 & color)420 tcu::TextureLevel generateReferenceImage(const tcu::TextureFormat format, const UVec2 &renderSize,
421                                          const uint32_t patternSize, const Vec4 &clearColor, const Vec4 &color)
422 {
423     tcu::TextureLevel image(format, renderSize.x(), renderSize.y());
424     tcu::clear(image.getAccess(), clearColor);
425 
426     uint32_t rows = renderSize.y() / patternSize;
427     uint32_t cols = renderSize.x() / patternSize;
428 
429     for (uint32_t i = 0; i < rows; i++)
430     {
431         for (uint32_t j = 0; j < cols; j++)
432         {
433             if ((i + j) % 2 == 0)
434                 tcu::clear(
435                     tcu::getSubregion(image.getAccess(), i * patternSize, j * patternSize, patternSize, patternSize),
436                     color);
437         }
438     }
439 
440     return image;
441 }
442 
testStencilExportReplace(Context & context,TestParams params)443 tcu::TestStatus testStencilExportReplace(Context &context, TestParams params)
444 {
445     auto &log = context.getTestContext().getLog();
446     log << tcu::TestLog::Message << "Drawing to stencil using shader then using it for another draw."
447         << tcu::TestLog::EndMessage;
448 
449     const InstanceInterface &vki          = context.getInstanceInterface();
450     const DeviceInterface &vk             = context.getDeviceInterface();
451     const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
452     const VkDevice device                 = context.getDevice();
453     Allocator &allocator                  = context.getDefaultAllocator();
454 
455     const UVec2 renderSize(128, 128);
456     const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
457     const Vec4 clearColor(0.5f, 0.5f, 0.5f, 1.0f);
458     const VkDeviceSize colorBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
459 
460     const Unique<VkBuffer> colorBuffer(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
461     const UniquePtr<Allocation> colorBufferAlloc(
462         bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
463 
464     // Zero color buffer.
465     deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
466     flushAlloc(vk, device, *colorBufferAlloc);
467 
468     // Draw two subpasses: first write the stencil data, then use that data when writing color.
469     //
470     // The first pass will produce a checkerboard stencil by having the shader filling gl_FragStencilRefARB with 0 or 1,
471     // and using OP_REPLACE to write those values to the stencil buffer.
472     //
473     // The second pass will use the stencil with a compare operation EQUAL with reference value 0.
474     {
475         const VkImageSubresourceRange stencilSubresourceRange =
476             makeImageSubresourceRange(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u);
477         Move<VkImage> stencilImage = makeImage(
478             vk, device,
479             makeImageCreateInfo(params.stencilFormat, renderSize, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT));
480         MovePtr<Allocation> stencilImageAlloc = bindImage(vk, device, allocator, *stencilImage, MemoryRequirement::Any);
481         Move<VkImageView> stencilAttachment   = makeImageView(vk, device, *stencilImage, VK_IMAGE_VIEW_TYPE_2D,
482                                                               params.stencilFormat, stencilSubresourceRange);
483 
484         const VkImageSubresourceRange colorSubresourceRange =
485             makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
486         Move<VkImage> colorImage =
487             makeImage(vk, device,
488                       makeImageCreateInfo(colorFormat, renderSize,
489                                           VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
490         MovePtr<Allocation> colorImageAlloc = bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any);
491         Move<VkImageView> colorAttachment =
492             makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange);
493 
494         ShaderWrapper vertexModule = ShaderWrapper(vk, device, context.getBinaryCollection().get("vert"), 0);
495         ShaderWrapper fragmentColorModule =
496             ShaderWrapper(vk, device, context.getBinaryCollection().get("frag-color"), 0);
497 
498         RenderPassWrapper renderPass =
499             makeTestRenderPass(vk, device, params.pipelineConstructionType, colorFormat, params.stencilFormat);
500         PipelineLayoutWrapper pipelineLayout(params.pipelineConstructionType, vk, device);
501         GraphicsPipelineWrapper colorPipeline(vki, vk, physicalDevice, device, context.getDeviceExtensions(),
502                                               params.pipelineConstructionType);
503 
504         preparePipelineWrapper(colorPipeline, pipelineLayout, *renderPass, 1, vertexModule, fragmentColorModule,
505                                renderSize, true);
506 
507         std::vector<VkImage> images = {
508             *colorImage,
509             *stencilImage,
510         };
511 
512         const VkImageView attachments[] = {
513             *colorAttachment,
514             *stencilAttachment,
515         };
516         renderPass.createFramebuffer(vk, device, 2u, &images[0], &attachments[0], renderSize.x(), renderSize.y());
517 
518         Move<VkCommandPool> cmdPool     = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
519                                                             context.getUniversalQueueFamilyIndex());
520         Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
521         const VkQueue queue             = context.getUniversalQueue();
522         tcu::TextureLevel referenceImage =
523             generateReferenceImage(mapVkFormat(colorFormat), renderSize, 1 << 4, clearColor, Vec4(0, 0, 1, 1));
524 
525         const int stencilModeCount = (params.early_and_late ? MODE_COUNT_AMD : 1);
526 
527         for (int stencilModeNdx = 0; stencilModeNdx < stencilModeCount; stencilModeNdx++)
528         {
529             std::ostringstream shaderName;
530             shaderName << "frag-stencil" << stencilModeNdx;
531 
532             ShaderWrapper fragmentStencilModule =
533                 ShaderWrapper(vk, device, context.getBinaryCollection().get(shaderName.str()), 0);
534             GraphicsPipelineWrapper stencilPipeline(vki, vk, physicalDevice, device, context.getDeviceExtensions(),
535                                                     params.pipelineConstructionType);
536 
537             preparePipelineWrapper(stencilPipeline, pipelineLayout, *renderPass, 0, vertexModule, fragmentStencilModule,
538                                    renderSize, false);
539             beginCommandBuffer(vk, *cmdBuffer);
540             if (params.early_and_late)
541             {
542                 switch (stencilModeNdx)
543                 {
544                 case MODE_STENCIL_REF_GREATER_FRONT_AMD:
545                 case MODE_STENCIL_REF_GREATER_BACK_AMD:
546                     renderPass.begin(vk, *cmdBuffer, makeRect2D(0, 0, renderSize.x(), renderSize.y()), clearColor, 0.0,
547                                      1u); //0
548                     break;
549                 case MODE_STENCIL_REF_LESS_FRONT_AMD:
550                 case MODE_STENCIL_REF_LESS_BACK_AMD:
551                     renderPass.begin(vk, *cmdBuffer, makeRect2D(0, 0, renderSize.x(), renderSize.y()), clearColor, 0.0,
552                                      1u); //10
553                     break;
554                 default:
555                     renderPass.begin(vk, *cmdBuffer, makeRect2D(0, 0, renderSize.x(), renderSize.y()), clearColor, 0.0,
556                                      1u);
557                     break;
558                 }
559             }
560             else
561             {
562                 renderPass.begin(vk, *cmdBuffer, makeRect2D(0, 0, renderSize.x(), renderSize.y()), clearColor, 0.0, 0u);
563             }
564 
565             stencilPipeline.bind(*cmdBuffer);
566             vk.cmdDraw(*cmdBuffer, 6u, 1u, 0u, 0u);
567 
568             renderPass.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
569 
570             colorPipeline.bind(*cmdBuffer);
571             vk.cmdDraw(*cmdBuffer, 6u, 1u, 0u, 0u);
572 
573             renderPass.end(vk, *cmdBuffer);
574 
575             copyImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, tcu::IVec2(renderSize.x(), renderSize.y()));
576 
577             VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
578             submitCommandsAndWait(vk, device, queue, *cmdBuffer);
579 
580             // Compare the resulting color buffer.
581             {
582                 invalidateAlloc(vk, device, *colorBufferAlloc);
583                 const tcu::ConstPixelBufferAccess resultImage(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(),
584                                                               1u, colorBufferAlloc->getHostPtr());
585 
586                 if (!tcu::floatThresholdCompare(log, "color", "Image compare", referenceImage.getAccess(), resultImage,
587                                                 Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
588                     TCU_FAIL("Rendered image is not correct" +
589                              (params.early_and_late ?
590                                   (" for OpExecutionMode: " + ExecutionModeStencil[stencilModeNdx]) :
591                                   ""));
592             }
593         }
594     }
595     return tcu::TestStatus::pass("OK");
596 }
597 
checkSupport(Context & context,TestParams params)598 void checkSupport(Context &context, TestParams params)
599 {
600     context.requireDeviceFunctionality("VK_EXT_shader_stencil_export");
601 
602     if (!isSupportedDepthStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice(),
603                                        params.stencilFormat))
604         TCU_THROW(NotSupportedError, "Image format not supported");
605 
606     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
607                                           params.pipelineConstructionType);
608 
609 #ifndef CTS_USES_VULKANSC
610     if (params.early_and_late)
611     {
612         context.requireDeviceFunctionality("VK_AMD_shader_early_and_late_fragment_tests");
613         if (context.getShaderEarlyAndLateFragmentTestsFeaturesAMD().shaderEarlyAndLateFragmentTests == VK_FALSE)
614             TCU_THROW(NotSupportedError, "shaderEarlyAndLateFragmentTests is not supported");
615     }
616 #endif
617 }
618 
619 } // namespace
620 
createStencilExportTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)621 tcu::TestCaseGroup *createStencilExportTests(tcu::TestContext &testCtx,
622                                              PipelineConstructionType pipelineConstructionType)
623 {
624     struct
625     {
626         const vk::VkFormat format;
627         const std::string name;
628     } kFormats[] = {
629         {vk::VK_FORMAT_S8_UINT, "s8_uint"},
630         {vk::VK_FORMAT_D24_UNORM_S8_UINT, "d24_unorm_s8_uint"},
631         {vk::VK_FORMAT_D32_SFLOAT_S8_UINT, "d32_sfloat_s8_uint"},
632     };
633 
634     TestParams params{pipelineConstructionType, vk::VK_FORMAT_S8_UINT, false};
635 
636     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "shader_stencil_export"));
637     for (int fmtIdx = 0; fmtIdx < DE_LENGTH_OF_ARRAY(kFormats); ++fmtIdx)
638     {
639         params.stencilFormat = kFormats[fmtIdx].format;
640         de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, kFormats[fmtIdx].name.c_str()));
641         addFunctionCaseWithPrograms(formatGroup.get(), "op_replace", checkSupport, initPrograms,
642                                     testStencilExportReplace, params);
643 #ifndef CTS_USES_VULKANSC
644         params.early_and_late = true;
645         addFunctionCaseWithPrograms(formatGroup.get(), "op_replace_early_and_late", checkSupport, initPrograms,
646                                     testStencilExportReplace, params);
647         params.early_and_late = false;
648 #endif
649         group->addChild(formatGroup.release());
650     }
651     return group.release();
652 }
653 
654 } // namespace pipeline
655 } // namespace vkt
656