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 (¶ms)
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, ©Region);
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