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