vulkanfullscreenquad: add locks for synchronisation

Now all API can be accessed from any thread.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9337>
This commit is contained in:
Matthew Waters 2025-07-07 10:12:52 +10:00 committed by GStreamer Marge Bot
parent f11d258545
commit 4ed83e5973
2 changed files with 194 additions and 105 deletions

View File

@ -2647,6 +2647,7 @@ gst_vulkan_full_screen_quad_set_blend_factors().</doc>
</parameters>
</method>
<method name="fill_command_buffer" c:identifier="gst_vulkan_full_screen_quad_fill_command_buffer" version="1.18" throws="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkfullscreenquad.c">@cmd must be locked with gst_vulkan_command_buffer_lock().</doc>
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkfullscreenquad.h"/>
<return-value transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkfullscreenquad.c">whether @cmd could be filled with the necessary commands</doc>

View File

@ -669,9 +669,15 @@ create_framebuffer (GstVulkanFullScreenQuad * self, GstVulkanImageView ** views,
GstVulkanFence *
gst_vulkan_full_screen_quad_get_last_fence (GstVulkanFullScreenQuad * self)
{
GstVulkanFence *ret;
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), NULL);
return LAST_FENCE_OR_ALWAYS_SIGNALLED (self, self->queue->device);
GST_OBJECT_LOCK (self);
ret = LAST_FENCE_OR_ALWAYS_SIGNALLED (self, self->queue->device);
GST_OBJECT_UNLOCK (self);
return ret;
}
#define clear_field(field,type,trash_free_func) \
@ -906,6 +912,8 @@ gboolean
gst_vulkan_full_screen_quad_set_info (GstVulkanFullScreenQuad * self,
const GstVideoInfo * in_info, const GstVideoInfo * out_info)
{
GST_OBJECT_LOCK (self);
self->out_info = *out_info;
self->in_info = *in_info;
@ -915,6 +923,8 @@ gst_vulkan_full_screen_quad_set_info (GstVulkanFullScreenQuad * self,
clear_descriptor_cache (self);
clear_uniform_data (self);
GST_OBJECT_UNLOCK (self);
return TRUE;
}
@ -938,8 +948,11 @@ gst_vulkan_full_screen_quad_set_input_buffer (GstVulkanFullScreenQuad * self,
priv = GET_PRIV (self);
GST_OBJECT_LOCK (self);
gst_buffer_replace (&priv->inbuf, buffer);
clear_descriptor_set (self);
GST_OBJECT_UNLOCK (self);
return TRUE;
}
@ -963,8 +976,11 @@ gst_vulkan_full_screen_quad_set_output_buffer (GstVulkanFullScreenQuad * self,
priv = GET_PRIV (self);
GST_OBJECT_LOCK (self);
gst_buffer_replace (&priv->outbuf, buffer);
clear_framebuffer (self);
GST_OBJECT_UNLOCK (self);
return TRUE;
}
@ -992,12 +1008,15 @@ gst_vulkan_full_screen_quad_set_shaders (GstVulkanFullScreenQuad * self,
priv = GET_PRIV (self);
GST_OBJECT_LOCK (self);
clear_shaders (self);
destroy_pipeline (self);
priv->vert = gst_vulkan_handle_ref (vert);
priv->frag = gst_vulkan_handle_ref (frag);
GST_OBJECT_UNLOCK (self);
return TRUE;
}
@ -1023,11 +1042,13 @@ gst_vulkan_full_screen_quad_set_uniform_buffer (GstVulkanFullScreenQuad * self,
priv = GET_PRIV (self);
GST_OBJECT_LOCK (self);
clear_uniform_data (self);
if (uniforms) {
priv->uniforms = gst_memory_ref (uniforms);
priv->uniform_size = gst_memory_get_sizes (uniforms, NULL, NULL);
}
GST_OBJECT_UNLOCK (self);
return TRUE;
}
@ -1057,11 +1078,13 @@ gst_vulkan_full_screen_quad_set_index_buffer (GstVulkanFullScreenQuad * self,
priv = GET_PRIV (self);
GST_OBJECT_LOCK (self);
clear_index_data (self);
if (indices) {
priv->indices = gst_memory_ref (indices);
priv->n_indices = n_indices;
}
GST_OBJECT_UNLOCK (self);
return TRUE;
}
@ -1088,10 +1111,12 @@ gst_vulkan_full_screen_quad_set_vertex_buffer (GstVulkanFullScreenQuad * self,
priv = GET_PRIV (self);
GST_OBJECT_LOCK (self);
clear_vertex_data (self);
if (vertices) {
priv->vertices = gst_memory_ref (vertices);
}
GST_OBJECT_UNLOCK (self);
return TRUE;
}
@ -1157,85 +1182,6 @@ failure:
return FALSE;
}
/**
* gst_vulkan_full_screen_quad_draw:
* @self: the #GstVulkanFullScreenQuad
* @error: a #GError filled on error
*
* Helper function for creation and submission of a command buffer that draws
* a full screen quad. If you need to add other things to the command buffer,
* create the command buffer manually and call
* gst_vulkan_full_screen_quad_prepare_draw(),
* gst_vulkan_full_screen_quad_fill_command_buffer() and
* gst_vulkan_full_screen_quad_submit() instead.
*
* Returns: whether the draw was successful
*
* Since: 1.18
*/
gboolean
gst_vulkan_full_screen_quad_draw (GstVulkanFullScreenQuad * self,
GError ** error)
{
GstVulkanCommandBuffer *cmd = NULL;
GstVulkanFence *fence = NULL;
VkResult err;
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), FALSE);
fence = gst_vulkan_device_create_fence (self->queue->device, error);
if (!fence)
goto error;
if (!gst_vulkan_full_screen_quad_prepare_draw (self, fence, error))
goto error;
if (!(cmd = gst_vulkan_command_pool_create (self->cmd_pool, error)))
goto error;
{
VkCommandBufferBeginInfo cmd_buf_info = { 0, };
/* *INDENT-OFF* */
cmd_buf_info = (VkCommandBufferBeginInfo) {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.pNext = NULL,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
.pInheritanceInfo = NULL
};
/* *INDENT-ON* */
gst_vulkan_command_buffer_lock (cmd);
err = vkBeginCommandBuffer (cmd->cmd, &cmd_buf_info);
if (gst_vulkan_error_to_g_error (err, error, "vkBeginCommandBuffer") < 0)
goto unlock_error;
}
if (!gst_vulkan_full_screen_quad_fill_command_buffer (self, cmd, fence,
error))
goto unlock_error;
err = vkEndCommandBuffer (cmd->cmd);
gst_vulkan_command_buffer_unlock (cmd);
if (gst_vulkan_error_to_g_error (err, error, "vkEndCommandBuffer") < 0)
goto error;
if (!gst_vulkan_full_screen_quad_submit (self, cmd, fence, error))
goto error;
gst_vulkan_fence_unref (fence);
return TRUE;
unlock_error:
gst_vulkan_command_buffer_unlock (cmd);
error:
gst_clear_mini_object ((GstMiniObject **) & cmd);
gst_clear_mini_object ((GstMiniObject **) & fence);
return FALSE;
}
/**
* gst_vulkan_full_screen_quad_enable_blend:
* @self: the #GstVulkanFullScreenQuad
@ -1364,19 +1310,8 @@ gst_vulkan_full_screen_quad_enable_clear (GstVulkanFullScreenQuad * self,
clear_render_pass (self);
}
/**
* gst_vulkan_full_screen_quad_prepare_draw:
* @self: the #GstVulkanFullScreenQuad
* @fence: a #GstVulkanFence that will be signalled after submission
* @error: a #GError filled on error
*
* Returns: whether the necessary information could be generated for drawing a
* frame.
*
* Since: 1.18
*/
gboolean
gst_vulkan_full_screen_quad_prepare_draw (GstVulkanFullScreenQuad * self,
static gboolean
prepare_draw_internal (GstVulkanFullScreenQuad * self,
GstVulkanFence * fence, GError ** error)
{
GstVulkanFullScreenQuadPrivate *priv;
@ -1394,7 +1329,7 @@ gst_vulkan_full_screen_quad_prepare_draw (GstVulkanFullScreenQuad * self,
return FALSE;
if (!ensure_vertex_data (self, error))
goto error;
return FALSE;
if (!self->descriptor_cache)
if (!create_descriptor_pool (self, error))
@ -1455,17 +1390,31 @@ error:
}
/**
* gst_vulkan_full_screen_quad_fill_command_buffer:
* @self: a #GstVulkanFullScreenQuad
* @cmd: the #GstVulkanCommandBuffer to fill with commands
* @error: a #GError to fill on error
* gst_vulkan_full_screen_quad_prepare_draw:
* @self: the #GstVulkanFullScreenQuad
* @fence: a #GstVulkanFence that will be signalled after submission
* @error: a #GError filled on error
*
* Returns: whether @cmd could be filled with the necessary commands
* Returns: whether the necessary information could be generated for drawing a
* frame.
*
* Since: 1.18
*/
gboolean
gst_vulkan_full_screen_quad_fill_command_buffer (GstVulkanFullScreenQuad * self,
gst_vulkan_full_screen_quad_prepare_draw (GstVulkanFullScreenQuad * self,
GstVulkanFence * fence, GError ** error)
{
gboolean ret;
GST_OBJECT_LOCK (self);
ret = prepare_draw_internal (self, fence, error);
GST_OBJECT_UNLOCK (self);
return ret;
}
static gboolean
fill_command_buffer_internal (GstVulkanFullScreenQuad * self,
GstVulkanCommandBuffer * cmd, GstVulkanFence * fence, GError ** error)
{
GstVulkanFullScreenQuadPrivate *priv;
@ -1619,19 +1568,33 @@ error:
}
/**
* gst_vulkan_full_screen_quad_submit:
* gst_vulkan_full_screen_quad_fill_command_buffer:
* @self: a #GstVulkanFullScreenQuad
* @cmd: (transfer full): a #GstVulkanCommandBuffer to submit
* @fence: a #GstVulkanFence to signal on completion
* @cmd: the #GstVulkanCommandBuffer to fill with commands
* @error: a #GError to fill on error
*
* Returns: whether @cmd could be submitted to the queue
* @cmd must be locked with gst_vulkan_command_buffer_lock().
*
* Returns: whether @cmd could be filled with the necessary commands
*
* Since: 1.18
*/
gboolean
gst_vulkan_full_screen_quad_submit (GstVulkanFullScreenQuad * self,
gst_vulkan_full_screen_quad_fill_command_buffer (GstVulkanFullScreenQuad * self,
GstVulkanCommandBuffer * cmd, GstVulkanFence * fence, GError ** error)
{
gboolean ret;
GST_OBJECT_LOCK (self);
ret = fill_command_buffer_internal (self, cmd, fence, error);
GST_OBJECT_UNLOCK (self);
return ret;
}
static gboolean
submit_internal (GstVulkanFullScreenQuad * self, GstVulkanCommandBuffer * cmd,
GstVulkanFence * fence, GError ** error)
{
VkResult err;
@ -1663,6 +1626,17 @@ gst_vulkan_full_screen_quad_submit (GstVulkanFullScreenQuad * self,
goto error;
}
return TRUE;
error:
return FALSE;
}
static void
submit_final_unlocked (GstVulkanFullScreenQuad * self,
GstVulkanCommandBuffer * cmd, GstVulkanFence * fence)
{
gst_vulkan_trash_list_add (self->trash_list,
gst_vulkan_trash_list_acquire (self->trash_list, fence,
gst_vulkan_trash_mini_object_unref, GST_MINI_OBJECT_CAST (cmd)));
@ -1672,10 +1646,124 @@ gst_vulkan_full_screen_quad_submit (GstVulkanFullScreenQuad * self,
if (self->last_fence)
gst_vulkan_fence_unref (self->last_fence);
self->last_fence = gst_vulkan_fence_ref (fence);
}
/**
* gst_vulkan_full_screen_quad_submit:
* @self: a #GstVulkanFullScreenQuad
* @cmd: (transfer full): a #GstVulkanCommandBuffer to submit
* @fence: a #GstVulkanFence to signal on completion
* @error: a #GError to fill on error
*
* Returns: whether @cmd could be submitted to the queue
*
* Since: 1.18
*/
gboolean
gst_vulkan_full_screen_quad_submit (GstVulkanFullScreenQuad * self,
GstVulkanCommandBuffer * cmd, GstVulkanFence * fence, GError ** error)
{
if (!submit_internal (self, cmd, fence, error))
return FALSE;
GST_OBJECT_LOCK (self);
submit_final_unlocked (self, cmd, fence);
GST_OBJECT_UNLOCK (self);
return TRUE;
}
/**
* gst_vulkan_full_screen_quad_draw:
* @self: the #GstVulkanFullScreenQuad
* @error: a #GError filled on error
*
* Helper function for creation and submission of a command buffer that draws
* a full screen quad. If you need to add other things to the command buffer,
* create the command buffer manually and call
* gst_vulkan_full_screen_quad_prepare_draw(),
* gst_vulkan_full_screen_quad_fill_command_buffer() and
* gst_vulkan_full_screen_quad_submit() instead.
*
* Returns: whether the draw was successful
*
* Since: 1.18
*/
gboolean
gst_vulkan_full_screen_quad_draw (GstVulkanFullScreenQuad * self,
GError ** error)
{
GstVulkanCommandBuffer *cmd = NULL;
GstVulkanFence *fence = NULL;
VkResult err;
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), FALSE);
fence = gst_vulkan_device_create_fence (self->queue->device, error);
if (!fence)
goto error;
GST_OBJECT_LOCK (self);
if (!prepare_draw_internal (self, fence, error)) {
GST_OBJECT_UNLOCK (self);
goto error;
}
if (!(cmd = gst_vulkan_command_pool_create (self->cmd_pool, error))) {
GST_OBJECT_UNLOCK (self);
goto error;
}
{
VkCommandBufferBeginInfo cmd_buf_info = { 0, };
/* *INDENT-OFF* */
cmd_buf_info = (VkCommandBufferBeginInfo) {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.pNext = NULL,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
.pInheritanceInfo = NULL
};
/* *INDENT-ON* */
gst_vulkan_command_buffer_lock (cmd);
err = vkBeginCommandBuffer (cmd->cmd, &cmd_buf_info);
if (gst_vulkan_error_to_g_error (err, error, "vkBeginCommandBuffer") < 0) {
GST_OBJECT_UNLOCK (self);
goto unlock_error;
}
}
if (!fill_command_buffer_internal (self, cmd, fence, error)) {
GST_OBJECT_UNLOCK (self);
goto unlock_error;
}
err = vkEndCommandBuffer (cmd->cmd);
gst_vulkan_command_buffer_unlock (cmd);
if (gst_vulkan_error_to_g_error (err, error, "vkEndCommandBuffer") < 0) {
GST_OBJECT_UNLOCK (self);
goto error;
}
if (!submit_internal (self, cmd, fence, error)) {
GST_OBJECT_UNLOCK (self);
goto error;
}
submit_final_unlocked (self, cmd, fence);
GST_OBJECT_UNLOCK (self);
gst_vulkan_fence_unref (fence);
return TRUE;
unlock_error:
gst_vulkan_command_buffer_unlock (cmd);
error:
gst_clear_mini_object ((GstMiniObject **) & cmd);
gst_clear_mini_object ((GstMiniObject **) & fence);
return FALSE;
}