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