1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 The Khronos Group Inc.
6 * Copyright (c) 2020 Valve 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 Concurrent Query Tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktQueryPoolConcurrentTests.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 "vkRef.hpp"
34#include "vkRefUtil.hpp"
35#include "vkTypeUtil.hpp"
36#include "vkCmdUtil.hpp"
37#include "vkQueryUtil.hpp"
38
39#include "tcuTestLog.hpp"
40#include "tcuImageCompare.hpp"
41
42#include <memory>
43
44namespace vkt
45{
46
47namespace QueryPool
48{
49
50using namespace Draw;
51
52namespace
53{
54
55enum QueryType
56{
57	QUERY_TYPE_OCCLUSION = vk::VK_QUERY_TYPE_OCCLUSION,
58	QUERY_TYPE_PIPELINE_STATISTICS = vk::VK_QUERY_TYPE_PIPELINE_STATISTICS,
59	QUERY_TYPE_TIMESTAMP = vk::VK_QUERY_TYPE_TIMESTAMP,
60	NUM_QUERY_POOLS = 3
61};
62
63struct StateObjects
64{
65			StateObjects	(const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive);
66	void	setVertices		(const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices);
67
68	enum
69	{
70		WIDTH	= 128,
71		HEIGHT	= 128
72	};
73
74	vkt::Context &m_context;
75
76	vk::Move<vk::VkPipeline>		m_pipeline;
77	vk::Move<vk::VkPipelineLayout>	m_pipelineLayout;
78
79	de::SharedPtr<Image>			m_colorAttachmentImage, m_DepthImage;
80	vk::Move<vk::VkImageView>		m_attachmentView;
81	vk::Move<vk::VkImageView>		m_depthiew;
82
83	vk::Move<vk::VkRenderPass>		m_renderPass;
84	vk::Move<vk::VkFramebuffer>		m_framebuffer;
85
86	de::SharedPtr<Buffer>			m_vertexBuffer;
87
88	vk::VkFormat					m_colorAttachmentFormat;
89};
90
91StateObjects::StateObjects (const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive)
92	: m_context(context)
93	, m_colorAttachmentFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)
94
95{
96	vk::VkFormat		depthFormat = vk::VK_FORMAT_D16_UNORM;
97	const vk::VkDevice	device		= m_context.getDevice();
98
99	//attachment images and views
100	{
101		vk::VkExtent3D imageExtent =
102		{
103			WIDTH,	// width;
104			HEIGHT,	// height;
105			1		// depth;
106		};
107
108		const ImageCreateInfo colorImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, imageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
109												   vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
110
111		m_colorAttachmentImage	= Image::createAndAlloc(vk, device, colorImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
112
113		const ImageViewCreateInfo attachmentViewInfo(m_colorAttachmentImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
114		m_attachmentView		= vk::createImageView(vk, device, &attachmentViewInfo);
115
116		ImageCreateInfo depthImageCreateInfo(vk::VK_IMAGE_TYPE_2D, depthFormat, imageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
117			vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
118
119		m_DepthImage			= Image::createAndAlloc(vk, device, depthImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
120
121		// Construct a depth  view from depth image
122		const ImageViewCreateInfo depthViewInfo(m_DepthImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, depthFormat);
123		m_depthiew				= vk::createImageView(vk, device, &depthViewInfo);
124	}
125
126	{
127		// Renderpass and Framebuffer
128
129		RenderPassCreateInfo renderPassCreateInfo;
130		renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,									// format
131																	vk::VK_SAMPLE_COUNT_1_BIT,								// samples
132																	vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						// loadOp
133																	vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,					// storeOp
134																	vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// stencilLoadOp
135																	vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,					// stencilLoadOp
136																	vk::VK_IMAGE_LAYOUT_GENERAL,							// initialLauout
137																	vk::VK_IMAGE_LAYOUT_GENERAL));							// finalLayout
138
139		renderPassCreateInfo.addAttachment(AttachmentDescription(depthFormat,												// format
140																 vk::VK_SAMPLE_COUNT_1_BIT,									// samples
141																 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,							// loadOp
142																 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,						// storeOp
143																 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,						// stencilLoadOp
144																 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,						// stencilLoadOp
145																 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,		// initialLauout
146																 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));	// finalLayout
147
148		const vk::VkAttachmentReference colorAttachmentReference =
149		{
150			0,															// attachment
151			vk::VK_IMAGE_LAYOUT_GENERAL									// layout
152		};
153
154		const vk::VkAttachmentReference depthAttachmentReference =
155		{
156			1,															// attachment
157			vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL		// layout
158		};
159
160		renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,					// pipelineBindPoint
161														   0,													// flags
162														   0,													// inputCount
163														   DE_NULL,												// pInputAttachments
164														   1,													// colorCount
165														   &colorAttachmentReference,							// pColorAttachments
166														   DE_NULL,												// pResolveAttachments
167														   depthAttachmentReference,							// depthStencilAttachment
168														   0,													// preserveCount
169														   DE_NULL));											// preserveAttachments
170
171		m_renderPass = vk::createRenderPass(vk, device, &renderPassCreateInfo);
172
173		std::vector<vk::VkImageView> attachments(2);
174		attachments[0] = *m_attachmentView;
175		attachments[1] = *m_depthiew;
176
177		FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
178		m_framebuffer = vk::createFramebuffer(vk, device, &framebufferCreateInfo);
179	}
180
181	{
182		// Pipeline
183
184		vk::Unique<vk::VkShaderModule> vs(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
185		vk::Unique<vk::VkShaderModule> fs(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
186
187		const PipelineCreateInfo::ColorBlendState::Attachment attachmentState;
188
189		const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
190		m_pipelineLayout = vk::createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
191
192		const vk::VkVertexInputBindingDescription vf_binding_desc		=
193		{
194			0,																// binding;
195			4 * (deUint32)sizeof(float),									// stride;
196			vk::VK_VERTEX_INPUT_RATE_VERTEX									// inputRate
197		};
198
199		const vk::VkVertexInputAttributeDescription vf_attribute_desc	=
200		{
201			0,																// location;
202			0,																// binding;
203			vk::VK_FORMAT_R32G32B32A32_SFLOAT,								// format;
204			0																// offset;
205		};
206
207		const vk::VkPipelineVertexInputStateCreateInfo vf_info			=
208		{																	// sType;
209			vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// pNext;
210			NULL,															// flags;
211			0u,																// vertexBindingDescriptionCount;
212			1,																// pVertexBindingDescriptions;
213			&vf_binding_desc,												// vertexAttributeDescriptionCount;
214			1,																// pVertexAttributeDescriptions;
215			&vf_attribute_desc
216		};
217
218		PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
219		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
220		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
221		pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(primitive));
222		pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &attachmentState));
223		const vk::VkViewport viewport	= vk::makeViewport(WIDTH, HEIGHT);
224		const vk::VkRect2D scissor		= vk::makeRect2D(WIDTH, HEIGHT);
225		pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
226		pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState(true, true, vk::VK_COMPARE_OP_GREATER_OR_EQUAL));
227		pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
228		pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
229		pipelineCreateInfo.addState(vf_info);
230		m_pipeline = vk::createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
231	}
232
233	{
234		// Vertex buffer
235		const size_t kBufferSize = numVertices * sizeof(tcu::Vec4);
236		m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(kBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
237	}
238}
239
240void StateObjects::setVertices (const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices)
241{
242	const vk::VkDevice device			= m_context.getDevice();
243
244	tcu::Vec4 *ptr = reinterpret_cast<tcu::Vec4*>(m_vertexBuffer->getBoundMemory().getHostPtr());
245	std::copy(vertices.begin(), vertices.end(), ptr);
246
247	vk::flushAlloc(vk, device,	m_vertexBuffer->getBoundMemory());
248}
249
250class PrimaryCommandBufferConcurrentTestInstance : public vkt::TestInstance
251{
252public:
253	PrimaryCommandBufferConcurrentTestInstance		(vkt::Context &context);
254	~PrimaryCommandBufferConcurrentTestInstance		(void);
255private:
256	tcu::TestStatus					iterate							(void);
257
258	enum
259	{
260		NUM_QUERIES_IN_POOL				= 2,
261		QUERY_INDEX_CAPTURE_EMPTY		= 0,
262		QUERY_INDEX_CAPTURE_DRAWCALL	= 1,
263		NUM_VERTICES_IN_DRAWCALL		= 3
264	};
265
266	std::unique_ptr<StateObjects>		m_stateObjects;
267	vk::Move<vk::VkQueryPool>			m_queryPools[NUM_QUERY_POOLS];
268	deBool								m_supportedQueryType[NUM_QUERY_POOLS];
269};
270
271PrimaryCommandBufferConcurrentTestInstance::PrimaryCommandBufferConcurrentTestInstance (vkt::Context &context)
272	: TestInstance		(context)
273{
274	// Check support for multiple query types
275	{
276		for(deUint32 poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
277			m_supportedQueryType[poolNdx] = DE_FALSE;
278
279		deUint32 numSupportedQueryTypes = 0;
280		m_supportedQueryType[QUERY_TYPE_OCCLUSION] = DE_TRUE;
281		numSupportedQueryTypes++;
282
283		if (context.getDeviceFeatures().pipelineStatisticsQuery)
284		{
285			m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS] = DE_TRUE;
286			numSupportedQueryTypes++;
287		}
288
289		// Check support for timestamp queries
290		{
291			const deUint32									queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
292			const std::vector<vk::VkQueueFamilyProperties>	queueProperties		= vk::getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
293
294			DE_ASSERT(queueFamilyIndex < (deUint32)queueProperties.size());
295
296			if (queueProperties[queueFamilyIndex].timestampValidBits)
297			 {
298				 m_supportedQueryType[QUERY_TYPE_TIMESTAMP] = DE_TRUE;
299				 numSupportedQueryTypes++;
300			 }
301		}
302		if (numSupportedQueryTypes < 2)
303			throw tcu::NotSupportedError("Device does not support multiple query types");
304	}
305
306	m_stateObjects = std::unique_ptr<StateObjects>(new StateObjects(m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
307
308	const vk::VkDevice			device	= m_context.getDevice();
309	const vk::DeviceInterface&	vk		= m_context.getDeviceInterface();
310
311	for(deUint32 poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
312	{
313		if (!m_supportedQueryType[poolNdx])
314			continue;
315
316		vk::VkQueryPoolCreateInfo queryPoolCreateInfo =
317		{
318			vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
319			DE_NULL,
320			0u,
321			static_cast<vk::VkQueryType>(poolNdx),
322			NUM_QUERIES_IN_POOL,
323			0u,
324		};
325		if (poolNdx == QUERY_TYPE_PIPELINE_STATISTICS)
326			queryPoolCreateInfo.pipelineStatistics = vk::VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT;
327
328		m_queryPools[poolNdx] = createQueryPool(vk, device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL);
329	}
330
331	std::vector<tcu::Vec4> vertices(NUM_VERTICES_IN_DRAWCALL);
332	vertices[0] = tcu::Vec4(0.5, 0.5, 0.0, 1.0);
333	vertices[1] = tcu::Vec4(0.5, 0.0, 0.0, 1.0);
334	vertices[2] = tcu::Vec4(0.0, 0.5, 0.0, 1.0);
335	m_stateObjects->setVertices(vk, vertices);
336}
337
338PrimaryCommandBufferConcurrentTestInstance::~PrimaryCommandBufferConcurrentTestInstance (void)
339{
340}
341
342tcu::TestStatus	PrimaryCommandBufferConcurrentTestInstance::iterate (void)
343{
344	tcu::TestLog &log				= m_context.getTestContext().getLog();
345	const vk::VkDevice device		= m_context.getDevice();
346	const vk::VkQueue queue			= m_context.getUniversalQueue();
347	const vk::DeviceInterface& vk	= m_context.getDeviceInterface();
348
349	const CmdPoolCreateInfo			cmdPoolCreateInfo	(m_context.getUniversalQueueFamilyIndex());
350	vk::Move<vk::VkCommandPool>		cmdPool				= vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
351
352	vk::Unique<vk::VkCommandBuffer> cmdBuffer			(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
353
354	beginCommandBuffer(vk, *cmdBuffer);
355
356	initialTransitionColor2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
357								  vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
358	initialTransitionDepth2DImage(vk, *cmdBuffer, m_stateObjects->m_DepthImage->object(), vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
359								  vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
360
361	std::vector<vk::VkClearValue> renderPassClearValues(2);
362	deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
363
364	for (deUint32 poolNdx = 0u; poolNdx < NUM_QUERY_POOLS; poolNdx++)
365	{
366		if (m_supportedQueryType[poolNdx])
367			vk.cmdResetQueryPool(*cmdBuffer, *m_queryPools[poolNdx], 0u, NUM_QUERIES_IN_POOL);
368	}
369
370	beginRenderPass(vk, *cmdBuffer, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0]);
371
372	vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
373
374	vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
375	const vk::VkDeviceSize vertexBufferOffset = 0;
376	vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
377
378	// Begin all queries
379	for (deUint32 poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
380	{
381		if (m_supportedQueryType[poolNdx])
382			vk.cmdBeginQuery(*cmdBuffer, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_EMPTY, 0u);
383	}
384
385	// End first capture (should not have any result). Start the second one.
386	for (deUint32 poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
387	{
388		if (m_supportedQueryType[poolNdx])
389		{
390			vk.cmdEndQuery(*cmdBuffer, *m_queryPools[poolNdx],	QUERY_INDEX_CAPTURE_EMPTY);
391			vk.cmdBeginQuery(*cmdBuffer, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_DRAWCALL, 0u);
392		}
393	}
394
395	vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, 0, 0);
396
397	if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
398		vk.cmdWriteTimestamp(*cmdBuffer, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, *m_queryPools[QUERY_TYPE_TIMESTAMP], QUERY_INDEX_CAPTURE_DRAWCALL);
399
400	for (deUint32 poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
401	{
402		if (m_supportedQueryType[poolNdx])
403			vk.cmdEndQuery(*cmdBuffer, *m_queryPools[poolNdx],	QUERY_INDEX_CAPTURE_DRAWCALL);
404	}
405
406	endRenderPass(vk, *cmdBuffer);
407
408	transition2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_ASPECT_COLOR_BIT,
409					  vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
410					  vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
411
412	endCommandBuffer(vk, *cmdBuffer);
413
414	submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
415
416	deUint64 queryResults[NUM_QUERIES_IN_POOL] = { 0 };
417	size_t queryResultsSize		= sizeof(queryResults);
418	bool passed = true;
419
420	// Occlusion and pipeline statistics queries verification
421	for (deUint32 poolNdx = 0; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
422	{
423		if (m_supportedQueryType[poolNdx] == DE_FALSE)
424			continue;
425		vk::VkResult queryResult	= vk.getQueryPoolResults(device, *m_queryPools[poolNdx], 0, NUM_QUERIES_IN_POOL, queryResultsSize, queryResults, sizeof(queryResults[0]), vk::VK_QUERY_RESULT_64_BIT);
426
427		if (queryResult == vk::VK_NOT_READY)
428		{
429			TCU_FAIL("Query result not available, but vkWaitIdle() was called.");
430		}
431
432		VK_CHECK(queryResult);
433		std::string name = (poolNdx == QUERY_TYPE_OCCLUSION) ? "OcclusionQueryResults" : "PipelineStatisticsQueryResults";
434		std::string desc = (poolNdx == QUERY_TYPE_OCCLUSION) ? "Occlusion query results" : "PipelineStatistics query results";
435		log << tcu::TestLog::Section(name, desc);
436		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(queryResults); ++ndx)
437		{
438			log << tcu::TestLog::Message << "query[slot == " << ndx
439				<< "] result == " << queryResults[ndx] << tcu::TestLog::EndMessage;
440		}
441
442
443		for (deUint32 queryNdx = 0; queryNdx < DE_LENGTH_OF_ARRAY(queryResults); ++queryNdx)
444		{
445			if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] != 0u)
446			{
447				log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
448					"wrong value of query for index "
449					<< queryNdx << ", expected any zero value, got "
450					<< queryResults[0] << "." << tcu::TestLog::EndMessage;
451				passed = false;
452			}
453
454			if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] == 0)
455			{
456				log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
457					"wrong value of query for index "
458					<< queryNdx << ", expected any non-zero value, got "
459					<< queryResults[0] << "." << tcu::TestLog::EndMessage;
460				passed = false;
461			}
462		}
463		log << tcu::TestLog::EndSection;
464	}
465
466	// Timestamp query verification
467	if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
468	{
469		std::pair<deUint64, deUint64>	queryResultsWithAvailabilityBit[NUM_QUERIES_IN_POOL];
470		size_t queryResultsWithAvailabilityBitSize		= sizeof(queryResultsWithAvailabilityBit);
471		vk::VkResult queryResult	= vk.getQueryPoolResults(device, *m_queryPools[QUERY_TYPE_TIMESTAMP], 0, NUM_QUERIES_IN_POOL, queryResultsWithAvailabilityBitSize, &queryResultsWithAvailabilityBit[0], sizeof(queryResultsWithAvailabilityBit[0]), vk::VK_QUERY_RESULT_64_BIT | vk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
472
473		if (queryResult != vk::VK_NOT_READY)
474		{
475			TCU_FAIL("We don't have available one query, it should return VK_NOT_READY");
476		}
477
478		log << tcu::TestLog::Section("TimestampQueryResults",
479									 "Timestamp query results");
480		for (int ndx = 0; ndx < NUM_QUERIES_IN_POOL; ++ndx)
481		{
482			log << tcu::TestLog::Message << "query[slot == " << ndx
483				<< "] result == " << queryResultsWithAvailabilityBit[ndx].first << tcu::TestLog::EndMessage;
484		}
485
486
487		for (deUint32 queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; ++queryNdx)
488		{
489			if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first != 0u || queryResultsWithAvailabilityBit[queryNdx].second != 0u))
490			{
491				log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
492					"either wrong value of query for index "
493					<< queryNdx << " (expected any zero value, got "
494					<< queryResultsWithAvailabilityBit[queryNdx].first << ") or the result is available (" << queryResultsWithAvailabilityBit[queryNdx].second << ")"
495					<< tcu::TestLog::EndMessage;
496				passed = false;
497			}
498
499			if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first == 0u || queryResultsWithAvailabilityBit[queryNdx].second == 0u))
500			{
501				log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
502					"either wrong value of query for index "
503					<< queryNdx << " (expected any non-zero value, got "
504					<< queryResults[0] << ") or result is unavailable." << tcu::TestLog::EndMessage;
505				passed = false;
506			}
507		}
508		log << tcu::TestLog::EndSection;
509	}
510
511	if (passed)
512	{
513		return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
514	}
515	return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
516}
517
518class SecondaryCommandBufferConcurrentTestInstance : public vkt::TestInstance
519{
520public:
521	SecondaryCommandBufferConcurrentTestInstance		(vkt::Context &context);
522	~SecondaryCommandBufferConcurrentTestInstance		(void);
523private:
524	tcu::TestStatus					iterate							(void);
525
526	enum
527	{
528		NUM_QUERIES_IN_POOL				= 2,
529		QUERY_INDEX_CAPTURE_EMPTY		= 0,
530		QUERY_INDEX_CAPTURE_DRAWCALL	= 1,
531		NUM_VERTICES_IN_DRAWCALL		= 3
532	};
533
534	std::unique_ptr<StateObjects>			m_stateObjects;
535	vk::Move<vk::VkQueryPool>				m_queryPools[NUM_QUERY_POOLS];
536	deBool									m_supportedQueryType[NUM_QUERY_POOLS];
537
538};
539
540SecondaryCommandBufferConcurrentTestInstance::SecondaryCommandBufferConcurrentTestInstance (vkt::Context &context)
541	: TestInstance		(context)
542{
543	// Check support for multiple query types
544	{
545		for(deUint32 poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
546			m_supportedQueryType[poolNdx] = DE_FALSE;
547
548		deUint32 numSupportedQueryTypes = 0;
549		m_supportedQueryType[QUERY_TYPE_OCCLUSION] = DE_TRUE;
550		numSupportedQueryTypes++;
551
552		if (context.getDeviceFeatures().pipelineStatisticsQuery)
553		{
554			m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS] = DE_TRUE;
555			numSupportedQueryTypes++;
556		}
557
558		// Check support for timestamp queries
559		{
560			const deUint32									queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
561			const std::vector<vk::VkQueueFamilyProperties>	queueProperties		= vk::getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
562
563			DE_ASSERT(queueFamilyIndex < (deUint32)queueProperties.size());
564
565			if (queueProperties[queueFamilyIndex].timestampValidBits)
566			 {
567				 m_supportedQueryType[QUERY_TYPE_TIMESTAMP] = DE_TRUE;
568				 numSupportedQueryTypes++;
569			 }
570		}
571		if (numSupportedQueryTypes < 2)
572			throw tcu::NotSupportedError("Device does not support multiple query types");
573	}
574
575	m_stateObjects = std::unique_ptr<StateObjects>(new StateObjects(m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
576
577	const vk::VkDevice			device	= m_context.getDevice();
578	const vk::DeviceInterface&	vk		= m_context.getDeviceInterface();
579
580	for(deUint32 poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
581	{
582		if (!m_supportedQueryType[poolNdx])
583			continue;
584
585		vk::VkQueryPoolCreateInfo queryPoolCreateInfo =
586		{
587			vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
588			DE_NULL,
589			0u,
590			static_cast<vk::VkQueryType>(poolNdx),
591			NUM_QUERIES_IN_POOL,
592			0u,
593		};
594		if (poolNdx == QUERY_TYPE_PIPELINE_STATISTICS)
595			queryPoolCreateInfo.pipelineStatistics = vk::VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT;
596
597		m_queryPools[poolNdx] = createQueryPool(vk, device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL);
598	}
599
600	std::vector<tcu::Vec4> vertices(NUM_VERTICES_IN_DRAWCALL);
601	vertices[0] = tcu::Vec4(0.5, 0.5, 0.0, 1.0);
602	vertices[1] = tcu::Vec4(0.5, 0.0, 0.0, 1.0);
603	vertices[2] = tcu::Vec4(0.0, 0.5, 0.0, 1.0);
604	m_stateObjects->setVertices(vk, vertices);
605}
606
607SecondaryCommandBufferConcurrentTestInstance::~SecondaryCommandBufferConcurrentTestInstance (void)
608{
609}
610
611void beginSecondaryCommandBuffer (const vk::DeviceInterface&				vk,
612								  const vk::VkCommandBuffer					secondaryCmdBuffer,
613								  const vk::VkCommandBufferInheritanceInfo	bufferInheritanceInfo)
614{
615	const vk::VkCommandBufferUsageFlags	flags		= bufferInheritanceInfo.renderPass != DE_NULL
616													  ? (vk::VkCommandBufferUsageFlags)vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
617													  : (vk::VkCommandBufferUsageFlags)0u;
618	const vk::VkCommandBufferBeginInfo	beginInfo	=
619	{
620		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,			// sType
621		DE_NULL,													// pNext
622		flags,														// flags
623		&bufferInheritanceInfo,										// pInheritanceInfo
624	};
625	VK_CHECK(vk.beginCommandBuffer(secondaryCmdBuffer, &beginInfo));
626}
627
628tcu::TestStatus	SecondaryCommandBufferConcurrentTestInstance::iterate (void)
629{
630	tcu::TestLog &log				= m_context.getTestContext().getLog();
631	const vk::VkDevice device		= m_context.getDevice();
632	const vk::VkQueue queue			= m_context.getUniversalQueue();
633	const vk::DeviceInterface& vk	= m_context.getDeviceInterface();
634	const deBool inheritedQueries	= m_context.getDeviceFeatures().inheritedQueries;
635
636	const CmdPoolCreateInfo			cmdPoolCreateInfo	(m_context.getUniversalQueueFamilyIndex());
637	vk::Move<vk::VkCommandPool>		cmdPool				= vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
638
639	vk::Unique<vk::VkCommandBuffer> cmdBufferPrimary			(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
640	vk::Unique<vk::VkCommandBuffer> cmdBufferSecondary			(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY));
641
642	// Secondary command buffer recording.
643	{
644		// Begin secondary command buffer
645		const vk::VkCommandBufferInheritanceInfo	secCmdBufInheritInfo	=
646		{
647			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
648			DE_NULL,
649			*m_stateObjects->m_renderPass,								// renderPass
650			0u,															// subpass
651			*m_stateObjects->m_framebuffer,								// framebuffer
652			inheritedQueries ? VK_TRUE : VK_FALSE,						// occlusionQueryEnable
653			(vk::VkQueryControlFlags)0u,								// queryFlags
654			(vk::VkQueryPipelineStatisticFlags)0u,						// pipelineStatistics
655		};
656		beginSecondaryCommandBuffer(vk, *cmdBufferSecondary, secCmdBufInheritInfo);
657
658		vk.cmdBindPipeline(*cmdBufferSecondary, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
659		vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
660		const vk::VkDeviceSize vertexBufferOffset = 0;
661		vk.cmdBindVertexBuffers(*cmdBufferSecondary, 0, 1, &vertexBuffer, &vertexBufferOffset);
662
663		if (!inheritedQueries && m_supportedQueryType[QUERY_TYPE_OCCLUSION])
664			vk.cmdBeginQuery(*cmdBufferSecondary, *m_queryPools[QUERY_TYPE_OCCLUSION], QUERY_INDEX_CAPTURE_DRAWCALL, 0u);
665
666		// Run pipeline statistics queries capture in the second command buffer
667		if (m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS])
668			vk.cmdBeginQuery(*cmdBufferSecondary, *m_queryPools[QUERY_TYPE_PIPELINE_STATISTICS], QUERY_INDEX_CAPTURE_DRAWCALL, 0u);
669
670		// Timestamp query happening in the secondary command buffer
671		if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
672			vk.cmdWriteTimestamp(*cmdBufferSecondary, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, *m_queryPools[QUERY_TYPE_TIMESTAMP], QUERY_INDEX_CAPTURE_DRAWCALL);
673
674		vk.cmdDraw(*cmdBufferSecondary, NUM_VERTICES_IN_DRAWCALL, 1, 0, 0);
675
676		if (m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS])
677			vk.cmdEndQuery(*cmdBufferSecondary, *m_queryPools[QUERY_TYPE_PIPELINE_STATISTICS], QUERY_INDEX_CAPTURE_DRAWCALL);
678
679		if (!inheritedQueries && m_supportedQueryType[QUERY_TYPE_OCCLUSION])
680			vk.cmdEndQuery(*cmdBufferSecondary, *m_queryPools[QUERY_TYPE_OCCLUSION], QUERY_INDEX_CAPTURE_DRAWCALL);
681
682		endCommandBuffer(vk, *cmdBufferSecondary);
683	}
684
685	// Primary command buffer recording
686	{
687		beginCommandBuffer(vk, *cmdBufferPrimary);
688
689		initialTransitionColor2DImage(vk, *cmdBufferPrimary, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
690									  vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
691		initialTransitionDepth2DImage(vk, *cmdBufferPrimary, m_stateObjects->m_DepthImage->object(), vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
692									  vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
693
694		std::vector<vk::VkClearValue> renderPassClearValues(2);
695		deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
696
697		for (deUint32 poolNdx = 0u; poolNdx < NUM_QUERY_POOLS; poolNdx++)
698		{
699			if (m_supportedQueryType[poolNdx])
700				vk.cmdResetQueryPool(*cmdBufferPrimary, *m_queryPools[poolNdx], 0u, NUM_QUERIES_IN_POOL);
701		}
702
703		for (deUint32 poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
704		{
705			if (m_supportedQueryType[poolNdx])
706				vk.cmdBeginQuery(*cmdBufferPrimary, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_EMPTY, 0u);
707		}
708
709		for (deUint32 poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
710		{
711			if (m_supportedQueryType[poolNdx])
712				vk.cmdEndQuery(*cmdBufferPrimary, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_EMPTY);
713		}
714
715		// Run oclussion queries capture in the primary command buffer, inherit the counters for the secondary command buffer
716		if (inheritedQueries && m_supportedQueryType[QUERY_TYPE_OCCLUSION])
717			vk.cmdBeginQuery(*cmdBufferPrimary, *m_queryPools[QUERY_TYPE_OCCLUSION], QUERY_INDEX_CAPTURE_DRAWCALL, 0u);
718
719		beginRenderPass(vk, *cmdBufferPrimary, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0], vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
720
721		vk.cmdExecuteCommands(*cmdBufferPrimary, 1u, &cmdBufferSecondary.get());
722
723		endRenderPass(vk, *cmdBufferPrimary);
724
725		if (inheritedQueries && m_supportedQueryType[QUERY_TYPE_OCCLUSION])
726			vk.cmdEndQuery(*cmdBufferPrimary, *m_queryPools[QUERY_TYPE_OCCLUSION], QUERY_INDEX_CAPTURE_DRAWCALL);
727
728		transition2DImage(vk, *cmdBufferPrimary,
729						  m_stateObjects->m_colorAttachmentImage->object(),
730						  vk::VK_IMAGE_ASPECT_COLOR_BIT,
731						  vk::VK_IMAGE_LAYOUT_GENERAL,
732						  vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
733						  vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
734						  vk::VK_ACCESS_TRANSFER_READ_BIT,
735						  vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
736						  vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
737
738		endCommandBuffer(vk, *cmdBufferPrimary);
739	}
740
741	submitCommandsAndWait(vk, device, queue, cmdBufferPrimary.get());
742
743	deUint64 queryResults[NUM_QUERIES_IN_POOL] = { 0 };
744	size_t queryResultsSize		= sizeof(queryResults);
745	bool passed = true;
746
747	// Occlusion and pipeline statistics queries verification
748	for (deUint32 poolNdx = 0; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
749	{
750		if (!m_supportedQueryType[poolNdx])
751			continue;
752		vk::VkResult queryResult	= vk.getQueryPoolResults(device, *m_queryPools[poolNdx], 0, NUM_QUERIES_IN_POOL, queryResultsSize, queryResults, sizeof(queryResults[0]), vk::VK_QUERY_RESULT_64_BIT);
753
754		if (queryResult == vk::VK_NOT_READY)
755		{
756			TCU_FAIL("Query result not available, but vkWaitIdle() was called.");
757		}
758
759		VK_CHECK(queryResult);
760		std::string name = (poolNdx == QUERY_TYPE_OCCLUSION) ? "OcclusionQueryResults" : "PipelineStatisticsQueryResults";
761		std::string desc = (poolNdx == QUERY_TYPE_OCCLUSION) ? "Occlusion query results" : "PipelineStatistics query results";
762		log << tcu::TestLog::Section(name, desc);
763		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(queryResults); ++ndx)
764		{
765			log << tcu::TestLog::Message << "query[slot == " << ndx
766				<< "] result == " << queryResults[ndx] << tcu::TestLog::EndMessage;
767		}
768
769		for (deUint32 queryNdx = 0; queryNdx < DE_LENGTH_OF_ARRAY(queryResults); ++queryNdx)
770		{
771			if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] != 0u)
772			{
773				log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
774					"wrong value of query for index "
775					<< queryNdx << ", expected any zero value, got "
776					<< queryResults[0] << "." << tcu::TestLog::EndMessage;
777				passed = false;
778			}
779
780			if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] == 0)
781			{
782				log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
783					"wrong value of query for index "
784					<< queryNdx << ", expected any non-zero value, got "
785					<< queryResults[0] << "." << tcu::TestLog::EndMessage;
786				passed = false;
787			}
788		}
789		log << tcu::TestLog::EndSection;
790	}
791
792	// Timestamp query verification
793	if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
794	{
795		std::pair<deUint64, deUint64>	queryResultsWithAvailabilityBit[NUM_QUERIES_IN_POOL];
796		size_t queryResultsWithAvailabilityBitSize		= sizeof(queryResultsWithAvailabilityBit);
797		vk::VkResult queryResult	= vk.getQueryPoolResults(device, *m_queryPools[QUERY_TYPE_TIMESTAMP], 0, NUM_QUERIES_IN_POOL, queryResultsWithAvailabilityBitSize, &queryResultsWithAvailabilityBit[0], sizeof(queryResultsWithAvailabilityBit[0]), vk::VK_QUERY_RESULT_64_BIT | vk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
798
799		if (queryResult != vk::VK_NOT_READY)
800		{
801			TCU_FAIL("We don't have available one query, it should return VK_NOT_READY");
802		}
803
804		log << tcu::TestLog::Section("TimestampQueryResults",
805									 "Timestamp query results");
806		for (int ndx = 0; ndx < NUM_QUERIES_IN_POOL; ++ndx)
807		{
808			log << tcu::TestLog::Message << "query[slot == " << ndx
809				<< "] result == " << queryResultsWithAvailabilityBit[ndx].first << tcu::TestLog::EndMessage;
810		}
811
812
813		for (deUint32 queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; ++queryNdx)
814		{
815			if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first != 0u || queryResultsWithAvailabilityBit[queryNdx].second != 0u))
816			{
817				log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
818					"either wrong value of query for index "
819					<< queryNdx << " (expected any zero value, got "
820					<< queryResultsWithAvailabilityBit[queryNdx].first << ") or the result is available (" << queryResultsWithAvailabilityBit[queryNdx].second << ")"
821					<< tcu::TestLog::EndMessage;
822				passed = false;
823			}
824
825			if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first == 0u || queryResultsWithAvailabilityBit[queryNdx].second == 0u))
826			{
827				log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
828					"either wrong value of query for index "
829					<< queryNdx << " (expected any non-zero value, got "
830					<< queryResults[0] << ") or result is unavailable." << tcu::TestLog::EndMessage;
831				passed = false;
832			}
833		}
834		log << tcu::TestLog::EndSection;
835	}
836
837	if (passed)
838	{
839		return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
840	}
841	return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
842}
843
844template<class Instance>
845class QueryPoolConcurrentTest : public vkt::TestCase
846{
847public:
848	QueryPoolConcurrentTest (tcu::TestContext &context, const char *name)
849		: TestCase			(context, name)
850	{
851	}
852private:
853	vkt::TestInstance* createInstance (vkt::Context& context) const
854	{
855		return new Instance(context);
856	}
857
858	void initPrograms(vk::SourceCollections& programCollection) const
859	{
860		const std::string fragSrc = std::string(
861			"#version 400\n"
862			"layout(location = 0) out vec4 out_FragColor;\n"
863			"void main()\n"
864			"{\n"
865			"	out_FragColor = vec4(0.07, 0.48, 0.75, 1.0);\n"
866			"	if ((int(gl_FragCoord.x) % 2) == (int(gl_FragCoord.y) % 2))\n"
867			"		discard;\n"
868			"}");
869
870		programCollection.glslSources.add("frag") << glu::FragmentSource(fragSrc.c_str());
871
872		programCollection.glslSources.add("vert") << glu::VertexSource("#version 430\n"
873																		 "layout(location = 0) in vec4 in_Position;\n"
874																		 "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
875																		 "void main() {\n"
876																		 "	gl_Position  = in_Position;\n"
877																		 "	gl_PointSize = 1.0;\n"
878																		 "}\n");
879	}
880};
881
882} //anonymous
883
884QueryPoolConcurrentTests::QueryPoolConcurrentTests (tcu::TestContext &testCtx)
885	: TestCaseGroup(testCtx, "concurrent_queries")
886{
887	/* Left blank on purpose */
888}
889
890QueryPoolConcurrentTests::~QueryPoolConcurrentTests (void)
891{
892	/* Left blank on purpose */
893}
894
895void QueryPoolConcurrentTests::init (void)
896{
897	addChild(new QueryPoolConcurrentTest<PrimaryCommandBufferConcurrentTestInstance>(m_testCtx, "primary_command_buffer"));
898	addChild(new QueryPoolConcurrentTest<SecondaryCommandBufferConcurrentTestInstance>(m_testCtx, "secondary_command_buffer"));
899}
900
901} //QueryPool
902} //vkt
903