• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
52 namespace vkt
53 {
54 namespace MeshShader
55 {
56 
57 namespace
58 {
59 
60 using namespace vk;
61 
62 using BufferWithMemoryPtr = de::MovePtr<BufferWithMemory>;
63 
64 constexpr uint32_t kImageWidth				= 32u;
65 constexpr uint32_t kMeshWorkGroupsPerCall	= 4u;
66 constexpr uint32_t kTaskWorkGroupsPerCall	= 2u;
67 constexpr uint32_t kMeshWorkGroupsPerTask	= kMeshWorkGroupsPerCall / kTaskWorkGroupsPerCall;
68 
69 constexpr uint32_t kMeshLocalInvocationsX	= 10u;
70 constexpr uint32_t kMeshLocalInvocationsY	= 4u;
71 constexpr uint32_t kMeshLocalInvocationsZ	= 1u;
72 constexpr uint32_t kMeshLocalInvocations	= kMeshLocalInvocationsX * kMeshLocalInvocationsY * kMeshLocalInvocationsZ;
73 
74 constexpr uint32_t kTaskLocalInvocationsX	= 1u;
75 constexpr uint32_t kTaskLocalInvocationsY	= 4u;
76 constexpr uint32_t kTaskLocalInvocationsZ	= 6u;
77 constexpr uint32_t kTaskLocalInvocations	= kTaskLocalInvocationsX * kTaskLocalInvocationsY * kTaskLocalInvocationsZ;
78 
79 constexpr VkDeviceSize k64sz				= static_cast<VkDeviceSize>(sizeof(uint64_t));
80 constexpr VkDeviceSize k32sz				= static_cast<VkDeviceSize>(sizeof(uint32_t));
81 
82 enum class QueryType
83 {
84 	PRIMITIVES = 0,
85 	TASK_INVOCATIONS,
86 	MESH_INVOCATIONS,
87 };
88 
89 enum class DrawCallType
90 {
91 	DIRECT = 0,
92 	INDIRECT,
93 	INDIRECT_WITH_COUNT,
94 };
95 
96 enum class GeometryType
97 {
98 	POINTS = 0,
99 	LINES,
100 	TRIANGLES,
101 };
102 
toString(GeometryType geometryType)103 std::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 
vertsPerPrimitive(GeometryType geometryType)118 uint32_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 
133 enum 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 
141 enum class AccessMethod
142 {
143 	COPY = 0,
144 	GET,
145 };
146 
checkGetQueryRes(VkResult result,bool allowNotReady)147 void 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.
getNewSeed(void)157 uint32_t getNewSeed (void)
158 {
159 	static uint32_t seed = 1656078156u;
160 	uint32_t returnedSeed = seed;
161 	seed += 2u;
162 	return returnedSeed;
163 }
164 
165 struct 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 
swapvkt::MeshShader::__anon91994d450111::TestParams182 	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 
TestParamsvkt::MeshShader::__anon91994d450111::TestParams200 	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 
TestParamsvkt::MeshShader::__anon91994d450111::TestParams217 	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 
TestParamsvkt::MeshShader::__anon91994d450111::TestParams234 	TestParams (TestParams&& other)
235 		: TestParams()
236 	{
237 		this->swap(other);
238 	}
239 
getTotalDrawCountvkt::MeshShader::__anon91994d450111::TestParams240 	uint32_t getTotalDrawCount (void) const
241 	{
242 		const uint32_t callCount = std::accumulate(drawBlocks.begin(), drawBlocks.end(), 0u);
243 		return callCount;
244 	}
245 
getImageHeightvkt::MeshShader::__anon91994d450111::TestParams246 	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.
getDrawGroupCountvkt::MeshShader::__anon91994d450111::TestParams254 	uint32_t getDrawGroupCount (void) const
255 	{
256 		return (useTaskShader ? kTaskWorkGroupsPerCall : kMeshWorkGroupsPerCall);
257 	}
258 
259 	// Gets the right query result flags for the current parameters.
getQueryResultFlagsvkt::MeshShader::__anon91994d450111::TestParams260 	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.
areQueriesInheritedvkt::MeshShader::__anon91994d450111::TestParams271 	bool areQueriesInherited (void) const
272 	{
273 		return (useSecondary && !insideRenderPass);
274 	}
275 
276 protected:
hasQueryTypevkt::MeshShader::__anon91994d450111::TestParams277 	bool hasQueryType (QueryType queryType) const
278 	{
279 		return de::contains(queryTypes.begin(), queryTypes.end(), queryType);
280 	}
281 
282 public:
hasPrimitivesQueryvkt::MeshShader::__anon91994d450111::TestParams283 	bool hasPrimitivesQuery (void) const
284 	{
285 		return hasQueryType(QueryType::PRIMITIVES);
286 	}
287 
hasMeshInvStatvkt::MeshShader::__anon91994d450111::TestParams288 	bool hasMeshInvStat (void) const
289 	{
290 		return hasQueryType(QueryType::MESH_INVOCATIONS);
291 	}
292 
hasTaskInvStatvkt::MeshShader::__anon91994d450111::TestParams293 	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 
getViewCountvkt::MeshShader::__anon91994d450111::TestParams306 	uint32_t getViewCount (void) const
307 	{
308 		return (multiView ? 2u : 1u);
309 	}
310 
getQuerySizesAndOffsetsvkt::MeshShader::__anon91994d450111::TestParams311 	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 
326 class MeshQueryCase : public vkt::TestCase
327 {
328 public:
MeshQueryCase(tcu::TestContext & testCtx,const std::string & name,TestParams && params)329 					MeshQueryCase	(tcu::TestContext& testCtx, const std::string& name, TestParams&& params)
330 						: vkt::TestCase	(testCtx, name)
331 						, m_params		(std::move(params))
332 						{}
~MeshQueryCase(void)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 
339 protected:
340 	TestParams m_params;
341 };
342 
343 class MeshQueryInstance : public vkt::TestInstance
344 {
345 public:
MeshQueryInstance(Context & context,const TestParams & params)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 							{}
~MeshQueryInstance(void)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 
359 protected:
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 
initPrograms(vk::SourceCollections & programCollection) const375 void 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 
createInstance(Context & context) const513 TestInstance* MeshQueryCase::createInstance (Context& context) const
514 {
515 	return new MeshQueryInstance(context, m_params);
516 }
517 
checkSupport(Context & context) const518 void 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 
getRandomShuffle(uint32_t groupCount)543 VkDrawMeshTasksIndirectCommandEXT 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 
recordDraws(const VkCommandBuffer cmdBuffer,const VkPipeline pipeline,const VkPipelineLayout layout)552 void 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 
beginFirstQueries(const VkCommandBuffer cmdBuffer,const std::vector<VkQueryPool> & queryPools) const649 void 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 
endFirstQueries(const VkCommandBuffer cmdBuffer,const std::vector<VkQueryPool> & queryPools) const656 void 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 
resetFirstQueries(const VkCommandBuffer cmdBuffer,const std::vector<VkQueryPool> & queryPools,const uint32_t queryCount) const663 void 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 
submitCommands(const VkCommandBuffer cmdBuffer) const670 void 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 
waitForFence(void) const691 void 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.
readFromPtrAndAdvance(uint8_t ** const ptr,VkDeviceSize itemSize)700 uint64_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.
readAndVerifyAvailabilityBit(uint8_t ** const resultsPtr,VkDeviceSize itemSize,const TestParams & params,const std::string & queryName)723 void 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).
verifyQueryCounter(uint64_t readVal,uint64_t expectedMinVal,uint64_t expectedMaxVal,const TestParams & params,const std::string & queryName)751 void 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 
makeCustomRenderPass(const DeviceInterface & vkd,VkDevice device,uint32_t layerCount,VkFormat format)773 Move<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 
iterate(void)835 tcu::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 
1322 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
1323 
1324 } // anonymous
1325 
createMeshShaderQueryTestsEXT(tcu::TestContext & testCtx)1326 tcu::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