summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIago Toral Quiroga <itoral@igalia.com>2020-06-01 12:00:16 +0200
committerMarge Bot <eric+marge@anholt.net>2020-10-13 21:21:30 +0000
commitca4b42a51df95bc94801c2c9f96585b31954bd52 (patch)
tree83c394568d031c73a41e1a0283b8e6ab9f7feeee
parent6a34ef65655fe329a5a4b7f6d2e5f7b4cebf2c33 (diff)
v3dv: implement vkCmdWaitEvents for secondary command buffers
Event waits can be safely moved before a render pass start, since event setting and resetting commands cannot happen inside one. We don't need to go that far, but we can use this to record the wait in its own separate job and then execute this job before the binning commands recorded in the secondary command buffer when we execute the secondary into a primary. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
-rw-r--r--src/broadcom/vulkan/v3dv_cmd_buffer.c95
-rw-r--r--src/broadcom/vulkan/v3dv_private.h6
2 files changed, 70 insertions, 31 deletions
diff --git a/src/broadcom/vulkan/v3dv_cmd_buffer.c b/src/broadcom/vulkan/v3dv_cmd_buffer.c
index 3504813f8d2..8c487269686 100644
--- a/src/broadcom/vulkan/v3dv_cmd_buffer.c
+++ b/src/broadcom/vulkan/v3dv_cmd_buffer.c
@@ -122,6 +122,7 @@ cmd_buffer_init(struct v3dv_cmd_buffer *cmd_buffer,
list_inithead(&cmd_buffer->private_objs);
list_inithead(&cmd_buffer->jobs);
+ list_inithead(&cmd_buffer->pre_jobs);
list_inithead(&cmd_buffer->list_link);
assert(pool);
@@ -249,6 +250,13 @@ cmd_buffer_free_resources(struct v3dv_cmd_buffer *cmd_buffer)
if (cmd_buffer->state.job)
v3dv_job_destroy(cmd_buffer->state.job);
+
+ list_for_each_entry_safe(struct v3dv_job, job,
+ &cmd_buffer->pre_jobs, list_link) {
+ assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_SECONDARY);
+ v3dv_job_destroy(job);
+ }
+
if (cmd_buffer->state.attachments) {
assert(cmd_buffer->state.attachment_count > 0);
vk_free(&cmd_buffer->pool->alloc, cmd_buffer->state.attachments);
@@ -2131,6 +2139,27 @@ cmd_buffer_copy_secondary_end_query_state(struct v3dv_cmd_buffer *primary,
}
}
+/* Clones a job for inclusion in the given command buffer. Note that this
+ * doesn't make a deep copy so the cloned job it doesn't own any resources.
+ * Useful when we need to have a job in more than one list, which happens
+ * for jobs recorded in secondary command buffers when we want to execute
+ * them in primaries.
+ */
+static struct v3dv_job *
+job_clone(struct v3dv_job *job, struct v3dv_cmd_buffer *cmd_buffer)
+{
+ struct v3dv_job *clone_job = vk_alloc(&job->device->alloc,
+ sizeof(struct v3dv_job), 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (!clone_job)
+ return NULL;
+
+ *clone_job = *job;
+ clone_job->is_clone = true;
+ clone_job->cmd_buffer = cmd_buffer;
+ return clone_job;
+}
+
static void
cmd_buffer_execute_inside_pass(struct v3dv_cmd_buffer *primary,
uint32_t cmd_buffer_count,
@@ -2148,6 +2177,18 @@ cmd_buffer_execute_inside_pass(struct v3dv_cmd_buffer *primary,
assert(secondary->usage_flags &
VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT);
+ /* Insert any jobs that should run before the secondary's commands */
+ list_for_each_entry(struct v3dv_job, pre_job,
+ &secondary->pre_jobs, list_link) {
+ struct v3dv_job *clone_job = job_clone(pre_job, primary);
+ if (!clone_job) {
+ v3dv_flag_oom(primary, NULL);
+ return;
+ }
+
+ list_addtail(&clone_job->list_link, &primary->jobs);
+ }
+
/* Secondaries that run inside a render pass only record commands inside
* a subpass, so they don't crate complete jobs (they don't have an RCL
* and their BCL doesn't include tiling setup). These are provided by
@@ -2189,27 +2230,6 @@ cmd_buffer_execute_inside_pass(struct v3dv_cmd_buffer *primary,
}
}
-/* Clones a job for inclusion in the given command buffer. Note that this
- * doesn't make a deep copy so the cloned job it doesn't own any resources.
- * Useful when we need to have a job in more than one list, which happens
- * for jobs recorded in secondary command buffers when we want to execute
- * them in primaries.
- */
-static struct v3dv_job *
-job_clone(struct v3dv_job *job, struct v3dv_cmd_buffer *cmd_buffer)
-{
- struct v3dv_job *clone_job = vk_alloc(&job->device->alloc,
- sizeof(struct v3dv_job), 8,
- VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
- if (!clone_job)
- return NULL;
-
- *clone_job = *job;
- clone_job->is_clone = true;
- clone_job->cmd_buffer = cmd_buffer;
- return clone_job;
-}
-
static void
cmd_buffer_execute_outside_pass(struct v3dv_cmd_buffer *primary,
uint32_t cmd_buffer_count,
@@ -4190,15 +4210,6 @@ v3dv_CmdWaitEvents(VkCommandBuffer commandBuffer,
{
V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
- /* vkCmdWaitEvents can be recorded inside a render pass, so we might have
- * an active job.
- *
- * FIXME: Since we can't signal/reset events inside a render pass, we could,
- * in theory, move this wait to an earlier point, such as before the
- * current job if it is inside a render pass, to avoid the split.
- */
- v3dv_cmd_buffer_finish_job(cmd_buffer);
-
assert(eventCount > 0);
struct v3dv_job *job =
@@ -4221,5 +4232,27 @@ v3dv_CmdWaitEvents(VkCommandBuffer commandBuffer,
for (uint32_t i = 0; i < eventCount; i++)
job->cpu.event_wait.events[i] = v3dv_event_from_handle(pEvents[i]);
- list_addtail(&job->list_link, &cmd_buffer->jobs);
+ /* vkCmdWaitEvents can be recorded inside a render pass, so we might have
+ * an active job.
+ *
+ * If we are inside a render pass, because we vkCmd(Re)SetEvent can't happen
+ * inside a render pass, it is safe to move the wait job so it happens right
+ * before the current job we are currently recording for the subpass, if any
+ * (it would actually be safe to move it all the way back to right before
+ * the start of the render pass). If we are a secondary command buffer
+ * inside a render pass though, we only have access to the currently
+ * recording job, so we put it in a "execute first" list that we will execute
+ * right before the secondary in vkCmdExecuteCommands.
+ *
+ * If we are outside a render pass then we should not have any on-going job
+ * and we are free to just add the wait job without restrictions.
+ */
+ assert(cmd_buffer->state.pass || !cmd_buffer->state.job);
+ if (!cmd_buffer->state.pass ||
+ cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
+ list_addtail(&job->list_link, &cmd_buffer->jobs);
+ } else {
+ assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_SECONDARY);
+ list_addtail(&job->list_link, &cmd_buffer->pre_jobs);
+ }
}
diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h
index b8ed1ae74e4..3a21fd28a81 100644
--- a/src/broadcom/vulkan/v3dv_private.h
+++ b/src/broadcom/vulkan/v3dv_private.h
@@ -967,6 +967,12 @@ struct v3dv_cmd_buffer {
* buffer via vkCmdExecuteCommands.
*/
struct list_head jobs;
+
+ /* For secondary command buffers inside a render pass, a list of jobs
+ * that should be executed right before the secondary job is executed
+ * inside a primary.
+ */
+ struct list_head pre_jobs;
};
struct v3dv_job *v3dv_cmd_buffer_start_job(struct v3dv_cmd_buffer *cmd_buffer,