1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2021 The Khronos Group Inc.
6 * Copyright (c) 2021 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 Mesh Shader Query Tests for VK_EXT_mesh_shader
23 *//*--------------------------------------------------------------------*/
24
25#include "vktMeshShaderQueryTestsEXT.hpp"
26#include "vktMeshShaderUtil.hpp"
27#include "vktTestCase.hpp"
28#include "vktTestCaseUtil.hpp"
29
30#include "vkImageWithMemory.hpp"
31#include "vkBufferWithMemory.hpp"
32#include "vkImageUtil.hpp"
33#include "vkTypeUtil.hpp"
34#include "vkObjUtil.hpp"
35#include "vkCmdUtil.hpp"
36#include "vkBarrierUtil.hpp"
37
38#include "tcuImageCompare.hpp"
39#include "tcuTextureUtil.hpp"
40
41#include "deRandom.hpp"
42#include "deUniquePtr.hpp"
43
44#include <vector>
45#include <algorithm>
46#include <sstream>
47#include <string>
48#include <numeric>
49#include <array>
50#include <limits>
51
52namespace vkt
53{
54namespace MeshShader
55{
56
57namespace
58{
59
60using namespace vk;
61
62using BufferWithMemoryPtr = de::MovePtr<BufferWithMemory>;
63
64constexpr uint32_t kImageWidth				= 32u;
65constexpr uint32_t kMeshWorkGroupsPerCall	= 4u;
66constexpr uint32_t kTaskWorkGroupsPerCall	= 2u;
67constexpr uint32_t kMeshWorkGroupsPerTask	= kMeshWorkGroupsPerCall / kTaskWorkGroupsPerCall;
68
69constexpr uint32_t kMeshLocalInvocationsX	= 10u;
70constexpr uint32_t kMeshLocalInvocationsY	= 4u;
71constexpr uint32_t kMeshLocalInvocationsZ	= 1u;
72constexpr uint32_t kMeshLocalInvocations	= kMeshLocalInvocationsX * kMeshLocalInvocationsY * kMeshLocalInvocationsZ;
73
74constexpr uint32_t kTaskLocalInvocationsX	= 1u;
75constexpr uint32_t kTaskLocalInvocationsY	= 4u;
76constexpr uint32_t kTaskLocalInvocationsZ	= 6u;
77constexpr uint32_t kTaskLocalInvocations	= kTaskLocalInvocationsX * kTaskLocalInvocationsY * kTaskLocalInvocationsZ;
78
79constexpr VkDeviceSize k64sz				= static_cast<VkDeviceSize>(sizeof(uint64_t));
80constexpr VkDeviceSize k32sz				= static_cast<VkDeviceSize>(sizeof(uint32_t));
81
82enum class QueryType
83{
84	PRIMITIVES = 0,
85	TASK_INVOCATIONS,
86	MESH_INVOCATIONS,
87};
88
89enum class DrawCallType
90{
91	DIRECT = 0,
92	INDIRECT,
93	INDIRECT_WITH_COUNT,
94};
95
96enum class GeometryType
97{
98	POINTS = 0,
99	LINES,
100	TRIANGLES,
101};
102
103std::string toString (GeometryType geometryType)
104{
105	std::string result;
106	switch (geometryType)
107	{
108	case GeometryType::POINTS:		result = "points";		break;
109	case GeometryType::LINES:		result = "lines";		break;
110	case GeometryType::TRIANGLES:	result = "triangles";	break;
111	default:
112		DE_ASSERT(false);
113		break;
114	}
115	return result;
116}
117
118uint32_t vertsPerPrimitive (GeometryType geometryType)
119{
120	uint32_t vertices = 0u;
121	switch (geometryType)
122	{
123	case GeometryType::POINTS:		vertices = 1u;	break;
124	case GeometryType::LINES:		vertices = 2u;	break;
125	case GeometryType::TRIANGLES:	vertices = 3u;	break;
126	default:
127		DE_ASSERT(false);
128		break;
129	}
130	return vertices;
131}
132
133enum class ResetCase
134{
135	NONE = 0,
136	NONE_WITH_HOST, // After checking results normally, reset query from the host and verify availability.
137	BEFORE_ACCESS,
138	AFTER_ACCESS,
139};
140
141enum class AccessMethod
142{
143	COPY = 0,
144	GET,
145};
146
147void checkGetQueryRes(VkResult result, bool allowNotReady)
148{
149	if (result == VK_SUCCESS || (result == VK_NOT_READY && allowNotReady))
150		return;
151
152	const auto msg = getResultStr(result);
153	TCU_FAIL(msg.toString());
154}
155
156// The pseudrandom number generator will be used in the test case and test instance, so we use two seeds per case.
157uint32_t getNewSeed (void)
158{
159	static uint32_t seed = 1656078156u;
160	uint32_t returnedSeed = seed;
161	seed += 2u;
162	return returnedSeed;
163}
164
165struct TestParams
166{
167	uint32_t				randomSeed;
168	std::vector<QueryType>	queryTypes;
169	std::vector<uint32_t>	drawBlocks;
170	DrawCallType			drawCall;
171	GeometryType			geometry;
172	ResetCase				resetType;
173	AccessMethod			access;
174	bool					use64Bits;
175	bool					availabilityBit;
176	bool					waitBit;
177	bool					useTaskShader;
178	bool					insideRenderPass;
179	bool					useSecondary;
180	bool					multiView;
181
182	void swap (TestParams& other)
183	{
184		std::swap(randomSeed, other.randomSeed);
185		queryTypes.swap(other.queryTypes);
186		drawBlocks.swap(other.drawBlocks);
187		std::swap(drawCall, other.drawCall);
188		std::swap(geometry, other.geometry);
189		std::swap(resetType, other.resetType);
190		std::swap(access, other.access);
191		std::swap(use64Bits, other.use64Bits);
192		std::swap(availabilityBit, other.availabilityBit);
193		std::swap(waitBit, other.waitBit);
194		std::swap(useTaskShader, other.useTaskShader);
195		std::swap(insideRenderPass, other.insideRenderPass);
196		std::swap(useSecondary, other.useSecondary);
197		std::swap(multiView, other.multiView);
198	}
199
200	TestParams ()
201		: randomSeed		(getNewSeed())
202		, queryTypes		()
203		, drawBlocks		()
204		, drawCall			(DrawCallType::DIRECT)
205		, geometry			(GeometryType::POINTS)
206		, resetType			(ResetCase::NONE)
207		, access			(AccessMethod::COPY)
208		, use64Bits			(false)
209		, availabilityBit	(false)
210		, waitBit			(false)
211		, useTaskShader		(false)
212		, insideRenderPass	(false)
213		, useSecondary		(false)
214		, multiView			(false)
215	{}
216
217	TestParams (const TestParams& other)
218		: randomSeed		(other.randomSeed)
219		, queryTypes		(other.queryTypes)
220		, drawBlocks		(other.drawBlocks)
221		, drawCall			(other.drawCall)
222		, geometry			(other.geometry)
223		, resetType			(other.resetType)
224		, access			(other.access)
225		, use64Bits			(other.use64Bits)
226		, availabilityBit	(other.availabilityBit)
227		, waitBit			(other.waitBit)
228		, useTaskShader		(other.useTaskShader)
229		, insideRenderPass	(other.insideRenderPass)
230		, useSecondary		(other.useSecondary)
231		, multiView			(other.multiView)
232	{}
233
234	TestParams (TestParams&& other)
235		: TestParams()
236	{
237		this->swap(other);
238	}
239
240	uint32_t getTotalDrawCount (void) const
241	{
242		const uint32_t callCount = std::accumulate(drawBlocks.begin(), drawBlocks.end(), 0u);
243		return callCount;
244	}
245
246	uint32_t getImageHeight (void) const
247	{
248		return getTotalDrawCount() * kMeshWorkGroupsPerCall;
249	}
250
251	// The goal is dispatching 4 mesh work groups per draw call in total. When not using task shaders, we dispatch that number
252	// directly. When using task shaders, we dispatch 2 task work groups that will dispatch 2 mesh work groups each. The axis will
253	// be pseudorandomly chosen in each case.
254	uint32_t getDrawGroupCount (void) const
255	{
256		return (useTaskShader ? kTaskWorkGroupsPerCall : kMeshWorkGroupsPerCall);
257	}
258
259	// Gets the right query result flags for the current parameters.
260	VkQueryResultFlags getQueryResultFlags (void) const
261	{
262		const VkQueryResultFlags queryResultFlags =	( (use64Bits		? VK_QUERY_RESULT_64_BIT				: 0)
263													| (availabilityBit	? VK_QUERY_RESULT_WITH_AVAILABILITY_BIT	: 0)
264													| (waitBit			? VK_QUERY_RESULT_WAIT_BIT				: VK_QUERY_RESULT_PARTIAL_BIT) );
265		return queryResultFlags;
266	}
267
268	// Queries will be inherited if they are started outside of a render pass and using secondary command buffers.
269	// - If secondary command buffers are not used, nothing will be inherited.
270	// - If secondary command buffers are used but queries start inside of a render pass, queries will run entirely inside the secondary command buffer.
271	bool areQueriesInherited (void) const
272	{
273		return (useSecondary && !insideRenderPass);
274	}
275
276protected:
277	bool hasQueryType (QueryType queryType) const
278	{
279		return de::contains(queryTypes.begin(), queryTypes.end(), queryType);
280	}
281
282public:
283	bool hasPrimitivesQuery (void) const
284	{
285		return hasQueryType(QueryType::PRIMITIVES);
286	}
287
288	bool hasMeshInvStat (void) const
289	{
290		return hasQueryType(QueryType::MESH_INVOCATIONS);
291	}
292
293	bool hasTaskInvStat (void) const
294	{
295		return hasQueryType(QueryType::TASK_INVOCATIONS);
296	}
297
298	struct QuerySizesAndOffsets
299	{
300		VkDeviceSize queryItemSize;
301		VkDeviceSize primitivesQuerySize;
302		VkDeviceSize statsQuerySize;
303		VkDeviceSize statsQueryOffset;
304	};
305
306	uint32_t getViewCount (void) const
307	{
308		return (multiView ? 2u : 1u);
309	}
310
311	QuerySizesAndOffsets getQuerySizesAndOffsets (void) const
312	{
313		QuerySizesAndOffsets	sizesAndOffsets;
314		const VkDeviceSize		extraQueryItems		= (availabilityBit ? 1ull : 0ull);
315		const VkDeviceSize		viewMultiplier		= getViewCount();
316
317		sizesAndOffsets.queryItemSize		= (use64Bits ? k64sz : k32sz);
318		sizesAndOffsets.primitivesQuerySize	= (extraQueryItems + 1ull) * sizesAndOffsets.queryItemSize;
319		sizesAndOffsets.statsQuerySize		= (extraQueryItems + (hasTaskInvStat() ? 1ull : 0ull) + (hasMeshInvStat() ? 1ull : 0ull)) * sizesAndOffsets.queryItemSize;
320		sizesAndOffsets.statsQueryOffset	= (hasPrimitivesQuery() ? (sizesAndOffsets.primitivesQuerySize * viewMultiplier) : 0ull);
321
322		return sizesAndOffsets;
323	}
324};
325
326class MeshQueryCase : public vkt::TestCase
327{
328public:
329					MeshQueryCase	(tcu::TestContext& testCtx, const std::string& name, TestParams&& params)
330						: vkt::TestCase	(testCtx, name)
331						, m_params		(std::move(params))
332						{}
333	virtual			~MeshQueryCase	(void) {}
334
335	void			initPrograms	(vk::SourceCollections& programCollection) const override;
336	TestInstance*	createInstance	(Context& context) const override;
337	void			checkSupport	(Context& context) const override;
338
339protected:
340	TestParams m_params;
341};
342
343class MeshQueryInstance : public vkt::TestInstance
344{
345public:
346						MeshQueryInstance		(Context& context, const TestParams& params)
347							: vkt::TestInstance		(context)
348							, m_params				(&params)
349							, m_rnd					(params.randomSeed + 1u) // Add 1 to make the instance seed different.
350							, m_indirectBuffer		()
351							, m_indirectCountBuffer	()
352							, m_fence				(createFence(context.getDeviceInterface(), context.getDevice()))
353							{}
354	virtual				~MeshQueryInstance		(void) {}
355
356	Move<VkRenderPass>	makeCustomRenderPass	(const DeviceInterface& vkd, VkDevice device, uint32_t layerCount, VkFormat format);
357	tcu::TestStatus		iterate					(void) override;
358
359protected:
360	VkDrawMeshTasksIndirectCommandEXT	getRandomShuffle	(uint32_t groupCount);
361	void								recordDraws			(const VkCommandBuffer cmdBuffer, const VkPipeline pipeline, const VkPipelineLayout layout);
362	void								beginFirstQueries	(const VkCommandBuffer cmdBuffer, const std::vector<VkQueryPool>& queryPools) const;
363	void								endFirstQueries		(const VkCommandBuffer cmdBuffer, const std::vector<VkQueryPool>& queryPools) const;
364	void								resetFirstQueries	(const VkCommandBuffer cmdBuffer, const std::vector<VkQueryPool>& queryPools, const uint32_t queryCount) const;
365	void								submitCommands		(const VkCommandBuffer cmdBuffer) const;
366	void								waitForFence		() const;
367
368	const TestParams*					m_params;
369	de::Random							m_rnd;
370	BufferWithMemoryPtr					m_indirectBuffer;
371	BufferWithMemoryPtr					m_indirectCountBuffer;
372	Move<VkFence>						m_fence;
373};
374
375void MeshQueryCase::initPrograms (vk::SourceCollections &programCollection) const
376{
377	const auto meshBuildOpts	= getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
378	const auto imageHeight		= m_params.getImageHeight();
379
380	const std::string taskDataDecl =
381		"struct TaskData {\n"
382		"    uint branch[" + std::to_string(kTaskLocalInvocations) + "];\n"
383		"    uint drawIndex;\n"
384		"};\n"
385		"taskPayloadSharedEXT TaskData td;\n"
386		;
387
388	std::ostringstream frag;
389	frag
390		<< "#version 460\n"
391		<< (m_params.multiView ? "#extension GL_EXT_multiview : enable\n" : "")
392		<< "layout (location=0) out vec4 outColor;\n"
393		<< "void main (void) { outColor = vec4(0.0, " << (m_params.multiView ? "float(gl_ViewIndex)" : "0.0") << ", 1.0, 1.0); }\n"
394		;
395	programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
396
397	std::ostringstream mesh;
398	mesh
399		<< "#version 460\n"
400		<< "#extension GL_EXT_mesh_shader : enable\n"
401		<< "\n"
402		<< "layout (local_size_x=" << kMeshLocalInvocationsX << ", local_size_y=" << kMeshLocalInvocationsY << ", local_size_z=" << kMeshLocalInvocationsZ << ") in;\n"
403		<< "layout (" << toString(m_params.geometry) << ") out;\n"
404		<< "layout (max_vertices=256, max_primitives=256) out;\n"
405		<< "\n"
406		<< "layout (push_constant, std430) uniform PushConstants {\n"
407		<< "	uint prevDrawCalls;\n"
408		<< "} pc;\n"
409		<< "\n"
410		;
411
412	if (m_params.useTaskShader)
413		mesh << taskDataDecl << "\n";
414
415	mesh
416		<< "\n"
417		<< "shared uint currentCol;\n"
418		<< "\n"
419		<< "void main (void)\n"
420		<< "{\n"
421		<< "    atomicExchange(currentCol, 0u);\n"
422		<< "    barrier();\n"
423		<< "\n"
424		<< "    const uint colCount = uint(" << kImageWidth << ");\n"
425		<< "    const uint rowCount = uint(" << imageHeight << ");\n"
426		<< "    const uint rowsPerDraw = uint(" << kMeshWorkGroupsPerCall << ");\n"
427		<< "\n"
428		<< "    const float pixWidth = 2.0 / float(colCount);\n"
429		<< "    const float pixHeight = 2.0 / float(rowCount);\n"
430		<< "    const float horDelta = pixWidth / 4.0;\n"
431		<< "    const float verDelta = pixHeight / 4.0;\n"
432		<< "\n"
433		<< "    const uint DrawIndex = " << (m_params.useTaskShader ? "td.drawIndex" : "uint(gl_DrawID)") << ";\n"
434		<< "    const uint currentWGIndex = (" << (m_params.useTaskShader ? "2u * td.branch[min(gl_LocalInvocationIndex, " + std::to_string(kTaskLocalInvocations - 1u) + ")] + " : "") << "gl_WorkGroupID.x + gl_WorkGroupID.y + gl_WorkGroupID.z);\n"
435		<< "    const uint row = (pc.prevDrawCalls + DrawIndex) * rowsPerDraw + currentWGIndex;\n"
436		<< "    const uint vertsPerPrimitive = " << vertsPerPrimitive(m_params.geometry) << ";\n"
437		<< "\n"
438		<< "    SetMeshOutputsEXT(colCount * vertsPerPrimitive, colCount);\n"
439		<< "\n"
440		<< "    const uint col = atomicAdd(currentCol, 1);\n"
441		<< "    if (col < colCount)\n"
442		<< "    {\n"
443		<< "        const float xCenter = (float(col) + 0.5) / colCount * 2.0 - 1.0;\n"
444		<< "        const float yCenter = (float(row) + 0.5) / rowCount * 2.0 - 1.0;\n"
445		<< "\n"
446		<< "        const uint firstVert = col * vertsPerPrimitive;\n"
447		<< "\n"
448		;
449
450	switch (m_params.geometry)
451	{
452	case GeometryType::POINTS:
453		mesh
454			<< "        gl_MeshVerticesEXT[firstVert].gl_Position = vec4(xCenter, yCenter, 0.0, 1.0);\n"
455			<< "        gl_MeshVerticesEXT[firstVert].gl_PointSize = 1.0;\n"
456			<< "        gl_PrimitivePointIndicesEXT[col] = firstVert;\n"
457			;
458		break;
459	case GeometryType::LINES:
460		mesh
461			<< "        gl_MeshVerticesEXT[firstVert + 0].gl_Position = vec4(xCenter - horDelta, yCenter, 0.0, 1.0);\n"
462			<< "        gl_MeshVerticesEXT[firstVert + 1].gl_Position = vec4(xCenter + horDelta, yCenter, 0.0, 1.0);\n"
463			<< "        gl_PrimitiveLineIndicesEXT[col] = uvec2(firstVert, firstVert + 1);\n"
464			;
465		break;
466	case GeometryType::TRIANGLES:
467		mesh
468			<< "        gl_MeshVerticesEXT[firstVert + 0].gl_Position = vec4(xCenter           , yCenter - verDelta, 0.0, 1.0);\n"
469			<< "        gl_MeshVerticesEXT[firstVert + 1].gl_Position = vec4(xCenter - horDelta, yCenter + verDelta, 0.0, 1.0);\n"
470			<< "        gl_MeshVerticesEXT[firstVert + 2].gl_Position = vec4(xCenter + horDelta, yCenter + verDelta, 0.0, 1.0);\n"
471			<< "        gl_PrimitiveTriangleIndicesEXT[col] = uvec3(firstVert, firstVert + 1, firstVert + 2);\n"
472			;
473		break;
474	default:
475		DE_ASSERT(false);
476		break;
477	}
478
479	mesh
480		<< "    }\n"
481		<< "}\n"
482		;
483	programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << meshBuildOpts;
484
485	if (m_params.useTaskShader)
486	{
487		// See TestParams::getDrawGroupCount().
488		de::Random				rnd				(m_params.randomSeed);
489		std::vector<uint32_t>	meshTaskCount	{kMeshWorkGroupsPerTask, 1u, 1u};
490
491		rnd.shuffle(meshTaskCount.begin(), meshTaskCount.end());
492
493		std::ostringstream task;
494		task
495			<< "#version 460\n"
496			<< "#extension GL_EXT_mesh_shader : enable\n"
497			<< "\n"
498			<< "layout (local_size_x=" << kTaskLocalInvocationsX << ", local_size_y=" << kTaskLocalInvocationsY << ", local_size_z=" << kTaskLocalInvocationsZ << ") in;\n"
499			<< "\n"
500			<< taskDataDecl
501			<< "\n"
502			<< "void main ()\n"
503			<< "{\n"
504			<< "   td.branch[gl_LocalInvocationIndex] = gl_WorkGroupID.x + gl_WorkGroupID.y + gl_WorkGroupID.z;\n"
505			<< "   td.drawIndex = uint(gl_DrawID);\n"
506			<< "   EmitMeshTasksEXT(" << meshTaskCount.at(0) << ", " << meshTaskCount.at(1) << ", " << meshTaskCount.at(2) << ");\n"
507			<< "}\n"
508			;
509		programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << meshBuildOpts;
510	}
511}
512
513TestInstance* MeshQueryCase::createInstance (Context& context) const
514{
515	return new MeshQueryInstance(context, m_params);
516}
517
518void MeshQueryCase::checkSupport (Context& context) const
519{
520	checkTaskMeshShaderSupportEXT(context, m_params.useTaskShader/*requireTask*/, true/*requireMesh*/);
521
522	const auto& meshFeatures = context.getMeshShaderFeaturesEXT();
523	if (!meshFeatures.meshShaderQueries)
524		TCU_THROW(NotSupportedError, "meshShaderQueries not supported");
525
526	if (m_params.areQueriesInherited())
527		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_INHERITED_QUERIES);
528
529	if (m_params.resetType == ResetCase::NONE_WITH_HOST)
530		context.requireDeviceFunctionality("VK_EXT_host_query_reset");
531
532	if (m_params.multiView)
533	{
534		if (!meshFeatures.multiviewMeshShader)
535			TCU_THROW(NotSupportedError, "multiviewMeshShader not supported");
536
537		const auto& meshProperties = context.getMeshShaderPropertiesEXT();
538		if (meshProperties.maxMeshMultiviewViewCount < m_params.getViewCount())
539			TCU_THROW(NotSupportedError, "maxMeshMultiviewViewCount too low");
540	}
541}
542
543VkDrawMeshTasksIndirectCommandEXT MeshQueryInstance::getRandomShuffle (uint32_t groupCount)
544{
545	std::array<uint32_t, 3> counts { groupCount, 1u, 1u };
546	m_rnd.shuffle(counts.begin(), counts.end());
547
548	const VkDrawMeshTasksIndirectCommandEXT result { counts[0], counts[1], counts[2] };
549	return result;
550}
551
552void MeshQueryInstance::recordDraws (const VkCommandBuffer cmdBuffer, const VkPipeline pipeline, const VkPipelineLayout layout)
553{
554	const auto&	vkd				= m_context.getDeviceInterface();
555	const auto	device			= m_context.getDevice();
556	auto&		alloc			= m_context.getDefaultAllocator();
557	const auto	drawGroupCount	= m_params->getDrawGroupCount();
558	const auto	pcSize			= static_cast<uint32_t>(sizeof(uint32_t));
559
560	vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
561
562	if (m_params->drawCall == DrawCallType::DIRECT)
563	{
564		uint32_t totalDrawCalls = 0u;
565		for (const auto& blockSize : m_params->drawBlocks)
566		{
567			for (uint32_t drawIdx = 0u; drawIdx < blockSize; ++drawIdx)
568			{
569				const auto counts = getRandomShuffle(drawGroupCount);
570				vkd.cmdPushConstants(cmdBuffer, layout, VK_SHADER_STAGE_MESH_BIT_EXT, 0u, pcSize, &totalDrawCalls);
571				vkd.cmdDrawMeshTasksEXT(cmdBuffer, counts.groupCountX, counts.groupCountY, counts.groupCountZ);
572				++totalDrawCalls;
573			}
574		}
575	}
576	else if (m_params->drawCall == DrawCallType::INDIRECT || m_params->drawCall == DrawCallType::INDIRECT_WITH_COUNT)
577	{
578		if (m_params->drawBlocks.empty())
579			return;
580
581		const auto totalDrawCount	= m_params->getTotalDrawCount();
582		const auto cmdSize			= static_cast<uint32_t>(sizeof(VkDrawMeshTasksIndirectCommandEXT));
583
584		std::vector<VkDrawMeshTasksIndirectCommandEXT> indirectCommands;
585		indirectCommands.reserve(totalDrawCount);
586
587		for (uint32_t i = 0u; i < totalDrawCount; ++i)
588			indirectCommands.emplace_back(getRandomShuffle(drawGroupCount));
589
590		// Copy the array to a host-visible buffer.
591		// Note: We make sure all indirect buffers are allocated with a non-zero size by adding cmdSize to the expected size.
592		// Size of buffer must be greater than stride * (maxDrawCount - 1) + offset + sizeof(VkDrawMeshTasksIndirectCommandEXT) so we multiply by 2
593		const auto indirectBufferSize		= de::dataSize(indirectCommands);
594		const auto indirectBufferCreateInfo	= makeBufferCreateInfo(static_cast<VkDeviceSize>((indirectBufferSize + cmdSize) * 2), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
595
596		m_indirectBuffer			= BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, indirectBufferCreateInfo, MemoryRequirement::HostVisible));
597		auto& indirectBufferAlloc	= m_indirectBuffer->getAllocation();
598		void* indirectBufferData	= indirectBufferAlloc.getHostPtr();
599
600		deMemcpy(indirectBufferData, indirectCommands.data(), indirectBufferSize);
601		flushAlloc(vkd, device, indirectBufferAlloc);
602
603		if (m_params->drawCall == DrawCallType::INDIRECT)
604		{
605			uint32_t accumulatedCount = 0u;
606
607			for (const auto& blockSize : m_params->drawBlocks)
608			{
609				const auto offset = static_cast<VkDeviceSize>(cmdSize * accumulatedCount);
610				vkd.cmdPushConstants(cmdBuffer, layout, VK_SHADER_STAGE_MESH_BIT_EXT, 0u, pcSize, &accumulatedCount);
611				vkd.cmdDrawMeshTasksIndirectEXT(cmdBuffer, m_indirectBuffer->get(), offset, blockSize, cmdSize);
612				accumulatedCount += blockSize;
613			}
614		}
615		else
616		{
617			// Copy the "block sizes" to a host-visible buffer.
618			const auto indirectCountBufferSize			= de::dataSize(m_params->drawBlocks);
619			const auto indirectCountBufferCreateInfo	= makeBufferCreateInfo(static_cast<VkDeviceSize>(indirectCountBufferSize + cmdSize), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
620
621			m_indirectCountBuffer = BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, indirectCountBufferCreateInfo, MemoryRequirement::HostVisible));
622			auto& indirectCountBufferAlloc = m_indirectCountBuffer->getAllocation();
623			void* indirectCountBufferData = indirectCountBufferAlloc.getHostPtr();
624
625			deMemcpy(indirectCountBufferData, m_params->drawBlocks.data(), indirectCountBufferSize);
626			flushAlloc(vkd, device, indirectCountBufferAlloc);
627
628			// Record indirect draws with count.
629			uint32_t accumulatedCount = 0u;
630
631			for (uint32_t countIdx = 0u; countIdx < m_params->drawBlocks.size(); ++countIdx)
632			{
633				const auto&	blockSize	= m_params->drawBlocks.at(countIdx);
634				const auto	offset		= static_cast<VkDeviceSize>(cmdSize * accumulatedCount);
635				const auto	countOffset	= static_cast<VkDeviceSize>(sizeof(uint32_t) * countIdx);
636
637				vkd.cmdPushConstants(cmdBuffer, layout, VK_SHADER_STAGE_MESH_BIT_EXT, 0u, pcSize, &accumulatedCount);
638				vkd.cmdDrawMeshTasksIndirectCountEXT(cmdBuffer, m_indirectBuffer->get(), offset, m_indirectCountBuffer->get(), countOffset, blockSize * 2u, cmdSize);
639				accumulatedCount += blockSize;
640			}
641		}
642	}
643	else
644	{
645		DE_ASSERT(false);
646	}
647}
648
649void MeshQueryInstance::beginFirstQueries (const VkCommandBuffer cmdBuffer, const std::vector<VkQueryPool>& queryPools) const
650{
651	const auto& vkd = m_context.getDeviceInterface();
652	for (const auto& pool : queryPools)
653		vkd.cmdBeginQuery(cmdBuffer, pool, 0u, 0u);
654}
655
656void MeshQueryInstance::endFirstQueries (const VkCommandBuffer cmdBuffer, const std::vector<VkQueryPool>& queryPools) const
657{
658	const auto& vkd = m_context.getDeviceInterface();
659	for (const auto& pool : queryPools)
660		vkd.cmdEndQuery(cmdBuffer, pool, 0u);
661}
662
663void MeshQueryInstance::resetFirstQueries (const VkCommandBuffer cmdBuffer, const std::vector<VkQueryPool>& queryPools, const uint32_t queryCount) const
664{
665	const auto& vkd = m_context.getDeviceInterface();
666	for (const auto& pool : queryPools)
667		vkd.cmdResetQueryPool(cmdBuffer, pool, 0u, queryCount);
668}
669
670void MeshQueryInstance::submitCommands (const VkCommandBuffer cmdBuffer) const
671{
672	const auto&	vkd		= m_context.getDeviceInterface();
673	const auto	queue	= m_context.getUniversalQueue();
674
675	const VkSubmitInfo submitInfo =
676	{
677		VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType				sType;
678		nullptr,						// const void*					pNext;
679		0u,								// deUint32						waitSemaphoreCount;
680		nullptr,						// const VkSemaphore*			pWaitSemaphores;
681		nullptr,						// const VkPipelineStageFlags*	pWaitDstStageMask;
682		1u,								// deUint32						commandBufferCount;
683		&cmdBuffer,						// const VkCommandBuffer*		pCommandBuffers;
684		0u,								// deUint32						signalSemaphoreCount;
685		nullptr,						// const VkSemaphore*			pSignalSemaphores;
686	};
687
688	VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, m_fence.get()));
689}
690
691void MeshQueryInstance::waitForFence (void) const
692{
693	const auto&	vkd		= m_context.getDeviceInterface();
694	const auto	device	= m_context.getDevice();
695
696	VK_CHECK(vkd.waitForFences(device, 1u, &m_fence.get(), VK_TRUE, ~0ull));
697}
698
699// Read query item from memory. Always returns uint64_t for convenience. Advances pointer to the next item.
700uint64_t readFromPtrAndAdvance (uint8_t** const ptr, VkDeviceSize itemSize)
701{
702	const auto	itemSizeSz	= static_cast<size_t>(itemSize);
703	uint64_t	result		= std::numeric_limits<uint64_t>::max();
704
705	if (itemSize == k64sz)
706	{
707		deMemcpy(&result, *ptr, itemSizeSz);
708	}
709	else if (itemSize == k32sz)
710	{
711		uint32_t aux = std::numeric_limits<uint32_t>::max();
712		deMemcpy(&aux, *ptr, itemSizeSz);
713		result = static_cast<uint64_t>(aux);
714	}
715	else
716		DE_ASSERT(false);
717
718	*ptr += itemSizeSz;
719	return result;
720}
721
722// General procedure to verify correctness of the availability bit, which does not depend on the exact query.
723void readAndVerifyAvailabilityBit (uint8_t** const resultsPtr, VkDeviceSize itemSize, const TestParams& params, const std::string& queryName)
724{
725	const uint64_t availabilityBitVal = readFromPtrAndAdvance(resultsPtr, itemSize);
726
727	if (params.resetType == ResetCase::BEFORE_ACCESS)
728	{
729		if (availabilityBitVal)
730		{
731			std::ostringstream msg;
732			msg << queryName << " availability bit expected to be zero due to reset before access, but found " << availabilityBitVal;
733			TCU_FAIL(msg.str());
734		}
735	}
736	else if (params.waitBit)
737	{
738		if (!availabilityBitVal)
739		{
740			std::ostringstream msg;
741			msg << queryName << " availability expected to be true due to wait bit and not previous reset, but found " << availabilityBitVal;
742			TCU_FAIL(msg.str());
743		}
744	}
745}
746
747// Verifies a query counter has the right value given the test parameters.
748// - readVal is the reported counter value.
749// - expectedMinVal and expectedMaxVal are the known right counts under "normal" circumstances.
750// - The actual range of valid values will be adjusted depending on the test parameters (wait bit, reset, etc).
751void verifyQueryCounter (uint64_t readVal, uint64_t expectedMinVal, uint64_t expectedMaxVal, const TestParams& params, const std::string& queryName)
752{
753	uint64_t minVal = expectedMinVal;
754	uint64_t maxVal = expectedMaxVal;
755
756	// Resetting a query via vkCmdResetQueryPool or vkResetQueryPool sets the status to unavailable and makes the numerical results undefined.
757	const bool wasReset = (params.resetType == ResetCase::BEFORE_ACCESS);
758
759	if (!wasReset)
760	{
761		if (!params.waitBit)
762			minVal = 0ull;
763
764		if (!de::inRange(readVal, minVal, maxVal))
765		{
766			std::ostringstream msg;
767			msg << queryName << " not in expected range: " << readVal << " out of [" << minVal << ", " << maxVal << "]";
768			TCU_FAIL(msg.str());
769		}
770	}
771}
772
773Move<VkRenderPass> MeshQueryInstance::makeCustomRenderPass (const DeviceInterface& vkd, VkDevice device, uint32_t layerCount, VkFormat format)
774{
775	DE_ASSERT(layerCount > 0u);
776
777	const VkAttachmentDescription colorAttachmentDescription =
778	{
779		0u,											// VkAttachmentDescriptionFlags    flags
780		format,										// VkFormat                        format
781		VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits           samples
782		VK_ATTACHMENT_LOAD_OP_CLEAR,				// VkAttachmentLoadOp              loadOp
783		VK_ATTACHMENT_STORE_OP_STORE,				// VkAttachmentStoreOp             storeOp
784		VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// VkAttachmentLoadOp              stencilLoadOp
785		VK_ATTACHMENT_STORE_OP_DONT_CARE,			// VkAttachmentStoreOp             stencilStoreOp
786		VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout                   initialLayout
787		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// VkImageLayout                   finalLayout
788	};
789
790	const VkAttachmentReference colorAttachmentRef = makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
791
792	const VkSubpassDescription subpassDescription =
793	{
794		0u,									// VkSubpassDescriptionFlags       flags
795		VK_PIPELINE_BIND_POINT_GRAPHICS,	// VkPipelineBindPoint             pipelineBindPoint
796		0u,									// deUint32                        inputAttachmentCount
797		nullptr,							// const VkAttachmentReference*    pInputAttachments
798		1u,									// deUint32                        colorAttachmentCount
799		&colorAttachmentRef,				// const VkAttachmentReference*    pColorAttachments
800		nullptr,							// const VkAttachmentReference*    pResolveAttachments
801		nullptr,							// const VkAttachmentReference*    pDepthStencilAttachment
802		0u,									// deUint32                        preserveAttachmentCount
803		nullptr								// const deUint32*                 pPreserveAttachments
804	};
805
806	const uint32_t viewMask = ((1u << layerCount) - 1u);
807	const VkRenderPassMultiviewCreateInfo multiviewCreateInfo =
808	{
809		VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO,	//	VkStructureType	sType;
810		nullptr,												//	const void*		pNext;
811		1u,														//	uint32_t		subpassCount;
812		&viewMask,												//	const uint32_t*	pViewMasks;
813		0u,														//	uint32_t		dependencyCount;
814		nullptr,												//	const int32_t*	pViewOffsets;
815		1u,														//	uint32_t		correlationMaskCount;
816		&viewMask,												//	const uint32_t*	pCorrelationMasks;
817	};
818
819	const VkRenderPassCreateInfo renderPassInfo =
820	{
821		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,				// VkStructureType                   sType
822		&multiviewCreateInfo,									// const void*                       pNext
823		0u,														// VkRenderPassCreateFlags           flags
824		1u,														// deUint32                          attachmentCount
825		&colorAttachmentDescription,							// const VkAttachmentDescription*    pAttachments
826		1u,														// deUint32                          subpassCount
827		&subpassDescription,									// const VkSubpassDescription*       pSubpasses
828		0u,														// deUint32                          dependencyCount
829		nullptr,												// const VkSubpassDependency*        pDependencies
830	};
831
832	return createRenderPass(vkd, device, &renderPassInfo);
833}
834
835tcu::TestStatus MeshQueryInstance::iterate (void)
836{
837	const auto&			vkd				= m_context.getDeviceInterface();
838	const auto			device			= m_context.getDevice();
839	auto&				alloc			= m_context.getDefaultAllocator();
840	const auto			queue			= m_context.getUniversalQueue();
841	const auto			queueIndex		= m_context.getUniversalQueueFamilyIndex();
842
843	const auto			colorFormat		= VK_FORMAT_R8G8B8A8_UNORM;
844	const auto			colorTcuFormat	= mapVkFormat(colorFormat);
845	const auto			imageHeight		= m_params->getImageHeight();
846	const auto			colorExtent		= makeExtent3D(kImageWidth, std::max(imageHeight, 1u), 1u);
847	const auto			viewCount		= m_params->getViewCount();
848	const tcu::IVec3	colorTcuExtent	(static_cast<int>(colorExtent.width), static_cast<int>(colorExtent.height), static_cast<int>(viewCount));
849	const auto			colorUsage		= (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
850	const tcu::Vec4		clearColor		(0.0f, 0.0f, 0.0f, 1.0f);
851	const auto			expectedPrims	= (imageHeight * kImageWidth);
852	const auto			expectedTaskInv	= (m_params->useTaskShader ? (imageHeight * kTaskLocalInvocations / 2u) : 0u);
853	const auto			expectedMeshInv	= imageHeight * kMeshLocalInvocations;
854	const auto			imageViewType	= ((viewCount > 1u) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D);
855
856	// Color buffer.
857	const VkImageCreateInfo colorBufferCreateInfo =
858	{
859		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
860		nullptr,								//	const void*				pNext;
861		0u,										//	VkImageCreateFlags		flags;
862		VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
863		colorFormat,							//	VkFormat				format;
864		colorExtent,							//	VkExtent3D				extent;
865		1u,										//	uint32_t				mipLevels;
866		viewCount,								//	uint32_t				arrayLayers;
867		VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
868		VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
869		colorUsage,								//	VkImageUsageFlags		usage;
870		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
871		0u,										//	uint32_t				queueFamilyIndexCount;
872		nullptr,								//	const uint32_t*			pQueueFamilyIndices;
873		VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
874	};
875
876	const ImageWithMemory	colorBuffer	(vkd, device, alloc, colorBufferCreateInfo, MemoryRequirement::Any);
877	const auto				colorSRR	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, viewCount);
878	const auto				colorSRL	= makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, viewCount);
879	const auto				colorView	= makeImageView(vkd, device, colorBuffer.get(), imageViewType, colorFormat, colorSRR);
880
881	// Verification buffer.
882	DE_ASSERT(colorExtent.depth == 1u);
883	const VkDeviceSize		verifBufferSize			= colorExtent.width * colorExtent.height * viewCount * static_cast<VkDeviceSize>(tcu::getPixelSize(colorTcuFormat));
884	const auto				verifBufferCreateInfo	= makeBufferCreateInfo(verifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
885	const BufferWithMemory	verifBuffer				(vkd, device, alloc, verifBufferCreateInfo, MemoryRequirement::HostVisible);
886
887	// Shader modules.
888	const auto&	binaries	= m_context.getBinaryCollection();
889	const auto	taskModule	= (binaries.contains("task")
890							? createShaderModule(vkd, device, binaries.get("task"))
891							: Move<VkShaderModule>());
892	const auto	meshModule	= createShaderModule(vkd, device, binaries.get("mesh"));
893	const auto	fragModule	= createShaderModule(vkd, device, binaries.get("frag"));
894
895	// Pipeline layout.
896	const auto pcSize			= static_cast<uint32_t>(sizeof(uint32_t));
897	const auto pcRange			= makePushConstantRange(VK_SHADER_STAGE_MESH_BIT_EXT, 0u, pcSize);
898	const auto pipelineLayout	= makePipelineLayout(vkd, device, DE_NULL, &pcRange);
899
900	// Render pass, framebuffer, viewports, scissors.
901	const auto renderPass	= makeCustomRenderPass(vkd, device, viewCount, colorFormat);
902	const auto framebuffer	= makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), colorExtent.width, colorExtent.height);
903
904	const std::vector<VkViewport>	viewports	(1u, makeViewport(colorExtent));
905	const std::vector<VkRect2D>		scissors	(1u, makeRect2D(colorExtent));
906
907	const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
908		taskModule.get(), meshModule.get(), fragModule.get(),
909		renderPass.get(), viewports, scissors);
910
911	// Command pool and buffers.
912	const auto cmdPool			= makeCommandPool(vkd, device, queueIndex);
913	const auto cmdBufferPtr		= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
914	const auto resetCmdBuffer	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
915	const auto cmdBuffer		= cmdBufferPtr.get();
916	const auto rawPipeline		= pipeline.get();
917	const auto rawPipeLayout	= pipelineLayout.get();
918
919	Move<VkCommandBuffer>	secCmdBufferPtr;
920	VkCommandBuffer			secCmdBuffer = DE_NULL;
921
922	if (m_params->useSecondary)
923	{
924		secCmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY);
925		secCmdBuffer	= secCmdBufferPtr.get();
926	}
927
928	// Create the query pools that we need.
929	Move<VkQueryPool> primitivesQueryPool;
930	Move<VkQueryPool> statsQueryPool;
931
932	const bool hasPrimitivesQuery	= m_params->hasPrimitivesQuery();
933	const bool hasMeshInvStat		= m_params->hasMeshInvStat();
934	const bool hasTaskInvStat		= m_params->hasTaskInvStat();
935	const bool hasStatsQuery		= (hasMeshInvStat || hasTaskInvStat);
936
937	std::vector<VkQueryPool> allQueryPools;
938
939	if (hasPrimitivesQuery)
940	{
941		const VkQueryPoolCreateInfo queryPoolCreateInfo =
942		{
943			VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,			//	VkStructureType					sType;
944			nullptr,											//	const void*						pNext;
945			0u,													//	VkQueryPoolCreateFlags			flags;
946			VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT,		//	VkQueryType						queryType;
947			viewCount,											//	uint32_t						queryCount;
948			0u,													//	VkQueryPipelineStatisticFlags	pipelineStatistics;
949		};
950		primitivesQueryPool = createQueryPool(vkd, device, &queryPoolCreateInfo);
951		allQueryPools.push_back(primitivesQueryPool.get());
952	}
953
954	const VkQueryPipelineStatisticFlags statQueryFlags =
955		( (hasMeshInvStat ? VK_QUERY_PIPELINE_STATISTIC_MESH_SHADER_INVOCATIONS_BIT_EXT : 0)
956		| (hasTaskInvStat ? VK_QUERY_PIPELINE_STATISTIC_TASK_SHADER_INVOCATIONS_BIT_EXT : 0) );
957
958	if (hasStatsQuery)
959	{
960		const VkQueryPoolCreateInfo queryPoolCreateInfo =
961		{
962			VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,	//	VkStructureType					sType;
963			nullptr,									//	const void*						pNext;
964			0u,											//	VkQueryPoolCreateFlags			flags;
965			VK_QUERY_TYPE_PIPELINE_STATISTICS,			//	VkQueryType						queryType;
966			viewCount,									//	uint32_t						queryCount;
967			statQueryFlags,								//	VkQueryPipelineStatisticFlags	pipelineStatistics;
968		};
969		statsQueryPool = createQueryPool(vkd, device, &queryPoolCreateInfo);
970		allQueryPools.push_back(statsQueryPool.get());
971	}
972
973	// Some query result parameters.
974	const auto		querySizesAndOffsets	= m_params->getQuerySizesAndOffsets();
975	const size_t	maxResultSize			= k64sz * 10ull; // 10 items at most: (prim+avail+task+mesh+avail)*2.
976	const auto		statsQueryOffsetSz		= static_cast<size_t>(querySizesAndOffsets.statsQueryOffset);
977
978	// Create output buffer for the queries.
979	BufferWithMemoryPtr queryResultsBuffer;
980	if (m_params->access == AccessMethod::COPY)
981	{
982		const auto queryResultsBufferInfo = makeBufferCreateInfo(static_cast<VkDeviceSize>(maxResultSize), VK_BUFFER_USAGE_TRANSFER_DST_BIT);
983		queryResultsBuffer = BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, queryResultsBufferInfo, MemoryRequirement::HostVisible));
984	}
985	std::vector<uint8_t> queryResultsHostVec(maxResultSize, 0);
986
987	const auto statsDataHostVecPtr	= queryResultsHostVec.data() + statsQueryOffsetSz;
988	const auto statsRemainingSize	= maxResultSize - statsQueryOffsetSz;
989
990	// Result flags when obtaining query results.
991	const auto queryResultFlags = m_params->getQueryResultFlags();
992
993	// Reset queries before use.
994	// Queries will be reset in a separate command buffer to make sure they are always properly reset before use.
995	// We could do this with VK_EXT_host_query_reset too.
996	{
997		beginCommandBuffer(vkd, resetCmdBuffer.get());
998		resetFirstQueries(resetCmdBuffer.get(), allQueryPools, viewCount);
999		endCommandBuffer(vkd, resetCmdBuffer.get());
1000		submitCommandsAndWait(vkd, device, queue, resetCmdBuffer.get());
1001	}
1002
1003	// Command recording.
1004	beginCommandBuffer(vkd, cmdBuffer);
1005
1006	if (m_params->useSecondary)
1007	{
1008		const VkCommandBufferInheritanceInfo inheritanceInfo =
1009		{
1010			VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,			//	VkStructureType					sType;
1011			nullptr,													//	const void*						pNext;
1012			renderPass.get(),											//	VkRenderPass					renderPass;
1013			0u,															//	uint32_t						subpass;
1014			framebuffer.get(),											//	VkFramebuffer					framebuffer;
1015			VK_FALSE,													//	VkBool32						occlusionQueryEnable;
1016			0u,															//	VkQueryControlFlags				queryFlags;
1017			(m_params->areQueriesInherited() ? statQueryFlags : 0u),	//	VkQueryPipelineStatisticFlags	pipelineStatistics;
1018		};
1019
1020		const auto secCmdBufferFlags = (VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
1021
1022		const VkCommandBufferBeginInfo secBeginInfo =
1023		{
1024			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	//	VkStructureType							sType;
1025			nullptr,										//	const void*								pNext;
1026			secCmdBufferFlags,								//	VkCommandBufferUsageFlags				flags;
1027			&inheritanceInfo,								//	const VkCommandBufferInheritanceInfo*	pInheritanceInfo;
1028		};
1029
1030		VK_CHECK(vkd.beginCommandBuffer(secCmdBuffer, &secBeginInfo));
1031	}
1032
1033	const auto subpassContents	= (m_params->useSecondary ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE);
1034
1035	// 4 cases:
1036	//
1037	// * Only primary, inside render pass
1038	// * Only primary, outside render pass
1039	// * Primary and secondary, inside render pass (query in secondary)
1040	// * Primary and secondary, outside render pass (query inheritance)
1041
1042	if (!m_params->useSecondary)
1043	{
1044		if (m_params->insideRenderPass)
1045		{
1046			beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), clearColor, subpassContents);
1047				beginFirstQueries(cmdBuffer, allQueryPools);
1048				recordDraws(cmdBuffer, rawPipeline, rawPipeLayout);
1049				endFirstQueries(cmdBuffer, allQueryPools);
1050			endRenderPass(vkd, cmdBuffer);
1051		}
1052		else
1053		{
1054			DE_ASSERT(!m_params->multiView);
1055			beginFirstQueries(cmdBuffer, allQueryPools);
1056			beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), clearColor, subpassContents);
1057				recordDraws(cmdBuffer, rawPipeline, rawPipeLayout);
1058			endRenderPass(vkd, cmdBuffer);
1059			endFirstQueries(cmdBuffer, allQueryPools);
1060		}
1061	}
1062	else
1063	{
1064		if (m_params->insideRenderPass) // Queries in secondary command buffer.
1065		{
1066			beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), clearColor, subpassContents);
1067				beginFirstQueries(secCmdBuffer, allQueryPools);
1068				recordDraws(secCmdBuffer, rawPipeline, rawPipeLayout);
1069				endFirstQueries(secCmdBuffer, allQueryPools);
1070				endCommandBuffer(vkd, secCmdBuffer);
1071				vkd.cmdExecuteCommands(cmdBuffer, 1u, &secCmdBuffer);
1072			endRenderPass(vkd, cmdBuffer);
1073		}
1074		else // Inherited queries case.
1075		{
1076			DE_ASSERT(!m_params->multiView);
1077			beginFirstQueries(cmdBuffer, allQueryPools);
1078			beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), clearColor, subpassContents);
1079				recordDraws(secCmdBuffer, rawPipeline, rawPipeLayout);
1080				endCommandBuffer(vkd, secCmdBuffer);
1081				vkd.cmdExecuteCommands(cmdBuffer, 1u, &secCmdBuffer);
1082			endRenderPass(vkd, cmdBuffer);
1083			endFirstQueries(cmdBuffer, allQueryPools);
1084		}
1085	}
1086
1087	// Render to copy barrier.
1088	{
1089		const auto preCopyImgBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.get(), colorSRR);
1090		cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preCopyImgBarrier);
1091	}
1092
1093	if (m_params->resetType == ResetCase::BEFORE_ACCESS)
1094		resetFirstQueries(cmdBuffer, allQueryPools, viewCount);
1095
1096	if (m_params->access == AccessMethod::COPY)
1097	{
1098		if (hasPrimitivesQuery)
1099			vkd.cmdCopyQueryPoolResults(cmdBuffer, primitivesQueryPool.get(), 0u, viewCount, queryResultsBuffer->get(), 0ull, querySizesAndOffsets.primitivesQuerySize, queryResultFlags);
1100
1101		if (hasStatsQuery)
1102			vkd.cmdCopyQueryPoolResults(cmdBuffer, statsQueryPool.get(), 0u, viewCount, queryResultsBuffer->get(), querySizesAndOffsets.statsQueryOffset, querySizesAndOffsets.statsQuerySize, queryResultFlags);
1103	}
1104
1105	if (m_params->resetType == ResetCase::AFTER_ACCESS)
1106		resetFirstQueries(cmdBuffer, allQueryPools, viewCount);
1107
1108	// Copy color attachment to verification buffer.
1109	{
1110		const auto copyRegion = makeBufferImageCopy(colorExtent, colorSRL);
1111		vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verifBuffer.get(), 1u, &copyRegion);
1112	}
1113
1114	// This barrier applies to both the color verification buffer and the queries if they were copied.
1115	const auto postCopyBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
1116	cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postCopyBarrier);
1117
1118	endCommandBuffer(vkd, cmdBuffer);
1119	submitCommands(cmdBuffer);
1120
1121	// When using GET, obtain results before actually waiting for the fence if possible. This way it's more interesting for cases
1122	// that do not use the wait bit.
1123	if (m_params->access == AccessMethod::GET)
1124	{
1125		// When resetting queries before access, we need to make sure the reset operation has really taken place.
1126		if (m_params->resetType == ResetCase::BEFORE_ACCESS)
1127			waitForFence();
1128
1129		const bool allowNotReady = !m_params->waitBit;
1130
1131		if (hasPrimitivesQuery)
1132		{
1133			const auto res = vkd.getQueryPoolResults(device, primitivesQueryPool.get(), 0u, viewCount, de::dataSize(queryResultsHostVec), queryResultsHostVec.data(), querySizesAndOffsets.primitivesQuerySize, queryResultFlags);
1134			checkGetQueryRes(res, allowNotReady);
1135		}
1136
1137		if (hasStatsQuery)
1138		{
1139			const auto res = vkd.getQueryPoolResults(device, statsQueryPool.get(), 0u, viewCount, statsRemainingSize, statsDataHostVecPtr, querySizesAndOffsets.statsQuerySize, queryResultFlags);
1140			checkGetQueryRes(res, allowNotReady);
1141		}
1142	}
1143
1144	waitForFence();
1145
1146	// Verify color buffer.
1147	{
1148		auto& log				= m_context.getTestContext().getLog();
1149		auto& verifBufferAlloc	= verifBuffer.getAllocation();
1150		void* verifBufferData	= verifBufferAlloc.getHostPtr();
1151
1152		invalidateAlloc(vkd, device, verifBufferAlloc);
1153
1154		tcu::ConstPixelBufferAccess	verifAccess		(colorTcuFormat, colorTcuExtent, verifBufferData);
1155		const tcu::Vec4				threshold		(0.0f, 0.0f, 0.0f, 0.0f); // Results should be exact.
1156
1157		for (int layer = 0; layer < colorTcuExtent.z(); ++layer)
1158		{
1159			// This should match the fragment shader.
1160			const auto green			= ((layer > 0) ? 1.0f : 0.0f);
1161			const auto referenceColor	= ((m_params->getTotalDrawCount() > 0u) ? tcu::Vec4(0.0f, green, 1.0f, 1.0f) : clearColor);
1162			const auto layerAccess		= tcu::getSubregion(verifAccess, 0, 0, layer, colorTcuExtent.x(), colorTcuExtent.y(), 1);
1163
1164			if (!tcu::floatThresholdCompare(log, "Color Result", "", referenceColor, layerAccess, threshold, tcu::COMPARE_LOG_ON_ERROR))
1165			{
1166				std::ostringstream msg;
1167				msg << "Color target mismatch at layer " << layer << "; check log for details";
1168				TCU_FAIL(msg.str());
1169			}
1170		}
1171	}
1172
1173	// Verify query results.
1174	{
1175		const auto	itemSize	= querySizesAndOffsets.queryItemSize;
1176		uint8_t*	resultsPtr	= nullptr;
1177
1178		if (m_params->access == AccessMethod::COPY)
1179		{
1180			auto& queryResultsBufferAlloc	= queryResultsBuffer->getAllocation();
1181			void* queryResultsBufferData	= queryResultsBufferAlloc.getHostPtr();
1182			invalidateAlloc(vkd, device, queryResultsBufferAlloc);
1183
1184			resultsPtr = reinterpret_cast<uint8_t*>(queryResultsBufferData);
1185		}
1186		else if (m_params->access == AccessMethod::GET)
1187		{
1188			resultsPtr = queryResultsHostVec.data();
1189		}
1190
1191
1192		if (hasPrimitivesQuery)
1193		{
1194			const std::string	queryGroupName		= "Primitive count";
1195			uint64_t			totalPrimitiveCount	= 0ull;
1196
1197			for (uint32_t viewIndex = 0u; viewIndex < viewCount; ++viewIndex)
1198			{
1199				const std::string	queryName		= queryGroupName + " for view " + std::to_string(viewIndex);
1200				const uint64_t		primitiveCount	= readFromPtrAndAdvance(&resultsPtr, itemSize);
1201
1202				totalPrimitiveCount += primitiveCount;
1203
1204				if (m_params->availabilityBit)
1205					readAndVerifyAvailabilityBit(&resultsPtr, itemSize, *m_params, queryName);
1206			}
1207
1208			verifyQueryCounter(totalPrimitiveCount, expectedPrims, expectedPrims * viewCount, *m_params, queryGroupName);
1209		}
1210
1211		if (hasStatsQuery)
1212		{
1213			const std::string	queryGroupName	= "Stats query";
1214			uint64_t			totalTaskInvs	= 0ull;
1215			uint64_t			totalMeshInvs	= 0ull;
1216
1217			for (uint32_t viewIndex = 0u; viewIndex < viewCount; ++viewIndex)
1218			{
1219				if (hasTaskInvStat)
1220				{
1221					const uint64_t taskInvs = readFromPtrAndAdvance(&resultsPtr, itemSize);
1222					totalTaskInvs += taskInvs;
1223				}
1224
1225				if (hasMeshInvStat)
1226				{
1227					const uint64_t meshInvs = readFromPtrAndAdvance(&resultsPtr, itemSize);
1228					totalMeshInvs += meshInvs;
1229				}
1230
1231				if (m_params->availabilityBit)
1232				{
1233					const std::string queryName = queryGroupName + " for view " + std::to_string(viewIndex);
1234					readAndVerifyAvailabilityBit(&resultsPtr, itemSize, *m_params, queryGroupName);
1235				}
1236			}
1237
1238			if (hasTaskInvStat)
1239				verifyQueryCounter(totalTaskInvs, expectedTaskInv, expectedTaskInv * viewCount, *m_params, "Task invocations");
1240
1241			if (hasMeshInvStat)
1242				verifyQueryCounter(totalMeshInvs, expectedMeshInv, expectedMeshInv * viewCount, *m_params, "Mesh invocations");
1243		}
1244	}
1245
1246	if (m_params->resetType == ResetCase::NONE_WITH_HOST)
1247	{
1248		// We'll reset the different queries that we used before and we'll retrieve results again with GET, forcing availability bit
1249		// and no wait bit. We'll verify availability bits are zero.
1250		uint8_t* resultsPtr = queryResultsHostVec.data();
1251
1252		// New parameters, based on the existing ones, that match the behavior we expect below.
1253		TestParams postResetParams		= *m_params;
1254		postResetParams.availabilityBit	= true;
1255		postResetParams.waitBit			= false;
1256		postResetParams.resetType		= ResetCase::BEFORE_ACCESS;
1257
1258		const auto postResetFlags			= postResetParams.getQueryResultFlags();
1259		const auto newSizesAndOffsets		= postResetParams.getQuerySizesAndOffsets();
1260		const auto newStatsQueryOffsetSz	= static_cast<size_t>(newSizesAndOffsets.statsQueryOffset);
1261		const auto newStatsDataHostVecPtr	= queryResultsHostVec.data() + newStatsQueryOffsetSz;
1262		const auto newStatsRemainingSize	= maxResultSize - newStatsQueryOffsetSz;
1263		const auto itemSize					= newSizesAndOffsets.queryItemSize;
1264
1265		if (hasPrimitivesQuery)
1266		{
1267			vkd.resetQueryPool(device, primitivesQueryPool.get(), 0u, viewCount);
1268			const auto res = vkd.getQueryPoolResults(device, primitivesQueryPool.get(), 0u, viewCount, de::dataSize(queryResultsHostVec), queryResultsHostVec.data(), newSizesAndOffsets.primitivesQuerySize, postResetFlags);
1269			checkGetQueryRes(res, true/*allowNotReady*/);
1270		}
1271
1272		if (hasStatsQuery)
1273		{
1274			vkd.resetQueryPool(device, statsQueryPool.get(), 0u, viewCount);
1275			const auto res = vkd.getQueryPoolResults(device, statsQueryPool.get(), 0u, viewCount, newStatsRemainingSize, newStatsDataHostVecPtr, newSizesAndOffsets.statsQuerySize, postResetFlags);
1276			checkGetQueryRes(res, true/*allowNotReady*/);
1277		}
1278
1279		if (hasPrimitivesQuery)
1280		{
1281			for (uint32_t viewIndex = 0u; viewIndex < viewCount; ++viewIndex)
1282			{
1283				const std::string	queryName		= "Post-reset primitive count for view " + std::to_string(viewIndex);
1284				const uint64_t		primitiveCount	= readFromPtrAndAdvance(&resultsPtr, itemSize);
1285
1286				// Resetting a query without beginning it again makes numerical results undefined.
1287				//verifyQueryCounter(primitiveCount, 0ull, postResetParams, queryName);
1288				DE_UNREF(primitiveCount);
1289				readAndVerifyAvailabilityBit(&resultsPtr, itemSize, postResetParams, queryName);
1290			}
1291		}
1292
1293		if (hasStatsQuery)
1294		{
1295			for (uint32_t viewIndex = 0u; viewIndex < viewCount; ++viewIndex)
1296			{
1297				if (hasTaskInvStat)
1298				{
1299					const uint64_t taskInvs = readFromPtrAndAdvance(&resultsPtr, itemSize);
1300					// Resetting a query without beginning it again makes numerical results undefined.
1301					//verifyQueryCounter(taskInvs, 0ull, postResetParams, "Post-reset task invocations");
1302					DE_UNREF(taskInvs);
1303				}
1304
1305				if (hasMeshInvStat)
1306				{
1307					const uint64_t meshInvs = readFromPtrAndAdvance(&resultsPtr, itemSize);
1308					// Resetting a query without beginning it again makes numerical results undefined.
1309					//verifyQueryCounter(meshInvs, 0ull, postResetParams, "Post-reset mesh invocations");
1310					DE_UNREF(meshInvs);
1311				}
1312
1313				const std::string queryName = "Post-reset stats query for view " + std::to_string(viewIndex);
1314				readAndVerifyAvailabilityBit(&resultsPtr, itemSize, postResetParams, queryName);
1315			}
1316		}
1317	}
1318
1319	return tcu::TestStatus::pass("Pass");
1320}
1321
1322using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
1323
1324} // anonymous
1325
1326tcu::TestCaseGroup* createMeshShaderQueryTestsEXT (tcu::TestContext& testCtx)
1327{
1328	GroupPtr queryGroup (new tcu::TestCaseGroup(testCtx, "query"));
1329
1330	const struct
1331	{
1332		std::vector<QueryType>	queryTypes;
1333		const char*				name;
1334	} queryCombinations[] =
1335	{
1336		{ { QueryType::PRIMITIVES },															"prim_query"		},
1337		{ { QueryType::TASK_INVOCATIONS },														"task_invs_query"	},
1338		{ { QueryType::MESH_INVOCATIONS },														"mesh_invs_query"	},
1339		{ { QueryType::TASK_INVOCATIONS, QueryType::MESH_INVOCATIONS },							"all_stats_query"	},
1340		{ { QueryType::PRIMITIVES, QueryType::TASK_INVOCATIONS, QueryType::MESH_INVOCATIONS },	"all_queries"		},
1341	};
1342
1343	const struct
1344	{
1345		DrawCallType	drawCallType;
1346		const char*		name;
1347	} drawCalls[] =
1348	{
1349		{ DrawCallType::DIRECT,					"draw"						},
1350		{ DrawCallType::INDIRECT,				"indirect_draw"				},
1351		{ DrawCallType::INDIRECT_WITH_COUNT,	"indirect_with_count_draw"	},
1352	};
1353
1354	const struct
1355	{
1356		std::vector<uint32_t>	drawBlocks;
1357		const char*				name;
1358	} blockCases[] =
1359	{
1360		{ {},				"no_blocks"				},
1361		{ {10u},			"single_block"			},
1362		{ {10u, 20u, 30u},	"multiple_blocks"		},
1363	};
1364
1365	const struct
1366	{
1367		ResetCase		resetCase;
1368		const char*		name;
1369	} resetTypes[] =
1370	{
1371		{ ResetCase::NONE,				"no_reset"		},
1372		{ ResetCase::NONE_WITH_HOST,	"host_reset"	},
1373		{ ResetCase::BEFORE_ACCESS,		"reset_before"	},
1374		{ ResetCase::AFTER_ACCESS,		"reset_after"	},
1375	};
1376
1377	const struct
1378	{
1379		AccessMethod	accessMethod;
1380		const char*		name;
1381	} accessMethods[] =
1382	{
1383		{ AccessMethod::COPY,	"copy"	},
1384		{ AccessMethod::GET,	"get"	},
1385	};
1386
1387	const struct
1388	{
1389		GeometryType	geometry;
1390		const char*		name;
1391	} geometryCases[] =
1392	{
1393		{ GeometryType::POINTS,		"points"	},
1394		{ GeometryType::LINES,		"lines"		},
1395		{ GeometryType::TRIANGLES,	"triangles"	},
1396	};
1397
1398	const struct
1399	{
1400		bool			use64Bits;
1401		const char*		name;
1402	} resultSizes[] =
1403	{
1404		{ false,		"32bit"	},
1405		{ true,			"64bit"	},
1406	};
1407
1408	const struct
1409	{
1410		bool			availabilityFlag;
1411		const char*		name;
1412	} availabilityCases[] =
1413	{
1414		{ false,		"no_availability"	},
1415		{ true,			"with_availability"	},
1416	};
1417
1418	const struct
1419	{
1420		bool			waitFlag;
1421		const char*		name;
1422	} waitCases[] =
1423	{
1424		{ false,		"no_wait"	},
1425		{ true,			"wait"		},
1426	};
1427
1428	const struct
1429	{
1430		bool			taskShader;
1431		const char*		name;
1432	} taskShaderCases[] =
1433	{
1434		{ false,		"mesh_only"	},
1435		{ true,			"task_mesh"	},
1436	};
1437
1438	const struct
1439	{
1440		bool			insideRenderPass;
1441		const char*		name;
1442	} orderingCases[] =
1443	{
1444		{ false,		"include_rp"	},
1445		{ true,			"inside_rp"		},
1446	};
1447
1448	const struct
1449	{
1450		bool			multiView;
1451		const char*		name;
1452	} multiViewCases[] =
1453	{
1454		{ false,		"single_view"	},
1455		{ true,			"multi_view"	},
1456	};
1457
1458	const struct
1459	{
1460		bool			useSecondary;
1461		const char*		name;
1462	} cmdBufferTypes[] =
1463	{
1464		{ false,		"only_primary"		},
1465		{ true,			"with_secondary"	},
1466	};
1467
1468	for (const auto& queryCombination : queryCombinations)
1469	{
1470		const bool hasPrimitivesQuery = de::contains(queryCombination.queryTypes.begin(), queryCombination.queryTypes.end(), QueryType::PRIMITIVES);
1471
1472		GroupPtr queryCombinationGroup (new tcu::TestCaseGroup(testCtx, queryCombination.name));
1473
1474		for (const auto& geometryCase : geometryCases)
1475		{
1476			const bool nonTriangles = (geometryCase.geometry != GeometryType::TRIANGLES);
1477
1478			// For cases without primitive queries, skip non-triangle geometries.
1479			if (!hasPrimitivesQuery && nonTriangles)
1480				continue;
1481
1482			GroupPtr geometryCaseGroup (new tcu::TestCaseGroup(testCtx, geometryCase.name));
1483
1484			for (const auto& resetType : resetTypes)
1485			{
1486				GroupPtr resetTypeGroup (new tcu::TestCaseGroup(testCtx, resetType.name));
1487
1488				for (const auto& accessMethod : accessMethods)
1489				{
1490					// Get + reset after access is not a valid combination (queries will be accessed after submission).
1491					if (accessMethod.accessMethod == AccessMethod::GET && resetType.resetCase == ResetCase::AFTER_ACCESS)
1492						continue;
1493
1494					GroupPtr accessMethodGroup (new tcu::TestCaseGroup(testCtx, accessMethod.name));
1495
1496					for (const auto& waitCase : waitCases)
1497					{
1498						// Wait and reset before access is not valid (the query would never finish).
1499						if (resetType.resetCase == ResetCase::BEFORE_ACCESS && waitCase.waitFlag)
1500							continue;
1501
1502						GroupPtr waitCaseGroup (new tcu::TestCaseGroup(testCtx, waitCase.name));
1503
1504						for (const auto& drawCall : drawCalls)
1505						{
1506							// Explicitly remove some combinations with non-triangles, just to reduce the number of tests.
1507							if (drawCall.drawCallType != DrawCallType::DIRECT && nonTriangles)
1508								continue;
1509
1510							GroupPtr drawCallGroup (new tcu::TestCaseGroup(testCtx, drawCall.name));
1511
1512							for (const auto& resultSize : resultSizes)
1513							{
1514								// Explicitly remove some combinations with non-triangles, just to reduce the number of tests.
1515								if (resultSize.use64Bits && nonTriangles)
1516									continue;
1517
1518								GroupPtr resultSizeGroup (new tcu::TestCaseGroup(testCtx, resultSize.name));
1519
1520								for (const auto& availabilityCase : availabilityCases)
1521								{
1522									// Explicitly remove some combinations with non-triangles, just to reduce the number of tests.
1523									if (availabilityCase.availabilityFlag && nonTriangles)
1524										continue;
1525
1526									GroupPtr availabilityCaseGroup (new tcu::TestCaseGroup(testCtx, availabilityCase.name));
1527
1528									for (const auto& blockCase : blockCases)
1529									{
1530										// Explicitly remove some combinations with non-triangles, just to reduce the number of tests.
1531										if (blockCase.drawBlocks.size() <= 1 && nonTriangles)
1532											continue;
1533
1534										GroupPtr blockCaseGroup (new tcu::TestCaseGroup(testCtx, blockCase.name));
1535
1536										for (const auto& taskShaderCase : taskShaderCases)
1537										{
1538											GroupPtr taskShaderCaseGroup (new tcu::TestCaseGroup(testCtx, taskShaderCase.name));
1539
1540											for (const auto& orderingCase : orderingCases)
1541											{
1542												GroupPtr orderingCaseGroup (new tcu::TestCaseGroup(testCtx, orderingCase.name));
1543
1544												for (const auto& multiViewCase : multiViewCases)
1545												{
1546													if (multiViewCase.multiView && !orderingCase.insideRenderPass)
1547														continue;
1548
1549													GroupPtr multiViewGroup (new tcu::TestCaseGroup(testCtx, multiViewCase.name));
1550
1551													for (const auto& cmdBufferType : cmdBufferTypes)
1552													{
1553														TestParams params;
1554														params.queryTypes		= queryCombination.queryTypes;
1555														params.drawBlocks		= blockCase.drawBlocks;
1556														params.drawCall			= drawCall.drawCallType;
1557														params.geometry			= geometryCase.geometry;
1558														params.resetType		= resetType.resetCase;
1559														params.access			= accessMethod.accessMethod;
1560														params.use64Bits		= resultSize.use64Bits;
1561														params.availabilityBit	= availabilityCase.availabilityFlag;
1562														params.waitBit			= waitCase.waitFlag;
1563														params.useTaskShader	= taskShaderCase.taskShader;
1564														params.insideRenderPass	= orderingCase.insideRenderPass;
1565														params.useSecondary		= cmdBufferType.useSecondary;
1566														params.multiView		= multiViewCase.multiView;
1567
1568														// VUID-vkCmdExecuteCommands-commandBuffer-07594
1569														if (params.areQueriesInherited() && params.hasPrimitivesQuery())
1570															continue;
1571
1572														multiViewGroup->addChild(new MeshQueryCase(testCtx, cmdBufferType.name, std::move(params)));
1573													}
1574
1575													orderingCaseGroup->addChild(multiViewGroup.release());
1576												}
1577
1578												taskShaderCaseGroup->addChild(orderingCaseGroup.release());
1579											}
1580
1581											blockCaseGroup->addChild(taskShaderCaseGroup.release());
1582										}
1583
1584										availabilityCaseGroup->addChild(blockCaseGroup.release());
1585									}
1586
1587									resultSizeGroup->addChild(availabilityCaseGroup.release());
1588								}
1589
1590								drawCallGroup->addChild(resultSizeGroup.release());
1591							}
1592
1593							waitCaseGroup->addChild(drawCallGroup.release());
1594						}
1595
1596						accessMethodGroup->addChild(waitCaseGroup.release());
1597					}
1598
1599					resetTypeGroup->addChild(accessMethodGroup.release());
1600				}
1601
1602				geometryCaseGroup->addChild(resetTypeGroup.release());
1603			}
1604
1605			queryCombinationGroup->addChild(geometryCaseGroup.release());
1606		}
1607
1608		queryGroup->addChild(queryCombinationGroup.release());
1609	}
1610
1611	return queryGroup.release();
1612}
1613
1614} // MeshShader
1615} // vkt
1616