diff --git a/layers/gpu/cmd_validation/gpuav_draw.cpp b/layers/gpu/cmd_validation/gpuav_draw.cpp index 4d9ded433f8..c7cc7798b44 100644 --- a/layers/gpu/cmd_validation/gpuav_draw.cpp +++ b/layers/gpu/cmd_validation/gpuav_draw.cpp @@ -600,7 +600,7 @@ void DrawMeshIndirect(Validator &gpuav, CommandBuffer &cb_state, const Location const bool is_task_shader = (stages & VK_SHADER_STAGE_TASK_BIT_EXT) == VK_SHADER_STAGE_TASK_BIT_EXT; CommandBuffer::ValidationCommandFunc validation_cmd = - [draw_buffer, draw_buffer_size = draw_buffer_state->create_info.size, draw_buffer_offset, draw_cmds_byte_stride, + [draw_buffer, draw_buffer_full_size = draw_buffer_state->create_info.size, draw_buffer_offset, draw_cmds_byte_stride, count_buffer, count_buffer_offset, draw_count, is_task_shader, draw_i = cb_state.draw_index, error_logger_i = uint32_t(cb_state.per_command_error_loggers.size()), loc](Validator &gpuav, CommandBuffer &cb_state) { SharedDrawValidationResources &shared_draw_validation_resources = @@ -656,8 +656,14 @@ void DrawMeshIndirect(Validator &gpuav, CommandBuffer &cb_state, const Location DispatchCmdBindPipeline(cb_state.VkHandle(), VK_PIPELINE_BIND_POINT_COMPUTE, validation_pipeline.pipeline); uint32_t max_held_draw_cmds = 0; - if (draw_buffer_size > draw_buffer_offset) { - max_held_draw_cmds = static_cast((draw_buffer_size - draw_buffer_offset) / draw_cmds_byte_stride); + if (draw_buffer_full_size > draw_buffer_offset) { + // If drawCount is less than or equal to one, stride is ignored + if (draw_cmds_byte_stride > 0) { + max_held_draw_cmds = + static_cast((draw_buffer_full_size - draw_buffer_offset) / draw_cmds_byte_stride); + } else { + max_held_draw_cmds = 1; + } } const uint32_t work_group_count = std::min(draw_count, max_held_draw_cmds); VVL_TracyPlot("gpuav::valcmd::DrawMeshIndirect Dispatch size", int64_t(work_group_count)); diff --git a/tests/unit/gpu_av_indirect_buffer_positive.cpp b/tests/unit/gpu_av_indirect_buffer_positive.cpp index f44c83ec01e..e918e998331 100644 --- a/tests/unit/gpu_av_indirect_buffer_positive.cpp +++ b/tests/unit/gpu_av_indirect_buffer_positive.cpp @@ -131,14 +131,14 @@ TEST_F(PositiveGpuAVIndirectBuffer, Mesh) { if (mesh_shader_props.maxMeshWorkGroupTotalCount > 0xfffffffe) { GTEST_SKIP() << "MeshWorkGroupTotalCount too high for this test"; } - const uint32_t num_commands = 3; - uint32_t buffer_size = num_commands * (sizeof(VkDrawMeshTasksIndirectCommandEXT) + 4); // 4 byte pad between commands + const uint32_t mesh_commands = 3; + uint32_t buffer_size = mesh_commands * (sizeof(VkDrawMeshTasksIndirectCommandEXT) + 4); // 4 byte pad between commands vkt::Buffer draw_buffer(*m_device, buffer_size, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, kHostVisibleMemProps); uint32_t *draw_ptr = static_cast(draw_buffer.Memory().Map()); // Set all mesh group counts to 1 - for (uint32_t i = 0; i < num_commands * 4; ++i) { - draw_ptr[i] = 42; + for (uint32_t i = 0; i < mesh_commands * 4; ++i) { + draw_ptr[i] = 1; } draw_buffer.Memory().Unmap(); @@ -176,3 +176,67 @@ TEST_F(PositiveGpuAVIndirectBuffer, Mesh) { m_default_queue->Submit(m_command_buffer); m_default_queue->Wait(); } + +TEST_F(PositiveGpuAVIndirectBuffer, MeshSingleCommand) { + TEST_DESCRIPTION("GPU validation: Validate DrawMeshTasksIndirect* DrawBuffer contents"); + SetTargetApiVersion(VK_API_VERSION_1_3); + AddRequiredExtensions(VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME); + AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::maintenance4); + AddRequiredFeature(vkt::Feature::meshShader); + AddRequiredFeature(vkt::Feature::taskShader); + AddRequiredFeature(vkt::Feature::multiDrawIndirect); + + RETURN_IF_SKIP(InitGpuAvFramework()); + RETURN_IF_SKIP(InitState()); + InitRenderTarget(); + VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_props = vku::InitStructHelper(); + GetPhysicalDeviceProperties2(mesh_shader_props); + + if (mesh_shader_props.maxMeshWorkGroupTotalCount > 0xfffffffe) { + GTEST_SKIP() << "MeshWorkGroupTotalCount too high for this test"; + } + const uint32_t mesh_commands = 1; + uint32_t buffer_size = mesh_commands * (sizeof(VkDrawMeshTasksIndirectCommandEXT) + 4); // 4 byte pad between commands + + vkt::Buffer draw_buffer(*m_device, buffer_size, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, kHostVisibleMemProps); + uint32_t *draw_ptr = static_cast(draw_buffer.Memory().Map()); + // Set all mesh group counts to 1 + for (uint32_t i = 0; i < mesh_commands * 4; ++i) { + draw_ptr[i] = 1; + } + draw_buffer.Memory().Unmap(); + + vkt::Buffer count_buffer(*m_device, sizeof(uint32_t), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, kHostVisibleMemProps); + uint32_t *count_ptr = static_cast(count_buffer.Memory().Map()); + *count_ptr = 3; + count_buffer.Memory().Unmap(); + char const *mesh_shader_source = R"glsl( + #version 450 + #extension GL_EXT_mesh_shader : require + layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + layout(max_vertices = 3, max_primitives = 1) out; + layout(triangles) out; + struct Task { + uint baseID; + }; + taskPayloadSharedEXT Task IN; + void main() {} + )glsl"; + VkShaderObj mesh_shader(this, mesh_shader_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3); + CreatePipelineHelper mesh_pipe(*this); + mesh_pipe.shader_stages_[0] = mesh_shader.GetStageCreateInfo(); + mesh_pipe.CreateGraphicsPipeline(); + + // Set x in third draw + m_command_buffer.Begin(); + m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); + vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, mesh_pipe.Handle()); + + vk::CmdDrawMeshTasksIndirectEXT(m_command_buffer.handle(), draw_buffer.handle(), 0, 1, 0); + m_command_buffer.EndRenderPass(); + m_command_buffer.end(); + + m_default_queue->Submit(m_command_buffer); + m_default_queue->Wait(); +}