1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * -----------------------------
4  *
5  * Copyright (c) 2020 Google Inc.
6  * Copyright (c) 2020 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 Tests for multiple color or depth clears within a render pass
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawMultipleClearsWithinRenderPass.hpp"
26 
27 #include "vktTestGroupUtil.hpp"
28 #include "vktTestCaseUtil.hpp"
29 #include "vktDrawCreateInfoUtil.hpp"
30 #include "vktDrawBufferObjectUtil.hpp"
31 #include "vktDrawImageObjectUtil.hpp"
32 #include "vkPrograms.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkCmdUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "tcuTextureUtil.hpp"
40 #include "vktDrawTestCaseUtil.hpp"
41 
42 #include "deStringUtil.hpp"
43 
44 #include <cmath>
45 #include <vector>
46 #include <string>
47 #include <sstream>
48 
49 namespace vkt
50 {
51 namespace Draw
52 {
53 namespace
54 {
55 using namespace vk;
56 using tcu::Vec4;
57 using de::SharedPtr;
58 using std::string;
59 using std::abs;
60 using std::vector;
61 using std::ostringstream;
62 
63 const deUint32						WIDTH					= 400;
64 const deUint32						HEIGHT					= 300;
65 
66 enum struct Topology
67 {
68 	TRIANGLE_STRIP = 0,
69 	TRIANGLES,
70 	TRIANGLE
71 };
72 
73 const Topology						topologiesToTest[]		=
74 {
75 	Topology::TRIANGLE_STRIP,
76 	Topology::TRIANGLES,
77 	Topology::TRIANGLE
78 };
79 
80 struct FormatPair
81 {
82 	VkFormat colorFormat;
83 	VkFormat depthFormat;
84 };
85 
86 const FormatPair					formatsToTest[]			=
87 {
88 	{ VK_FORMAT_R8G8B8A8_UNORM	, VK_FORMAT_UNDEFINED	},
89 	{ VK_FORMAT_R8G8B8A8_SNORM	, VK_FORMAT_UNDEFINED	},
90 	{ VK_FORMAT_UNDEFINED		, VK_FORMAT_D32_SFLOAT	},
91 	{ VK_FORMAT_UNDEFINED		, VK_FORMAT_D16_UNORM	},
92 	{ VK_FORMAT_R8G8B8A8_UNORM	, VK_FORMAT_D32_SFLOAT	},
93 	{ VK_FORMAT_R8G8B8A8_UNORM	, VK_FORMAT_D16_UNORM	},
94 	{ VK_FORMAT_R8G8B8A8_SNORM	, VK_FORMAT_D32_SFLOAT	},
95 	{ VK_FORMAT_R8G8B8A8_SNORM	, VK_FORMAT_D16_UNORM	},
96 };
97 
98 const Vec4							verticesTriangleStrip[]	=
99 {
100 	Vec4(-1.0f, -1.0f,	0.0f, 1.0f),	// 0 -- 2
101 	Vec4(-1.0f,	 1.0f,	0.0f, 1.0f),	// |  / |
102 	Vec4( 1.0f, -1.0f,	0.0f, 1.0f),	// | /	|
103 	Vec4( 1.0f,	 1.0f,	0.0f, 1.0f)		// 1 -- 3
104 };
105 const Vec4							verticesTriangles[]		=
106 {
107 	Vec4(-1.0f, -1.0f,	0.0f, 1.0f),	// 0 - 1
108 	Vec4(-1.0f,	 1.0f,	0.0f, 1.0f),	// | /
109 	Vec4( 1.0f, -1.0f,	0.0f, 1.0f),	// 2
110 	Vec4( 1.0f, -1.0f,	0.0f, 1.0f),	//	   4
111 	Vec4(-1.0f,	 1.0f,	0.0f, 1.0f),	//	 / |
112 	Vec4( 1.0f,	 1.0f,	0.0f, 1.0f)		// 3 - 5
113 };
114 const Vec4							verticesBigTriangle[]	=
115 {
116 	Vec4(-1.0f, -1.0f,	0.0f, 1.0f),	// 0 - 2
117 	Vec4(-1.0f,	 3.0f,	0.0f, 1.0f),	// | /
118 	Vec4( 3.0f, -1.0f,	0.0f, 1.0f),	// 1
119 };
120 
121 const deUint32			TOPOLOGY_MAX_VERTICES_COUNT			= 6;
122 const deUint32			TEST_MAX_STEPS_COUNT				= 3;
123 
124 struct Vertices
125 {
126 	const char*			testNameSuffix;
127 	VkPrimitiveTopology	topology;
128 	deUint32			verticesCount;
129 	const Vec4*			vertices;
130 };
131 
132 const Vertices			verticesByTopology[]				=
133 {
134 	{
135 		"_triangle_strip",
136 		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
137 		DE_LENGTH_OF_ARRAY(verticesTriangleStrip),
138 		verticesTriangleStrip
139 	},
140 	{
141 		"_triangles",
142 		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
143 		DE_LENGTH_OF_ARRAY(verticesTriangles),
144 		verticesTriangles
145 	},
146 	{
147 		"_big_triangle",
148 		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
149 		DE_LENGTH_OF_ARRAY(verticesBigTriangle),
150 		verticesBigTriangle
151 	}
152 };
153 
154 enum struct ClearOp
155 {
156 	LOAD = 0,
157 	DRAW,
158 	CLEAR
159 };
160 
161 struct ClearStep
162 {
163 	ClearOp					clearOp;
164 	Vec4					color;
165 	float					depth;
166 };
167 
168 struct TestParams
169 {
170 	VkFormat				colorFormat;
171 	VkFormat				depthFormat;
172 	Topology				topology;
173 	Vec4					expectedColor;
174 	float					colorEpsilon;
175 	float					expectedDepth;
176 	float					depthEpsilon;
177 	deUint32				repeatCount;
178 	bool					enableBlend;
179 	vector<ClearStep>		steps;
180 };
181 
182 class MultipleClearsTest : public TestInstance
183 {
184 public:
185 							MultipleClearsTest		(Context& context, const TestParams& params);
186 	virtual tcu::TestStatus	iterate					(void);
187 private:
188 	void					clearAttachments		(const DeviceInterface& vk, VkCommandBuffer cmdBuffer, const ClearOp clearOp, const size_t stepIndex);
189 
190 	SharedPtr<Image>		m_colorTargetImage;
191 	SharedPtr<Image>		m_depthTargetImage;
192 	Move<VkImageView>		m_colorTargetView;
193 	Move<VkImageView>		m_depthTargetView;
194 	SharedPtr<Buffer>		m_vertexBuffer;
195 	Move<VkRenderPass>		m_renderPass;
196 	Move<VkFramebuffer>		m_framebuffer;
197 	Move<VkPipelineLayout>	m_pipelineLayout;
198 	Move<VkPipeline>		m_pipeline;
199 
200 	const TestParams		m_params;
201 	Vec4					m_vertices[TOPOLOGY_MAX_VERTICES_COUNT * TEST_MAX_STEPS_COUNT];
202 };
203 
MultipleClearsTest(Context & context,const TestParams & params)204 MultipleClearsTest::MultipleClearsTest (Context &context, const TestParams& params)
205 	: TestInstance(context)
206 	, m_params(params)
207 {
208 	const DeviceInterface&		vk					= m_context.getDeviceInterface();
209 	const VkDevice				device				= m_context.getDevice();
210 	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
211 	const bool					hasColor			= m_params.colorFormat != VK_FORMAT_UNDEFINED;
212 	const bool					hasDepth			= m_params.depthFormat != VK_FORMAT_UNDEFINED;
213 
214 	DescriptorSetLayoutBuilder	descriptorSetLayoutBuilder;
215 	// Vertex data
216 	const auto&					vertexData			= verticesByTopology[(size_t)m_params.topology];
217 	{
218 		DE_ASSERT(vertexData.verticesCount <= TOPOLOGY_MAX_VERTICES_COUNT);
219 		const size_t			verticesCount		= vertexData.verticesCount;
220 		const VkDeviceSize		dataSize			= verticesCount * sizeof(Vec4);
221 		const VkDeviceSize		totalDataSize		= m_params.steps.size() * dataSize;
222 		DE_ASSERT(totalDataSize <= sizeof(m_vertices));
223 
224 		for(size_t i = 0; i < m_params.steps.size(); ++i)
225 		{
226 			const size_t start = i * verticesCount;
227 			deMemcpy(&m_vertices[start], vertexData.vertices, static_cast<size_t>(dataSize));
228 			for(size_t j = 0; j < verticesCount; ++j)
229 				m_vertices[start + j][2] = m_params.steps[i].depth;
230 		}
231 		m_vertexBuffer								= Buffer::createAndAlloc(vk, device, BufferCreateInfo(totalDataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
232 																			 m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
233 		deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), m_vertices, static_cast<std::size_t>(totalDataSize));
234 		flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
235 	}
236 	// Render pass
237 	std::vector<VkImageView>			attachments;
238 	{
239 		RenderPassCreateInfo			renderPassCreateInfo;
240 		if (hasColor)
241 		{
242 			const VkImageUsageFlags		targetImageUsageFlags		= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
243 			const ImageCreateInfo		targetImageCreateInfo		(VK_IMAGE_TYPE_2D, m_params.colorFormat, { WIDTH, HEIGHT, 1u }, 1u,	1u,	VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, targetImageUsageFlags);
244 			m_colorTargetImage										= Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), queueFamilyIndex);
245 
246 			renderPassCreateInfo.addAttachment(AttachmentDescription(
247 				 m_params.colorFormat,								// format
248 				 VK_SAMPLE_COUNT_1_BIT,								// samples
249 				 VK_ATTACHMENT_LOAD_OP_LOAD,						// loadOp
250 				 VK_ATTACHMENT_STORE_OP_STORE,						// storeOp
251 				 VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// stencilLoadOp
252 				 VK_ATTACHMENT_STORE_OP_DONT_CARE,					// stencilStoreOp
253 				 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// initialLayout
254 				 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));		// finalLayout
255 
256 			const ImageViewCreateInfo	colorTargetViewInfo			(m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_params.colorFormat);
257 			m_colorTargetView										= createImageView(vk, device, &colorTargetViewInfo);
258 			attachments.push_back(*m_colorTargetView);
259 		}
260 		if (hasDepth)
261 		{
262 			const VkImageUsageFlags		depthImageUsageFlags		= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
263 			const ImageCreateInfo		depthImageCreateInfo		(VK_IMAGE_TYPE_2D, m_params.depthFormat, { WIDTH, HEIGHT, 1u }, 1u,	1u,	VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, depthImageUsageFlags);
264 			m_depthTargetImage										= Image::createAndAlloc(vk, device, depthImageCreateInfo, m_context.getDefaultAllocator(), queueFamilyIndex);
265 
266 			renderPassCreateInfo.addAttachment(AttachmentDescription(
267 				m_params.depthFormat,								// format
268 				VK_SAMPLE_COUNT_1_BIT,								// samples
269 				VK_ATTACHMENT_LOAD_OP_LOAD,							// loadOp
270 				VK_ATTACHMENT_STORE_OP_STORE,						// storeOp
271 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// stencilLoadOp
272 				VK_ATTACHMENT_STORE_OP_DONT_CARE,					// stencilStoreOp
273 				VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	// initialLayout
274 				VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));	// finalLayout
275 
276 			const ImageViewCreateInfo	depthTargetViewInfo			(m_depthTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_params.depthFormat);
277 			m_depthTargetView										= createImageView(vk, device, &depthTargetViewInfo);;
278 			attachments.push_back(*m_depthTargetView);
279 		}
280 		const VkAttachmentReference colorAttachmentReference		= hasColor ? makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) : AttachmentReference();
281 		const VkAttachmentReference depthAttachmentReference		= hasDepth ? makeAttachmentReference(hasColor ? 1u : 0u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) : AttachmentReference();
282 		renderPassCreateInfo.addSubpass(SubpassDescription(
283 			VK_PIPELINE_BIND_POINT_GRAPHICS,						// pipelineBindPoint
284 			(VkSubpassDescriptionFlags)0,							// flags
285 			0u,														// inputAttachmentCount
286 			DE_NULL,												// inputAttachments
287 			hasColor ? 1 : 0,										// colorAttachmentCount
288 			hasColor ? &colorAttachmentReference : DE_NULL,			// colorAttachments
289 			DE_NULL,												// resolveAttachments
290 			depthAttachmentReference,								// depthStencilAttachment
291 			0u,														// preserveAttachmentCount
292 			DE_NULL));												// preserveAttachments
293 		m_renderPass												= createRenderPass(vk, device, &renderPassCreateInfo);
294 	}
295 	const FramebufferCreateInfo					framebufferCreateInfo			(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
296 	m_framebuffer																= createFramebuffer(vk, device, &framebufferCreateInfo);
297 
298 	// Vertex input
299 	const VkVertexInputBindingDescription		vertexInputBindingDescription	=
300 	{
301 		0u,										// uint32_t				binding;
302 		sizeof(Vec4),							// uint32_t				stride;
303 		VK_VERTEX_INPUT_RATE_VERTEX,			// VkVertexInputRate	inputRate;
304 	};
305 
306 	const VkVertexInputAttributeDescription		vertexInputAttributeDescription =
307 	{
308 		0u,										// uint32_t		location;
309 		0u,										// uint32_t		binding;
310 		VK_FORMAT_R32G32B32A32_SFLOAT,			// VkFormat		format;
311 		0u										// uint32_t		offset;
312 	};
313 
314 	const PipelineCreateInfo::VertexInputState	vertexInputState				= PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription,
315 																													   1, &vertexInputAttributeDescription);
316 
317 	// Graphics pipeline
318 	const Unique<VkShaderModule>				vertexModule					(createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
319 	const Unique<VkShaderModule>				fragmentModule					(createShaderModule(vk, device, m_context.getBinaryCollection().get(hasColor ? "frag" : "frag_depthonly"), 0));
320 
321 	const VkPushConstantRange					pcRange							= vk::VkPushConstantRange { VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ClearStep::color) };
322 	const PipelineLayoutCreateInfo				pipelineLayoutCreateInfo		(0u, DE_NULL, 1u, &pcRange);
323 	m_pipelineLayout															= createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
324 
325 	const VkRect2D								scissor							= makeRect2D(WIDTH, HEIGHT);
326 	const VkViewport							viewport						= makeViewport(WIDTH, HEIGHT);
327 
328 	const auto									vkCbAttachmentState				= makePipelineColorBlendAttachmentState(
329 		m_params.enableBlend ? VK_TRUE : VK_FALSE,	// VkBool32					blendEnable
330 		VK_BLEND_FACTOR_SRC_ALPHA,					// VkBlendFactor			srcColorBlendFactor
331 		VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,		// VkBlendFactor			dstColorBlendFactor
332 		VK_BLEND_OP_ADD,							// VkBlendOp				colorBlendOp
333 		VK_BLEND_FACTOR_ZERO,						// VkBlendFactor			srcAlphaBlendFactor
334 		VK_BLEND_FACTOR_ONE,						// VkBlendFactor			dstAlphaBlendFactor
335 		VK_BLEND_OP_ADD,							// VkBlendOp				alphaBlendOp
336 		VK_COLOR_COMPONENT_R_BIT |					// VkColorComponentFlags	colorWriteMask
337 		VK_COLOR_COMPONENT_G_BIT |
338 		VK_COLOR_COMPONENT_B_BIT |
339 		VK_COLOR_COMPONENT_A_BIT);
340 	PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0);
341 	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vertexModule,	  "main", VK_SHADER_STAGE_VERTEX_BIT));
342 	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
343 	pipelineCreateInfo.addState (PipelineCreateInfo::VertexInputState	(vertexInputState));
344 	pipelineCreateInfo.addState (PipelineCreateInfo::InputAssemblerState(vertexData.topology));
345 	pipelineCreateInfo.addState (PipelineCreateInfo::ColorBlendState	(1, &vkCbAttachmentState));
346 	pipelineCreateInfo.addState (PipelineCreateInfo::ViewportState		(1, std::vector<VkViewport>(1, viewport), std::vector<VkRect2D>(1, scissor)));
347 	pipelineCreateInfo.addState (PipelineCreateInfo::DepthStencilState	(hasDepth, hasDepth, VK_COMPARE_OP_ALWAYS, VK_FALSE, VK_FALSE));
348 	pipelineCreateInfo.addState (PipelineCreateInfo::RasterizerState	());
349 	pipelineCreateInfo.addState (PipelineCreateInfo::MultiSampleState	());
350 	m_pipeline																	= createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
351 }
352 
clearAttachments(const DeviceInterface & vk,vk::VkCommandBuffer cmdBuffer,const ClearOp clearOp,const size_t stepIndex)353 void MultipleClearsTest::clearAttachments (const DeviceInterface& vk, vk::VkCommandBuffer cmdBuffer, const ClearOp clearOp, const size_t stepIndex)
354 {
355 	const Vec4& color = m_params.steps[stepIndex].color;
356 	const float depth = m_params.steps[stepIndex].depth;
357 	switch(clearOp) {
358 	case ClearOp::LOAD:
359 		break;
360 	case ClearOp::DRAW:
361 		{
362 			const auto&		vertexData		= verticesByTopology[(size_t)m_params.topology];
363 			const deUint32	verticesCount	= vertexData.verticesCount;
364 			vk.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(color), color.getPtr());
365 			vk.cmdDraw(cmdBuffer, verticesCount, 1, static_cast<deUint32>(verticesCount * stepIndex), 0);
366 		}
367 		break;
368 	case ClearOp::CLEAR:
369 		{
370 			vector<VkClearAttachment>	clearAttachments;
371 			if (m_params.colorFormat != VK_FORMAT_UNDEFINED)
372 			{
373 				const VkClearAttachment	clearAttachment	=
374 				{
375 					VK_IMAGE_ASPECT_COLOR_BIT,						// VkImageAspectFlags	 aspectMask
376 					static_cast<deUint32>(clearAttachments.size()),	// uint32_t				 colorAttachment
377 					makeClearValueColor(color)						// VkClearValue			 clearValue
378 				};
379 				clearAttachments.push_back(clearAttachment);
380 			}
381 			if (m_params.depthFormat != VK_FORMAT_UNDEFINED)
382 			{
383 				const VkClearAttachment	clearAttachment	=
384 				{
385 					VK_IMAGE_ASPECT_DEPTH_BIT,						// VkImageAspectFlags	 aspectMask
386 					static_cast<deUint32>(clearAttachments.size()),	// uint32_t				 colorAttachment
387 					makeClearValueDepthStencil(depth, 0)			// VkClearValue			 clearValue
388 				};
389 				clearAttachments.push_back(clearAttachment);
390 			}
391 			const VkClearRect			clearRect		=
392 			{
393 				makeRect2D(WIDTH, HEIGHT),							// VkRect2D	   rect
394 				0,													// uint32_t	   baseArrayLayer
395 				1													// uint32_t	   layerCount
396 			};
397 			vk.cmdClearAttachments(cmdBuffer, static_cast<deUint32>(clearAttachments.size()), clearAttachments.data(), 1, &clearRect);
398 		}
399 		break;
400 	default:
401 		break;
402 	}
403 }
404 
iterate(void)405 tcu::TestStatus MultipleClearsTest::iterate (void)
406 {
407 	const DeviceInterface&			vk					= m_context.getDeviceInterface();
408 	const VkDevice					device				= m_context.getDevice();
409 	const VkQueue					queue				= m_context.getUniversalQueue();
410 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
411 
412 	const CmdPoolCreateInfo			cmdPoolCreateInfo	(queueFamilyIndex);
413 	const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, device, &cmdPoolCreateInfo));
414 	const Unique<VkCommandBuffer>	cmdBuffer			(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
415 
416 	const bool						hasColor			= m_params.colorFormat != VK_FORMAT_UNDEFINED;
417 	const bool						hasDepth			= m_params.depthFormat != VK_FORMAT_UNDEFINED;
418 
419 	beginCommandBuffer(vk, *cmdBuffer);
420 	if (hasColor)
421 		initialTransitionColor2DImage(vk, *cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
422 	if (hasDepth)
423 		initialTransitionDepth2DImage(vk, *cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
424 
425 	if (!m_params.steps.empty() && m_params.steps[0].clearOp == ClearOp::LOAD)
426 		beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, WIDTH, HEIGHT), m_params.steps[0].color, m_params.steps[0].depth, 0);
427 	else
428 		beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, WIDTH, HEIGHT));
429 	vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
430 	{
431 		const VkDeviceSize	offset	= 0;
432 		const VkBuffer		buffer	= m_vertexBuffer->object();
433 		vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &offset);
434 	}
435 	for(deUint32 i = 0; i < m_params.repeatCount; ++i)
436 		for(size_t j = 0; j < m_params.steps.size(); ++j)
437 		{
438 			const auto& step = m_params.steps[j];
439 			// ClearOp::LOAD only supported for first step
440 			DE_ASSERT(j == 0 || step.clearOp != ClearOp::LOAD);
441 			clearAttachments(vk, *cmdBuffer, step.clearOp, j);
442 		}
443 
444 	endRenderPass(vk, *cmdBuffer);
445 
446 	if (hasDepth)
447 	{
448 		const VkMemoryBarrier	memBarrier	= { VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT };
449 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
450 	}
451 	if (hasColor)
452 	{
453 		const VkMemoryBarrier	memBarrier	= { VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT };
454 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
455 	}
456 
457 	if (hasColor)
458 		transition2DImage(vk, *cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_ASPECT_COLOR_BIT,
459 						  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
460 						  VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
461 						  VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_HOST_BIT);
462 	if (hasDepth)
463 		transition2DImage(vk, *cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_ASPECT_DEPTH_BIT,
464 						  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
465 						  VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
466 						  VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_HOST_BIT);
467 
468 	endCommandBuffer(vk, *cmdBuffer);
469 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
470 
471 	VK_CHECK(vk.queueWaitIdle(queue));
472 
473 	if (hasColor)
474 	{
475 		const auto		resultImage	= m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, { 0, 0, 0 }, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT);
476 
477 		for(int z = 0; z < resultImage.getDepth(); ++z)
478 		for(int y = 0; y < resultImage.getHeight(); ++y)
479 		for(int x = 0; x < resultImage.getWidth(); ++x)
480 		{
481 			const Vec4	difference	= m_params.expectedColor - resultImage.getPixel(x,y,z);
482 			if (abs(difference.x()) >= m_params.colorEpsilon || abs(difference.y()) >= m_params.colorEpsilon || abs(difference.z()) >= m_params.colorEpsilon)
483 			{
484 				ostringstream msg;
485 				msg << "Color value mismatch, expected: " << m_params.expectedColor << ", got: " << resultImage.getPixel(x,y,z) << " at " << "(" << x << ", " << y << ", " << z << ")";
486 				return tcu::TestStatus::fail(msg.str());
487 			}
488 		}
489 	}
490 	if (hasDepth)
491 	{
492 		const auto		resultImage	= m_depthTargetImage->readSurface(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, { 0, 0, 0 }, WIDTH, HEIGHT, VK_IMAGE_ASPECT_DEPTH_BIT);
493 
494 		for(int z = 0; z < resultImage.getDepth(); ++z)
495 		for(int y = 0; y < resultImage.getHeight(); ++y)
496 		for(int x = 0; x < resultImage.getWidth(); ++x)
497 		{
498 			const float	difference	= m_params.expectedDepth - resultImage.getPixDepth(x,y,z);
499 			if (abs(difference) >= m_params.depthEpsilon)
500 			{
501 				ostringstream msg;
502 				msg << "Depth value mismatch, expected: " << m_params.expectedDepth << ", got: " << resultImage.getPixDepth(x,y,z) << " at " << "(" << x << ", " << y << ", " << z << ")";
503 				return tcu::TestStatus::fail(msg.str());
504 			}
505 		}
506 	}
507 	return tcu::TestStatus::pass("Pass");
508 }
509 
510 class MultipleClearsWithinRenderPassTest : public TestCase
511 {
512 public:
MultipleClearsWithinRenderPassTest(tcu::TestContext & testCtx,const string & name,const string & description,const TestParams & params)513 	MultipleClearsWithinRenderPassTest (tcu::TestContext& testCtx, const string& name, const string& description, const TestParams& params)
514 		: TestCase(testCtx, name, description)
515 		, m_params(params)
516 	{
517 		DE_ASSERT(m_params.steps.size() <= static_cast<size_t>(TEST_MAX_STEPS_COUNT));
518 	}
519 
initPrograms(SourceCollections & programCollection) const520 	virtual void initPrograms (SourceCollections& programCollection) const
521 	{
522 		{
523 			ostringstream src;
524 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
525 				<< "\n"
526 				<< "layout(location = 0) in vec4 in_position;\n"
527 				<< "\n"
528 				<< "out gl_PerVertex {\n"
529 				<< "    vec4  gl_Position;\n"
530 				<< "};\n"
531 				<< "\n"
532 				<< "void main(void)\n"
533 				<< "{\n"
534 				<< "    gl_Position = in_position;\n"
535 				<< "}\n";
536 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
537 		}
538 		{
539 			ostringstream src;
540 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
541 				<< "\n"
542 				<< "layout(push_constant) uniform Color { vec4 color; } u_color;\n"
543 				<< "layout(location = 0) out vec4 out_color;\n"
544 				<< "\n"
545 				<< "void main(void)\n"
546 				<< "{\n"
547 				<< "    out_color = u_color.color;\n"
548 				<< "}\n";
549 			programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
550 		}
551 		{
552 			ostringstream src;
553 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
554 				<< "\n"
555 				<< "layout(push_constant) uniform Color { vec4 color; } u_color;\n"
556 				<< "\n"
557 				<< "void main(void)\n"
558 				<< "{\n"
559 				<< "}\n";
560 			programCollection.glslSources.add("frag_depthonly") << glu::FragmentSource(src.str());
561 		}
562 	}
563 
checkSupport(Context & context) const564 	virtual void checkSupport (Context& context) const
565 	{
566 		VkImageFormatProperties imageFormatProperties;
567 		const auto&	vki	= context.getInstanceInterface();
568 		const auto&	vkd	= context.getPhysicalDevice();
569 		if (m_params.colorFormat != VK_FORMAT_UNDEFINED)
570 		{
571 			const auto	colorUsage	= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
572 			if (vki.getPhysicalDeviceImageFormatProperties(vkd, m_params.colorFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, colorUsage, 0u, &imageFormatProperties) != VK_SUCCESS)
573 				TCU_THROW(NotSupportedError, "Color format not supported");
574 		}
575 		if (m_params.depthFormat != VK_FORMAT_UNDEFINED)
576 		{
577 			const auto	depthUsage	= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
578 			if (vki.getPhysicalDeviceImageFormatProperties(vkd, m_params.depthFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, depthUsage, 0u, &imageFormatProperties) != VK_SUCCESS)
579 				TCU_THROW(NotSupportedError, "Depth format not supported");
580 		}
581 	}
582 
createInstance(Context & context) const583 	virtual TestInstance* createInstance (Context& context) const
584 	{
585 		return new MultipleClearsTest(context, m_params);
586 	}
587 
588 private:
589 	const TestParams	m_params;
590 };
591 
592 }	// anonymous
593 
MultipleClearsWithinRenderPassTests(tcu::TestContext & testCtx)594 MultipleClearsWithinRenderPassTests::MultipleClearsWithinRenderPassTests (tcu::TestContext &testCtx)
595 	: TestCaseGroup	(testCtx, "multiple_clears_within_render_pass", "Tests for multiple clears within render pass")
596 {
597 }
598 
~MultipleClearsWithinRenderPassTests()599 MultipleClearsWithinRenderPassTests::~MultipleClearsWithinRenderPassTests ()
600 {
601 }
602 
init()603 void MultipleClearsWithinRenderPassTests::init ()
604 {
605 	for(const auto &formatPair : formatsToTest)
606 	{
607 		ostringstream			formatSuffix;
608 		if (formatPair.colorFormat != VK_FORMAT_UNDEFINED)
609 			formatSuffix << "_c" << de::toLower(string(getFormatName(formatPair.colorFormat)).substr(9));
610 		if (formatPair.depthFormat != VK_FORMAT_UNDEFINED)
611 			formatSuffix << "_d" << de::toLower(string(getFormatName(formatPair.depthFormat)).substr(9));
612 		for(const auto &topology : topologiesToTest)
613 		{
614 			const string	testNameSuffix	= formatSuffix.str() + verticesByTopology[(deUint32)topology].testNameSuffix;
615 			{
616 				const TestParams params	=
617 				{
618 					formatPair.colorFormat,			// VkFormat				colorFormat;
619 					formatPair.depthFormat,			// VkFormat				depthFormat;
620 					topology,						// Topology				topology;
621 					Vec4(0.0f, 0.5f, 0.5f, 1.0f),	// Vec4					expectedColor;
622 					0.01f,							// float				colorEpsilon;
623 					0.9f,							// float				expectedDepth;
624 					0.01f,							// float				depthEpsilon;
625 					1u,								// deUint32				repeatCount;
626 					true,							// bool					enableBlend;
627 					{								// vector<ClearStep>	steps;
628 						{ ClearOp::LOAD		, Vec4(1.0f, 0.0f, 0.0f, 1.0f)	, 0.7f },
629 						{ ClearOp::CLEAR	, Vec4(0.0f, 1.0f, 0.0f, 1.0f)	, 0.3f },
630 						{ ClearOp::DRAW		, Vec4(0.0f, 0.0f, 1.0f, 0.5f)	, 0.9f }
631 					}
632 				};
633 				addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "load_clear_draw" + testNameSuffix, "Multiple clears within same render pass, methods: load, clear, draw", params));
634 			}
635 			{
636 				const TestParams params	=
637 				{
638 					formatPair.colorFormat,			// VkFormat				format;
639 					formatPair.depthFormat,			// VkFormat				depthFormat;
640 					topology,						// Topology				topology;
641 					Vec4(0.0f, 0.5f, 0.5f, 1.0f),	// Vec4					expectedColor;
642 					0.01f,							// float				colorEpsilon;
643 					0.9f,							// float				expectedDepth;
644 					0.01f,							// float				depthEpsilon;
645 					1u,								// deUint32				repeatCount;
646 					true,							// bool					enableBlend;
647 					{								// vector<ClearStep>	steps;
648 						{ ClearOp::DRAW		, Vec4(1.0f, 0.0f, 0.0f, 1.0f)	, 0.7f },
649 						{ ClearOp::CLEAR	, Vec4(0.0f, 1.0f, 0.0f, 1.0f)	, 0.3f },
650 						{ ClearOp::DRAW		, Vec4(0.0f, 0.0f, 1.0f, 0.5f)	, 0.9f }
651 					}
652 				};
653 				addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "draw_clear_draw" + testNameSuffix, "Multiple clears within same render pass, methods: draw, clear, draw", params));
654 			}
655 			{
656 				const TestParams params	=
657 				{
658 					formatPair.colorFormat,			// VkFormat				format;
659 					formatPair.depthFormat,			// VkFormat				depthFormat;
660 					topology,						// Topology				topology;
661 					Vec4(0.0f, 0.5f, 0.5f, 1.0f),	// Vec4					expectedColor;
662 					0.01f,							// float				colorEpsilon;
663 					0.9f,							// float				expectedDepth;
664 					0.01f,							// float				depthEpsilon;
665 					1u,								// deUint32				repeatCount;
666 					true,							// bool					enableBlend;
667 					{								// vector<ClearStep>	steps;
668 						{ ClearOp::CLEAR	, Vec4(1.0f, 0.0f, 0.0f, 1.0f)	, 0.7f },
669 						{ ClearOp::CLEAR	, Vec4(0.0f, 1.0f, 0.0f, 1.0f)	, 0.3f },
670 						{ ClearOp::DRAW		, Vec4(0.0f, 0.0f, 1.0f, 0.5f)	, 0.9f }
671 					}
672 				};
673 				addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "clear_clear_draw" + testNameSuffix, "Multiple clears within same render pass, methods: clear, clear, draw", params));
674 			}
675 			{
676 				const TestParams params	=
677 				{
678 					formatPair.colorFormat,			// VkFormat				format;
679 					formatPair.depthFormat,			// VkFormat				depthFormat;
680 					topology,						// Topology				topology;
681 					Vec4(0.0f, 1.0f, 0.0f, 1.0f),	// Vec4					expectedColor;
682 					0.01f,							// float				colorEpsilon;
683 					0.9f,							// float				expectedDepth;
684 					0.01f,							// float				depthEpsilon;
685 					1u,								// deUint32				repeatCount;
686 					false,							// bool					enableBlend;
687 					{								// vector<ClearStep>	steps;
688 						{ ClearOp::LOAD		, Vec4(1.0f, 0.0f, 0.0f, 1.0f)	, 0.3f },
689 						{ ClearOp::CLEAR	, Vec4(0.0f, 1.0f, 0.0f, 1.0f)	, 0.9f }
690 					}
691 				};
692 				addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "load_clear" + testNameSuffix, "Multiple clears within same render pass, methods: load, clear", params));
693 			}
694 			{
695 				const TestParams params	=
696 				{
697 					formatPair.colorFormat,			// VkFormat				format;
698 					formatPair.depthFormat,			// VkFormat				depthFormat;
699 					topology,						// Topology				topology;
700 					Vec4(0.0f, 1.0f, 0.0f, 1.0f),	// Vec4					expectedColor;
701 					0.01f,							// float				colorEpsilon;
702 					0.9f,							// float				expectedDepth;
703 					0.01f,							// float				depthEpsilon;
704 					1u,								// deUint32				repeatCount;
705 					false,							// bool					enableBlend;
706 					{								// vector<ClearStep>	steps;
707 						{ ClearOp::DRAW		, Vec4(1.0f, 0.0f, 0.0f, 1.0f)	, 0.3f },
708 						{ ClearOp::CLEAR	, Vec4(0.0f, 1.0f, 0.0f, 1.0f)	, 0.9f }
709 					}
710 				};
711 				addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "draw_clear" + testNameSuffix, "Multiple clears within same render pass, methods: draw, clear", params));
712 			}
713 			{
714 				const TestParams params	=
715 				{
716 					formatPair.colorFormat,			// VkFormat				format;
717 					formatPair.depthFormat,			// VkFormat				depthFormat;
718 					topology,						// Topology				topology;
719 					Vec4(0.0f, 1.0f, 0.0f, 1.0f),	// Vec4					expectedColor;
720 					0.01f,							// float				colorEpsilon;
721 					0.9f,							// float				expectedDepth;
722 					0.01f,							// float				depthEpsilon;
723 					1u,								// deUint32				repeatCount;
724 					false,							// bool					enableBlend;
725 					{								// vector<ClearStep>	steps;
726 						{ ClearOp::CLEAR	, Vec4(1.0f, 0.0f, 0.0f, 1.0f)	, 0.3f },
727 						{ ClearOp::CLEAR	, Vec4(0.0f, 1.0f, 0.0f, 1.0f)	, 0.9f }
728 					}
729 				};
730 				addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "clear_clear" + testNameSuffix, "Multiple clears within same render pass, methods: clear, clear", params));
731 			}
732 		}
733 	}
734 }
735 }	// Draw
736 }	// vkt
737