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