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