• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::__anon7a4e82f00111::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 BufferType	bufferType,
361 														 const DiscardType	discardType,
362 														 const MutationMode	mutationMode,
363 														 const VkFormat		bufferFormat);
364 
365 	virtual void		checkSupport					 (Context&				context) const;
366 	void				initPrograms					 (SourceCollections&	programCollection) const;
367 	TestInstance*		createInstance					 (Context&				context) const;
368 private:
369 	BufferType		m_bufferType;
370 	DiscardType		m_discardType;
371 	MutationMode	m_mutationMode;
372 	VkFormat		m_bufferFormat;
373 };
374 
DepthStencilWriteConditionsTest(tcu::TestContext & testCtx,const std::string & name,const BufferType bufferType,const DiscardType discardType,const MutationMode mutationMode,const VkFormat bufferFormat)375 DepthStencilWriteConditionsTest::DepthStencilWriteConditionsTest (tcu::TestContext&		testCtx,
376 																  const std::string&	name,
377 																  const BufferType		bufferType,
378 																  const DiscardType		discardType,
379 																  const MutationMode	mutationMode,
380 																  const VkFormat		bufferFormat)
381 	: TestCase	(testCtx, name)
382 	, m_bufferType(bufferType)
383 	, m_discardType(discardType)
384 	, m_mutationMode(mutationMode)
385 	, m_bufferFormat(bufferFormat)
386 {
387 }
388 
initPrograms(SourceCollections & programCollection) const389 void DepthStencilWriteConditionsTest::initPrograms (SourceCollections& programCollection) const
390 {
391 	/*
392 	 * The fragment shader has been compiled from the following GLSL shader:
393 	 *
394 	 * layout(location = 0) out vec4 outColor;
395 	 * void main() {
396 	 *     if (int(gl_FragCoord.x) % 2 == 0)
397 	 *         discard;
398 	 *     outColor = vec4(1., 1., 1., 1.);
399 	 *     gl_FragDepth = 0.2;
400 	 * }
401 	 *
402 	 * If a stencil buffer is enabled, the shader writes to gl_FragStencilRefARB
403 	 * instead of gl_FragDepth.
404 	 *
405 	 * If the mutation mode is INITIALIZE or INITIALIZE_WRITE, the object that
406 	 * is written to the buffer is allocated with an initial value.
407 	 *
408 	 * Demote and terminate commands are used instead of discard if a corresponding
409 	 * DiscardType has been given.
410 	 */
411 
412 	std::ostringstream	vertexSrc;
413 	vertexSrc
414 		<< glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
415 		<< "layout(location = 0) in highp vec4 a_position;\n"
416 		<< "void main (void) {\n"
417 		<< "    gl_Position = a_position;\n"
418 		<< "}\n";
419 
420 	std::string			discardCommand	= "OpKill\n";
421 	std::string			extensions		= "";
422 	std::string			capabilities	= "";
423 
424 	if (m_discardType == DiscardType::TERMINATE)
425 	{
426 		extensions = "OpExtension \"SPV_KHR_terminate_invocation\"\n";
427 		discardCommand = "OpTerminateInvocation\n";
428 	}
429 	else if (m_discardType == DiscardType::DEMOTE)
430 	{
431 		capabilities = "OpCapability DemoteToHelperInvocationEXT\n";
432 		extensions = "OpExtension \"SPV_EXT_demote_to_helper_invocation\"\n";
433 		discardCommand = "OpDemoteToHelperInvocationEXT\n";
434 	}
435 
436 	if (m_bufferType == BufferType::STENCIL)
437 	{
438 		capabilities += "OpCapability StencilExportEXT\n";
439 		extensions += "OpExtension \"SPV_EXT_shader_stencil_export\"\n";
440 	}
441 
442 	std::ostringstream	fragmentSrc;
443 	fragmentSrc
444 		<< "OpCapability Shader\n"
445 		<< capabilities
446 		<< extensions
447 		<< "%1 = OpExtInstImport \"GLSL.std.450\"\n"
448 		<< "OpMemoryModel Logical GLSL450\n";
449 
450 	fragmentSrc
451 		<< "OpEntryPoint Fragment %4 \"main\" %9 %26 %30\n"
452 		<< "OpExecutionMode %4 OriginUpperLeft\n";
453 
454 	if (m_bufferType == BufferType::DEPTH)
455 		fragmentSrc << "OpExecutionMode %4 DepthReplacing\n";
456 
457 	fragmentSrc
458 		<< "OpDecorate %9 BuiltIn FragCoord\n"
459 		<< "OpDecorate %26 Location 0\n";
460 
461 	if (m_bufferType == BufferType::DEPTH)
462 		fragmentSrc << "OpDecorate %30 BuiltIn FragDepth\n";
463 	else
464 		fragmentSrc << "OpDecorate %30 BuiltIn FragStencilRefEXT\n";
465 
466 	fragmentSrc
467 		<< "%2 = OpTypeVoid\n"
468 		<< "%3 = OpTypeFunction %2\n"
469 		<< "%6 = OpTypeFloat 32\n"
470 		<< "%7 = OpTypeVector %6 4\n"
471 		<< "%8 = OpTypePointer Input %7\n"
472 		<< "%9 = OpVariable %8 Input\n"
473 		<< "%10 = OpTypeInt 32 0\n"
474 		<< "%11 = OpConstant %10 0\n"
475 		<< "%12 = OpTypePointer Input %6\n"
476 		<< "%15 = OpTypeInt 32 1\n"
477 		<< "%17 = OpConstant %15 2\n"
478 		<< "%19 = OpConstant %15 0\n"
479 		<< "%20 = OpTypeBool\n"
480 		<< "%25 = OpTypePointer Output %7\n"
481 		<< "%26 = OpVariable %25 Output\n"
482 		<< "%27 = OpConstant %6 1\n"
483 		<< "%28 = OpConstantComposite %7 %27 %27 %27 %27\n";
484 	if (m_bufferType == BufferType::DEPTH)
485 	{
486 		fragmentSrc << "%29 = OpTypePointer Output %6\n";
487 
488 		if (m_mutationMode == MutationMode::INITIALIZE || m_mutationMode == MutationMode::INITIALIZE_WRITE)
489 		{
490 			// The value the depth buffer is initialized with.
491 			fragmentSrc << "%const_f32_02 = OpConstant %6 0.2\n";
492 			fragmentSrc << "%30 = OpVariable %29 Output %const_f32_02\n";
493 		}
494 		else
495 			fragmentSrc << "%30 = OpVariable %29 Output\n";
496 
497 		// The value written to the depth buffer.
498 		fragmentSrc << "%31 = OpConstant %6 0.2\n";
499 	}
500 	else
501 	{
502 		fragmentSrc << "%29 = OpTypePointer Output %15\n";
503 
504 		if (m_mutationMode == MutationMode::INITIALIZE || m_mutationMode == MutationMode::INITIALIZE_WRITE)
505 		{
506 			// The value the stencil buffer is initialized with.
507 			fragmentSrc << "%const_int_1 = OpConstant %15 1\n";
508 			fragmentSrc << "%30 = OpVariable %29 Output %const_int_1\n";
509 		}
510 		else
511 			fragmentSrc << "%30 = OpVariable %29 Output\n";
512 
513 		// The value written to the stencil buffer.
514 		fragmentSrc << "%31 = OpConstant %15 1\n";
515 	}
516 
517 	fragmentSrc
518 		<< "%4 = OpFunction %2 None %3\n"
519 		<< "%5 = OpLabel\n"
520 		<< "%13 = OpAccessChain %12 %9 %11\n"
521 		<< "%14 = OpLoad %6 %13\n"
522 		<< "%16 = OpConvertFToS %15 %14\n"
523 		<< "%18 = OpSMod %15 %16 %17\n"
524 		<< "%21 = OpIEqual %20 %18 %19\n"
525 		<< "OpSelectionMerge %23 None\n"
526 		<< "OpBranchConditional %21 %22 %23\n"
527 		<< "%22 = OpLabel\n"
528 		<< discardCommand;
529 	if (m_discardType == DiscardType::DEMOTE)
530 		fragmentSrc << "OpBranch %23\n";
531 	fragmentSrc
532 		<< "%23 = OpLabel\n"
533 		<< "OpStore %26 %28\n";
534 
535 	if (m_mutationMode == MutationMode::WRITE || m_mutationMode == MutationMode::INITIALIZE_WRITE)
536 		fragmentSrc << "OpStore %30 %31\n";
537 
538 	fragmentSrc
539 		<< "OpReturn\n"
540 		<< "OpFunctionEnd\n";
541 
542 	programCollection.spirvAsmSources.add("frag") << fragmentSrc.str().c_str();
543 	programCollection.glslSources.add("vert") << glu::VertexSource(vertexSrc.str());
544 }
545 
checkSupport(Context & context) const546 void DepthStencilWriteConditionsTest::checkSupport (Context& context) const
547 {
548 	if (m_discardType == DiscardType::DEMOTE)
549 		context.requireDeviceFunctionality("VK_EXT_shader_demote_to_helper_invocation");
550 	if (m_discardType == DiscardType::TERMINATE)
551 		context.requireDeviceFunctionality("VK_KHR_shader_terminate_invocation");
552 	if (m_bufferType == BufferType::STENCIL)
553 		context.requireDeviceFunctionality("VK_EXT_shader_stencil_export");
554 
555 	std::string				formatName				= "VK_FORMAT_D32_SFLOAT_S8_UINT";
556 	if (m_bufferFormat == VK_FORMAT_D24_UNORM_S8_UINT)
557 		formatName = "VK_FORMAT_D24_UNORM_S8_UINT";
558 	if (m_bufferFormat == VK_FORMAT_X8_D24_UNORM_PACK32)
559 		formatName = "VK_FORMAT_X8_D24_UNORM_PACK32";
560 	if (m_bufferFormat == VK_FORMAT_D32_SFLOAT)
561 		formatName = "VK_FORMAT_D32_SFLOAT";
562 
563 	const auto&				vki						= context.getInstanceInterface();
564 	const auto				physicalDevice			= context.getPhysicalDevice();
565 	const VkImageUsageFlags	depthStencilUsage		= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
566 
567 	VkImageFormatProperties	imageFormatProperties;
568 	if (vki.getPhysicalDeviceImageFormatProperties(physicalDevice, m_bufferFormat, VK_IMAGE_TYPE_2D,
569 												   VK_IMAGE_TILING_OPTIMAL, depthStencilUsage, (VkImageCreateFlags)0,
570 												   &imageFormatProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
571 		TCU_THROW(NotSupportedError, formatName + " not supported.");
572 }
573 
createInstance(Context & context) const574 TestInstance* DepthStencilWriteConditionsTest::createInstance (Context& context) const
575 {
576 	return new DepthStencilWriteConditionsInstance(context, m_bufferType, m_bufferFormat);
577 }
578 
579 } // anonymous ns
580 
createDepthStencilWriteConditionsTests(tcu::TestContext & testCtx)581 tcu::TestCaseGroup* createDepthStencilWriteConditionsTests (tcu::TestContext& testCtx)
582 {
583 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "depth_stencil_write_conditions"));
584 
585 	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};
586 	const VkFormat	stencilFormats[2]	= {VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT};
587 
588 	for (int i = 0; i < 4; i++)
589 	{
590 		VkFormat		format	= depthFormats[i];
591 		std::string		postfix	= "_d32sf_s8ui";
592 		if (format == VK_FORMAT_D24_UNORM_S8_UINT)
593 			postfix = "_d24unorm_s8ui";
594 		if (format == VK_FORMAT_X8_D24_UNORM_PACK32)
595 			postfix = "_d24_unorm";
596 		if (format == VK_FORMAT_D32_SFLOAT)
597 			postfix = "_d32sf";
598 
599 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_kill_write" + postfix, BufferType::DEPTH, DiscardType::KILL, MutationMode::WRITE, format));
600 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_kill_initialize" + postfix, BufferType::DEPTH, DiscardType::KILL, MutationMode::INITIALIZE, format));
601 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_kill_write_initialize" + postfix, BufferType::DEPTH, DiscardType::KILL, MutationMode::INITIALIZE_WRITE, format));
602 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_terminate_write" + postfix, BufferType::DEPTH, DiscardType::TERMINATE, MutationMode::WRITE, format));
603 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_terminate_initialize" + postfix, BufferType::DEPTH, DiscardType::TERMINATE, MutationMode::INITIALIZE, format));
604 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_terminate_write_initialize" + postfix, BufferType::DEPTH, DiscardType::TERMINATE, MutationMode::INITIALIZE_WRITE, format));
605 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_demote_write" + postfix, BufferType::DEPTH, DiscardType::DEMOTE, MutationMode::WRITE, format));
606 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_demote_initialize" + postfix, BufferType::DEPTH, DiscardType::DEMOTE, MutationMode::INITIALIZE, format));
607 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "depth_demote_write_initialize" + postfix, BufferType::DEPTH, DiscardType::DEMOTE, MutationMode::INITIALIZE_WRITE, format));
608 	}
609 
610 	for (int i = 0; i < 2; i++)
611 	{
612 		VkFormat		format	= stencilFormats[i];
613 		std::string		postfix	= "_d32sf_s8ui";
614 		if (format == VK_FORMAT_D24_UNORM_S8_UINT)
615 			postfix = "_d24unorm_s8ui";
616 
617 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_kill_write" + postfix, BufferType::STENCIL, DiscardType::KILL, MutationMode::WRITE, format));
618 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_kill_initialize" + postfix, BufferType::STENCIL, DiscardType::KILL, MutationMode::INITIALIZE, format));
619 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_kill_write_initialize" + postfix, BufferType::STENCIL, DiscardType::KILL, MutationMode::INITIALIZE_WRITE, format));
620 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_terminate_write" + postfix, BufferType::STENCIL, DiscardType::TERMINATE, MutationMode::WRITE, format));
621 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_terminate_initialize" + postfix, BufferType::STENCIL, DiscardType::TERMINATE, MutationMode::INITIALIZE, format));
622 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_terminate_write_initialize" + postfix, BufferType::STENCIL, DiscardType::TERMINATE, MutationMode::INITIALIZE_WRITE, format));
623 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_demote_write" + postfix, BufferType::STENCIL, DiscardType::DEMOTE, MutationMode::WRITE, format));
624 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_demote_initialize" + postfix, BufferType::STENCIL, DiscardType::DEMOTE, MutationMode::INITIALIZE, format));
625 		testGroup->addChild(new DepthStencilWriteConditionsTest(testCtx, "stencil_demote_write_initialize" + postfix, BufferType::STENCIL, DiscardType::DEMOTE, MutationMode::INITIALIZE_WRITE, format));
626 	}
627 
628 	return testGroup.release();
629 }
630 
631 } // renderpass
632 } // vkt
633