1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Intel Corporation
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 Vulkan Occlusion Query Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktQueryPoolOcclusionTests.hpp"
26 
27 #include "vktTestCase.hpp"
28 
29 #include "vktDrawImageObjectUtil.hpp"
30 #include "vktDrawBufferObjectUtil.hpp"
31 #include "vktDrawCreateInfoUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 
38 #include "tcuTestLog.hpp"
39 #include "tcuResource.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuCommandLine.hpp"
42 
43 namespace vkt
44 {
45 
46 namespace QueryPool
47 {
48 
49 using namespace Draw;
50 
51 namespace
52 {
53 
54 struct StateObjects
55 {
56 			StateObjects	(const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive, const bool noColorAttachments);
57 	void	setVertices		(const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices);
58 
59 	enum
60 	{
61 		WIDTH	= 128,
62 		HEIGHT	= 128
63 	};
64 
65 	vkt::Context &m_context;
66 
67 	vk::Move<vk::VkPipeline>		m_pipeline;
68 	vk::Move<vk::VkPipelineLayout>	m_pipelineLayout;
69 
70 	de::SharedPtr<Image>			m_colorAttachmentImage, m_DepthImage;
71 	vk::Move<vk::VkImageView>		m_attachmentView;
72 	vk::Move<vk::VkImageView>		m_depthView;
73 
74 	vk::Move<vk::VkRenderPass>		m_renderPass;
75 	vk::Move<vk::VkFramebuffer>		m_framebuffer;
76 
77 	de::SharedPtr<Buffer>			m_vertexBuffer;
78 
79 	vk::VkFormat					m_colorAttachmentFormat;
80 };
81 
StateObjects(const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive, const bool noColorAttachments)82 StateObjects::StateObjects (const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive, const bool noColorAttachments)
83 	: m_context(context)
84 	, m_colorAttachmentFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)
85 
86 {
87 	vk::VkFormat		depthFormat = vk::VK_FORMAT_D16_UNORM;
88 	const vk::VkDevice	device		= m_context.getDevice();
89 
90 	vk::VkExtent3D imageExtent =
91 	{
92 		WIDTH,	// width;
93 		HEIGHT,	// height;
94 		1		// depth;
95 	};
96 
97 	ImageCreateInfo depthImageCreateInfo(vk::VK_IMAGE_TYPE_2D, depthFormat, imageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
98 		vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
99 
100 	m_DepthImage			= Image::createAndAlloc(vk, device, depthImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
101 
102 	// Construct a depth  view from depth image
103 	const ImageViewCreateInfo depthViewInfo(m_DepthImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, depthFormat);
104 	m_depthView				= vk::createImageView(vk, device, &depthViewInfo);
105 
106 	// Renderpass and Framebuffer
107 	if (noColorAttachments)
108 	{
109 		RenderPassCreateInfo renderPassCreateInfo;
110 
111 		renderPassCreateInfo.addAttachment(AttachmentDescription(depthFormat,												// format
112 																 vk::VK_SAMPLE_COUNT_1_BIT,									// samples
113 																 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,							// loadOp
114 																 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,						// storeOp
115 																 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,						// stencilLoadOp
116 																 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,						// stencilLoadOp
117 																 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,		// initialLauout
118 																 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));	// finalLayout
119 
120 		const vk::VkAttachmentReference depthAttachmentReference =
121 		{
122 			0,															// attachment
123 			vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL		// layout
124 		};
125 
126 		renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,					// pipelineBindPoint
127 														   0,													// flags
128 														   0,													// inputCount
129 														   DE_NULL,												// pInputAttachments
130 														   0,													// colorCount
131 														   DE_NULL,												// pColorAttachments
132 														   DE_NULL,												// pResolveAttachments
133 														   depthAttachmentReference,							// depthStencilAttachment
134 														   0,													// preserveCount
135 														   DE_NULL));											// preserveAttachments
136 
137 		m_renderPass = vk::createRenderPass(vk, device, &renderPassCreateInfo);
138 
139 		std::vector<vk::VkImageView> attachments(1);
140 		attachments[0] = *m_depthView;
141 		FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
142 		m_framebuffer = vk::createFramebuffer(vk, device, &framebufferCreateInfo);
143 	}
144 	else
145 	{
146 		const ImageCreateInfo colorImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, imageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
147 												   vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
148 
149 		m_colorAttachmentImage	= Image::createAndAlloc(vk, device, colorImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
150 
151 		const ImageViewCreateInfo attachmentViewInfo(m_colorAttachmentImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
152 
153 		m_attachmentView		= vk::createImageView(vk, device, &attachmentViewInfo);
154 
155 		RenderPassCreateInfo renderPassCreateInfo;
156 		renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,									// format
157 																	vk::VK_SAMPLE_COUNT_1_BIT,								// samples
158 																	vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						// loadOp
159 																	vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,					// storeOp
160 																	vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// stencilLoadOp
161 																	vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,					// stencilLoadOp
162 																	vk::VK_IMAGE_LAYOUT_GENERAL,							// initialLauout
163 																	vk::VK_IMAGE_LAYOUT_GENERAL));							// finalLayout
164 
165 		renderPassCreateInfo.addAttachment(AttachmentDescription(depthFormat,												// format
166 																 vk::VK_SAMPLE_COUNT_1_BIT,									// samples
167 																 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,							// loadOp
168 																 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,						// storeOp
169 																 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,						// stencilLoadOp
170 																 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,						// stencilLoadOp
171 																 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,		// initialLauout
172 																 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));	// finalLayout
173 
174 		const vk::VkAttachmentReference colorAttachmentReference =
175 		{
176 			0,															// attachment
177 			vk::VK_IMAGE_LAYOUT_GENERAL									// layout
178 		};
179 
180 		const vk::VkAttachmentReference depthAttachmentReference =
181 		{
182 			1,															// attachment
183 			vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL		// layout
184 		};
185 
186 		renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,					// pipelineBindPoint
187 														   0,													// flags
188 														   0,													// inputCount
189 														   DE_NULL,												// pInputAttachments
190 														   1,													// colorCount
191 														   &colorAttachmentReference,							// pColorAttachments
192 														   DE_NULL,												// pResolveAttachments
193 														   depthAttachmentReference,							// depthStencilAttachment
194 														   0,													// preserveCount
195 														   DE_NULL));											// preserveAttachments
196 
197 		m_renderPass = vk::createRenderPass(vk, device, &renderPassCreateInfo);
198 
199 		std::vector<vk::VkImageView> attachments(2);
200 		attachments[0] = *m_attachmentView;
201 		attachments[1] = *m_depthView;
202 
203 		FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
204 		m_framebuffer = vk::createFramebuffer(vk, device, &framebufferCreateInfo);
205 	}
206 
207 	{
208 		// Pipeline
209 
210 		vk::Unique<vk::VkShaderModule> vs(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
211 		vk::Unique<vk::VkShaderModule> fs(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
212 
213 		const PipelineCreateInfo::ColorBlendState::Attachment attachmentState;
214 
215 		const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
216 		m_pipelineLayout = vk::createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
217 
218 		const vk::VkVertexInputBindingDescription vf_binding_desc		=
219 		{
220 			0,																// binding;
221 			4 * (deUint32)sizeof(float),									// stride;
222 			vk::VK_VERTEX_INPUT_RATE_VERTEX									// inputRate
223 		};
224 
225 		const vk::VkVertexInputAttributeDescription vf_attribute_desc	=
226 		{
227 			0,																// location;
228 			0,																// binding;
229 			vk::VK_FORMAT_R32G32B32A32_SFLOAT,								// format;
230 			0																// offset;
231 		};
232 
233 		const vk::VkPipelineVertexInputStateCreateInfo vf_info			=
234 		{																	// sType;
235 			vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// pNext;
236 			NULL,															// flags;
237 			0u,																// vertexBindingDescriptionCount;
238 			1,																// pVertexBindingDescriptions;
239 			&vf_binding_desc,												// vertexAttributeDescriptionCount;
240 			1,																// pVertexAttributeDescriptions;
241 			&vf_attribute_desc
242 		};
243 
244 		PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
245 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
246 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
247 		pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(primitive));
248 		pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &attachmentState));
249 		const vk::VkViewport viewport	= vk::makeViewport(WIDTH, HEIGHT);
250 		const vk::VkRect2D scissor		= vk::makeRect2D(WIDTH, HEIGHT);
251 		pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
252 		pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState(true, true, vk::VK_COMPARE_OP_GREATER_OR_EQUAL));
253 		pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
254 		pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
255 		pipelineCreateInfo.addState(vf_info);
256 		m_pipeline = vk::createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
257 	}
258 
259 	{
260 		// Vertex buffer
261 		const size_t kBufferSize = numVertices * sizeof(tcu::Vec4);
262 		m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(kBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
263 	}
264 }
265 
setVertices(const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices)266 void StateObjects::setVertices (const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices)
267 {
268 	const vk::VkDevice device			= m_context.getDevice();
269 
270 	tcu::Vec4 *ptr = reinterpret_cast<tcu::Vec4*>(m_vertexBuffer->getBoundMemory().getHostPtr());
271 	std::copy(vertices.begin(), vertices.end(), ptr);
272 
273 	vk::flushAlloc(vk, device,	m_vertexBuffer->getBoundMemory());
274 }
275 
276 enum OcclusionQueryResultSize
277 {
278 	RESULT_SIZE_64_BIT,
279 	RESULT_SIZE_32_BIT,
280 };
281 
282 enum OcclusionQueryWait
283 {
284 	WAIT_QUEUE,
285 	WAIT_QUERY,
286 	WAIT_NONE
287 };
288 
289 enum OcclusionQueryResultsMode
290 {
291 	RESULTS_MODE_GET,
292 	RESULTS_MODE_GET_RESET,
293 	RESULTS_MODE_COPY,
294 	RESULTS_MODE_COPY_RESET
295 };
296 
297 enum OcculusionQueryClearOp
298 {
299 	CLEAR_NOOP,
300 	CLEAR_COLOR,
301 	CLEAR_DEPTH
302 };
303 
304 struct OcclusionQueryTestVector
305 {
306 	vk::VkQueryControlFlags		queryControlFlags;
307 	OcclusionQueryResultSize	queryResultSize;
308 	OcclusionQueryWait			queryWait;
309 	OcclusionQueryResultsMode	queryResultsMode;
310 	vk::VkDeviceSize			queryResultsStride;
311 	bool						queryResultsAvailability;
312 	vk::VkPrimitiveTopology		primitiveTopology;
313 	bool						discardHalf;
314 	deBool						queryResultsDstOffset;
315 	OcculusionQueryClearOp		clearOp;
316 	bool						noColorAttachments;
317 };
318 
319 class BasicOcclusionQueryTestInstance : public vkt::TestInstance
320 {
321 public:
322 					BasicOcclusionQueryTestInstance		(vkt::Context &context, const OcclusionQueryTestVector&  testVector);
323 					~BasicOcclusionQueryTestInstance	(void);
324 private:
325 	tcu::TestStatus	iterate								(void);
326 
327 	enum
328 	{
329 		NUM_QUERIES_IN_POOL				= 2,
330 		QUERY_INDEX_CAPTURE_EMPTY		= 0,
331 		QUERY_INDEX_CAPTURE_DRAWCALL	= 1,
332 		NUM_VERTICES_IN_DRAWCALL		= 3
333 	};
334 
335 	OcclusionQueryTestVector	m_testVector;
336 	StateObjects*				m_stateObjects;
337 	vk::VkQueryPool				m_queryPool;
338 };
339 
BasicOcclusionQueryTestInstance(vkt::Context &context, const OcclusionQueryTestVector& testVector)340 BasicOcclusionQueryTestInstance::BasicOcclusionQueryTestInstance (vkt::Context &context, const OcclusionQueryTestVector&  testVector)
341 	: TestInstance		(context)
342 	, m_testVector		(testVector)
343 {
344 	DE_ASSERT(testVector.queryResultSize			== RESULT_SIZE_64_BIT
345 			&& testVector.queryWait					== WAIT_QUEUE
346 			&& (testVector.queryResultsMode			== RESULTS_MODE_GET || testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
347 			&& testVector.queryResultsStride		== sizeof(deUint64)
348 			&& testVector.queryResultsAvailability	== false
349 			&& testVector.primitiveTopology			== vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
350 
351 	if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) && !m_context.getDeviceFeatures().occlusionQueryPrecise)
352 		throw tcu::NotSupportedError("Precise occlusion queries are not supported");
353 
354 	m_stateObjects = new StateObjects(m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL, m_testVector.primitiveTopology, m_testVector.noColorAttachments);
355 
356 	const vk::VkDevice			device	= m_context.getDevice();
357 	const vk::DeviceInterface&	vk		= m_context.getDeviceInterface();
358 
359 	const vk::VkQueryPoolCreateInfo queryPoolCreateInfo =
360 	{
361 		vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
362 		DE_NULL,
363 		0u,
364 		vk::VK_QUERY_TYPE_OCCLUSION,
365 		NUM_QUERIES_IN_POOL,
366 		0
367 	};
368 	VK_CHECK(vk.createQueryPool(device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL, &m_queryPool));
369 
370 	std::vector<tcu::Vec4> vertices(NUM_VERTICES_IN_DRAWCALL);
371 	vertices[0] = tcu::Vec4(0.5, 0.5, 0.0, 1.0);
372 	vertices[1] = tcu::Vec4(0.5, 0.0, 0.0, 1.0);
373 	vertices[2] = tcu::Vec4(0.0, 0.5, 0.0, 1.0);
374 	m_stateObjects->setVertices(vk, vertices);
375 }
376 
~BasicOcclusionQueryTestInstance(void)377 BasicOcclusionQueryTestInstance::~BasicOcclusionQueryTestInstance (void)
378 {
379 	if (m_stateObjects)
380 		delete m_stateObjects;
381 
382 	if (m_queryPool != DE_NULL)
383 	{
384 #ifndef CTS_USES_VULKANSC
385 		const vk::VkDevice device		= m_context.getDevice();
386 		const vk::DeviceInterface& vk	= m_context.getDeviceInterface();
387 		vk.destroyQueryPool(device, m_queryPool, /*pAllocator*/ DE_NULL);
388 #endif
389 	}
390 }
391 
iterate(void)392 tcu::TestStatus	BasicOcclusionQueryTestInstance::iterate (void)
393 {
394 	tcu::TestLog &log				= m_context.getTestContext().getLog();
395 	const vk::VkDevice device		= m_context.getDevice();
396 	const vk::VkQueue queue			= m_context.getUniversalQueue();
397 	const vk::DeviceInterface& vk	= m_context.getDeviceInterface();
398 
399 	if (m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
400 	{
401 		// Check VK_EXT_host_query_reset is supported
402 		m_context.requireDeviceFunctionality("VK_EXT_host_query_reset");
403 		if(m_context.getHostQueryResetFeatures().hostQueryReset == VK_FALSE)
404 			throw tcu::NotSupportedError(std::string("Implementation doesn't support resetting queries from the host").c_str());
405 	}
406 
407 	const CmdPoolCreateInfo			cmdPoolCreateInfo	(m_context.getUniversalQueueFamilyIndex());
408 	vk::Move<vk::VkCommandPool>		cmdPool				= vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
409 
410 	vk::Unique<vk::VkCommandBuffer> cmdBuffer			(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
411 
412 	beginCommandBuffer(vk, *cmdBuffer);
413 
414 	if (!m_testVector.noColorAttachments)
415 		initialTransitionColor2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
416 									  vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
417 	initialTransitionDepth2DImage(vk, *cmdBuffer, m_stateObjects->m_DepthImage->object(), vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
418 								  vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
419 
420 	std::vector<vk::VkClearValue> renderPassClearValues(2);
421 	deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
422 
423 	if (m_testVector.queryResultsMode != RESULTS_MODE_GET_RESET)
424 		vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
425 
426 	beginRenderPass(vk, *cmdBuffer, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0]);
427 
428 	vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
429 
430 	vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
431 	const vk::VkDeviceSize vertexBufferOffset = 0;
432 	vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
433 
434 	vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_EMPTY, m_testVector.queryControlFlags);
435 	vk.cmdEndQuery(*cmdBuffer, m_queryPool,	QUERY_INDEX_CAPTURE_EMPTY);
436 
437 	vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_DRAWCALL, m_testVector.queryControlFlags);
438 	vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, 0, 0);
439 	vk.cmdEndQuery(*cmdBuffer, m_queryPool,	QUERY_INDEX_CAPTURE_DRAWCALL);
440 
441 	endRenderPass(vk, *cmdBuffer);
442 
443 	if (!m_testVector.noColorAttachments)
444 		transition2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_ASPECT_COLOR_BIT,
445 						  vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
446 						  vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
447 
448 	endCommandBuffer(vk, *cmdBuffer);
449 
450 	if (m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
451 		vk.resetQueryPool(device, m_queryPool, 0, NUM_QUERIES_IN_POOL);
452 
453 	submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
454 
455 	deUint64 queryResults[NUM_QUERIES_IN_POOL] = { 0 };
456 	size_t queryResultsSize		= sizeof(queryResults);
457 
458 	vk::VkResult queryResult	= vk.getQueryPoolResults(device, m_queryPool, 0, NUM_QUERIES_IN_POOL, queryResultsSize, queryResults, sizeof(queryResults[0]), vk::VK_QUERY_RESULT_64_BIT);
459 
460 	if (queryResult == vk::VK_NOT_READY)
461 	{
462 		TCU_FAIL("Query result not avaliable, but vkWaitIdle() was called.");
463 	}
464 
465 	VK_CHECK(queryResult);
466 
467 	log << tcu::TestLog::Section("OcclusionQueryResults",
468 		"Occlusion query results");
469 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(queryResults); ++ndx)
470 	{
471 		log << tcu::TestLog::Message << "query[slot == " << ndx
472 			<< "] result == " << queryResults[ndx] << tcu::TestLog::EndMessage;
473 	}
474 
475 	bool passed = true;
476 
477 	for (int queryNdx = 0; queryNdx < DE_LENGTH_OF_ARRAY(queryResults); ++queryNdx)
478 	{
479 
480 		deUint64 expectedValue;
481 
482 		switch (queryNdx)
483 		{
484 			case QUERY_INDEX_CAPTURE_EMPTY:
485 				expectedValue = 0;
486 				break;
487 			case QUERY_INDEX_CAPTURE_DRAWCALL:
488 				expectedValue = NUM_VERTICES_IN_DRAWCALL;
489 				break;
490 		}
491 
492 		if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) || expectedValue == 0)
493 		{
494 			// require precise value
495 			if (queryResults[queryNdx] != expectedValue)
496 			{
497 				log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
498 					"wrong value of query for index "
499 					<< queryNdx << ", expected " << expectedValue << ", got "
500 					<< queryResults[0] << "." << tcu::TestLog::EndMessage;
501 				passed = false;
502 			}
503 		}
504 		else
505 		{
506 			// require imprecize value > 0
507 			if (queryResults[queryNdx] == 0)
508 			{
509 				log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
510 					"wrong value of query for index "
511 					<< queryNdx << ", expected any non-zero value, got "
512 					<< queryResults[0] << "." << tcu::TestLog::EndMessage;
513 				passed = false;
514 			}
515 		}
516 	}
517 	log << tcu::TestLog::EndSection;
518 
519 	if (passed)
520 	{
521 		return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
522 	}
523 	return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
524 }
525 
526 class OcclusionQueryTestInstance : public vkt::TestInstance
527 {
528 public:
529 	OcclusionQueryTestInstance		(vkt::Context &context, const OcclusionQueryTestVector& testVector);
530 	~OcclusionQueryTestInstance		(void);
531 private:
532 	tcu::TestStatus					iterate							(void);
533 
534 	bool							hasSeparateResetCmdBuf			(void) const;
535 	bool							hasSeparateCopyCmdBuf			(void) const;
536 	void							commandClearAttachment			(const vk::DeviceInterface&	vk, const vk::VkCommandBuffer commandBuffer);
537 
538 	vk::Move<vk::VkCommandBuffer>	recordQueryPoolReset			(vk::VkCommandPool commandPool);
539 	vk::Move<vk::VkCommandBuffer>	recordRender					(vk::VkCommandPool commandPool);
540 	vk::Move<vk::VkCommandBuffer>	recordCopyResults				(vk::VkCommandPool commandPool);
541 
542 	void							captureResults					(deUint64*			retResults,	deUint64*		retAvailability,	bool	allowNotReady);
543 	void							logResults						(const deUint64*	results,	const deUint64* availability);
544 	bool							validateResults					(const deUint64*	results,	const deUint64* availability,		bool	allowUnavailable,	vk::VkPrimitiveTopology primitiveTopology);
545 
546 	enum
547 	{
548 		NUM_QUERIES_IN_POOL							= 3,
549 		QUERY_INDEX_CAPTURE_ALL						= 0,
550 		QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED		= 1,
551 		QUERY_INDEX_CAPTURE_OCCLUDED				= 2
552 	};
553 	enum
554 	{
555 		NUM_VERTICES_IN_DRAWCALL					= 3,
556 		NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL	= 3,
557 		NUM_VERTICES_IN_OCCLUDER_DRAWCALL			= 3,
558 		NUM_VERTICES								= NUM_VERTICES_IN_DRAWCALL + NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL + NUM_VERTICES_IN_OCCLUDER_DRAWCALL
559 	};
560 	enum
561 	{
562 		START_VERTEX								= 0,
563 		START_VERTEX_PARTIALLY_OCCLUDED				= START_VERTEX + NUM_VERTICES_IN_DRAWCALL,
564 		START_VERTEX_OCCLUDER						= START_VERTEX_PARTIALLY_OCCLUDED + NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL
565 	};
566 
567 	OcclusionQueryTestVector		m_testVector;
568 
569 	const vk::VkQueryResultFlags	m_queryResultFlags;
570 
571 	StateObjects*					m_stateObjects;
572 	vk::VkQueryPool					m_queryPool;
573 	de::SharedPtr<Buffer>			m_queryPoolResultsBuffer;
574 
575 	vk::Move<vk::VkCommandPool>		m_commandPool;
576 	vk::Move<vk::VkCommandBuffer>	m_queryPoolResetCommandBuffer;
577 	vk::Move<vk::VkCommandBuffer>	m_renderCommandBuffer;
578 	vk::Move<vk::VkCommandBuffer>	m_copyResultsCommandBuffer;
579 };
580 
OcclusionQueryTestInstance(vkt::Context &context, const OcclusionQueryTestVector& testVector)581 OcclusionQueryTestInstance::OcclusionQueryTestInstance (vkt::Context &context, const OcclusionQueryTestVector& testVector)
582 	: vkt::TestInstance		(context)
583 	, m_testVector			(testVector)
584 	, m_queryResultFlags	(((m_testVector.queryWait == WAIT_QUERY && m_testVector.queryResultsMode != RESULTS_MODE_COPY_RESET)? vk::VK_QUERY_RESULT_WAIT_BIT				: 0)
585 							| (m_testVector.queryResultSize == RESULT_SIZE_64_BIT												? vk::VK_QUERY_RESULT_64_BIT				: 0)
586 							| (m_testVector.queryResultsAvailability															? vk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT	: 0))
587 {
588 	const vk::VkDevice			device				= m_context.getDevice();
589 	const vk::DeviceInterface&	vk					= m_context.getDeviceInterface();
590 
591 	if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) && !m_context.getDeviceFeatures().occlusionQueryPrecise)
592 		throw tcu::NotSupportedError("Precise occlusion queries are not supported");
593 
594 	m_stateObjects  = new StateObjects(m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL + NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL + NUM_VERTICES_IN_OCCLUDER_DRAWCALL, m_testVector.primitiveTopology, m_testVector.noColorAttachments);
595 
596 	const vk::VkQueryPoolCreateInfo queryPoolCreateInfo	=
597 	{
598 		vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
599 		DE_NULL,
600 		0u,
601 		vk::VK_QUERY_TYPE_OCCLUSION,
602 		NUM_QUERIES_IN_POOL,
603 		0
604 	};
605 
606 	VK_CHECK(vk.createQueryPool(device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL, &m_queryPool));
607 
608 	if (m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
609 	{
610 		deUint32				numQueriesinPool			= NUM_QUERIES_IN_POOL + (m_testVector.queryResultsDstOffset ? 1 : 0);
611 		const vk::VkDeviceSize	elementSize					= m_testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
612 		const vk::VkDeviceSize	resultsBufferSize			= m_testVector.queryResultsStride == 0
613 															? (elementSize + elementSize * m_testVector.queryResultsAvailability) * numQueriesinPool
614 															: m_testVector.queryResultsStride * numQueriesinPool;
615 								m_queryPoolResultsBuffer	= Buffer::createAndAlloc(vk, device, BufferCreateInfo(resultsBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
616 	}
617 
618 	const CmdPoolCreateInfo	cmdPoolCreateInfo		(m_context.getUniversalQueueFamilyIndex());
619 							m_commandPool			= vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
620 							m_renderCommandBuffer	= recordRender(*m_commandPool);
621 
622 	if (hasSeparateResetCmdBuf())
623 	{
624 		m_queryPoolResetCommandBuffer	= recordQueryPoolReset(*m_commandPool);
625 	}
626 
627 	if (hasSeparateCopyCmdBuf())
628 	{
629 		m_copyResultsCommandBuffer = recordCopyResults(*m_commandPool);
630 	}
631 }
632 
~OcclusionQueryTestInstance(void)633 OcclusionQueryTestInstance::~OcclusionQueryTestInstance (void)
634 {
635 
636 	if (m_stateObjects)
637 		delete m_stateObjects;
638 
639 	if (m_queryPool != DE_NULL)
640 	{
641 #ifndef CTS_USES_VULKANSC
642 		const vk::VkDevice device		= m_context.getDevice();
643 		const vk::DeviceInterface& vk	= m_context.getDeviceInterface();
644 		vk.destroyQueryPool(device, m_queryPool, /*pAllocator*/ DE_NULL);
645 #endif
646 	}
647 }
648 
iterate(void)649 tcu::TestStatus OcclusionQueryTestInstance::iterate (void)
650 {
651 	const vk::VkQueue			queue		= m_context.getUniversalQueue();
652 	const vk::DeviceInterface&	vk			= m_context.getDeviceInterface();
653 	tcu::TestLog&				log			= m_context.getTestContext().getLog();
654 	std::vector<tcu::Vec4>		vertices	(NUM_VERTICES);
655 
656 	if (m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
657 	{
658 		// Check VK_EXT_host_query_reset is supported
659 		m_context.requireDeviceFunctionality("VK_EXT_host_query_reset");
660 		if(m_context.getHostQueryResetFeatures().hostQueryReset == VK_FALSE)
661 			throw tcu::NotSupportedError(std::string("Implementation doesn't support resetting queries from the host").c_str());
662 	}
663 
664 	// 1st triangle
665 	vertices[START_VERTEX + 0] = tcu::Vec4( 0.5,  0.5, 0.5, 1.0);
666 	vertices[START_VERTEX + 1] = tcu::Vec4( 0.5, -0.5, 0.5, 1.0);
667 	vertices[START_VERTEX + 2] = tcu::Vec4(-0.5,  0.5, 0.5, 1.0);
668 	// 2nd triangle - partially occluding the scene
669 	vertices[START_VERTEX_PARTIALLY_OCCLUDED + 0] = tcu::Vec4(-0.5, -0.5, 1.0, 1.0);
670 	vertices[START_VERTEX_PARTIALLY_OCCLUDED + 1] = tcu::Vec4( 0.5, -0.5, 1.0, 1.0);
671 	vertices[START_VERTEX_PARTIALLY_OCCLUDED + 2] = tcu::Vec4(-0.5,  0.5, 1.0, 1.0);
672 	// 3nd triangle - fully occluding the scene
673 	vertices[START_VERTEX_OCCLUDER + 0] = tcu::Vec4( 0.5,  0.5, 1.0, 1.0);
674 	vertices[START_VERTEX_OCCLUDER + 1] = tcu::Vec4( 0.5, -0.5, 1.0, 1.0);
675 	vertices[START_VERTEX_OCCLUDER + 2] = tcu::Vec4(-0.5,  0.5, 1.0, 1.0);
676 
677 	m_stateObjects->setVertices(vk, vertices);
678 
679 	if (hasSeparateResetCmdBuf())
680 	{
681 		const vk::VkSubmitInfo		submitInfoReset =
682 		{
683 			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,			// VkStructureType			sType;
684 			DE_NULL,									// const void*				pNext;
685 			0u,											// deUint32					waitSemaphoreCount;
686 			DE_NULL,									// const VkSemaphore*		pWaitSemaphores;
687 			(const vk::VkPipelineStageFlags*)DE_NULL,
688 			1u,											// deUint32					commandBufferCount;
689 			&m_queryPoolResetCommandBuffer.get(),		// const VkCommandBuffer*	pCommandBuffers;
690 			0u,											// deUint32					signalSemaphoreCount;
691 			DE_NULL										// const VkSemaphore*		pSignalSemaphores;
692 		};
693 
694 		vk.queueSubmit(queue, 1, &submitInfoReset, DE_NULL);
695 
696 		// Trivially wait for reset to complete. This is to ensure the query pool is in reset state before
697 		// host accesses, so as to not insert any synchronization before capturing the results needed for WAIT_NONE
698 		// variant of test.
699 		VK_CHECK(vk.queueWaitIdle(queue));
700 	}
701 
702 	{
703 		const vk::VkSubmitInfo submitInfoRender =
704 		{
705 			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
706 			DE_NULL,							// const void*				pNext;
707 			0,									// deUint32					waitSemaphoreCount;
708 			DE_NULL,							// const VkSemaphore*		pWaitSemaphores;
709 			(const vk::VkPipelineStageFlags*)DE_NULL,
710 			1,									// deUint32					commandBufferCount;
711 			&m_renderCommandBuffer.get(),		// const VkCommandBuffer*	pCommandBuffers;
712 			0,									// deUint32					signalSemaphoreCount;
713 			DE_NULL								// const VkSemaphore*		pSignalSemaphores;
714 		};
715 
716 		if (!hasSeparateResetCmdBuf() && m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
717 			vk.resetQueryPool(m_context.getDevice(), m_queryPool, 0, NUM_QUERIES_IN_POOL);
718 		vk.queueSubmit(queue, 1, &submitInfoRender, DE_NULL);
719 	}
720 
721 	if (m_testVector.queryWait == WAIT_QUEUE)
722 	{
723 		VK_CHECK(vk.queueWaitIdle(queue));
724 	}
725 
726 	if (hasSeparateCopyCmdBuf())
727 	{
728 		// In case of WAIT_QUEUE test variant, the previously submitted m_renderCommandBuffer did not
729 		// contain vkCmdCopyQueryResults, so additional cmd buffer is needed.
730 
731 		// In the case of WAIT_NONE or WAIT_QUERY, vkCmdCopyQueryResults is stored in m_renderCommandBuffer.
732 
733 		const vk::VkSubmitInfo submitInfo =
734 		{
735 			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
736 			DE_NULL,							// const void*				pNext;
737 			0,									// deUint32					waitSemaphoreCount;
738 			DE_NULL,							// const VkSemaphore*		pWaitSemaphores;
739 			(const vk::VkPipelineStageFlags*)DE_NULL,
740 			1,									// deUint32					commandBufferCount;
741 			&m_copyResultsCommandBuffer.get(),	// const VkCommandBuffer*	pCommandBuffers;
742 			0,									// deUint32					signalSemaphoreCount;
743 			DE_NULL								// const VkSemaphore*		pSignalSemaphores;
744 		};
745 		vk.queueSubmit(queue, 1, &submitInfo, DE_NULL);
746 	}
747 
748 	if (m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
749 	{
750 		// In case of vkCmdCopyQueryResults is used, test must always wait for it
751 		// to complete before we can read the result buffer.
752 
753 		VK_CHECK(vk.queueWaitIdle(queue));
754 	}
755 
756 	deUint64	queryResults		[NUM_QUERIES_IN_POOL];
757 	deUint64	queryAvailability	[NUM_QUERIES_IN_POOL];
758 
759 	// Allow not ready results only if nobody waited before getting the query results
760 	const bool	allowNotReady		= (m_testVector.queryWait == WAIT_NONE);
761 
762 	captureResults(queryResults, queryAvailability, allowNotReady);
763 
764 	log << tcu::TestLog::Section("OcclusionQueryResults", "Occlusion query results");
765 
766 	logResults(queryResults, queryAvailability);
767 	bool passed = validateResults(queryResults, queryAvailability, allowNotReady, m_testVector.primitiveTopology);
768 
769 	log << tcu::TestLog::EndSection;
770 
771 	if (m_testVector.queryResultsMode != RESULTS_MODE_COPY && m_testVector.queryResultsMode != RESULTS_MODE_COPY_RESET)
772 	{
773 		VK_CHECK(vk.queueWaitIdle(queue));
774 	}
775 
776 		if (passed)
777 	{
778 		return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
779 	}
780 	return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
781 }
782 
hasSeparateResetCmdBuf(void) const783 bool OcclusionQueryTestInstance::hasSeparateResetCmdBuf (void) const
784 {
785 	// Determine if resetting query pool should be performed in separate command buffer
786 	// to avoid race condition between host query access and device query reset.
787 
788 	if (m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
789 	{
790 		// We copy query results on device, so there is no race condition between
791 		// host and device
792 		return false;
793 	}
794 	if (m_testVector.queryWait == WAIT_QUEUE)
795 	{
796 		// We wait for queue to be complete before accessing query results
797 		return false;
798 	}
799 
800 	// Separate command buffer with reset must be submitted & completed before
801 	// host accesses the query results
802 	return true;
803 }
804 
hasSeparateCopyCmdBuf(void) const805 bool OcclusionQueryTestInstance::hasSeparateCopyCmdBuf (void) const
806 {
807 	// Copy query results must go into separate command buffer, if we want to wait on queue before that
808 	return ((m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
809 			&& m_testVector.queryWait == WAIT_QUEUE);
810 }
811 
recordQueryPoolReset(vk::VkCommandPool cmdPool)812 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordQueryPoolReset (vk::VkCommandPool cmdPool)
813 {
814 	const vk::VkDevice				device		= m_context.getDevice();
815 	const vk::DeviceInterface&		vk			= m_context.getDeviceInterface();
816 
817 	DE_ASSERT(hasSeparateResetCmdBuf());
818 
819 	vk::Move<vk::VkCommandBuffer>	cmdBuffer	(vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
820 
821 	beginCommandBuffer(vk, *cmdBuffer);
822 	vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
823 	endCommandBuffer(vk, *cmdBuffer);
824 
825 	return cmdBuffer;
826 }
827 
commandClearAttachment(const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer)828 void OcclusionQueryTestInstance::commandClearAttachment (const vk::DeviceInterface&	vk,
829 														 const vk::VkCommandBuffer	commandBuffer)
830 {
831 	if (m_testVector.clearOp == CLEAR_NOOP)
832 		return;
833 
834 	const vk::VkOffset2D offset = vk::makeOffset2D(0, 0);
835 	const vk::VkExtent2D extent = vk::makeExtent2D(StateObjects::WIDTH, StateObjects::HEIGHT);
836 
837 	const vk::VkClearAttachment	attachment =
838 	{
839 		m_testVector.clearOp == CLEAR_COLOR ? vk::VK_IMAGE_ASPECT_COLOR_BIT	: vk::VK_IMAGE_ASPECT_DEPTH_BIT, // VkImageAspectFlags	aspectMask;
840 		m_testVector.clearOp == CLEAR_COLOR ? 0u : 1u,														 // uint32_t			colorAttachment;
841 		m_testVector.clearOp == CLEAR_COLOR ? vk::makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f)) :
842 											  vk::makeClearValueDepthStencil(0.0f, 0u)						 // VkClearValue		clearValue;
843 	};
844 
845 	const vk::VkClearRect rect =
846 	{
847 		{ offset, extent },		// VkRect2D		rect;
848 		0u,						// uint32_t		baseArrayLayer;
849 		1u,						// uint32_t		layerCount;
850 	};
851 
852 	vk.cmdClearAttachments(commandBuffer, 1u, &attachment, 1u, &rect);
853 }
854 
recordRender(vk::VkCommandPool cmdPool)855 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordRender (vk::VkCommandPool cmdPool)
856 {
857 	const vk::VkDevice				device		= m_context.getDevice();
858 	const vk::DeviceInterface&		vk			= m_context.getDeviceInterface();
859 
860 	vk::Move<vk::VkCommandBuffer>	cmdBuffer	(vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
861 
862 	beginCommandBuffer(vk, *cmdBuffer);
863 
864 	if (!m_testVector.noColorAttachments)
865 		initialTransitionColor2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
866 									  vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
867 
868 	initialTransitionDepth2DImage(vk, *cmdBuffer, m_stateObjects->m_DepthImage->object(), vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
869 								  vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
870 
871 	std::vector<vk::VkClearValue>	renderPassClearValues(2);
872 	deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
873 
874 	if (!hasSeparateResetCmdBuf() && m_testVector.queryResultsMode != RESULTS_MODE_GET_RESET)
875 	{
876 		vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
877 	}
878 
879 	beginRenderPass(vk, *cmdBuffer, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0]);
880 
881 	vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS,	*m_stateObjects->m_pipeline);
882 
883 	vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
884 	const vk::VkDeviceSize vertexBufferOffset = 0;
885 	vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
886 
887 	// Draw un-occluded geometry
888 	vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_ALL, m_testVector.queryControlFlags);
889 	vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
890 	commandClearAttachment(vk, *cmdBuffer);
891 	vk.cmdEndQuery(*cmdBuffer, m_queryPool,	QUERY_INDEX_CAPTURE_ALL);
892 
893 	endRenderPass(vk, *cmdBuffer);
894 
895 	beginRenderPass(vk, *cmdBuffer, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0]);
896 
897 	vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
898 
899 	// Draw un-occluded geometry
900 	vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
901 
902 	// Partially occlude geometry
903 	vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL, 1, START_VERTEX_PARTIALLY_OCCLUDED, 0);
904 
905 	// Draw partially-occluded geometry
906 	vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED, m_testVector.queryControlFlags);
907 	vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
908 	commandClearAttachment(vk, *cmdBuffer);
909 	vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED);
910 
911 	endRenderPass(vk, *cmdBuffer);
912 
913 	beginRenderPass(vk, *cmdBuffer, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0]);
914 
915 	vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
916 
917 	// Draw un-occluded geometry
918 	vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
919 
920 	// Partially occlude geometry
921 	vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL, 1, START_VERTEX_PARTIALLY_OCCLUDED, 0);
922 
923 	// Occlude geometry
924 	vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_OCCLUDER_DRAWCALL, 1, START_VERTEX_OCCLUDER, 0);
925 
926 	// Draw occluded geometry
927 	vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_OCCLUDED, m_testVector.queryControlFlags);
928 	vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
929 	commandClearAttachment(vk, *cmdBuffer);
930 	vk.cmdEndQuery(*cmdBuffer, m_queryPool,	QUERY_INDEX_CAPTURE_OCCLUDED);
931 
932 	endRenderPass(vk, *cmdBuffer);
933 
934 	if (m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
935 	{
936 		vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
937 	}
938 
939 	if ((m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
940 		&& !hasSeparateCopyCmdBuf())
941 	{
942 		vk::VkDeviceSize dstOffset = m_testVector.queryResultsDstOffset ? m_testVector.queryResultsStride : 0u;
943 
944 		if (m_testVector.queryResultsStride != 0u)
945 		{
946 			vk.cmdCopyQueryPoolResults(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL, m_queryPoolResultsBuffer->object(), dstOffset, m_testVector.queryResultsStride, m_queryResultFlags);
947 		}
948 		else
949 		{
950 			const vk::VkDeviceSize	elementSize	= m_testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
951 			const vk::VkDeviceSize	strideSize	= elementSize + elementSize * m_testVector.queryResultsAvailability;
952 
953 			for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; queryNdx++)
954 			{
955 				vk.cmdCopyQueryPoolResults(*cmdBuffer, m_queryPool, queryNdx, 1, m_queryPoolResultsBuffer->object(), strideSize * queryNdx, 0, m_queryResultFlags);
956 			}
957 		}
958 
959 		bufferBarrier(vk, *cmdBuffer, m_queryPoolResultsBuffer->object(), vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT);
960 	}
961 
962 	if (!m_testVector.noColorAttachments)
963 		transition2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_ASPECT_COLOR_BIT, vk::VK_IMAGE_LAYOUT_GENERAL,
964 						  vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT,
965 						  vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
966 
967 	endCommandBuffer(vk, *cmdBuffer);
968 
969 	return cmdBuffer;
970 }
971 
recordCopyResults(vk::VkCommandPool cmdPool)972 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordCopyResults (vk::VkCommandPool cmdPool)
973 {
974 	const vk::VkDevice				device		= m_context.getDevice();
975 	const vk::DeviceInterface&		vk			= m_context.getDeviceInterface();
976 
977 	vk::Move<vk::VkCommandBuffer>	cmdBuffer	(vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
978 
979 	beginCommandBuffer(vk, *cmdBuffer);
980 
981 	vk::VkDeviceSize dstOffset = m_testVector.queryResultsDstOffset ? m_testVector.queryResultsStride : 0u;
982 
983 	if (m_testVector.queryResultsStride != 0u)
984 	{
985 		vk.cmdCopyQueryPoolResults(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL, m_queryPoolResultsBuffer->object(), dstOffset, m_testVector.queryResultsStride, m_queryResultFlags);
986 	}
987 	else
988 	{
989 		const vk::VkDeviceSize	elementSize	= m_testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
990 		const vk::VkDeviceSize	strideSize	= elementSize + elementSize * m_testVector.queryResultsAvailability;
991 
992 		for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; queryNdx++)
993 		{
994 			vk.cmdCopyQueryPoolResults(*cmdBuffer, m_queryPool, queryNdx, 1, m_queryPoolResultsBuffer->object(), strideSize * queryNdx, 0, m_queryResultFlags);
995 		}
996 	}
997 
998 	bufferBarrier(vk, *cmdBuffer, m_queryPoolResultsBuffer->object(), vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT);
999 
1000 	endCommandBuffer(vk, *cmdBuffer);
1001 
1002 	return cmdBuffer;
1003 }
1004 
captureResults(deUint64* retResults, deUint64* retAvailAbility, bool allowNotReady)1005 void OcclusionQueryTestInstance::captureResults (deUint64* retResults, deUint64* retAvailAbility, bool allowNotReady)
1006 {
1007 	const vk::VkDevice			device			= m_context.getDevice();
1008 	const vk::DeviceInterface&	vk				= m_context.getDeviceInterface();
1009 	const vk::VkDeviceSize		elementSize		= m_testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
1010 	const vk::VkDeviceSize		resultsSize		= m_testVector.queryResultsStride == 0
1011 												? elementSize + elementSize * m_testVector.queryResultsAvailability
1012 												: m_testVector.queryResultsStride;
1013 	std::vector<deUint8>		resultsBuffer	(static_cast<size_t>(resultsSize * NUM_QUERIES_IN_POOL));
1014 
1015 	if (m_testVector.queryResultsMode == RESULTS_MODE_GET || m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
1016 	{
1017 		vk::VkResult queryResult = vk.getQueryPoolResults(device, m_queryPool, 0, NUM_QUERIES_IN_POOL, resultsBuffer.size(), &resultsBuffer[0], m_testVector.queryResultsStride, m_queryResultFlags);
1018 		if (queryResult == vk::VK_NOT_READY && !allowNotReady)
1019 		{
1020 			TCU_FAIL("getQueryPoolResults returned VK_NOT_READY, but results should be already available.");
1021 		}
1022 		else
1023 		{
1024 			VK_CHECK(queryResult);
1025 		}
1026 	}
1027 	else if (m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
1028 	{
1029 		const vk::Allocation& allocation = m_queryPoolResultsBuffer->getBoundMemory();
1030 		const deUint8* allocationData = static_cast<deUint8*>(allocation.getHostPtr());
1031 		const deInt32 indexData = m_testVector.queryResultsDstOffset ? (deInt32)m_testVector.queryResultsStride : 0u;
1032 
1033 		vk::invalidateAlloc(vk, device, allocation);
1034 
1035 		deMemcpy(&resultsBuffer[0], &allocationData[indexData], resultsBuffer.size());
1036 	}
1037 
1038 	for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; queryNdx++)
1039 	{
1040 		const void* srcPtr = &resultsBuffer[queryNdx * static_cast<size_t>(resultsSize)];
1041 
1042 		if (m_testVector.queryResultSize == RESULT_SIZE_32_BIT)
1043 		{
1044 			const deUint32* srcPtrTyped = static_cast<const deUint32*>(srcPtr);
1045 			retResults[queryNdx]		= *srcPtrTyped;
1046 			if (m_testVector.queryResultsAvailability)
1047 			{
1048 				retAvailAbility[queryNdx] = *(srcPtrTyped + 1);
1049 			}
1050 		}
1051 		else if (m_testVector.queryResultSize == RESULT_SIZE_64_BIT)
1052 		{
1053 			const deUint64* srcPtrTyped = static_cast<const deUint64*>(srcPtr);
1054 			retResults[queryNdx]		= *srcPtrTyped;
1055 
1056 			if (m_testVector.queryResultsAvailability)
1057 			{
1058 				retAvailAbility[queryNdx] = *(srcPtrTyped + 1);
1059 			}
1060 		}
1061 		else
1062 		{
1063 			TCU_FAIL("Wrong m_testVector.queryResultSize");
1064 		}
1065 	}
1066 
1067 	if (m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
1068 	{
1069 		vk.resetQueryPool(device, m_queryPool, 0, NUM_QUERIES_IN_POOL);
1070 
1071 		vk::VkResult queryResult = vk.getQueryPoolResults(device, m_queryPool, 0, NUM_QUERIES_IN_POOL, resultsBuffer.size(), &resultsBuffer[0], m_testVector.queryResultsStride, m_queryResultFlags);
1072 
1073 		if (queryResult != vk::VK_NOT_READY)
1074 		{
1075 			TCU_FAIL("getQueryPoolResults did not return VK_NOT_READY");
1076 		}
1077 
1078 		/* From Vulkan spec:
1079 		 *
1080 		 * If VK_QUERY_RESULT_WAIT_BIT and VK_QUERY_RESULT_PARTIAL_BIT are both not set then no result values are written to pData
1081 		 * for queries that are in the unavailable state at the time of the call, and vkGetQueryPoolResults returns VK_NOT_READY.
1082 		 * However, availability state is still written to pData for those queries if VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set.
1083 		 */
1084 		for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; queryNdx++)
1085 		{
1086 			const void* srcPtr = &resultsBuffer[queryNdx * static_cast<size_t>(resultsSize)];
1087 			if (m_testVector.queryResultSize == RESULT_SIZE_32_BIT)
1088 			{
1089 				const deUint32* srcPtrTyped = static_cast<const deUint32*>(srcPtr);
1090 				if (*srcPtrTyped != retResults[queryNdx])
1091 				{
1092 					TCU_FAIL("getQueryPoolResults returned modified values");
1093 				}
1094 
1095 				if (m_testVector.queryResultsAvailability && *(srcPtrTyped + 1) != 0)
1096 				{
1097 					TCU_FAIL("resetQueryPool did not disable availability bit");
1098 				}
1099 			}
1100 			else if (m_testVector.queryResultSize == RESULT_SIZE_64_BIT)
1101 			{
1102 				const deUint64* srcPtrTyped = static_cast<const deUint64*>(srcPtr);
1103 				if (*srcPtrTyped != retResults[queryNdx])
1104 				{
1105 					TCU_FAIL("getQueryPoolResults returned modified values");
1106 				}
1107 
1108 				if (m_testVector.queryResultsAvailability && *(srcPtrTyped + 1) != 0)
1109 				{
1110 					TCU_FAIL("resetQueryPool did not disable availability bit");
1111 				}
1112 			}
1113 			else
1114 			{
1115 				TCU_FAIL("Wrong m_testVector.queryResultSize");
1116 			}
1117 		}
1118 	}
1119 }
1120 
logResults(const deUint64* results, const deUint64* availability)1121 void OcclusionQueryTestInstance::logResults (const deUint64* results, const deUint64* availability)
1122 {
1123 	tcu::TestLog& log = m_context.getTestContext().getLog();
1124 
1125 	for (int ndx = 0; ndx < NUM_QUERIES_IN_POOL; ++ndx)
1126 	{
1127 		if (!m_testVector.queryResultsAvailability)
1128 		{
1129 			log << tcu::TestLog::Message << "query[slot == " << ndx << "] result == " << results[ndx] << tcu::TestLog::EndMessage;
1130 		}
1131 		else
1132 		{
1133 			log << tcu::TestLog::Message << "query[slot == " << ndx << "] result == " << results[ndx] << ", availability == " << availability[ndx] << tcu::TestLog::EndMessage;
1134 		}
1135 	}
1136 }
1137 
validateResults(const deUint64* results , const deUint64* availability, bool allowUnavailable, vk::VkPrimitiveTopology primitiveTopology)1138 bool OcclusionQueryTestInstance::validateResults (const deUint64* results , const deUint64* availability, bool allowUnavailable, vk::VkPrimitiveTopology primitiveTopology)
1139 {
1140 	bool passed			= true;
1141 	tcu::TestLog& log	= m_context.getTestContext().getLog();
1142 
1143 	for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; ++queryNdx)
1144 	{
1145 		deUint64 expectedValueMin = 0;
1146 		deUint64 expectedValueMax = 0;
1147 
1148 		if (m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
1149 		{
1150 			DE_ASSERT(m_testVector.queryResultsAvailability);
1151 			if (availability[queryNdx] != 0)
1152 			{
1153 				// In copy-reset mode results should always be unavailable due to the reset command issued before copying results.
1154 				log << tcu::TestLog::Message << "query results availability was nonzero for index "
1155 					<< queryNdx << " when resetting the query before copying results"
1156 					<< tcu::TestLog::EndMessage;
1157 				passed = false;
1158 			}
1159 
1160 			// Not interested in the actual results.
1161 			continue;
1162 		}
1163 		else if (m_testVector.queryResultsAvailability && availability[queryNdx] == 0)
1164 		{
1165 			// query result was not available
1166 			if (!allowUnavailable)
1167 			{
1168 				log << tcu::TestLog::Message << "query results availability was 0 for index "
1169 					<< queryNdx << ", expected any value greater than 0." << tcu::TestLog::EndMessage;
1170 				passed = false;
1171 				continue;
1172 			}
1173 		}
1174 		else
1175 		{
1176 			// query is available, so expect proper result values
1177 			if (primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
1178 			{
1179 				switch (queryNdx)
1180 				{
1181 					case QUERY_INDEX_CAPTURE_OCCLUDED:
1182 						expectedValueMin = 0;
1183 						expectedValueMax = 0;
1184 						break;
1185 					case QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED:
1186 						expectedValueMin = 1;
1187 						expectedValueMax = 1;
1188 						break;
1189 					case QUERY_INDEX_CAPTURE_ALL:
1190 						expectedValueMin = NUM_VERTICES_IN_DRAWCALL;
1191 						expectedValueMax = NUM_VERTICES_IN_DRAWCALL;
1192 						break;
1193 				}
1194 			}
1195 			else if (primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
1196 			{
1197 				switch (queryNdx)
1198 				{
1199 					case QUERY_INDEX_CAPTURE_OCCLUDED:
1200 						expectedValueMin = 0;
1201 						expectedValueMax = 0;
1202 						break;
1203 					case QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED:
1204 					case QUERY_INDEX_CAPTURE_ALL:
1205 						{
1206 							const int primWidth		= StateObjects::WIDTH  / 2;
1207 							const int primHeight	= StateObjects::HEIGHT / 2;
1208 							const int primArea		= primWidth * primHeight / 2;
1209 
1210 							if (m_testVector.discardHalf)
1211 							{
1212 								expectedValueMin	= (int)(0.95f * primArea * 0.5f);
1213 								expectedValueMax	= (int)(1.05f * primArea * 0.5f);
1214 							}
1215 							else
1216 							{
1217 								expectedValueMin	= (int)(0.97f * primArea);
1218 								expectedValueMax	= (int)(1.03f * primArea);
1219 							}
1220 						}
1221 				}
1222 			}
1223 			else
1224 			{
1225 				TCU_FAIL("Unsupported primitive topology");
1226 			}
1227 		}
1228 
1229 		if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) || (expectedValueMin == 0 && expectedValueMax == 0))
1230 		{
1231 			// require precise value
1232 			if (results[queryNdx] < expectedValueMin || results[queryNdx] > expectedValueMax)
1233 			{
1234 				log << tcu::TestLog::Message << "wrong value of query for index "
1235 					<< queryNdx << ", expected the value minimum of " << expectedValueMin << ", maximum of " << expectedValueMax << " got "
1236 					<< results[queryNdx] << "." << tcu::TestLog::EndMessage;
1237 				passed = false;
1238 			}
1239 		}
1240 		else
1241 		{
1242 			// require imprecise value greater than 0
1243 			if (results[queryNdx] == 0)
1244 			{
1245 				log << tcu::TestLog::Message << "wrong value of query for index "
1246 					<< queryNdx << ", expected any non-zero value, got "
1247 					<< results[queryNdx] << "." << tcu::TestLog::EndMessage;
1248 				passed = false;
1249 			}
1250 		}
1251 	}
1252 	return passed;
1253 }
1254 
1255 template<class Instance>
1256 class QueryPoolOcclusionTest : public vkt::TestCase
1257 {
1258 public:
QueryPoolOcclusionTest(tcu::TestContext &context, const char *name, const char *description, const OcclusionQueryTestVector& testVector)1259 	QueryPoolOcclusionTest (tcu::TestContext &context, const char *name, const char *description, const OcclusionQueryTestVector& testVector)
1260 		: TestCase			(context, name, description)
1261 		, m_testVector		(testVector)
1262 	{
1263 	}
1264 private:
createInstance(vkt::Context& context) const1265 	vkt::TestInstance* createInstance (vkt::Context& context) const
1266 	{
1267 		return new Instance(context, m_testVector);
1268 	}
1269 
initPrograms(vk::SourceCollections& programCollection) const1270 	void initPrograms(vk::SourceCollections& programCollection) const
1271 	{
1272 		const char* const discard =
1273 			"	if ((int(gl_FragCoord.x) % 2) == (int(gl_FragCoord.y) % 2))\n"
1274 			"		discard;\n";
1275 
1276 		const std::string fragSrc = std::string(
1277 			"#version 400\n"
1278 			"layout(location = 0) out vec4 out_FragColor;\n"
1279 			"void main()\n"
1280 			"{\n"
1281 			"	out_FragColor = vec4(0.07, 0.48, 0.75, 1.0);\n")
1282 			+ std::string(m_testVector.discardHalf ? discard : "")
1283 			+ "}\n";
1284 
1285 		programCollection.glslSources.add("frag") << glu::FragmentSource(fragSrc.c_str());
1286 
1287 		programCollection.glslSources.add("vert") << glu::VertexSource("#version 430\n"
1288 																		 "layout(location = 0) in vec4 in_Position;\n"
1289 																		 "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
1290 																		 "void main() {\n"
1291 																		 "	gl_Position  = in_Position;\n"
1292 																		 "	gl_PointSize = 1.0;\n"
1293 																		 "}\n");
1294 	}
1295 
1296 	OcclusionQueryTestVector m_testVector;
1297 };
1298 
1299 } //anonymous
1300 
QueryPoolOcclusionTests(tcu::TestContext &testCtx)1301 QueryPoolOcclusionTests::QueryPoolOcclusionTests (tcu::TestContext &testCtx)
1302 	: TestCaseGroup(testCtx, "occlusion_query", "Tests for occlusion queries")
1303 {
1304 	/* Left blank on purpose */
1305 }
1306 
~QueryPoolOcclusionTests(void)1307 QueryPoolOcclusionTests::~QueryPoolOcclusionTests (void)
1308 {
1309 	/* Left blank on purpose */
1310 }
1311 
init(void)1312 void QueryPoolOcclusionTests::init (void)
1313 {
1314 	OcclusionQueryTestVector baseTestVector;
1315 	baseTestVector.queryControlFlags		= 0;
1316 	baseTestVector.queryResultSize			= RESULT_SIZE_64_BIT;
1317 	baseTestVector.queryWait				= WAIT_QUEUE;
1318 	baseTestVector.queryResultsMode			= RESULTS_MODE_GET;
1319 	baseTestVector.queryResultsStride		= sizeof(deUint64);
1320 	baseTestVector.queryResultsAvailability = false;
1321 	baseTestVector.primitiveTopology		= vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
1322 	baseTestVector.discardHalf				= false;
1323 	baseTestVector.clearOp					= CLEAR_NOOP;
1324 	baseTestVector.noColorAttachments		= false;
1325 
1326 	//Basic tests
1327 	{
1328 		OcclusionQueryTestVector testVector = baseTestVector;
1329 		testVector.queryControlFlags = 0;
1330 		addChild(new QueryPoolOcclusionTest<BasicOcclusionQueryTestInstance>(m_testCtx,	"basic_conservative",	"draw with conservative occlusion query",	testVector));
1331 		testVector.queryControlFlags = vk::VK_QUERY_CONTROL_PRECISE_BIT;
1332 		addChild(new QueryPoolOcclusionTest<BasicOcclusionQueryTestInstance>(m_testCtx,	"basic_precise",		"draw with precise occlusion query",		testVector));
1333 	}
1334 
1335 	// Functional test
1336 	{
1337 		const vk::VkQueryControlFlags	controlFlags[]		= { 0,					vk::VK_QUERY_CONTROL_PRECISE_BIT	};
1338 		const char* const				controlFlagsStr[]	= { "conservative",		"precise"							};
1339 
1340 		for (int controlFlagIdx = 0; controlFlagIdx < DE_LENGTH_OF_ARRAY(controlFlags); ++controlFlagIdx)
1341 		{
1342 
1343 			const vk::VkPrimitiveTopology	primitiveTopology[]		= { vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST };
1344 			const char* const				primitiveTopologyStr[]	= { "points", "triangles" };
1345 			for (int primitiveTopologyIdx = 0; primitiveTopologyIdx < DE_LENGTH_OF_ARRAY(primitiveTopology); ++primitiveTopologyIdx)
1346 			{
1347 
1348 				const OcclusionQueryResultSize	resultSize[]	= { RESULT_SIZE_32_BIT, RESULT_SIZE_64_BIT };
1349 				const char* const				resultSizeStr[] = { "32",				"64" };
1350 
1351 				for (int resultSizeIdx = 0; resultSizeIdx < DE_LENGTH_OF_ARRAY(resultSize); ++resultSizeIdx)
1352 				{
1353 
1354 					const OcclusionQueryWait	wait[]		= { WAIT_QUEUE, WAIT_QUERY };
1355 					const char* const			waitStr[]	= { "queue",	"query" };
1356 
1357 					for (int waitIdx = 0; waitIdx < DE_LENGTH_OF_ARRAY(wait); ++waitIdx)
1358 					{
1359 						const OcclusionQueryResultsMode	resultsMode[]		= { RESULTS_MODE_GET,	RESULTS_MODE_GET_RESET,	RESULTS_MODE_COPY,	RESULTS_MODE_COPY_RESET };
1360 						const char* const				resultsModeStr[]	= { "get",				"get_reset",			"copy",				"copy_reset" };
1361 
1362 						for (int resultsModeIdx = 0; resultsModeIdx < DE_LENGTH_OF_ARRAY(resultsMode); ++resultsModeIdx)
1363 						{
1364 							if (wait[waitIdx] == WAIT_QUERY && resultsMode[resultsModeIdx] == RESULTS_MODE_GET_RESET)
1365 							{
1366 								/* In RESULTS_MODE_GET_RESET we are going to reset the queries and get the query pool results again
1367 								 * without issueing them, in order to check the availability field. In Vulkan spec it mentions that
1368 								 * vkGetQueryPoolResults may not return in finite time. Because of that, we skip those tests.
1369 								 */
1370 								continue;
1371 							}
1372 
1373 							const bool			testAvailability[]		= { false, true };
1374 							const char* const	testAvailabilityStr[]	= { "without", "with"};
1375 
1376 							for (int testAvailabilityIdx = 0; testAvailabilityIdx < DE_LENGTH_OF_ARRAY(testAvailability); ++testAvailabilityIdx)
1377 							{
1378 								if (resultsMode[resultsModeIdx] == RESULTS_MODE_COPY_RESET && (! testAvailability[testAvailabilityIdx]))
1379 								{
1380 									/* In RESULTS_MODE_COPY_RESET mode we will reset queries and make sure the availability flag is
1381 									 * set to zero. It does not make sense to run in this mode without obtaining the availability
1382 									 * flag.
1383 									 */
1384 									continue;
1385 								}
1386 
1387 								const bool			discardHalf[]		= { false, true };
1388 								const char* const	discardHalfStr[]	= { "", "_discard" };
1389 
1390 								for (int discardHalfIdx = 0; discardHalfIdx < DE_LENGTH_OF_ARRAY(discardHalf); ++discardHalfIdx)
1391 								{
1392 									OcclusionQueryTestVector testVector			= baseTestVector;
1393 									testVector.queryControlFlags				= controlFlags[controlFlagIdx];
1394 									testVector.queryResultSize					= resultSize[resultSizeIdx];
1395 									testVector.queryWait						= wait[waitIdx];
1396 									testVector.queryResultsMode					= resultsMode[resultsModeIdx];
1397 									testVector.queryResultsStride				= testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
1398 									testVector.queryResultsAvailability			= testAvailability[testAvailabilityIdx];
1399 									testVector.primitiveTopology				= primitiveTopology[primitiveTopologyIdx];
1400 									testVector.discardHalf						= discardHalf[discardHalfIdx];
1401 
1402 									if (testVector.discardHalf && testVector.primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
1403 										continue; // Discarding half of the pixels in fragment shader doesn't make sense with one-pixel-sized points.
1404 
1405 									if (testVector.queryResultsAvailability)
1406 									{
1407 										testVector.queryResultsStride *= 2;
1408 									}
1409 
1410 									std::ostringstream testName;
1411 									std::ostringstream testDescr;
1412 
1413 									testName << resultsModeStr[resultsModeIdx] << "_results"
1414 											 << "_" << controlFlagsStr[controlFlagIdx]
1415 											 << "_size_" << resultSizeStr[resultSizeIdx]
1416 											 << "_wait_" << waitStr[waitIdx]
1417 											 << "_" << testAvailabilityStr[testAvailabilityIdx] << "_availability"
1418 											 << "_draw_" <<  primitiveTopologyStr[primitiveTopologyIdx]
1419 											 << discardHalfStr[discardHalfIdx];
1420 
1421 									testDescr << "draw occluded " << primitiveTopologyStr[primitiveTopologyIdx]
1422 											  << "with " << controlFlagsStr[controlFlagIdx] << ", "
1423 											  << resultsModeStr[resultsModeIdx] << " results "
1424 											  << testAvailabilityStr[testAvailabilityIdx] << " availability bit as "
1425 											  << resultSizeStr[resultSizeIdx] << "bit variables,"
1426 											  << (testVector.discardHalf ? " discarding half of the fragments," : "")
1427 											  << "wait for results on" << waitStr[waitIdx];
1428 
1429 									addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));
1430 								}
1431 							}
1432 						}
1433 
1434 						/* Tests for clear operation within a occulusion query activated.
1435 						 * The query shouldn't count internal driver operations relevant to the clear operations.
1436 						 */
1437 						const OcculusionQueryClearOp		clearOp[]		= { CLEAR_COLOR,  CLEAR_DEPTH };
1438 						const char* const					clearOpStr[]	= { "clear_color", "clear_depth" };
1439 
1440 						for (int clearOpIdx = 0; clearOpIdx < DE_LENGTH_OF_ARRAY(clearOp); ++clearOpIdx)
1441 						{
1442 							OcclusionQueryTestVector testVector			= baseTestVector;
1443 							testVector.queryControlFlags				= controlFlags[controlFlagIdx];
1444 							testVector.queryResultSize					= resultSize[resultSizeIdx];
1445 							testVector.queryWait						= wait[waitIdx];
1446 							testVector.queryResultsMode					= RESULTS_MODE_GET;
1447 							testVector.queryResultsStride				= testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
1448 							testVector.primitiveTopology				= primitiveTopology[primitiveTopologyIdx];
1449 							testVector.clearOp							= clearOp[clearOpIdx];
1450 
1451 							std::ostringstream testName;
1452 							std::ostringstream testDescr;
1453 
1454 							testName << "get_results"
1455 									 << "_" << controlFlagsStr[controlFlagIdx]
1456 									 << "_size_" << resultSizeStr[resultSizeIdx]
1457 									 << "_wait_" << waitStr[waitIdx]
1458 									 << "_without_availability"
1459 									 << "_draw_" <<  primitiveTopologyStr[primitiveTopologyIdx]
1460 									 << "_" << clearOpStr[clearOpIdx];
1461 
1462 							testDescr << "draw occluded " << primitiveTopologyStr[primitiveTopologyIdx]
1463 									  << "with " << controlFlagsStr[controlFlagIdx] << ", "
1464 									  << "get results without availability bit "
1465 									  << "with " << clearOpStr[clearOpIdx] << " as "
1466 									  << resultSizeStr[resultSizeIdx] << "bit variables,"
1467 									  << "wait for results on" << waitStr[waitIdx];
1468 
1469 							addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));
1470 						}
1471 
1472 						// Tests with no color attachments.
1473 						{
1474 							OcclusionQueryTestVector testVector			= baseTestVector;
1475 							testVector.queryControlFlags				= controlFlags[controlFlagIdx];
1476 							testVector.queryResultSize					= resultSize[resultSizeIdx];
1477 							testVector.queryWait						= wait[waitIdx];
1478 							testVector.queryResultsMode					= RESULTS_MODE_GET;
1479 							testVector.queryResultsStride				= testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
1480 							testVector.primitiveTopology				= primitiveTopology[primitiveTopologyIdx];
1481 							testVector.noColorAttachments				= true;
1482 
1483 							std::ostringstream testName;
1484 							std::ostringstream testDescr;
1485 
1486 							testName << "get_results"
1487 									 << "_" << controlFlagsStr[controlFlagIdx]
1488 									 << "_size_" << resultSizeStr[resultSizeIdx]
1489 									 << "_wait_" << waitStr[waitIdx]
1490 									 << "_without_availability"
1491 									 << "_draw_" <<  primitiveTopologyStr[primitiveTopologyIdx]
1492 									 << "_no_color_attachments";
1493 
1494 							testDescr << "draw occluded " << primitiveTopologyStr[primitiveTopologyIdx]
1495 									  << "with " << controlFlagsStr[controlFlagIdx] << ", "
1496 									  << "get results without availability bit and attachments as "
1497 									  << resultSizeStr[resultSizeIdx] << "bit variables,"
1498 									  << "wait for results on" << waitStr[waitIdx];
1499 
1500 							addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));
1501 						}
1502 					}
1503 				}
1504 			}
1505 		}
1506 	}
1507 	// Test different strides
1508 	{
1509 		const OcclusionQueryResultsMode	resultsMode[]		= { RESULTS_MODE_GET,	RESULTS_MODE_GET_RESET,	RESULTS_MODE_COPY,	RESULTS_MODE_COPY_RESET	};
1510 		const char* const				resultsModeStr[]	= { "get",				"get_reset",			"copy",				"copy_reset"			};
1511 
1512 		for (int resultsModeIdx = 0; resultsModeIdx < DE_LENGTH_OF_ARRAY(resultsMode); ++resultsModeIdx)
1513 		{
1514 			const OcclusionQueryResultSize	resultSizes[]	= { RESULT_SIZE_32_BIT, RESULT_SIZE_64_BIT };
1515 			const char* const				resultSizeStr[] = { "32", "64" };
1516 
1517 			const deBool		copyQueryDstOffset[] =		{ DE_TRUE,		DE_FALSE };
1518 			const char *const	copyQueryDstOffsetStr[] =	{ "_dstoffset",	""};
1519 
1520 			const bool			testAvailability[]		= { false,		true	};
1521 			const char* const	testAvailabilityStr[]	= { "without",	"with"	};
1522 
1523 			for (int testAvailabilityIdx = 0; testAvailabilityIdx < DE_LENGTH_OF_ARRAY(testAvailability); ++testAvailabilityIdx)
1524 			{
1525 				if (resultsMode[resultsModeIdx] == RESULTS_MODE_COPY_RESET && (! testAvailability[testAvailabilityIdx]))
1526 				{
1527 					/* In RESULTS_MODE_COPY_RESET mode we will reset queries and make sure the availability flag is set to zero. It
1528 					 * does not make sense to run in this mode without obtaining the availability flag.
1529 					 */
1530 					continue;
1531 				}
1532 
1533 				for (int resultSizeIdx = 0; resultSizeIdx < DE_LENGTH_OF_ARRAY(resultSizes); ++resultSizeIdx)
1534 				{
1535 					const vk::VkDeviceSize resultSize	= (resultSizes[resultSizeIdx] == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64));
1536 
1537 					// \todo [2015-12-18 scygan] Ensure only stride values aligned to resultSize are allowed. Otherwise test should be extended.
1538 					const vk::VkDeviceSize strides[]	=
1539 					{
1540 						0u,
1541 						1 * resultSize,
1542 						2 * resultSize,
1543 						3 * resultSize,
1544 						4 * resultSize,
1545 						5 * resultSize,
1546 						13 * resultSize,
1547 						1024 * resultSize
1548 					};
1549 
1550 					for (int dstOffsetIdx = 0; dstOffsetIdx < DE_LENGTH_OF_ARRAY(copyQueryDstOffset); dstOffsetIdx++)
1551 					{
1552 						for (int strideIdx = 0; strideIdx < DE_LENGTH_OF_ARRAY(strides); strideIdx++)
1553 						{
1554 							OcclusionQueryTestVector testVector		= baseTestVector;
1555 							testVector.queryResultsMode				= resultsMode[resultsModeIdx];
1556 							testVector.queryResultSize				= resultSizes[resultSizeIdx];
1557 							testVector.queryResultsAvailability		= testAvailability[testAvailabilityIdx];
1558 							testVector.queryResultsStride			= strides[strideIdx];
1559 							testVector.queryResultsDstOffset		= copyQueryDstOffset[dstOffsetIdx];
1560 
1561 							const vk::VkDeviceSize elementSize		= (testVector.queryResultsAvailability ? resultSize * 2 : resultSize);
1562 
1563 							if (elementSize > testVector.queryResultsStride && strides[strideIdx] != 0)
1564 							{
1565 								continue;
1566 							}
1567 
1568 							if (strides[strideIdx] == 0)
1569 							{
1570 								// Due to the nature of the test, the dstOffset is tested automatically when stride size is 0.
1571 								if (testVector.queryResultsDstOffset)
1572 								{
1573 									continue;
1574 								}
1575 
1576 								// We are testing only VkCmdCopyQueryPoolResults with stride 0.
1577 								if (testVector.queryResultsMode != RESULTS_MODE_COPY)
1578 								{
1579 									continue;
1580 								}
1581 							}
1582 
1583 							std::ostringstream testName;
1584 							std::ostringstream testDescr;
1585 
1586 							testName << resultsModeStr[resultsModeIdx]
1587 									 << "_results_size_" << resultSizeStr[resultSizeIdx]
1588 									 << "_stride_" << strides[strideIdx]
1589 									 << "_" << testAvailabilityStr[testAvailabilityIdx] << "_availability"
1590 									 << copyQueryDstOffsetStr[dstOffsetIdx];
1591 
1592 							testDescr << resultsModeStr[resultsModeIdx] << " results "
1593 									  << testAvailabilityStr[testAvailabilityIdx] << " availability bit as "
1594 									  << resultSizeStr[resultSizeIdx] << "bit variables, with stride" << strides[strideIdx];
1595 
1596 							addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));
1597 						}
1598 					}
1599 				}
1600 			}
1601 		}
1602 
1603 	}
1604 }
1605 
1606 } //QueryPool
1607 } //vkt
1608