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