1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Imagination Technologies Ltd.
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 Stencil Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktPipelineStencilTests.hpp"
26 #include "vktPipelineClearUtil.hpp"
27 #include "vktPipelineImageUtil.hpp"
28 #include "vktPipelineVertexUtil.hpp"
29 #include "vktPipelineReferenceRenderer.hpp"
30 #include "vktPipelineUniqueRandomIterator.hpp"
31 #include "vktTestCase.hpp"
32 #include "vkImageUtil.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkRef.hpp"
37 #include "vkRefUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "deMemory.h"
43 #include "deRandom.hpp"
44 #include "deStringUtil.hpp"
45 #include "deUniquePtr.hpp"
46
47 #include <algorithm>
48 #include <sstream>
49 #include <vector>
50
51 namespace vkt
52 {
53 namespace pipeline
54 {
55
56 using namespace vk;
57
58 namespace
59 {
60
isSupportedDepthStencilFormat(const InstanceInterface & instanceInterface,VkPhysicalDevice device,VkFormat format)61 bool isSupportedDepthStencilFormat (const InstanceInterface& instanceInterface, VkPhysicalDevice device, VkFormat format)
62 {
63 VkFormatProperties formatProps;
64
65 instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps);
66
67 return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
68 }
69
70 class StencilOpStateUniqueRandomIterator : public UniqueRandomIterator<VkStencilOpState>
71 {
72 public:
73 StencilOpStateUniqueRandomIterator (int seed);
~StencilOpStateUniqueRandomIterator(void)74 virtual ~StencilOpStateUniqueRandomIterator (void) {}
75 virtual VkStencilOpState getIndexedValue (deUint32 index);
76
77 private:
78
79 // Pre-calculated constants
80 const static deUint32 s_stencilOpsLength;
81 const static deUint32 s_stencilOpsLength2;
82 const static deUint32 s_stencilOpsLength3;
83 const static deUint32 s_compareOpsLength;
84
85 // Total number of cross-combinations of (stencilFailOp x stencilPassOp x stencilDepthFailOp x stencilCompareOp)
86 const static deUint32 s_totalStencilOpStates;
87 };
88
89
90 class StencilTest : public vkt::TestCase
91 {
92 public:
93 enum
94 {
95 QUAD_COUNT = 4
96 };
97
98 struct StencilStateConfig
99 {
100 deUint32 frontReadMask;
101 deUint32 frontWriteMask;
102 deUint32 frontRef;
103
104 deUint32 backReadMask;
105 deUint32 backWriteMask;
106 deUint32 backRef;
107 };
108
109 const static StencilStateConfig s_stencilStateConfigs[QUAD_COUNT];
110 const static float s_quadDepths[QUAD_COUNT];
111
112
113 StencilTest (tcu::TestContext& testContext,
114 const std::string& name,
115 const std::string& description,
116 VkFormat stencilFormat,
117 const VkStencilOpState& stencilOpStateFront,
118 const VkStencilOpState& stencilOpStateBack);
119 virtual ~StencilTest (void);
120 virtual void initPrograms (SourceCollections& sourceCollections) const;
121 virtual TestInstance* createInstance (Context& context) const;
122
123 private:
124 VkFormat m_stencilFormat;
125 const VkStencilOpState m_stencilOpStateFront;
126 const VkStencilOpState m_stencilOpStateBack;
127 };
128
129 class StencilTestInstance : public vkt::TestInstance
130 {
131 public:
132 StencilTestInstance (Context& context,
133 VkFormat stencilFormat,
134 const VkStencilOpState& stencilOpStatesFront,
135 const VkStencilOpState& stencilOpStatesBack);
136 virtual ~StencilTestInstance (void);
137 virtual tcu::TestStatus iterate (void);
138
139 private:
140 tcu::TestStatus verifyImage (void);
141
142 VkStencilOpState m_stencilOpStateFront;
143 VkStencilOpState m_stencilOpStateBack;
144 const tcu::UVec2 m_renderSize;
145 const VkFormat m_colorFormat;
146 const VkFormat m_stencilFormat;
147 VkImageSubresourceRange m_stencilImageSubresourceRange;
148
149 VkImageCreateInfo m_colorImageCreateInfo;
150 Move<VkImage> m_colorImage;
151 de::MovePtr<Allocation> m_colorImageAlloc;
152 Move<VkImage> m_stencilImage;
153 de::MovePtr<Allocation> m_stencilImageAlloc;
154 Move<VkImageView> m_colorAttachmentView;
155 Move<VkImageView> m_stencilAttachmentView;
156 Move<VkRenderPass> m_renderPass;
157 Move<VkFramebuffer> m_framebuffer;
158
159 Move<VkShaderModule> m_vertexShaderModule;
160 Move<VkShaderModule> m_fragmentShaderModule;
161
162 Move<VkBuffer> m_vertexBuffer;
163 std::vector<Vertex4RGBA> m_vertices;
164 de::MovePtr<Allocation> m_vertexBufferAlloc;
165
166 Move<VkPipelineLayout> m_pipelineLayout;
167 Move<VkPipeline> m_graphicsPipelines[StencilTest::QUAD_COUNT];
168
169 Move<VkCommandPool> m_cmdPool;
170 Move<VkCommandBuffer> m_cmdBuffer;
171 };
172
173 const VkStencilOp stencilOps[] =
174 {
175 VK_STENCIL_OP_KEEP,
176 VK_STENCIL_OP_ZERO,
177 VK_STENCIL_OP_REPLACE,
178 VK_STENCIL_OP_INCREMENT_AND_CLAMP,
179 VK_STENCIL_OP_DECREMENT_AND_CLAMP,
180 VK_STENCIL_OP_INVERT,
181 VK_STENCIL_OP_INCREMENT_AND_WRAP,
182 VK_STENCIL_OP_DECREMENT_AND_WRAP
183 };
184
185 const VkCompareOp compareOps[] =
186 {
187 VK_COMPARE_OP_NEVER,
188 VK_COMPARE_OP_LESS,
189 VK_COMPARE_OP_EQUAL,
190 VK_COMPARE_OP_LESS_OR_EQUAL,
191 VK_COMPARE_OP_GREATER,
192 VK_COMPARE_OP_NOT_EQUAL,
193 VK_COMPARE_OP_GREATER_OR_EQUAL,
194 VK_COMPARE_OP_ALWAYS
195 };
196
197 // StencilOpStateUniqueRandomIterator
198
199 const deUint32 StencilOpStateUniqueRandomIterator::s_stencilOpsLength = DE_LENGTH_OF_ARRAY(stencilOps);
200 const deUint32 StencilOpStateUniqueRandomIterator::s_stencilOpsLength2 = s_stencilOpsLength * s_stencilOpsLength;
201 const deUint32 StencilOpStateUniqueRandomIterator::s_stencilOpsLength3 = s_stencilOpsLength2 * s_stencilOpsLength;
202 const deUint32 StencilOpStateUniqueRandomIterator::s_compareOpsLength = DE_LENGTH_OF_ARRAY(compareOps);
203 const deUint32 StencilOpStateUniqueRandomIterator::s_totalStencilOpStates = s_stencilOpsLength3 * s_compareOpsLength;
204
StencilOpStateUniqueRandomIterator(int seed)205 StencilOpStateUniqueRandomIterator::StencilOpStateUniqueRandomIterator (int seed)
206 : UniqueRandomIterator<VkStencilOpState>(s_totalStencilOpStates, s_totalStencilOpStates, seed)
207 {
208 }
209
getIndexedValue(deUint32 index)210 VkStencilOpState StencilOpStateUniqueRandomIterator::getIndexedValue (deUint32 index)
211 {
212 const deUint32 stencilCompareOpIndex = index / s_stencilOpsLength3;
213 const deUint32 stencilCompareOpSeqIndex = stencilCompareOpIndex * s_stencilOpsLength3;
214
215 const deUint32 stencilDepthFailOpIndex = (index - stencilCompareOpSeqIndex) / s_stencilOpsLength2;
216 const deUint32 stencilDepthFailOpSeqIndex = stencilDepthFailOpIndex * s_stencilOpsLength2;
217
218 const deUint32 stencilPassOpIndex = (index - stencilCompareOpSeqIndex - stencilDepthFailOpSeqIndex) / s_stencilOpsLength;
219 const deUint32 stencilPassOpSeqIndex = stencilPassOpIndex * s_stencilOpsLength;
220
221 const deUint32 stencilFailOpIndex = index - stencilCompareOpSeqIndex - stencilDepthFailOpSeqIndex - stencilPassOpSeqIndex;
222
223 const VkStencilOpState stencilOpState =
224 {
225 stencilOps[stencilFailOpIndex], // VkStencilOp failOp;
226 stencilOps[stencilPassOpIndex], // VkStencilOp passOp;
227 stencilOps[stencilDepthFailOpIndex], // VkStencilOp depthFailOp;
228 compareOps[stencilCompareOpIndex], // VkCompareOp compareOp;
229 0x0, // deUint32 compareMask;
230 0x0, // deUint32 writeMask;
231 0x0 // deUint32 reference;
232 };
233
234 return stencilOpState;
235 }
236
237
238 // StencilTest
239
240 const StencilTest::StencilStateConfig StencilTest::s_stencilStateConfigs[QUAD_COUNT] =
241 {
242 // frontReadMask frontWriteMask frontRef backReadMask backWriteMask backRef
243 { 0xFF, 0xFF, 0xAB, 0xF0, 0xFF, 0xFF },
244 { 0xFF, 0xF0, 0xCD, 0xF0, 0xF0, 0xEF },
245 { 0xF0, 0x0F, 0xEF, 0xFF, 0x0F, 0xCD },
246 { 0xF0, 0x01, 0xFF, 0xFF, 0x01, 0xAB }
247 };
248
249 const float StencilTest::s_quadDepths[QUAD_COUNT] =
250 {
251 0.1f,
252 0.0f,
253 0.3f,
254 0.2f
255 };
256
StencilTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,VkFormat stencilFormat,const VkStencilOpState & stencilOpStateFront,const VkStencilOpState & stencilOpStateBack)257 StencilTest::StencilTest (tcu::TestContext& testContext,
258 const std::string& name,
259 const std::string& description,
260 VkFormat stencilFormat,
261 const VkStencilOpState& stencilOpStateFront,
262 const VkStencilOpState& stencilOpStateBack)
263 : vkt::TestCase (testContext, name, description)
264 , m_stencilFormat (stencilFormat)
265 , m_stencilOpStateFront (stencilOpStateFront)
266 , m_stencilOpStateBack (stencilOpStateBack)
267 {
268 }
269
~StencilTest(void)270 StencilTest::~StencilTest (void)
271 {
272 }
273
createInstance(Context & context) const274 TestInstance* StencilTest::createInstance (Context& context) const
275 {
276 return new StencilTestInstance(context, m_stencilFormat, m_stencilOpStateFront, m_stencilOpStateBack);
277 }
278
initPrograms(SourceCollections & sourceCollections) const279 void StencilTest::initPrograms (SourceCollections& sourceCollections) const
280 {
281 sourceCollections.glslSources.add("color_vert") << glu::VertexSource(
282 "#version 310 es\n"
283 "layout(location = 0) in vec4 position;\n"
284 "layout(location = 1) in vec4 color;\n"
285 "layout(location = 0) out highp vec4 vtxColor;\n"
286 "void main (void)\n"
287 "{\n"
288 " gl_Position = position;\n"
289 " vtxColor = color;\n"
290 "}\n");
291
292 sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(
293 "#version 310 es\n"
294 "layout(location = 0) in highp vec4 vtxColor;\n"
295 "layout(location = 0) out highp vec4 fragColor;\n"
296 "void main (void)\n"
297 "{\n"
298 " fragColor = vtxColor;\n"
299 "}\n");
300 }
301
302
303 // StencilTestInstance
304
StencilTestInstance(Context & context,VkFormat stencilFormat,const VkStencilOpState & stencilOpStateFront,const VkStencilOpState & stencilOpStateBack)305 StencilTestInstance::StencilTestInstance (Context& context,
306 VkFormat stencilFormat,
307 const VkStencilOpState& stencilOpStateFront,
308 const VkStencilOpState& stencilOpStateBack)
309 : vkt::TestInstance (context)
310 , m_stencilOpStateFront (stencilOpStateFront)
311 , m_stencilOpStateBack (stencilOpStateBack)
312 , m_renderSize (32, 32)
313 , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
314 , m_stencilFormat (stencilFormat)
315 {
316 const DeviceInterface& vk = context.getDeviceInterface();
317 const VkDevice vkDevice = context.getDevice();
318 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
319 SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
320 const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
321
322 // Create color image
323 {
324 const VkImageCreateInfo colorImageParams =
325 {
326 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
327 DE_NULL, // const void* pNext;
328 0u, // VkImageCreateFlags flags;
329 VK_IMAGE_TYPE_2D, // VkImageType imageType;
330 m_colorFormat, // VkFormat format;
331 { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
332 1u, // deUint32 mipLevels;
333 1u, // deUint32 arrayLayers;
334 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
335 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
336 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
337 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
338 1u, // deUint32 queueFamilyIndexCount;
339 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
340 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
341 };
342
343 m_colorImageCreateInfo = colorImageParams;
344 m_colorImage = createImage(vk, vkDevice, &m_colorImageCreateInfo);
345
346 // Allocate and bind color image memory
347 m_colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
348 VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
349 }
350
351 // Create stencil image
352 {
353 // Check format support
354 if (!isSupportedDepthStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice(), m_stencilFormat))
355 throw tcu::NotSupportedError(std::string("Unsupported depth/stencil format: ") + getFormatName(m_stencilFormat));
356
357 const VkImageCreateInfo stencilImageParams =
358 {
359 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
360 DE_NULL, // const void* pNext;
361 0u, // VkImageCreateFlags flags;
362 VK_IMAGE_TYPE_2D, // VkImageType imageType;
363 m_stencilFormat, // VkFormat format;
364 { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
365 1u, // deUint32 mipLevels;
366 1u, // deUint32 arrayLayers;
367 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
368 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
369 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, // VkImageUsageFlags usage;
370 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
371 1u, // deUint32 queueFamilyIndexCount;
372 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
373 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
374 };
375
376 m_stencilImage = createImage(vk, vkDevice, &stencilImageParams);
377
378 // Allocate and bind stencil image memory
379 m_stencilImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_stencilImage), MemoryRequirement::Any);
380 VK_CHECK(vk.bindImageMemory(vkDevice, *m_stencilImage, m_stencilImageAlloc->getMemory(), m_stencilImageAlloc->getOffset()));
381
382 const VkImageAspectFlags aspect = (mapVkFormat(m_stencilFormat).order == tcu::TextureFormat::DS ? VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT
383 : VK_IMAGE_ASPECT_STENCIL_BIT);
384 m_stencilImageSubresourceRange = makeImageSubresourceRange(aspect, 0u, stencilImageParams.mipLevels, 0u, stencilImageParams.arrayLayers);
385 }
386
387 // Create color attachment view
388 {
389 const VkImageViewCreateInfo colorAttachmentViewParams =
390 {
391 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
392 DE_NULL, // const void* pNext;
393 0u, // VkImageViewCreateFlags flags;
394 *m_colorImage, // VkImage image;
395 VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
396 m_colorFormat, // VkFormat format;
397 componentMappingRGBA, // VkComponentMapping components;
398 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange;
399 };
400
401 m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
402 }
403
404 // Create stencil attachment view
405 {
406 const VkImageViewCreateInfo stencilAttachmentViewParams =
407 {
408 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
409 DE_NULL, // const void* pNext;
410 0u, // VkImageViewCreateFlags flags;
411 *m_stencilImage, // VkImage image;
412 VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
413 m_stencilFormat, // VkFormat format;
414 componentMappingRGBA, // VkComponentMapping components;
415 m_stencilImageSubresourceRange, // VkImageSubresourceRange subresourceRange;
416 };
417
418 m_stencilAttachmentView = createImageView(vk, vkDevice, &stencilAttachmentViewParams);
419 }
420
421 // Create render pass
422 m_renderPass = makeRenderPass(vk, vkDevice, m_colorFormat, m_stencilFormat);
423
424 // Create framebuffer
425 {
426 const VkImageView attachmentBindInfos[2] = { *m_colorAttachmentView, *m_stencilAttachmentView };
427
428 const VkFramebufferCreateInfo framebufferParams =
429 {
430 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
431 DE_NULL, // const void* pNext;
432 0u, // VkFramebufferCreateFlags flags;
433 *m_renderPass, // VkRenderPass renderPass;
434 2u, // deUint32 attachmentCount;
435 attachmentBindInfos, // const VkImageView* pAttachments;
436 (deUint32)m_renderSize.x(), // deUint32 width;
437 (deUint32)m_renderSize.y(), // deUint32 height;
438 1u // deUint32 layers;
439 };
440
441 m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
442 }
443
444 // Create pipeline layout
445 {
446 const VkPipelineLayoutCreateInfo pipelineLayoutParams =
447 {
448 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
449 DE_NULL, // const void* pNext;
450 0u, // VkPipelineLayoutCreateFlags flags;
451 0u, // deUint32 setLayoutCount;
452 DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
453 0u, // deUint32 pushConstantRangeCount;
454 DE_NULL // const VkPushConstantRange* pPushConstantRanges;
455 };
456
457 m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
458 }
459
460 m_vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
461 m_fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
462
463 // Create pipeline
464 {
465 const VkVertexInputBindingDescription vertexInputBindingDescription =
466 {
467 0u, // deUint32 binding;
468 sizeof(Vertex4RGBA), // deUint32 strideInBytes;
469 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate;
470 };
471
472 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
473 {
474 {
475 0u, // deUint32 location;
476 0u, // deUint32 binding;
477 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
478 0u // deUint32 offsetInBytes;
479 },
480 {
481 1u, // deUint32 location;
482 0u, // deUint32 binding;
483 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
484 DE_OFFSET_OF(Vertex4RGBA, color), // deUint32 offsetInBytes;
485 }
486 };
487
488 const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
489 {
490 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
491 DE_NULL, // const void* pNext;
492 0u, // VkPipelineVertexInputStateCreateFlags flags;
493 1u, // deUint32 vertexBindingDescriptionCount;
494 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
495 2u, // deUint32 vertexAttributeDescriptionCount;
496 vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
497 };
498
499 const std::vector<VkViewport> viewports (1, makeViewport(m_renderSize));
500 const std::vector<VkRect2D> scissors (1, makeRect2D(m_renderSize));
501
502 const bool isDepthEnabled = (vk::mapVkFormat(m_stencilFormat).order != tcu::TextureFormat::S);
503
504 VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
505 {
506 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
507 DE_NULL, // const void* pNext;
508 0u, // VkPipelineDepthStencilStateCreateFlags flags;
509 isDepthEnabled, // VkBool32 depthTestEnable;
510 isDepthEnabled, // VkBool32 depthWriteEnable;
511 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
512 false, // VkBool32 depthBoundsTestEnable;
513 true, // VkBool32 stencilTestEnable;
514 m_stencilOpStateFront, // VkStencilOpState front;
515 m_stencilOpStateBack, // VkStencilOpState back;
516 0.0f, // float minDepthBounds;
517 1.0f // float maxDepthBounds;
518 };
519
520 // Setup different stencil masks and refs in each quad
521 for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
522 {
523 const StencilTest::StencilStateConfig& config = StencilTest::s_stencilStateConfigs[quadNdx];
524 VkStencilOpState& front = depthStencilStateParams.front;
525 VkStencilOpState& back = depthStencilStateParams.back;
526
527 front.compareMask = config.frontReadMask;
528 front.writeMask = config.frontWriteMask;
529 front.reference = config.frontRef;
530
531 back.compareMask = config.backReadMask;
532 back.writeMask = config.backWriteMask;
533 back.reference = config.backRef;
534
535 m_graphicsPipelines[quadNdx] = makeGraphicsPipeline(vk, // const DeviceInterface& vk
536 vkDevice, // const VkDevice device
537 *m_pipelineLayout, // const VkPipelineLayout pipelineLayout
538 *m_vertexShaderModule, // const VkShaderModule vertexShaderModule
539 DE_NULL, // const VkShaderModule tessellationControlModule
540 DE_NULL, // const VkShaderModule tessellationEvalModule
541 DE_NULL, // const VkShaderModule geometryShaderModule
542 *m_fragmentShaderModule, // const VkShaderModule fragmentShaderModule
543 *m_renderPass, // const VkRenderPass renderPass
544 viewports, // const std::vector<VkViewport>& viewports
545 scissors, // const std::vector<VkRect2D>& scissors
546 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
547 0u, // const deUint32 subpass
548 0u, // const deUint32 patchControlPoints
549 &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
550 DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
551 DE_NULL, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
552 &depthStencilStateParams); // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo
553 }
554 }
555
556
557 // Create vertex buffer
558 {
559 const VkBufferCreateInfo vertexBufferParams =
560 {
561 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
562 DE_NULL, // const void* pNext;
563 0u, // VkBufferCreateFlags flags;
564 1024u, // VkDeviceSize size;
565 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
566 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
567 1u, // deUint32 queueFamilyIndexCount;
568 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
569 };
570
571 m_vertices = createOverlappingQuads();
572 m_vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
573 m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
574
575 VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
576
577 // Adjust depths
578 for (int quadNdx = 0; quadNdx < 4; quadNdx++)
579 for (int vertexNdx = 0; vertexNdx < 6; vertexNdx++)
580 m_vertices[quadNdx * 6 + vertexNdx].position.z() = StencilTest::s_quadDepths[quadNdx];
581
582 // Load vertices into vertex buffer
583 deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
584 flushAlloc(vk, vkDevice, *m_vertexBufferAlloc);
585 }
586
587 // Create command pool
588 m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
589
590 // Create command buffer
591 {
592 const VkClearValue attachmentClearValues[2] =
593 {
594 defaultClearValue(m_colorFormat),
595 defaultClearValue(m_stencilFormat)
596 };
597
598 const VkImageMemoryBarrier imageLayoutBarriers[] =
599 {
600 // color image layout transition
601 {
602 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
603 DE_NULL, // const void* pNext;
604 (VkAccessFlags)0, // VkAccessFlags srcAccessMask;
605 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask;
606 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
607 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
608 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
609 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
610 *m_colorImage, // VkImage image;
611 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange;
612 },
613 // stencil image layout transition
614 {
615 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
616 DE_NULL, // const void* pNext;
617 (VkAccessFlags)0, // VkAccessFlags srcAccessMask;
618 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask;
619 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
620 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
621 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
622 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
623 *m_stencilImage, // VkImage image;
624 m_stencilImageSubresourceRange, // VkImageSubresourceRange subresourceRange;
625 },
626 };
627
628 m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
629
630 beginCommandBuffer(vk, *m_cmdBuffer, 0u);
631
632 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, (VkDependencyFlags)0,
633 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(imageLayoutBarriers), imageLayoutBarriers);
634
635 beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), 2u, attachmentClearValues);
636
637 const VkDeviceSize quadOffset = (m_vertices.size() / StencilTest::QUAD_COUNT) * sizeof(Vertex4RGBA);
638
639 for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
640 {
641 VkDeviceSize vertexBufferOffset = quadOffset * quadNdx;
642
643 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelines[quadNdx]);
644 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
645 vk.cmdDraw(*m_cmdBuffer, (deUint32)(m_vertices.size() / StencilTest::QUAD_COUNT), 1, 0, 0);
646 }
647
648 endRenderPass(vk, *m_cmdBuffer);
649 endCommandBuffer(vk, *m_cmdBuffer);
650 }
651 }
652
~StencilTestInstance(void)653 StencilTestInstance::~StencilTestInstance (void)
654 {
655 }
656
iterate(void)657 tcu::TestStatus StencilTestInstance::iterate (void)
658 {
659 const DeviceInterface& vk = m_context.getDeviceInterface();
660 const VkDevice vkDevice = m_context.getDevice();
661 const VkQueue queue = m_context.getUniversalQueue();
662
663 submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
664
665 return verifyImage();
666 }
667
verifyImage(void)668 tcu::TestStatus StencilTestInstance::verifyImage (void)
669 {
670 const tcu::TextureFormat tcuColorFormat = mapVkFormat(m_colorFormat);
671 const tcu::TextureFormat tcuStencilFormat = mapVkFormat(m_stencilFormat);
672 const ColorVertexShader vertexShader;
673 const ColorFragmentShader fragmentShader (tcuColorFormat, tcuStencilFormat);
674 const rr::Program program (&vertexShader, &fragmentShader);
675 ReferenceRenderer refRenderer (m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuStencilFormat, &program);
676 bool compareOk = false;
677
678 // Render reference image
679 {
680 // Set depth state
681 rr::RenderState renderState(refRenderer.getViewportState());
682
683 renderState.fragOps.depthTestEnabled = true;
684 renderState.fragOps.depthFunc = mapVkCompareOp(VK_COMPARE_OP_LESS);
685 renderState.fragOps.stencilTestEnabled = true;
686
687 rr::StencilState& refStencilFront = renderState.fragOps.stencilStates[rr::FACETYPE_FRONT];
688 rr::StencilState& refStencilBack = renderState.fragOps.stencilStates[rr::FACETYPE_BACK];
689
690 refStencilFront.sFail = mapVkStencilOp(m_stencilOpStateFront.failOp);
691 refStencilFront.dpFail = mapVkStencilOp(m_stencilOpStateFront.depthFailOp);
692 refStencilFront.dpPass = mapVkStencilOp(m_stencilOpStateFront.passOp);
693 refStencilFront.func = mapVkCompareOp(m_stencilOpStateFront.compareOp);
694
695 refStencilBack.sFail = mapVkStencilOp(m_stencilOpStateBack.failOp);
696 refStencilBack.dpPass = mapVkStencilOp(m_stencilOpStateBack.passOp);
697 refStencilBack.dpFail = mapVkStencilOp(m_stencilOpStateBack.depthFailOp);
698 refStencilBack.func = mapVkCompareOp(m_stencilOpStateBack.compareOp);
699
700 // Reverse winding of vertices, as Vulkan screen coordinates start at upper left
701 std::vector<Vertex4RGBA> cwVertices(m_vertices);
702 for (size_t vertexNdx = 0; vertexNdx < cwVertices.size() - 2; vertexNdx += 3)
703 {
704 const Vertex4RGBA cwVertex1 = cwVertices[vertexNdx + 1];
705
706 cwVertices[vertexNdx + 1] = cwVertices[vertexNdx + 2];
707 cwVertices[vertexNdx + 2] = cwVertex1;
708 }
709
710 for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
711 {
712 refStencilFront.ref = (int)StencilTest::s_stencilStateConfigs[quadNdx].frontRef;
713 refStencilFront.compMask = StencilTest::s_stencilStateConfigs[quadNdx].frontReadMask;
714 refStencilFront.writeMask = StencilTest::s_stencilStateConfigs[quadNdx].frontWriteMask;
715
716 refStencilBack.ref = (int)StencilTest::s_stencilStateConfigs[quadNdx].backRef;
717 refStencilBack.compMask = StencilTest::s_stencilStateConfigs[quadNdx].backReadMask;
718 refStencilBack.writeMask = StencilTest::s_stencilStateConfigs[quadNdx].backWriteMask;
719
720 refRenderer.draw(renderState,
721 rr::PRIMITIVETYPE_TRIANGLES,
722 std::vector<Vertex4RGBA>(cwVertices.begin() + quadNdx * 6,
723 cwVertices.begin() + (quadNdx + 1) * 6));
724 }
725 }
726
727 // Compare result with reference image
728 {
729 const DeviceInterface& vk = m_context.getDeviceInterface();
730 const VkDevice vkDevice = m_context.getDevice();
731 const VkQueue queue = m_context.getUniversalQueue();
732 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
733 SimpleAllocator allocator (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
734 de::UniquePtr<tcu::TextureLevel> result (readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize).release());
735
736 compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
737 "IntImageCompare",
738 "Image comparison",
739 refRenderer.getAccess(),
740 result->getAccess(),
741 tcu::UVec4(2, 2, 2, 2),
742 tcu::IVec3(1, 1, 0),
743 true,
744 tcu::COMPARE_LOG_RESULT);
745 }
746
747 if (compareOk)
748 return tcu::TestStatus::pass("Result image matches reference");
749 else
750 return tcu::TestStatus::fail("Image mismatch");
751 }
752
753
754 // Utilities for test names
755
getShortName(VkCompareOp compareOp)756 std::string getShortName (VkCompareOp compareOp)
757 {
758 const std::string fullName = getCompareOpName(compareOp);
759
760 DE_ASSERT(de::beginsWith(fullName, "VK_COMPARE_OP_"));
761
762 return de::toLower(fullName.substr(14));
763 }
764
getShortName(VkStencilOp stencilOp)765 const char* getShortName (VkStencilOp stencilOp)
766 {
767 switch (stencilOp)
768 {
769 case VK_STENCIL_OP_KEEP: return "keep";
770 case VK_STENCIL_OP_ZERO: return "zero";
771 case VK_STENCIL_OP_REPLACE: return "repl";
772 case VK_STENCIL_OP_INCREMENT_AND_CLAMP: return "incc";
773 case VK_STENCIL_OP_DECREMENT_AND_CLAMP: return "decc";
774 case VK_STENCIL_OP_INVERT: return "inv";
775 case VK_STENCIL_OP_INCREMENT_AND_WRAP: return "wrap";
776 case VK_STENCIL_OP_DECREMENT_AND_WRAP: return "decw";
777
778 default:
779 DE_FATAL("Invalid VkStencilOpState value");
780 }
781 return DE_NULL;
782 }
783
getStencilStateSetDescription(const VkStencilOpState & stencilOpStateFront,const VkStencilOpState & stencilOpStateBack)784 std::string getStencilStateSetDescription(const VkStencilOpState& stencilOpStateFront,
785 const VkStencilOpState& stencilOpStateBack)
786 {
787 std::ostringstream desc;
788
789 desc << "\nFront faces:\n" << stencilOpStateFront;
790 desc << "Back faces:\n" << stencilOpStateBack;
791
792 return desc.str();
793 }
794
getFormatCaseName(VkFormat format)795 std::string getFormatCaseName (VkFormat format)
796 {
797 const std::string fullName = getFormatName(format);
798
799 DE_ASSERT(de::beginsWith(fullName, "VK_FORMAT_"));
800
801 return de::toLower(fullName.substr(10));
802 }
803
804 } // anonymous
805
createStencilTests(tcu::TestContext & testCtx)806 tcu::TestCaseGroup* createStencilTests (tcu::TestContext& testCtx)
807 {
808 const VkFormat stencilFormats[] =
809 {
810 VK_FORMAT_S8_UINT,
811 VK_FORMAT_D16_UNORM_S8_UINT,
812 VK_FORMAT_D24_UNORM_S8_UINT,
813 VK_FORMAT_D32_SFLOAT_S8_UINT
814 };
815
816 de::MovePtr<tcu::TestCaseGroup> stencilTests (new tcu::TestCaseGroup(testCtx, "stencil", "Stencil tests"));
817 de::MovePtr<tcu::TestCaseGroup> formatTests (new tcu::TestCaseGroup(testCtx, "format", "Uses different stencil formats"));
818 StencilOpStateUniqueRandomIterator stencilOpItr (123);
819
820 for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(stencilFormats); formatNdx++)
821 {
822 const VkFormat stencilFormat = stencilFormats[formatNdx];
823 de::MovePtr<tcu::TestCaseGroup> formatTest (new tcu::TestCaseGroup(testCtx,
824 getFormatCaseName(stencilFormat).c_str(),
825 (std::string("Uses format ") + getFormatName(stencilFormat)).c_str()));
826
827 de::MovePtr<tcu::TestCaseGroup> stencilStateTests;
828 {
829 std::ostringstream desc;
830 desc << "Draws 4 quads with the following depths and dynamic stencil states: ";
831 for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
832 {
833 const StencilTest::StencilStateConfig& stencilConfig = StencilTest::s_stencilStateConfigs[quadNdx];
834
835 desc << "(" << quadNdx << ") "
836 << "z = " << StencilTest::s_quadDepths[quadNdx] << ", "
837 << "frontReadMask = " << stencilConfig.frontReadMask << ", "
838 << "frontWriteMask = " << stencilConfig.frontWriteMask << ", "
839 << "frontRef = " << stencilConfig.frontRef << ", "
840 << "backReadMask = " << stencilConfig.backReadMask << ", "
841 << "backWriteMask = " << stencilConfig.backWriteMask << ", "
842 << "backRef = " << stencilConfig.backRef;
843 }
844
845 stencilStateTests = de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, "states", desc.str().c_str()));
846 }
847
848 stencilOpItr.reset();
849
850 for (deUint32 failOpNdx = 0u; failOpNdx < DE_LENGTH_OF_ARRAY(stencilOps); failOpNdx++)
851 {
852 const std::string failOpName = std::string("fail_") + getShortName(stencilOps[failOpNdx]);
853 de::MovePtr<tcu::TestCaseGroup> failOpTest (new tcu::TestCaseGroup(testCtx, failOpName.c_str(), ""));
854
855 for (deUint32 passOpNdx = 0u; passOpNdx < DE_LENGTH_OF_ARRAY(stencilOps); passOpNdx++)
856 {
857 const std::string passOpName = std::string("pass_") + getShortName(stencilOps[passOpNdx]);
858 de::MovePtr<tcu::TestCaseGroup> passOpTest (new tcu::TestCaseGroup(testCtx, passOpName.c_str(), ""));
859
860 for (deUint32 dFailOpNdx = 0u; dFailOpNdx < DE_LENGTH_OF_ARRAY(stencilOps); dFailOpNdx++)
861 {
862 const std::string dFailOpName = std::string("dfail_") + getShortName(stencilOps[dFailOpNdx]);
863 de::MovePtr<tcu::TestCaseGroup> dFailOpTest (new tcu::TestCaseGroup(testCtx, dFailOpName.c_str(), ""));
864
865 for (deUint32 compareOpNdx = 0u; compareOpNdx < DE_LENGTH_OF_ARRAY(compareOps); compareOpNdx++)
866 {
867 // Iterate front set of stencil state in ascending order
868 const VkStencilOpState stencilStateFront =
869 {
870 stencilOps[failOpNdx], // failOp
871 stencilOps[passOpNdx], // passOp
872 stencilOps[dFailOpNdx], // depthFailOp
873 compareOps[compareOpNdx], // compareOp
874 0x0, // compareMask
875 0x0, // writeMask
876 0x0 // reference
877 };
878
879 // Iterate back set of stencil state in random order
880 const VkStencilOpState stencilStateBack = stencilOpItr.next();
881 const std::string caseName = std::string("comp_") + getShortName(compareOps[compareOpNdx]);
882 const std::string caseDesc = getStencilStateSetDescription(stencilStateFront, stencilStateBack);
883
884 dFailOpTest->addChild(new StencilTest(testCtx, caseName, caseDesc, stencilFormat, stencilStateFront, stencilStateBack));
885 }
886 passOpTest->addChild(dFailOpTest.release());
887 }
888 failOpTest->addChild(passOpTest.release());
889 }
890 stencilStateTests->addChild(failOpTest.release());
891 }
892
893 formatTest->addChild(stencilStateTests.release());
894 formatTests->addChild(formatTest.release());
895 }
896 stencilTests->addChild(formatTests.release());
897
898 return stencilTests.release();
899 }
900
901 } // pipeline
902 } // vkt
903