From a26755458e12ae3d4af1167a10eec1161ec942d7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 8 Jun 2022 10:45:44 +1000 Subject: [PATCH] vulkan: Add common cmd buffer state tracking For drivers already using vk_common_ResetCommandBuffer(), it now only calls the driver's reset hook if the command buffer is not in the INITIAL state. Pulled this trick from the PowerVR driver. v2 (Jason Ekstrand): - Rename from "status" to "state" since that's what's in the spec - Add vk_command_buffer_begin/end instead of drivers setting it all manually Reviewed-by: Samuel Pitoiset Reviewed-by: Boris Brezillon Part-of: --- src/vulkan/runtime/vk_command_buffer.c | 29 +++++++++++++++++++++++++- src/vulkan/runtime/vk_command_buffer.h | 18 ++++++++++++++++ src/vulkan/runtime/vk_queue.c | 10 +++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/vulkan/runtime/vk_command_buffer.c b/src/vulkan/runtime/vk_command_buffer.c index 2be9eeaf840..2eef386ff5a 100644 --- a/src/vulkan/runtime/vk_command_buffer.c +++ b/src/vulkan/runtime/vk_command_buffer.c @@ -41,6 +41,7 @@ vk_command_buffer_init(struct vk_command_pool *pool, command_buffer->level = level; command_buffer->ops = ops; vk_dynamic_graphics_state_init(&command_buffer->dynamic_graphics_state); + command_buffer->state = MESA_VK_COMMAND_BUFFER_STATE_INITIAL; command_buffer->record_result = VK_SUCCESS; vk_cmd_queue_init(&command_buffer->cmd_queue, &pool->alloc); util_dynarray_init(&command_buffer->labels, NULL); @@ -55,6 +56,7 @@ void vk_command_buffer_reset(struct vk_command_buffer *command_buffer) { vk_dynamic_graphics_state_clear(&command_buffer->dynamic_graphics_state); + command_buffer->state = MESA_VK_COMMAND_BUFFER_STATE_INITIAL; command_buffer->record_result = VK_SUCCESS; vk_command_buffer_reset_render_pass(command_buffer); vk_cmd_queue_reset(&command_buffer->cmd_queue); @@ -62,6 +64,30 @@ vk_command_buffer_reset(struct vk_command_buffer *command_buffer) command_buffer->region_begin = true; } +void +vk_command_buffer_begin(struct vk_command_buffer *command_buffer, + const VkCommandBufferBeginInfo *pBeginInfo) +{ + if (command_buffer->state != MESA_VK_COMMAND_BUFFER_STATE_INITIAL && + command_buffer->ops->reset != NULL) + command_buffer->ops->reset(command_buffer, 0); + + command_buffer->state = MESA_VK_COMMAND_BUFFER_STATE_RECORDING; +} + +VkResult +vk_command_buffer_end(struct vk_command_buffer *command_buffer) +{ + assert(command_buffer->state == MESA_VK_COMMAND_BUFFER_STATE_RECORDING); + + if (vk_command_buffer_has_error(command_buffer)) + command_buffer->state = MESA_VK_COMMAND_BUFFER_STATE_INVALID; + else + command_buffer->state = MESA_VK_COMMAND_BUFFER_STATE_EXECUTABLE; + + return vk_command_buffer_get_record_result(command_buffer); +} + void vk_command_buffer_finish(struct vk_command_buffer *command_buffer) { @@ -92,7 +118,8 @@ vk_common_ResetCommandBuffer(VkCommandBuffer commandBuffer, { VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer); - cmd_buffer->ops->reset(cmd_buffer, flags); + if (cmd_buffer->state != MESA_VK_COMMAND_BUFFER_STATE_INITIAL) + cmd_buffer->ops->reset(cmd_buffer, flags); return VK_SUCCESS; } diff --git a/src/vulkan/runtime/vk_command_buffer.h b/src/vulkan/runtime/vk_command_buffer.h index 8c02284f310..a9cc03170e8 100644 --- a/src/vulkan/runtime/vk_command_buffer.h +++ b/src/vulkan/runtime/vk_command_buffer.h @@ -88,6 +88,14 @@ struct vk_command_buffer_ops { void (*destroy)(struct vk_command_buffer *); }; +enum mesa_vk_command_buffer_state { + MESA_VK_COMMAND_BUFFER_STATE_INVALID, + MESA_VK_COMMAND_BUFFER_STATE_INITIAL, + MESA_VK_COMMAND_BUFFER_STATE_RECORDING, + MESA_VK_COMMAND_BUFFER_STATE_EXECUTABLE, + MESA_VK_COMMAND_BUFFER_STATE_PENDING, +}; + struct vk_command_buffer { struct vk_object_base base; @@ -100,6 +108,9 @@ struct vk_command_buffer { struct vk_dynamic_graphics_state dynamic_graphics_state; + /** State of the command buffer */ + enum mesa_vk_command_buffer_state state; + /** Command buffer recording error state. */ VkResult record_result; @@ -179,6 +190,13 @@ vk_command_buffer_reset(struct vk_command_buffer *command_buffer); void vk_command_buffer_recycle(struct vk_command_buffer *command_buffer); +void +vk_command_buffer_begin(struct vk_command_buffer *command_buffer, + const VkCommandBufferBeginInfo *pBeginInfo); + +VkResult +vk_command_buffer_end(struct vk_command_buffer *command_buffer); + void vk_command_buffer_finish(struct vk_command_buffer *command_buffer); diff --git a/src/vulkan/runtime/vk_queue.c b/src/vulkan/runtime/vk_queue.c index b79553fc374..8eeb2f7dbc9 100644 --- a/src/vulkan/runtime/vk_queue.c +++ b/src/vulkan/runtime/vk_queue.c @@ -695,6 +695,16 @@ vk_queue_submit(struct vk_queue *queue, assert(info->command_buffers[i].deviceMask == 0 || info->command_buffers[i].deviceMask == 1); assert(cmd_buffer->pool->queue_family_index == queue->queue_family_index); + + /* Some drivers don't call vk_command_buffer_begin/end() yet and, for + * those, we'll see initial layout. However, this is enough to catch + * command buffers which get submitted without calling EndCommandBuffer. + */ + assert(cmd_buffer->state == MESA_VK_COMMAND_BUFFER_STATE_INITIAL || + cmd_buffer->state == MESA_VK_COMMAND_BUFFER_STATE_EXECUTABLE || + cmd_buffer->state == MESA_VK_COMMAND_BUFFER_STATE_PENDING); + cmd_buffer->state = MESA_VK_COMMAND_BUFFER_STATE_PENDING; + submit->command_buffers[i] = cmd_buffer; }