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