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