1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  * Copyright (c) 2015 The Khronos Group Inc.
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 Early fragment tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktFragmentOperationsEarlyFragmentTests.hpp"
26 #include "vktFragmentOperationsMakeUtil.hpp"
27 #include "vktTestCaseUtil.hpp"
28 
29 #include "vkDefs.hpp"
30 #include "vkRef.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkMemUtil.hpp"
35 #include "vkBuilderUtil.hpp"
36 #include "vkStrUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkImageUtil.hpp"
40 #include "vkBarrierUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkObjUtil.hpp"
43 
44 #include "tcuTestLog.hpp"
45 
46 #include "deUniquePtr.hpp"
47 #include "deStringUtil.hpp"
48 
49 #include <string>
50 
51 namespace vkt
52 {
53 namespace FragmentOperations
54 {
55 namespace
56 {
57 using namespace vk;
58 using de::UniquePtr;
59 
60 //! Basic 2D image.
makeImageCreateInfo(const tcu::IVec2 & size,const VkFormat format,const VkImageUsageFlags usage)61 inline VkImageCreateInfo makeImageCreateInfo (const tcu::IVec2& size, const VkFormat format, const VkImageUsageFlags usage)
62 {
63 	const VkImageCreateInfo imageParams =
64 	{
65 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,					// VkStructureType			sType;
66 		DE_NULL,												// const void*				pNext;
67 		(VkImageCreateFlags)0,									// VkImageCreateFlags		flags;
68 		VK_IMAGE_TYPE_2D,										// VkImageType				imageType;
69 		format,													// VkFormat					format;
70 		makeExtent3D(size.x(), size.y(), 1),					// VkExtent3D				extent;
71 		1u,														// deUint32					mipLevels;
72 		1u,														// deUint32					arrayLayers;
73 		VK_SAMPLE_COUNT_1_BIT,									// VkSampleCountFlagBits	samples;
74 		VK_IMAGE_TILING_OPTIMAL,								// VkImageTiling			tiling;
75 		usage,													// VkImageUsageFlags		usage;
76 		VK_SHARING_MODE_EXCLUSIVE,								// VkSharingMode			sharingMode;
77 		0u,														// deUint32					queueFamilyIndexCount;
78 		DE_NULL,												// const deUint32*			pQueueFamilyIndices;
79 		VK_IMAGE_LAYOUT_UNDEFINED,								// VkImageLayout			initialLayout;
80 	};
81 	return imageParams;
82 }
83 
makeRenderPass(const DeviceInterface & vk,const VkDevice device,const VkFormat colorFormat,const bool useDepthStencilAttachment,const VkFormat depthStencilFormat)84 Move<VkRenderPass> makeRenderPass (const DeviceInterface&	vk,
85 								   const VkDevice			device,
86 								   const VkFormat			colorFormat,
87 								   const bool				useDepthStencilAttachment,
88 								   const VkFormat			depthStencilFormat)
89 {
90 	return makeRenderPass(vk, device, colorFormat, useDepthStencilAttachment ? depthStencilFormat : VK_FORMAT_UNDEFINED);
91 }
92 
makeFramebuffer(const DeviceInterface & vk,const VkDevice device,const VkRenderPass renderPass,const deUint32 attachmentCount,const VkImageView * pAttachments,const tcu::IVec2 size)93 Move<VkFramebuffer> makeFramebuffer (const DeviceInterface&		vk,
94 									 const VkDevice				device,
95 									 const VkRenderPass			renderPass,
96 									 const deUint32				attachmentCount,
97 									 const VkImageView*			pAttachments,
98 									 const tcu::IVec2			size)
99 {
100 	const VkFramebufferCreateInfo framebufferInfo = {
101 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		// VkStructureType                             sType;
102 		DE_NULL,										// const void*                                 pNext;
103 		(VkFramebufferCreateFlags)0,					// VkFramebufferCreateFlags                    flags;
104 		renderPass,										// VkRenderPass                                renderPass;
105 		attachmentCount,								// uint32_t                                    attachmentCount;
106 		pAttachments,									// const VkImageView*                          pAttachments;
107 		static_cast<deUint32>(size.x()),				// uint32_t                                    width;
108 		static_cast<deUint32>(size.y()),				// uint32_t                                    height;
109 		1u,												// uint32_t                                    layers;
110 	};
111 
112 	return createFramebuffer(vk, device, &framebufferInfo);
113 }
114 
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const tcu::IVec2 & renderSize,const bool enableDepthTest,const bool enableStencilTest)115 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&	vk,
116 									   const VkDevice			device,
117 									   const VkPipelineLayout	pipelineLayout,
118 									   const VkRenderPass		renderPass,
119 									   const VkShaderModule		vertexModule,
120 									   const VkShaderModule		fragmentModule,
121 									   const tcu::IVec2&		renderSize,
122 									   const bool				enableDepthTest,
123 									   const bool				enableStencilTest)
124 {
125 	const std::vector<VkViewport>			viewports					(1, makeViewport(renderSize));
126 	const std::vector<VkRect2D>				scissors					(1, makeRect2D(renderSize));
127 
128 	const VkStencilOpState					stencilOpState				= makeStencilOpState(
129 		VK_STENCIL_OP_KEEP,		// stencil fail
130 		VK_STENCIL_OP_KEEP,		// depth & stencil pass
131 		VK_STENCIL_OP_KEEP,		// depth only fail
132 		VK_COMPARE_OP_EQUAL,	// compare op
133 		1u,						// compare mask
134 		1u,						// write mask
135 		1u);					// reference
136 
137 	VkPipelineDepthStencilStateCreateInfo	depthStencilStateCreateInfo	=
138 	{
139 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType                          sType
140 		DE_NULL,													// const void*                              pNext
141 		0u,															// VkPipelineDepthStencilStateCreateFlags   flags
142 		enableDepthTest ? VK_TRUE : VK_FALSE,						// VkBool32                                 depthTestEnable
143 		enableDepthTest ? VK_TRUE : VK_FALSE,						// VkBool32                                 depthWriteEnable
144 		VK_COMPARE_OP_LESS,											// VkCompareOp                              depthCompareOp
145 		VK_FALSE,													// VkBool32                                 depthBoundsTestEnable
146 		enableStencilTest ? VK_TRUE : VK_FALSE,						// VkBool32                                 stencilTestEnable
147 		stencilOpState,												// VkStencilOpState                         front
148 		stencilOpState,												// VkStencilOpState                         back
149 		0.0f,														// float                                    minDepthBounds
150 		1.0f														// float                                    maxDepthBounds
151 	};
152 
153 	return vk::makeGraphicsPipeline(vk,										// const DeviceInterface&                        vk
154 									device,									// const VkDevice                                device
155 									pipelineLayout,							// const VkPipelineLayout                        pipelineLayout
156 									vertexModule,							// const VkShaderModule                          vertexShaderModule
157 									DE_NULL,								// const VkShaderModule                          tessellationControlModule
158 									DE_NULL,								// const VkShaderModule                          tessellationEvalModule
159 									DE_NULL,								// const VkShaderModule                          geometryShaderModule
160 									fragmentModule,							// const VkShaderModule                          fragmentShaderModule
161 									renderPass,								// const VkRenderPass                            renderPass
162 									viewports,								// const std::vector<VkViewport>&                viewports
163 									scissors,								// const std::vector<VkRect2D>&                  scissors
164 									VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	// const VkPrimitiveTopology                     topology
165 									0u,										// const deUint32                                subpass
166 									0u,										// const deUint32                                patchControlPoints
167 									DE_NULL,								// const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
168 									DE_NULL,								// const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
169 									DE_NULL,								// const VkPipelineMultisampleStateCreateInfo*   multisampleStateCreateInfo
170 									&depthStencilStateCreateInfo);			// const VkPipelineDepthStencilStateCreateInfo*  depthStencilStateCreateInfo
171 }
172 
commandClearStencilAttachment(const DeviceInterface & vk,const VkCommandBuffer commandBuffer,const VkOffset2D & offset,const VkExtent2D & extent,const deUint32 clearValue)173 void commandClearStencilAttachment (const DeviceInterface&	vk,
174 									const VkCommandBuffer	commandBuffer,
175 									const VkOffset2D&		offset,
176 									const VkExtent2D&		extent,
177 									const deUint32			clearValue)
178 {
179 	const VkClearAttachment stencilAttachment =
180 	{
181 		VK_IMAGE_ASPECT_STENCIL_BIT,					// VkImageAspectFlags    aspectMask;
182 		0u,												// uint32_t              colorAttachment;
183 		makeClearValueDepthStencil(0.0f, clearValue),	// VkClearValue          clearValue;
184 	};
185 
186 	const VkClearRect rect =
187 	{
188 		{ offset, extent },		// VkRect2D    rect;
189 		0u,						// uint32_t    baseArrayLayer;
190 		1u,						// uint32_t    layerCount;
191 	};
192 
193 	vk.cmdClearAttachments(commandBuffer, 1u, &stencilAttachment, 1u, &rect);
194 }
195 
getImageAspectFlags(const VkFormat format)196 VkImageAspectFlags getImageAspectFlags (const VkFormat format)
197 {
198 	const tcu::TextureFormat tcuFormat = mapVkFormat(format);
199 
200 	if      (tcuFormat.order == tcu::TextureFormat::DS)		return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
201 	else if (tcuFormat.order == tcu::TextureFormat::D)		return VK_IMAGE_ASPECT_DEPTH_BIT;
202 	else if (tcuFormat.order == tcu::TextureFormat::S)		return VK_IMAGE_ASPECT_STENCIL_BIT;
203 
204 	DE_ASSERT(false);
205 	return 0u;
206 }
207 
isSupportedDepthStencilFormat(const InstanceInterface & instanceInterface,const VkPhysicalDevice device,const VkFormat format)208 bool isSupportedDepthStencilFormat (const InstanceInterface& instanceInterface, const VkPhysicalDevice device, const VkFormat format)
209 {
210 	VkFormatProperties formatProps;
211 	instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps);
212 	return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
213 }
214 
pickSupportedDepthStencilFormat(const InstanceInterface & instanceInterface,const VkPhysicalDevice device,const deUint32 numFormats,const VkFormat * pFormats)215 VkFormat pickSupportedDepthStencilFormat (const InstanceInterface&	instanceInterface,
216 										  const VkPhysicalDevice	device,
217 										  const deUint32			numFormats,
218 										  const VkFormat*			pFormats)
219 {
220 	for (deUint32 i = 0; i < numFormats; ++i)
221 		if (isSupportedDepthStencilFormat(instanceInterface, device, pFormats[i]))
222 			return pFormats[i];
223 	return VK_FORMAT_UNDEFINED;
224 }
225 
226 enum Flags
227 {
228 	FLAG_TEST_DEPTH							= 1u << 0,
229 	FLAG_TEST_STENCIL						= 1u << 1,
230 	FLAG_DONT_USE_TEST_ATTACHMENT			= 1u << 2,
231 	FLAG_DONT_USE_EARLY_FRAGMENT_TESTS		= 1u << 3,
232 };
233 
234 class EarlyFragmentTest : public TestCase
235 {
236 public:
237 						EarlyFragmentTest	(tcu::TestContext&		testCtx,
238 											 const std::string		name,
239 											 const deUint32			flags);
240 
241 	void				initPrograms		(SourceCollections&		programCollection) const;
242 	TestInstance*		createInstance		(Context&				context) const;
243 
244 private:
245 	const deUint32		m_flags;
246 };
247 
EarlyFragmentTest(tcu::TestContext & testCtx,const std::string name,const deUint32 flags)248 EarlyFragmentTest::EarlyFragmentTest (tcu::TestContext& testCtx, const std::string name, const deUint32 flags)
249 	: TestCase	(testCtx, name, "")
250 	, m_flags	(flags)
251 {
252 }
253 
initPrograms(SourceCollections & programCollection) const254 void EarlyFragmentTest::initPrograms (SourceCollections& programCollection) const
255 {
256 	// Vertex
257 	{
258 		std::ostringstream src;
259 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
260 			<< "\n"
261 			<< "layout(location = 0) in highp vec4 position;\n"
262 			<< "\n"
263 			<< "out gl_PerVertex {\n"
264 			<< "   vec4 gl_Position;\n"
265 			<< "};\n"
266 			<< "\n"
267 			<< "void main (void)\n"
268 			<< "{\n"
269 			<< "    gl_Position = position;\n"
270 			<< "}\n";
271 
272 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
273 	}
274 
275 	// Fragment
276 	{
277 		const bool useEarlyTests = (m_flags & FLAG_DONT_USE_EARLY_FRAGMENT_TESTS) == 0;
278 		std::ostringstream src;
279 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
280 			<< "\n"
281 			<< (useEarlyTests ? "layout(early_fragment_tests) in;\n" : "")
282 			<< "layout(location = 0) out highp vec4 fragColor;\n"
283 			<< "\n"
284 			<< "layout(binding = 0) coherent buffer Output {\n"
285 			<< "    uint result;\n"
286 			<< "} sb_out;\n"
287 			<< "\n"
288 			<< "void main (void)\n"
289 			<< "{\n"
290 			<< "    atomicAdd(sb_out.result, 1u);\n"
291 			<< "	fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
292 			<< "}\n";
293 
294 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
295 	}
296 }
297 
298 class EarlyFragmentTestInstance : public TestInstance
299 {
300 public:
301 							EarlyFragmentTestInstance (Context& context, const deUint32 flags);
302 
303 	tcu::TestStatus			iterate					  (void);
304 
305 private:
306 	enum TestMode
307 	{
308 		MODE_INVALID,
309 		MODE_DEPTH,
310 		MODE_STENCIL,
311 	};
312 
313 	const TestMode			m_testMode;
314 	const bool				m_useTestAttachment;
315 	const bool				m_useEarlyTests;
316 };
317 
EarlyFragmentTestInstance(Context & context,const deUint32 flags)318 EarlyFragmentTestInstance::EarlyFragmentTestInstance (Context& context, const deUint32 flags)
319 	: TestInstance			(context)
320 	, m_testMode			(flags & FLAG_TEST_DEPTH   ? MODE_DEPTH :
321 							 flags & FLAG_TEST_STENCIL ? MODE_STENCIL : MODE_INVALID)
322 	, m_useTestAttachment	((flags & FLAG_DONT_USE_TEST_ATTACHMENT) == 0)
323 	, m_useEarlyTests		((flags & FLAG_DONT_USE_EARLY_FRAGMENT_TESTS) == 0)
324 {
325 	DE_ASSERT(m_testMode != MODE_INVALID);
326 }
327 
iterate(void)328 tcu::TestStatus EarlyFragmentTestInstance::iterate (void)
329 {
330 	const DeviceInterface&		vk					= m_context.getDeviceInterface();
331 	const InstanceInterface&	vki					= m_context.getInstanceInterface();
332 	const VkDevice				device				= m_context.getDevice();
333 	const VkPhysicalDevice		physDevice			= m_context.getPhysicalDevice();
334 	const VkQueue				queue				= m_context.getUniversalQueue();
335 	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
336 	Allocator&					allocator			= m_context.getDefaultAllocator();
337 
338 	// Color attachment
339 
340 	const tcu::IVec2				renderSize			= tcu::IVec2(32, 32);
341 	const VkFormat					colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
342 	const VkImageSubresourceRange	colorSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
343 	const Unique<VkImage>			colorImage			(makeImage(vk, device, makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
344 	const UniquePtr<Allocation>		colorImageAlloc		(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
345 	const Unique<VkImageView>		colorImageView		(makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
346 
347 	// Test attachment (depth or stencil)
348 	static const VkFormat stencilFormats[] =
349 	{
350 		// One of the following formats must be supported, as per spec requirement.
351 		VK_FORMAT_S8_UINT,
352 		VK_FORMAT_D16_UNORM_S8_UINT,
353 		VK_FORMAT_D24_UNORM_S8_UINT,
354 		VK_FORMAT_D32_SFLOAT_S8_UINT,
355 	};
356 
357 	const VkFormat testFormat = (m_testMode == MODE_STENCIL ? pickSupportedDepthStencilFormat(vki, physDevice, DE_LENGTH_OF_ARRAY(stencilFormats), stencilFormats)
358 															: VK_FORMAT_D16_UNORM);		// spec requires this format to be supported
359 	if (testFormat == VK_FORMAT_UNDEFINED)
360 		return tcu::TestStatus::fail("Required depth/stencil format not supported");
361 
362 	if (m_useTestAttachment)
363 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Using depth/stencil format " << getFormatName(testFormat) << tcu::TestLog::EndMessage;
364 
365 	const VkImageSubresourceRange	testSubresourceRange	= makeImageSubresourceRange(getImageAspectFlags(testFormat), 0u, 1u, 0u, 1u);
366 	const Unique<VkImage>			testImage				(makeImage(vk, device, makeImageCreateInfo(renderSize, testFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)));
367 	const UniquePtr<Allocation>		testImageAlloc			(bindImage(vk, device, allocator, *testImage, MemoryRequirement::Any));
368 	const Unique<VkImageView>		testImageView			(makeImageView(vk, device, *testImage, VK_IMAGE_VIEW_TYPE_2D, testFormat, testSubresourceRange));
369 	const VkImageView				attachmentImages[]		= { *colorImageView, *testImageView };
370 	const deUint32					numUsedAttachmentImages = (m_useTestAttachment ? 2u : 1u);
371 
372 	// Vertex buffer
373 
374 	const deUint32					numVertices				= 6;
375 	const VkDeviceSize				vertexBufferSizeBytes	= sizeof(tcu::Vec4) * numVertices;
376 	const Unique<VkBuffer>			vertexBuffer			(makeBuffer(vk, device, makeBufferCreateInfo(vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)));
377 	const UniquePtr<Allocation>		vertexBufferAlloc		(bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
378 
379 	{
380 		tcu::Vec4* const pVertices = reinterpret_cast<tcu::Vec4*>(vertexBufferAlloc->getHostPtr());
381 
382 		pVertices[0] = tcu::Vec4( 1.0f, -1.0f,  0.5f,  1.0f);
383 		pVertices[1] = tcu::Vec4(-1.0f, -1.0f,  0.0f,  1.0f);
384 		pVertices[2] = tcu::Vec4(-1.0f,  1.0f,  0.5f,  1.0f);
385 
386 		pVertices[3] = tcu::Vec4(-1.0f,  1.0f,  0.5f,  1.0f);
387 		pVertices[4] = tcu::Vec4( 1.0f,  1.0f,  1.0f,  1.0f);
388 		pVertices[5] = tcu::Vec4( 1.0f, -1.0f,  0.5f,  1.0f);
389 
390 		flushAlloc(vk, device, *vertexBufferAlloc);
391 		// No barrier needed, flushed memory is automatically visible
392 	}
393 
394 	// Result buffer
395 
396 	const VkDeviceSize				resultBufferSizeBytes	= sizeof(deUint32);
397 	const Unique<VkBuffer>			resultBuffer			(makeBuffer(vk, device, makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)));
398 	const UniquePtr<Allocation>		resultBufferAlloc		(bindBuffer(vk, device, allocator, *resultBuffer, MemoryRequirement::HostVisible));
399 
400 	{
401 		deUint32* const pData = static_cast<deUint32*>(resultBufferAlloc->getHostPtr());
402 
403 		*pData = 0;
404 		flushAlloc(vk, device, *resultBufferAlloc);
405 	}
406 
407 	// Render result buffer (to retrieve color attachment contents)
408 
409 	const VkDeviceSize				colorBufferSizeBytes	= tcu::getPixelSize(mapVkFormat(colorFormat)) * renderSize.x() * renderSize.y();
410 	const Unique<VkBuffer>			colorBuffer				(makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
411 	const UniquePtr<Allocation>		colorBufferAlloc		(bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
412 
413 	// Descriptors
414 
415 	const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
416 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
417 		.build(vk, device));
418 
419 	const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
420 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
421 		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
422 
423 	const Unique<VkDescriptorSet> descriptorSet				 (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
424 	const VkDescriptorBufferInfo  resultBufferDescriptorInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes);
425 
426 	DescriptorSetUpdateBuilder()
427 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferDescriptorInfo)
428 		.update(vk, device);
429 
430 	// Pipeline
431 
432 	const Unique<VkShaderModule>	vertexModule  (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
433 	const Unique<VkShaderModule>	fragmentModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
434 	const Unique<VkRenderPass>		renderPass	  (makeRenderPass(vk, device, colorFormat, m_useTestAttachment, testFormat));
435 	const Unique<VkFramebuffer>		framebuffer	  (makeFramebuffer(vk, device, *renderPass, numUsedAttachmentImages, attachmentImages, renderSize));
436 	const Unique<VkPipelineLayout>	pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
437 	const Unique<VkPipeline>		pipeline	  (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, renderSize,
438 												  (m_testMode == MODE_DEPTH), (m_testMode == MODE_STENCIL)));
439 	const Unique<VkCommandPool>		cmdPool		  (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
440 	const Unique<VkCommandBuffer>	cmdBuffer	  (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
441 
442 	// Draw commands
443 
444 	{
445 		const VkRect2D renderArea = {
446 			makeOffset2D(0, 0),
447 			makeExtent2D(renderSize.x(), renderSize.y()),
448 		};
449 		const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
450 		const VkDeviceSize vertexBufferOffset = 0ull;
451 
452 		beginCommandBuffer(vk, *cmdBuffer);
453 
454 		{
455 			const VkImageMemoryBarrier barriers[] = {
456 				makeImageMemoryBarrier(
457 					0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
458 					VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
459 					*colorImage, colorSubresourceRange),
460 				makeImageMemoryBarrier(
461 					0u, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
462 					VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
463 					*testImage, testSubresourceRange),
464 			};
465 
466 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
467 				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
468 		}
469 
470 		// Will clear the attachments with specified depth and stencil values.
471 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor, 0.5f, 0u);
472 
473 		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
474 		vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
475 		vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
476 
477 		// Mask half of the attachment image with value that will pass the stencil test.
478 		if (m_useTestAttachment && m_testMode == MODE_STENCIL)
479 			commandClearStencilAttachment(vk, *cmdBuffer, makeOffset2D(0, 0), makeExtent2D(renderSize.x()/2, renderSize.y()), 1u);
480 
481 		vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
482 		endRenderPass(vk, *cmdBuffer);
483 
484 		copyImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, renderSize, VK_ACCESS_SHADER_WRITE_BIT);
485 
486 		endCommandBuffer(vk, *cmdBuffer);
487 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
488 	}
489 
490 	// Log result image
491 	{
492 		invalidateAlloc(vk, device, *colorBufferAlloc);
493 
494 		const tcu::ConstPixelBufferAccess imagePixelAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc->getHostPtr());
495 
496 		tcu::TestLog& log = m_context.getTestContext().getLog();
497 		log << tcu::TestLog::Image("color0", "Rendered image", imagePixelAccess);
498 	}
499 
500 	// Verify results
501 	{
502 		invalidateAlloc(vk, device, *resultBufferAlloc);
503 
504 		const int  actualCounter	   = *static_cast<deInt32*>(resultBufferAlloc->getHostPtr());
505 		const bool expectPartialResult = (m_useEarlyTests && m_useTestAttachment);
506 		const int  expectedCounter	   = expectPartialResult ? renderSize.x() * renderSize.y() / 2 : renderSize.x() * renderSize.y();
507 		const int  tolerance		   = expectPartialResult ? de::max(renderSize.x(), renderSize.y()) * 3	: 0;
508 		const int  expectedMin         = de::max(0, expectedCounter - tolerance);
509 		const int  expectedMax		   = expectedCounter + tolerance;
510 
511 		tcu::TestLog& log = m_context.getTestContext().getLog();
512 		log << tcu::TestLog::Message << "Expected value"
513 			<< (expectPartialResult ? " in range: [" + de::toString(expectedMin) + ", " + de::toString(expectedMax) + "]" : ": " + de::toString(expectedCounter))
514 			<< tcu::TestLog::EndMessage;
515 		log << tcu::TestLog::Message << "Result value: " << de::toString(actualCounter) << tcu::TestLog::EndMessage;
516 
517 		if (expectedMin <= actualCounter && actualCounter <= expectedMax)
518 			return tcu::TestStatus::pass("Success");
519 		else
520 			return tcu::TestStatus::fail("Value out of range");
521 	}
522 }
523 
createInstance(Context & context) const524 TestInstance* EarlyFragmentTest::createInstance (Context& context) const
525 {
526 	// Check required features
527 	{
528 		VkPhysicalDeviceFeatures features;
529 		context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), &features);
530 
531 		// SSBO writes in fragment shader
532 		if (!features.fragmentStoresAndAtomics)
533 			throw tcu::NotSupportedError("Missing required feature: fragmentStoresAndAtomics");
534 	}
535 
536 	return new EarlyFragmentTestInstance(context, m_flags);
537 }
538 
539 } // anonymous ns
540 
createEarlyFragmentTests(tcu::TestContext & testCtx)541 tcu::TestCaseGroup* createEarlyFragmentTests (tcu::TestContext& testCtx)
542 {
543 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "early_fragment", "early fragment test cases"));
544 
545 	static const struct
546 	{
547 		std::string caseName;
548 		deUint32	flags;
549 	} cases[] =
550 	{
551 		{ "no_early_fragment_tests_depth",					FLAG_TEST_DEPTH   | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS									},
552 		{ "no_early_fragment_tests_stencil",				FLAG_TEST_STENCIL | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS									},
553 		{ "early_fragment_tests_depth",						FLAG_TEST_DEPTH																			},
554 		{ "early_fragment_tests_stencil",					FLAG_TEST_STENCIL																		},
555 		{ "no_early_fragment_tests_depth_no_attachment",	FLAG_TEST_DEPTH   | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS | FLAG_DONT_USE_TEST_ATTACHMENT	},
556 		{ "no_early_fragment_tests_stencil_no_attachment",	FLAG_TEST_STENCIL | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS | FLAG_DONT_USE_TEST_ATTACHMENT	},
557 		{ "early_fragment_tests_depth_no_attachment",		FLAG_TEST_DEPTH   |										 FLAG_DONT_USE_TEST_ATTACHMENT	},
558 		{ "early_fragment_tests_stencil_no_attachment",		FLAG_TEST_STENCIL |										 FLAG_DONT_USE_TEST_ATTACHMENT	},
559 	};
560 
561 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
562 		testGroup->addChild(new EarlyFragmentTest(testCtx, cases[i].caseName, cases[i].flags));
563 
564 	return testGroup.release();
565 }
566 
567 } // FragmentOperations
568 } // vkt
569