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