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