vulkan: implement command buffer reuse

Using a similar design for reference counting as
GstBuffer/GstBufferPool.
This commit is contained in:
Matthew Waters 2019-09-17 22:24:04 +10:00
parent 06d7a5ca3c
commit 82e86573b8
19 changed files with 743 additions and 174 deletions

View file

@ -1661,7 +1661,7 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
GstVulkanImageMemory *out_img_mems[4] = { NULL, };
GstVulkanFence *fence = NULL;
VkFramebuffer framebuffer;
VkCommandBuffer cmd;
GstVulkanCommandBuffer *cmd_buf;
GError *error = NULL;
VkResult err;
int i;
@ -1692,7 +1692,7 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
goto error;
}
if (!(cmd = gst_vulkan_command_pool_create (conv->cmd_pool, &error)))
if (!(cmd_buf = gst_vulkan_command_pool_create (conv->cmd_pool, &error)))
goto error;
fence = gst_vulkan_fence_new (render->device, 0, &error);
@ -1711,7 +1711,8 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
};
/* *INDENT-ON* */
err = vkBeginCommandBuffer (cmd, &cmd_buf_info);
gst_vulkan_command_buffer_lock (cmd_buf);
err = vkBeginCommandBuffer (cmd_buf->cmd, &cmd_buf_info);
if (gst_vulkan_error_to_g_error (err, &error, "vkBeginCommandBuffer") < 0)
goto error;
}
@ -1733,7 +1734,8 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd, in_img_mems[i]->barrier.parent.pipeline_stages,
vkCmdPipelineBarrier (cmd_buf->cmd,
in_img_mems[i]->barrier.parent.pipeline_stages,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1,
&in_image_memory_barrier);
@ -1785,7 +1787,7 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd,
vkCmdPipelineBarrier (cmd_buf->cmd,
render_img_mems[i]->barrier.parent.pipeline_stages,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1,
&render_image_memory_barrier);
@ -1812,11 +1814,14 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
}
}
conv->current_shader->cmd_state_update (conv, cmd, conv->current_shader,
in_img_mems, render_img_mems);
if (!gst_vulkan_full_screen_render_fill_command_buffer (render, cmd,
framebuffer))
return GST_FLOW_ERROR;
conv->current_shader->cmd_state_update (conv, cmd_buf->cmd,
conv->current_shader, in_img_mems, render_img_mems);
if (!gst_vulkan_full_screen_render_fill_command_buffer (render, cmd_buf->cmd,
framebuffer)) {
g_set_error (&error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
"Failed to fill framebuffer");
goto unlock_error;
}
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&render->out_info); i++) {
if (render_img_mems[i] != out_img_mems[i]) {
@ -1875,7 +1880,7 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd,
vkCmdPipelineBarrier (cmd_buf->cmd,
render_img_mems[i]->barrier.parent.pipeline_stages,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
&render_image_memory_barrier);
@ -1887,7 +1892,7 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
render_img_mems[i]->barrier.image_layout =
render_image_memory_barrier.newLayout;
vkCmdPipelineBarrier (cmd,
vkCmdPipelineBarrier (cmd_buf->cmd,
out_img_mems[i]->barrier.parent.pipeline_stages,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
&out_image_memory_barrier);
@ -1901,7 +1906,7 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
/* XXX: This is mostly right for a downsampling pass however if
* anything is more complicated, then we will need a new render pass */
vkCmdBlitImage (cmd, render_img_mems[i]->image,
vkCmdBlitImage (cmd_buf->cmd, render_img_mems[i]->image,
render_img_mems[i]->barrier.image_layout, out_img_mems[i]->image,
out_img_mems[i]->barrier.image_layout, 1, &blit, VK_FILTER_LINEAR);
@ -1912,7 +1917,8 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
}
}
err = vkEndCommandBuffer (cmd);
err = vkEndCommandBuffer (cmd_buf->cmd);
gst_vulkan_command_buffer_unlock (cmd_buf);
if (gst_vulkan_error_to_g_error (err, &error, "vkEndCommandBuffer") < 0)
goto error;
@ -1920,14 +1926,19 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
gst_vulkan_trash_new_free_framebuffer (gst_vulkan_fence_ref (fence),
framebuffer));
gst_vulkan_trash_list_add (render->trash_list,
gst_vulkan_trash_new_free_command_buffer (gst_vulkan_fence_ref (fence),
conv->cmd_pool, cmd));
gst_vulkan_trash_new_mini_object_unref (gst_vulkan_fence_ref (fence),
GST_MINI_OBJECT_CAST (cmd_buf)));
if (!gst_vulkan_full_screen_render_submit (render, cmd, fence))
if (!gst_vulkan_full_screen_render_submit (render, cmd_buf->cmd, fence))
return GST_FLOW_ERROR;
return GST_FLOW_OK;
unlock_error:
if (cmd_buf) {
gst_vulkan_command_buffer_unlock (cmd_buf);
gst_vulkan_command_buffer_unref (cmd_buf);
}
error:
GST_ELEMENT_ERROR (bt, LIBRARY, FAILED, ("%s", error->message), (NULL));
g_clear_error (&error);

View file

@ -143,7 +143,7 @@ static GstFlowReturn
_image_to_raw_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
{
struct ImageToRawDownload *raw = impl;
VkCommandBuffer cmd;
GstVulkanCommandBuffer *cmd_buf;
GError *error = NULL;
GstFlowReturn ret;
VkResult err;
@ -157,7 +157,7 @@ _image_to_raw_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
}
}
if (!(cmd = gst_vulkan_command_pool_create (raw->cmd_pool, &error)))
if (!(cmd_buf = gst_vulkan_command_pool_create (raw->cmd_pool, &error)))
goto error;
if (!raw->pool) {
@ -191,9 +191,10 @@ _image_to_raw_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
};
/* *INDENT-ON* */
err = vkBeginCommandBuffer (cmd, &cmd_buf_info);
gst_vulkan_command_buffer_lock (cmd_buf);
err = vkBeginCommandBuffer (cmd_buf->cmd, &cmd_buf_info);
if (gst_vulkan_error_to_g_error (err, &error, "vkBeginCommandBuffer") < 0)
return FALSE;
goto unlock_error;
}
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&raw->out_info); i++) {
@ -207,7 +208,7 @@ _image_to_raw_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
in_mem = gst_buffer_peek_memory (inbuf, i);
if (!gst_is_vulkan_image_memory (in_mem)) {
GST_WARNING_OBJECT (raw->download, "Input is not a GstVulkanImageMemory");
goto error;
goto unlock_error;
}
img_mem = (GstVulkanImageMemory *) in_mem;
@ -215,7 +216,7 @@ _image_to_raw_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
if (!gst_is_vulkan_buffer_memory (out_mem)) {
GST_WARNING_OBJECT (raw->download,
"Output is not a GstVulkanBufferMemory");
goto error;
goto unlock_error;
}
buf_mem = (GstVulkanBufferMemory *) out_mem;
@ -266,7 +267,7 @@ _image_to_raw_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd,
vkCmdPipelineBarrier (cmd_buf->cmd,
buf_mem->barrier.parent.pipeline_stages | img_mem->barrier.
parent.pipeline_stages, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1,
&buffer_memory_barrier, 1, &image_memory_barrier);
@ -278,13 +279,14 @@ _image_to_raw_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
img_mem->barrier.parent.access_flags = image_memory_barrier.dstAccessMask;
img_mem->barrier.image_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
vkCmdCopyImageToBuffer (cmd, img_mem->image, img_mem->barrier.image_layout,
buf_mem->buffer, 1, &region);
vkCmdCopyImageToBuffer (cmd_buf->cmd, img_mem->image,
img_mem->barrier.image_layout, buf_mem->buffer, 1, &region);
}
err = vkEndCommandBuffer (cmd);
err = vkEndCommandBuffer (cmd_buf->cmd);
gst_vulkan_command_buffer_unlock (cmd_buf);
if (gst_vulkan_error_to_g_error (err, &error, "vkEndCommandBuffer") < 0)
return FALSE;
goto error;
{
VkSubmitInfo submit_info = { 0, };
@ -299,7 +301,7 @@ _image_to_raw_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
.pWaitSemaphores = NULL,
.pWaitDstStageMask = &stages,
.commandBufferCount = 1,
.pCommandBuffers = &cmd,
.pCommandBuffers = &cmd_buf->cmd,
.signalSemaphoreCount = 0,
.pSignalSemaphores = NULL
};
@ -316,7 +318,8 @@ _image_to_raw_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
goto error;
gst_vulkan_trash_list_add (raw->trash_list,
gst_vulkan_trash_new_free_command_buffer (fence, raw->cmd_pool, cmd));
gst_vulkan_trash_new_mini_object_unref (fence,
GST_MINI_OBJECT_CAST (cmd_buf)));
}
/* XXX: STALL!
@ -330,16 +333,19 @@ _image_to_raw_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
out:
return ret;
unlock_error:
if (cmd_buf) {
gst_vulkan_command_buffer_unlock (cmd_buf);
gst_vulkan_command_buffer_unref (cmd_buf);
}
error:
if (error) {
GST_WARNING_OBJECT (raw->download, "Error: %s", error->message);
g_clear_error (&error);
}
gst_buffer_unref (*outbuf);
*outbuf = NULL;
gst_clear_buffer (outbuf);
ret = GST_FLOW_ERROR;
goto out;
return GST_FLOW_OK;
}
static void

View file

@ -538,7 +538,7 @@ gst_vulkan_image_identity_transform (GstBaseTransform * bt, GstBuffer * inbuf,
GstVulkanFence *fence = NULL;
GstMemory *in_mem, *out_mem;
VkFramebuffer framebuffer;
VkCommandBuffer cmd;
GstVulkanCommandBuffer *cmd_buf;
GError *error = NULL;
VkResult err;
@ -565,7 +565,8 @@ gst_vulkan_image_identity_transform (GstBaseTransform * bt, GstBuffer * inbuf,
update_descriptor_set (vk_identity, in_img_mem->view);
}
if (!(cmd = gst_vulkan_command_pool_create (vk_identity->cmd_pool, &error)))
if (!(cmd_buf =
gst_vulkan_command_pool_create (vk_identity->cmd_pool, &error)))
goto error;
if (!(framebuffer = _create_framebuffer (vk_identity, out_img_mem->view))) {
@ -590,9 +591,10 @@ gst_vulkan_image_identity_transform (GstBaseTransform * bt, GstBuffer * inbuf,
};
/* *INDENT-ON* */
err = vkBeginCommandBuffer (cmd, &cmd_buf_info);
gst_vulkan_command_buffer_lock (cmd_buf);
err = vkBeginCommandBuffer (cmd_buf->cmd, &cmd_buf_info);
if (gst_vulkan_error_to_g_error (err, &error, "vkBeginCommandBuffer") < 0)
goto error;
goto unlock_error;
}
{
@ -626,7 +628,8 @@ gst_vulkan_image_identity_transform (GstBaseTransform * bt, GstBuffer * inbuf,
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd, in_img_mem->barrier.parent.pipeline_stages,
vkCmdPipelineBarrier (cmd_buf->cmd,
in_img_mem->barrier.parent.pipeline_stages,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1,
&in_image_memory_barrier);
@ -636,7 +639,8 @@ gst_vulkan_image_identity_transform (GstBaseTransform * bt, GstBuffer * inbuf,
in_image_memory_barrier.dstAccessMask;
in_img_mem->barrier.image_layout = in_image_memory_barrier.newLayout;
vkCmdPipelineBarrier (cmd, out_img_mem->barrier.parent.pipeline_stages,
vkCmdPipelineBarrier (cmd_buf->cmd,
out_img_mem->barrier.parent.pipeline_stages,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1,
&out_image_memory_barrier);
@ -647,13 +651,14 @@ gst_vulkan_image_identity_transform (GstBaseTransform * bt, GstBuffer * inbuf,
out_img_mem->barrier.image_layout = out_image_memory_barrier.newLayout;
}
vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
vkCmdBindDescriptorSets (cmd_buf->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
render->pipeline_layout, 0, 1, &vk_identity->descriptor_set, 0, NULL);
if (!gst_vulkan_full_screen_render_fill_command_buffer (render, cmd,
if (!gst_vulkan_full_screen_render_fill_command_buffer (render, cmd_buf->cmd,
framebuffer))
return GST_FLOW_ERROR;
goto unlock_error;
err = vkEndCommandBuffer (cmd);
err = vkEndCommandBuffer (cmd_buf->cmd);
gst_vulkan_command_buffer_unlock (cmd_buf);
if (gst_vulkan_error_to_g_error (err, &error, "vkEndCommandBuffer") < 0)
goto error;
@ -661,14 +666,19 @@ gst_vulkan_image_identity_transform (GstBaseTransform * bt, GstBuffer * inbuf,
gst_vulkan_trash_new_free_framebuffer (gst_vulkan_fence_ref (fence),
framebuffer));
gst_vulkan_trash_list_add (render->trash_list,
gst_vulkan_trash_new_free_command_buffer (gst_vulkan_fence_ref (fence),
vk_identity->cmd_pool, cmd));
gst_vulkan_trash_new_mini_object_unref (gst_vulkan_fence_ref (fence),
GST_MINI_OBJECT_CAST (cmd_buf)));
if (!gst_vulkan_full_screen_render_submit (render, cmd, fence))
if (!gst_vulkan_full_screen_render_submit (render, cmd_buf->cmd, fence))
return GST_FLOW_ERROR;
return GST_FLOW_OK;
unlock_error:
if (cmd_buf) {
gst_vulkan_command_buffer_unlock (cmd_buf);
gst_vulkan_command_buffer_unref (cmd_buf);
}
error:
GST_ELEMENT_ERROR (bt, LIBRARY, FAILED, ("%s", error->message), (NULL));
g_clear_error (&error);

View file

@ -440,7 +440,7 @@ _buffer_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
GstFlowReturn ret;
GError *error = NULL;
VkResult err;
VkCommandBuffer cmd;
GstVulkanCommandBuffer *cmd_buf;
guint i;
if (!raw->cmd_pool) {
@ -451,7 +451,7 @@ _buffer_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
}
}
if (!(cmd = gst_vulkan_command_pool_create (raw->cmd_pool, &error)))
if (!(cmd_buf = gst_vulkan_command_pool_create (raw->cmd_pool, &error)))
goto error;
if (!raw->pool) {
@ -485,9 +485,10 @@ _buffer_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
};
/* *INDENT-ON* */
err = vkBeginCommandBuffer (cmd, &cmd_buf_info);
gst_vulkan_command_buffer_lock (cmd_buf);
err = vkBeginCommandBuffer (cmd_buf->cmd, &cmd_buf_info);
if (gst_vulkan_error_to_g_error (err, &error, "vkBeginCommandBuffer") < 0)
return FALSE;
goto unlock_error;
}
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&raw->out_info); i++) {
@ -501,14 +502,14 @@ _buffer_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
in_mem = gst_buffer_peek_memory (inbuf, i);
if (!gst_is_vulkan_buffer_memory (in_mem)) {
GST_WARNING_OBJECT (raw->upload, "Input is not a GstVulkanBufferMemory");
goto error;
goto unlock_error;
}
buf_mem = (GstVulkanBufferMemory *) in_mem;
out_mem = gst_buffer_peek_memory (*outbuf, i);
if (!gst_is_vulkan_image_memory (out_mem)) {
GST_WARNING_OBJECT (raw->upload, "Output is not a GstVulkanImageMemory");
goto error;
goto unlock_error;
}
img_mem = (GstVulkanImageMemory *) out_mem;
@ -559,7 +560,7 @@ _buffer_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd,
vkCmdPipelineBarrier (cmd_buf->cmd,
buf_mem->barrier.parent.pipeline_stages | img_mem->barrier.
parent.pipeline_stages, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1,
&buffer_memory_barrier, 1, &image_memory_barrier);
@ -571,13 +572,14 @@ _buffer_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
img_mem->barrier.parent.access_flags = image_memory_barrier.dstAccessMask;
img_mem->barrier.image_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
vkCmdCopyBufferToImage (cmd, buf_mem->buffer, img_mem->image,
vkCmdCopyBufferToImage (cmd_buf->cmd, buf_mem->buffer, img_mem->image,
img_mem->barrier.image_layout, 1, &region);
}
err = vkEndCommandBuffer (cmd);
err = vkEndCommandBuffer (cmd_buf->cmd);
gst_vulkan_command_buffer_unlock (cmd_buf);
if (gst_vulkan_error_to_g_error (err, &error, "vkEndCommandBuffer") < 0)
return FALSE;
goto error;
{
VkSubmitInfo submit_info = { 0, };
@ -592,7 +594,7 @@ _buffer_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
.pWaitSemaphores = NULL,
.pWaitDstStageMask = &stages,
.commandBufferCount = 1,
.pCommandBuffers = &cmd,
.pCommandBuffers = &cmd_buf->cmd,
.signalSemaphoreCount = 0,
.pSignalSemaphores = NULL
};
@ -609,7 +611,8 @@ _buffer_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
goto error;
gst_vulkan_trash_list_add (raw->trash_list,
gst_vulkan_trash_new_free_command_buffer (fence, raw->cmd_pool, cmd));
gst_vulkan_trash_new_mini_object_unref (fence,
GST_MINI_OBJECT_CAST (cmd_buf)));
}
gst_vulkan_trash_list_gc (raw->trash_list);
@ -619,13 +622,17 @@ _buffer_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
out:
return ret;
unlock_error:
if (cmd_buf) {
gst_vulkan_command_buffer_unlock (cmd_buf);
gst_vulkan_command_buffer_unref (cmd_buf);
}
error:
if (error) {
GST_WARNING_OBJECT (raw->upload, "Error: %s", error->message);
g_clear_error (&error);
}
gst_buffer_unref (*outbuf);
*outbuf = NULL;
gst_clear_buffer (outbuf);
ret = GST_FLOW_ERROR;
goto out;
}
@ -758,9 +765,9 @@ _raw_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
struct RawToImageUpload *raw = impl;
GstFlowReturn ret;
GstBuffer *in_vk_copy = NULL;
GstVulkanCommandBuffer *cmd_buf;
GError *error = NULL;
VkResult err;
VkCommandBuffer cmd;
guint i;
if (!raw->cmd_pool) {
@ -771,7 +778,7 @@ _raw_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
}
}
if (!(cmd = gst_vulkan_command_pool_create (raw->cmd_pool, &error)))
if (!(cmd_buf = gst_vulkan_command_pool_create (raw->cmd_pool, &error)))
goto error;
if (!raw->pool) {
@ -805,7 +812,8 @@ _raw_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
};
/* *INDENT-ON* */
err = vkBeginCommandBuffer (cmd, &cmd_buf_info);
gst_vulkan_command_buffer_lock (cmd_buf);
err = vkBeginCommandBuffer (cmd_buf->cmd, &cmd_buf_info);
if (gst_vulkan_error_to_g_error (err, &error, "vkBeginCommandBuffer") < 0)
return FALSE;
}
@ -852,26 +860,26 @@ _raw_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
if ((ret =
gst_buffer_pool_acquire_buffer (raw->in_pool, &in_vk_copy,
NULL)) != GST_FLOW_OK) {
goto out;
goto unlock_error;
}
if (!gst_video_frame_map (&in_frame, &raw->in_info, inbuf, GST_MAP_READ)) {
GST_WARNING_OBJECT (raw->upload, "Failed to map input buffer");
goto error;
goto unlock_error;
}
if (!gst_video_frame_map (&out_frame, &raw->in_info, in_vk_copy,
GST_MAP_WRITE)) {
gst_video_frame_unmap (&in_frame);
GST_WARNING_OBJECT (raw->upload, "Failed to map input buffer");
goto error;
goto unlock_error;
}
if (!gst_video_frame_copy (&out_frame, &in_frame)) {
gst_video_frame_unmap (&in_frame);
gst_video_frame_unmap (&out_frame);
GST_WARNING_OBJECT (raw->upload, "Failed to copy input buffer");
goto error;
goto unlock_error;
}
gst_video_frame_unmap (&in_frame);
@ -884,7 +892,7 @@ _raw_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
out_mem = gst_buffer_peek_memory (*outbuf, i);
if (!gst_is_vulkan_image_memory (out_mem)) {
GST_WARNING_OBJECT (raw->upload, "Output is not a GstVulkanImageMemory");
goto error;
goto unlock_error;
}
img_mem = (GstVulkanImageMemory *) out_mem;
@ -935,7 +943,7 @@ _raw_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd,
vkCmdPipelineBarrier (cmd_buf->cmd,
buf_mem->barrier.parent.pipeline_stages | img_mem->barrier.
parent.pipeline_stages, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1,
&buffer_memory_barrier, 1, &image_memory_barrier);
@ -947,11 +955,12 @@ _raw_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
img_mem->barrier.parent.access_flags = image_memory_barrier.dstAccessMask;
img_mem->barrier.image_layout = image_memory_barrier.newLayout;
vkCmdCopyBufferToImage (cmd, buf_mem->buffer, img_mem->image,
vkCmdCopyBufferToImage (cmd_buf->cmd, buf_mem->buffer, img_mem->image,
img_mem->barrier.image_layout, 1, &region);
}
err = vkEndCommandBuffer (cmd);
err = vkEndCommandBuffer (cmd_buf->cmd);
gst_vulkan_command_buffer_unlock (cmd_buf);
if (gst_vulkan_error_to_g_error (err, &error, "vkEndCommandBuffer") < 0) {
goto error;
}
@ -968,7 +977,7 @@ _raw_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
.pWaitSemaphores = NULL,
.pWaitDstStageMask = NULL,
.commandBufferCount = 1,
.pCommandBuffers = &cmd,
.pCommandBuffers = &cmd_buf->cmd,
.signalSemaphoreCount = 0,
.pSignalSemaphores = NULL,
};
@ -985,7 +994,8 @@ _raw_to_image_perform (gpointer impl, GstBuffer * inbuf, GstBuffer ** outbuf)
goto error;
gst_vulkan_trash_list_add (raw->trash_list,
gst_vulkan_trash_new_free_command_buffer (fence, raw->cmd_pool, cmd));
gst_vulkan_trash_new_mini_object_unref (fence,
GST_MINI_OBJECT_CAST (cmd_buf)));
}
gst_vulkan_trash_list_gc (raw->trash_list);
@ -998,13 +1008,17 @@ out:
return ret;
unlock_error:
if (cmd_buf) {
gst_vulkan_command_buffer_lock (cmd_buf);
gst_vulkan_command_buffer_unref (cmd_buf);
}
error:
if (error) {
GST_WARNING_OBJECT (raw->upload, "Error: %s", error->message);
g_clear_error (&error);
}
gst_buffer_unref (*outbuf);
*outbuf = NULL;
gst_clear_buffer (outbuf);
ret = GST_FLOW_ERROR;
goto out;
}

View file

@ -2234,8 +2234,8 @@ gst_vulkan_view_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
GstVulkanImageMemory *in_img_mems[GST_VIDEO_MAX_PLANES] = { NULL, };
GstVulkanImageMemory *out_img_mems[4] = { NULL, };
GstVulkanFence *fence = NULL;
GstVulkanCommandBuffer *cmd_buf;
VkFramebuffer framebuffer;
VkCommandBuffer cmd;
GError *error = NULL;
VkResult err;
int i;
@ -2266,7 +2266,7 @@ gst_vulkan_view_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
goto error;
}
if (!(cmd = gst_vulkan_command_pool_create (conv->cmd_pool, &error)))
if (!(cmd_buf = gst_vulkan_command_pool_create (conv->cmd_pool, &error)))
goto error;
fence = gst_vulkan_fence_new (render->device, 0, &error);
@ -2285,9 +2285,10 @@ gst_vulkan_view_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
};
/* *INDENT-ON* */
err = vkBeginCommandBuffer (cmd, &cmd_buf_info);
gst_vulkan_command_buffer_lock (cmd_buf);
err = vkBeginCommandBuffer (cmd_buf->cmd, &cmd_buf_info);
if (gst_vulkan_error_to_g_error (err, &error, "vkBeginCommandBuffer") < 0)
goto error;
goto unlock_error;
}
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&render->in_info); i++) {
@ -2307,7 +2308,8 @@ gst_vulkan_view_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd, in_img_mems[i]->barrier.parent.pipeline_stages,
vkCmdPipelineBarrier (cmd_buf->cmd,
in_img_mems[i]->barrier.parent.pipeline_stages,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1,
&in_image_memory_barrier);
@ -2337,7 +2339,7 @@ gst_vulkan_view_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd,
vkCmdPipelineBarrier (cmd_buf->cmd,
out_img_mems[i]->barrier.parent.pipeline_stages,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1,
&out_image_memory_barrier);
@ -2359,17 +2361,22 @@ gst_vulkan_view_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
GST_VIDEO_INFO_N_PLANES (&render->out_info), attachments))) {
g_set_error_literal (&error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
"Failed to create framebuffer");
goto error;
goto unlock_error;
}
}
view_convert_update_command_state (conv, cmd, in_img_mems, out_img_mems);
view_convert_update_command_state (conv, cmd_buf->cmd, in_img_mems,
out_img_mems);
if (!gst_vulkan_full_screen_render_fill_command_buffer (render, cmd,
framebuffer))
return GST_FLOW_ERROR;
if (!gst_vulkan_full_screen_render_fill_command_buffer (render, cmd_buf->cmd,
framebuffer)) {
g_set_error (&error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
"Failed to fill framebuffer");
goto unlock_error;
}
err = vkEndCommandBuffer (cmd);
err = vkEndCommandBuffer (cmd_buf->cmd);
gst_vulkan_command_buffer_unlock (cmd_buf);
if (gst_vulkan_error_to_g_error (err, &error, "vkEndCommandBuffer") < 0)
goto error;
@ -2377,14 +2384,19 @@ gst_vulkan_view_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
gst_vulkan_trash_new_free_framebuffer (gst_vulkan_fence_ref (fence),
framebuffer));
gst_vulkan_trash_list_add (render->trash_list,
gst_vulkan_trash_new_free_command_buffer (gst_vulkan_fence_ref (fence),
conv->cmd_pool, cmd));
gst_vulkan_trash_new_mini_object_unref (gst_vulkan_fence_ref (fence),
GST_MINI_OBJECT_CAST (cmd_buf)));
if (!gst_vulkan_full_screen_render_submit (render, cmd, fence))
if (!gst_vulkan_full_screen_render_submit (render, cmd_buf->cmd, fence))
return GST_FLOW_ERROR;
return GST_FLOW_OK;
unlock_error:
if (cmd_buf) {
gst_vulkan_command_buffer_unlock (cmd_buf);
gst_vulkan_command_buffer_unref (cmd_buf);
}
error:
GST_ELEMENT_ERROR (bt, LIBRARY, FAILED, ("%s", error->message), (NULL));
g_clear_error (&error);

View file

@ -0,0 +1,113 @@
/*
* GStreamer
* Copyright (C) 2019 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:vulkancommandbuffer
* @title: vulkancommandbuffer
*
* vulkancommandbuffer holds information about a command buffer.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstvkcommandbuffer.h"
#include "gstvkcommandpool.h"
#include "gstvkcommandpool-private.h"
#define GST_CAT_DEFAULT gst_debug_vulkan_command_buffer
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
static void
init_debug (void)
{
static volatile gsize _init = 0;
if (g_once_init_enter (&_init)) {
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "vulkancommandbuffer", 0,
"Vulkan command buffer");
g_once_init_leave (&_init, 1);
}
}
static gboolean
gst_vulkan_command_buffer_dispose (GstVulkanCommandBuffer * cmd)
{
GstVulkanCommandPool *pool;
/* no pool, do free */
if ((pool = cmd->pool) == NULL)
return TRUE;
/* keep the buffer alive */
gst_vulkan_command_buffer_ref (cmd);
/* return the buffer to the pool */
gst_vulkan_command_pool_release_buffer (pool, cmd);
return FALSE;
}
static void
gst_vulkan_command_buffer_free (GstVulkanCommandBuffer * cmd)
{
g_assert (cmd->pool == NULL);
GST_TRACE ("Freeing %p", cmd);
g_free (cmd);
}
static void
gst_vulkan_command_buffer_init (GstVulkanCommandBuffer * cmd,
VkCommandBuffer cmd_buf, VkCommandBufferLevel level)
{
cmd->cmd = cmd_buf;
cmd->level = level;
init_debug ();
GST_TRACE ("new %p", cmd);
gst_mini_object_init (&cmd->parent, 0, GST_TYPE_VULKAN_COMMAND_BUFFER,
NULL, (GstMiniObjectDisposeFunction) gst_vulkan_command_buffer_dispose,
(GstMiniObjectFreeFunction) gst_vulkan_command_buffer_free);
}
/**
* gst_vulkan_command_buffer_new_wrapped:
* @cmd: a VkCommandBuffer
* @level: the VkCommandBufferLevel for @cmd
*
* Returns: (transfer full): a new #GstVulkanCommandBuffer
*/
GstVulkanCommandBuffer *
gst_vulkan_command_buffer_new_wrapped (VkCommandBuffer cmd,
VkCommandBufferLevel level)
{
GstVulkanCommandBuffer *ret;
ret = g_new0 (GstVulkanCommandBuffer, 1);
gst_vulkan_command_buffer_init (ret, cmd, level);
return ret;
}
GST_DEFINE_MINI_OBJECT_TYPE (GstVulkanCommandBuffer, gst_vulkan_command_buffer);

View file

@ -0,0 +1,108 @@
/*
* GStreamer
* Copyright (C) 2019 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_VULKAN_COMMAND_BUFFER_H__
#define __GST_VULKAN_COMMAND_BUFFER_H__
#include <gst/gst.h>
#include <gst/vulkan/vulkan_fwd.h>
#include <gst/vulkan/gstvkapi.h>
G_BEGIN_DECLS
GST_VULKAN_API
GType gst_vulkan_command_buffer_get_type (void);
#define GST_TYPE_VULKAN_COMMAND_BUFFER (gst_vulkan_command_buffer_get_type ())
typedef struct _GstVulkanCommandBuffer GstVulkanCommandBuffer;
struct _GstVulkanCommandBuffer
{
GstMiniObject parent;
VkCommandBuffer cmd;
/* <protected> */
GstVulkanCommandPool *pool;
VkCommandBufferLevel level;
GMutex lock;
};
/**
* gst_vulkan_command_buffer_ref: (skip)
* @cmd: a #GstVulkanCommandBuffer.
*
* Increases the refcount of the given buffer by one.
*
* Returns: (transfer full): @buf
*/
static inline GstVulkanCommandBuffer* gst_vulkan_command_buffer_ref(GstVulkanCommandBuffer* cmd);
static inline GstVulkanCommandBuffer *
gst_vulkan_command_buffer_ref (GstVulkanCommandBuffer * cmd)
{
return (GstVulkanCommandBuffer *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (cmd));
}
/**
* gst_vulkan_command_buffer_unref: (skip)
* @cmd: (transfer full): a #GstVulkanCommandBuffer.
*
* Decreases the refcount of the buffer. If the refcount reaches 0, the buffer
* will be freed.
*/
static inline void gst_vulkan_command_buffer_unref(GstVulkanCommandBuffer* cmd);
static inline void
gst_vulkan_command_buffer_unref (GstVulkanCommandBuffer * cmd)
{
gst_mini_object_unref (GST_MINI_OBJECT_CAST (cmd));
}
/**
* gst_clear_vulkan_command_buffer: (skip)
* @cmd_ptr: a pointer to a #GstVulkanCommandBuffer reference
*
* Clears a reference to a #GstVulkanCommandBuffer.
*
* @buf_ptr must not be %NULL.
*
* If the reference is %NULL then this function does nothing. Otherwise, the
* reference count of the command buffer is decreased and the pointer is set
* to %NULL.
*
* Since: 1.16
*/
static inline void
gst_clear_vulkan_command_buffer (GstVulkanCommandBuffer ** cmd_ptr)
{
gst_clear_mini_object ((GstMiniObject **) cmd_ptr);
}
#define gst_vulkan_command_buffer_lock(cmd) (gst_vulkan_command_pool_lock((cmd)->pool))
#define gst_vulkan_command_buffer_unlock(cmd) (gst_vulkan_command_pool_unlock((cmd)->pool))
GST_VULKAN_API
GstVulkanCommandBuffer * gst_vulkan_command_buffer_new_wrapped (VkCommandBuffer cmd,
VkCommandBufferLevel level);
G_END_DECLS
#endif /* _GST_VULKAN_COMMAND_BUFFER_H_ */

View file

@ -0,0 +1,33 @@
/*
* GStreamer
* Copyright (C) 2016 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_VULKAN_COMMAND_POOL_PRIVATE_H__
#define __GST_VULKAN_COMMAND_POOL_PRIVATE_H__
#include <gst/gst.h>
G_BEGIN_DECLS
void gst_vulkan_command_pool_release_buffer (GstVulkanCommandPool * pool,
GstVulkanCommandBuffer * buffer);
G_END_DECLS
#endif /* __GST_VULKAN_IMAGE_BUFFER_POOL_H__ */

View file

@ -23,6 +23,7 @@
#endif
#include "gstvkcommandpool.h"
#include "gstvkcommandpool-private.h"
/**
* SECTION:vkcommandpool
@ -31,19 +32,40 @@
* @see_also: #GstVulkanDevice
*/
#define GST_VULKAN_COMMAND_POOL_LARGE_OUTSTANDING 1024
#define GET_PRIV(pool) G_TYPE_INSTANCE_GET_PRIVATE(pool, GST_TYPE_VULKAN_COMMAND_POOL, GstVulkanCommandPoolPrivate)
#define GST_VULKAN_COMMAND_POOL_LOCK(pool) (g_rec_mutex_lock(&GET_PRIV(pool)->rec_mutex))
#define GST_VULKAN_COMMAND_POOL_UNLOCK(pool) (g_rec_mutex_unlock(&GET_PRIV(pool)->rec_mutex))
#define GST_CAT_DEFAULT gst_vulkan_command_pool_debug
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
struct _GstVulkanCommandPoolPrivate
{
GQueue *available;
GRecMutex rec_mutex;
gsize outstanding;
};
#define parent_class gst_vulkan_command_pool_parent_class
G_DEFINE_TYPE_WITH_CODE (GstVulkanCommandPool, gst_vulkan_command_pool,
GST_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT,
GST_TYPE_OBJECT, G_ADD_PRIVATE (GstVulkanCommandPool);
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT,
"vulkancommandpool", 0, "Vulkan Command Pool"));
static void gst_vulkan_command_pool_dispose (GObject * object);
static void gst_vulkan_command_pool_finalize (GObject * object);
static void
gst_vulkan_command_pool_init (GstVulkanCommandPool * device)
gst_vulkan_command_pool_init (GstVulkanCommandPool * pool)
{
GstVulkanCommandPoolPrivate *priv = GET_PRIV (pool);
g_rec_mutex_init (&priv->rec_mutex);
priv->available = g_queue_new ();
}
static void
@ -51,23 +73,39 @@ gst_vulkan_command_pool_class_init (GstVulkanCommandPoolClass * device_class)
{
GObjectClass *gobject_class = (GObjectClass *) device_class;
gobject_class->dispose = gst_vulkan_command_pool_dispose;
gobject_class->finalize = gst_vulkan_command_pool_finalize;
}
static void
gst_vulkan_command_pool_dispose (GObject * object)
do_free_buffer (GstVulkanCommandBuffer * cmd_buf)
{
gst_vulkan_command_buffer_unref (cmd_buf);
}
static void
gst_vulkan_command_pool_finalize (GObject * object)
{
GstVulkanCommandPool *pool = GST_VULKAN_COMMAND_POOL (object);
GstVulkanCommandPoolPrivate *priv = GET_PRIV (pool);
GST_VULKAN_COMMAND_POOL_LOCK (pool);
g_queue_free_full (priv->available, (GDestroyNotify) do_free_buffer);
priv->available = NULL;
GST_VULKAN_COMMAND_POOL_UNLOCK (pool);
if (priv->outstanding > 0)
g_critical
("Destroying a Vulkan command pool that has outstanding buffers!");
if (pool->pool)
vkDestroyCommandPool (pool->queue->device->device, pool->pool, NULL);
pool->pool = VK_NULL_HANDLE;
if (pool->queue)
gst_object_unref (pool->queue);
pool->queue = NULL;
gst_clear_object (&pool->queue);
G_OBJECT_CLASS (parent_class)->dispose (object);
g_rec_mutex_clear (&priv->rec_mutex);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
/**
@ -86,35 +124,145 @@ gst_vulkan_command_pool_get_queue (GstVulkanCommandPool * pool)
return pool->queue ? gst_object_ref (pool->queue) : NULL;
}
/**
* gst_vulkan_command_pool_create: (skip)
* @pool: a #GstVulkanCommandPool
* @error: a #GError
*
* Returns: a new primary VkCommandBuffer
*
* Since: 1.18
*/
VkCommandBuffer
gst_vulkan_command_pool_create (GstVulkanCommandPool * pool, GError ** error)
static GstVulkanCommandBuffer *
command_alloc (GstVulkanCommandPool * pool, GError ** error)
{
VkResult err;
VkCommandBufferAllocateInfo cmd_info = { 0, };
GstVulkanCommandBuffer *buf;
VkCommandBuffer cmd;
g_return_val_if_fail (GST_IS_VULKAN_COMMAND_POOL (pool), NULL);
cmd_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmd_info.pNext = NULL;
cmd_info.commandPool = pool->pool;
cmd_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cmd_info.commandBufferCount = 1;
GST_VULKAN_COMMAND_POOL_LOCK (pool);
err = vkAllocateCommandBuffers (pool->queue->device->device, &cmd_info, &cmd);
GST_VULKAN_COMMAND_POOL_UNLOCK (pool);
if (gst_vulkan_error_to_g_error (err, error, "vkCreateCommandBuffer") < 0)
return NULL;
GST_LOG_OBJECT (pool, "created cmd buffer %p", cmd);
buf =
gst_vulkan_command_buffer_new_wrapped (cmd,
VK_COMMAND_BUFFER_LEVEL_PRIMARY);
GST_LOG_OBJECT (pool, "created cmd buffer %p", buf);
return buf;
}
static gboolean
gst_vulkan_command_pool_can_reset (GstVulkanCommandPool * pool)
{
g_return_val_if_fail (GST_IS_VULKAN_COMMAND_POOL (pool), FALSE);
/* whether VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT was in flags on
* pool creation */
return TRUE;
}
/**
* gst_vulkan_command_pool_create:
* @pool: a #GstVulkanCommandPool
* @error: a #GError
*
* Returns: a new or recycled primary #GstVulkanCommandBuffer
*
* Since: 1.18
*/
GstVulkanCommandBuffer *
gst_vulkan_command_pool_create (GstVulkanCommandPool * pool, GError ** error)
{
GstVulkanCommandBuffer *cmd = NULL;
GstVulkanCommandPoolPrivate *priv;
g_return_val_if_fail (GST_IS_VULKAN_COMMAND_POOL (pool), NULL);
priv = GET_PRIV (pool);
if (gst_vulkan_command_pool_can_reset (pool)) {
GST_VULKAN_COMMAND_POOL_LOCK (pool);
cmd = g_queue_pop_head (priv->available);
GST_VULKAN_COMMAND_POOL_UNLOCK (pool);
}
if (!cmd)
cmd = command_alloc (pool, error);
if (!cmd)
return NULL;
cmd->pool = gst_object_ref (pool);
GST_VULKAN_COMMAND_POOL_LOCK (pool);
priv->outstanding++;
if (priv->outstanding > GST_VULKAN_COMMAND_POOL_LARGE_OUTSTANDING)
g_critical ("%s: There are a large number of command buffers outstanding! "
"This usually means there is a reference counting issue somewhere.",
GST_OBJECT_NAME (pool));
GST_VULKAN_COMMAND_POOL_UNLOCK (pool);
return cmd;
}
void
gst_vulkan_command_pool_release_buffer (GstVulkanCommandPool * pool,
GstVulkanCommandBuffer * buffer)
{
GstVulkanCommandPoolPrivate *priv;
gboolean can_reset;
g_return_if_fail (GST_IS_VULKAN_COMMAND_POOL (pool));
g_return_if_fail (buffer != NULL);
g_return_if_fail (buffer->pool == pool);
priv = GET_PRIV (pool);
can_reset = gst_vulkan_command_pool_can_reset (pool);
GST_VULKAN_COMMAND_POOL_LOCK (pool);
if (can_reset) {
vkResetCommandBuffer (buffer->cmd, 0);
g_queue_push_tail (priv->available, buffer);
GST_TRACE_OBJECT (pool, "reset command buffer %p", buffer);
}
/* TODO: if this is a secondary command buffer, all primary command buffers
* that reference this command buffer will be invalid */
priv->outstanding--;
GST_VULKAN_COMMAND_POOL_UNLOCK (pool);
/* decrease the refcount that the buffer had to us */
gst_clear_object (&buffer->pool);
if (!can_reset)
gst_vulkan_command_buffer_unref (buffer);
}
/**
* gst_vulkan_command_pool_lock:
* @pool: a #GstVulkanCommandPool
*
* This should be called to ensure no other thread will attempt to access
* the pool's internal resources. Any modification of any of the allocated
* #GstVulkanCommandBuffer's need to be encapsulated in a
* gst_vulkan_command_pool_lock()/gst_vulkan_command_pool_unlock() pair to meet
* the Vulkan API requirements that host access to the command pool is
* externally synchronised.
*/
void
gst_vulkan_command_pool_lock (GstVulkanCommandPool * pool)
{
g_return_if_fail (GST_IS_VULKAN_COMMAND_POOL (pool));
GST_VULKAN_COMMAND_POOL_LOCK (pool);
}
/**
* gst_vulkan_command_pool_unlock:
* @pool: a #GstVulkanCommandPool
*
* See the documentation for gst_vulkan_command_pool_lock() for when you would
* need to use this function.
*/
void
gst_vulkan_command_pool_unlock (GstVulkanCommandPool * pool)
{
g_return_if_fail (GST_IS_VULKAN_COMMAND_POOL (pool));
GST_VULKAN_COMMAND_POOL_UNLOCK (pool);
}

View file

@ -47,10 +47,15 @@ struct _GstVulkanCommandPoolClass
};
GST_VULKAN_API
GstVulkanQueue * gst_vulkan_command_pool_get_queue (GstVulkanCommandPool * pool);
GstVulkanQueue * gst_vulkan_command_pool_get_queue (GstVulkanCommandPool * pool);
GST_VULKAN_API
VkCommandBuffer gst_vulkan_command_pool_create (GstVulkanCommandPool * pool,
GError ** error);
GstVulkanCommandBuffer * gst_vulkan_command_pool_create (GstVulkanCommandPool * pool,
GError ** error);
GST_VULKAN_API
void gst_vulkan_command_pool_lock (GstVulkanCommandPool * pool);
GST_VULKAN_API
void gst_vulkan_command_pool_unlock (GstVulkanCommandPool * pool);
#endif /* __GST_VULKAN_COMMAND_POOL_H__ */

View file

@ -118,7 +118,7 @@ gst_vulkan_queue_create_command_pool (GstVulkanQueue * queue, GError ** error)
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmd_pool_info.pNext = NULL;
cmd_pool_info.queueFamilyIndex = queue->family;
cmd_pool_info.flags = 0;
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
GST_OBJECT_LOCK (queue->device);
err =

View file

@ -963,18 +963,18 @@ gst_vulkan_swapper_set_caps (GstVulkanSwapper * swapper, GstCaps * caps,
static gboolean
_build_render_buffer_cmd (GstVulkanSwapper * swapper, guint32 swap_idx,
GstBuffer * buffer, VkCommandBuffer * cmd_ret, GError ** error)
GstBuffer * buffer, GstVulkanCommandBuffer ** cmd_ret, GError ** error)
{
GstMemory *in_mem;
GstVulkanImageMemory *swap_img;
VkCommandBuffer cmd;
GstVulkanCommandBuffer *cmd_buf;
GstVideoRectangle src, dst, rslt;
VkResult err;
g_return_val_if_fail (swap_idx < swapper->priv->n_swap_chain_images, FALSE);
swap_img = swapper->priv->swap_chain_images[swap_idx];
if (!(cmd = gst_vulkan_command_pool_create (swapper->cmd_pool, error)))
if (!(cmd_buf = gst_vulkan_command_pool_create (swapper->cmd_pool, error)))
return FALSE;
{
@ -987,9 +987,10 @@ _build_render_buffer_cmd (GstVulkanSwapper * swapper, guint32 swap_idx,
};
/* *INDENT-ON* */
err = vkBeginCommandBuffer (cmd, &cmd_buf_info);
gst_vulkan_command_buffer_lock (cmd_buf);
err = vkBeginCommandBuffer (cmd_buf->cmd, &cmd_buf_info);
if (gst_vulkan_error_to_g_error (err, error, "vkBeginCommandBuffer") < 0)
return FALSE;
goto unlock_error;
}
{
@ -1009,7 +1010,8 @@ _build_render_buffer_cmd (GstVulkanSwapper * swapper, guint32 swap_idx,
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd, swap_img->barrier.parent.pipeline_stages,
vkCmdPipelineBarrier (cmd_buf->cmd,
swap_img->barrier.parent.pipeline_stages,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
&image_memory_barrier);
@ -1082,7 +1084,7 @@ _build_render_buffer_cmd (GstVulkanSwapper * swapper, guint32 swap_idx,
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd, img_mem->barrier.parent.pipeline_stages,
vkCmdPipelineBarrier (cmd_buf->cmd, img_mem->barrier.parent.pipeline_stages,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
&image_memory_barrier);
@ -1090,9 +1092,9 @@ _build_render_buffer_cmd (GstVulkanSwapper * swapper, guint32 swap_idx,
img_mem->barrier.parent.access_flags = image_memory_barrier.dstAccessMask;
img_mem->barrier.image_layout = image_memory_barrier.newLayout;
vkCmdClearColorImage (cmd, swap_img->image, swap_img->barrier.image_layout,
&clear, 1, &clear_range);
vkCmdBlitImage (cmd, img_mem->image, img_mem->barrier.image_layout,
vkCmdClearColorImage (cmd_buf->cmd, swap_img->image,
swap_img->barrier.image_layout, &clear, 1, &clear_range);
vkCmdBlitImage (cmd_buf->cmd, img_mem->image, img_mem->barrier.image_layout,
swap_img->image, swap_img->barrier.image_layout, 1, &blit,
VK_FILTER_LINEAR);
}
@ -1113,7 +1115,8 @@ _build_render_buffer_cmd (GstVulkanSwapper * swapper, guint32 swap_idx,
};
/* *INDENT-ON* */
vkCmdPipelineBarrier (cmd, swap_img->barrier.parent.pipeline_stages,
vkCmdPipelineBarrier (cmd_buf->cmd,
swap_img->barrier.parent.pipeline_stages,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
&image_memory_barrier);
@ -1122,13 +1125,18 @@ _build_render_buffer_cmd (GstVulkanSwapper * swapper, guint32 swap_idx,
swap_img->barrier.image_layout = image_memory_barrier.newLayout;
}
err = vkEndCommandBuffer (cmd);
err = vkEndCommandBuffer (cmd_buf->cmd);
if (gst_vulkan_error_to_g_error (err, error, "vkEndCommandBuffer") < 0)
return FALSE;
goto unlock_error;
gst_vulkan_command_buffer_unlock (cmd_buf);
*cmd_ret = cmd;
*cmd_ret = cmd_buf;
return TRUE;
unlock_error:
gst_vulkan_command_buffer_unlock (cmd_buf);
return FALSE;
}
static gboolean
@ -1140,7 +1148,7 @@ _render_buffer_unlocked (GstVulkanSwapper * swapper,
VkSemaphoreCreateInfo semaphore_info = { 0, };
GstVulkanFence *fence = NULL;
VkPresentInfoKHR present;
VkCommandBuffer cmd = VK_NULL_HANDLE;
GstVulkanCommandBuffer *cmd_buf = NULL;
guint32 swap_idx;
VkResult err, present_err = VK_SUCCESS;
@ -1192,7 +1200,7 @@ reacquire:
goto error;
}
if (!_build_render_buffer_cmd (swapper, swap_idx, buffer, &cmd, error))
if (!_build_render_buffer_cmd (swapper, swap_idx, buffer, &cmd_buf, error))
goto error;
err = vkCreateSemaphore (swapper->device->device, &semaphore_info,
@ -1212,7 +1220,7 @@ reacquire:
.pWaitSemaphores = &acquire_semaphore,
.pWaitDstStageMask = &stages,
.commandBufferCount = 1,
.pCommandBuffers = &cmd,
.pCommandBuffers = &cmd_buf->cmd,
.signalSemaphoreCount = 1,
.pSignalSemaphores = &present_semaphore,
};
@ -1229,13 +1237,14 @@ reacquire:
goto error;
gst_vulkan_trash_list_add (swapper->priv->trash_list,
gst_vulkan_trash_new_free_command_buffer (gst_vulkan_fence_ref (fence),
swapper->cmd_pool, cmd));
gst_vulkan_trash_new_mini_object_unref (gst_vulkan_fence_ref (fence),
GST_MINI_OBJECT_CAST (cmd_buf)));
gst_vulkan_trash_list_add (swapper->priv->trash_list,
gst_vulkan_trash_new_free_semaphore (fence, acquire_semaphore));
acquire_semaphore = NULL;
cmd = VK_NULL_HANDLE;
gst_vulkan_command_buffer_unlock (cmd_buf);
cmd_buf = NULL;
fence = NULL;
}
@ -1297,9 +1306,10 @@ error:
vkDestroySemaphore (swapper->device->device, acquire_semaphore, NULL);
if (present_semaphore)
vkDestroySemaphore (swapper->device->device, present_semaphore, NULL);
if (cmd)
vkFreeCommandBuffers (swapper->device->device, swapper->cmd_pool->pool,
1, &cmd);
if (cmd_buf) {
gst_vulkan_command_buffer_unlock (cmd_buf);
gst_vulkan_command_buffer_unref (cmd_buf);
}
return FALSE;
}
}

View file

@ -116,36 +116,6 @@ FREE_DESTROY_FUNC (vkDestroyPipelineLayout, VkPipelineLayout, pipeline_layout);
FREE_DESTROY_FUNC (vkDestroyRenderPass, VkRenderPass, render_pass);
FREE_DESTROY_FUNC (vkDestroySemaphore, VkSemaphore, semaphore)
FREE_DESTROY_FUNC (vkDestroySampler, VkSampler, sampler);
#define FREE_WITH_GST_PARENT(func, type, type_name, parent_type, parent_resource) \
struct G_PASTE(free_parent_info_,type_name) \
{ \
parent_type parent; \
type resource; \
}; \
static void \
G_PASTE(_free_,type_name) (GstVulkanDevice * device, struct G_PASTE(free_parent_info_,type_name) *info) \
{ \
GST_TRACE_OBJECT (device, "Freeing vulkan " G_STRINGIFY (type) " %p", info->resource); \
func (device->device, info->parent parent_resource, 1, &info->resource); \
gst_object_unref (info->parent); \
g_free (info); \
} \
GstVulkanTrash * \
G_PASTE(gst_vulkan_trash_new_free_,type_name) (GstVulkanFence * fence, \
parent_type parent, type type_name) \
{ \
struct G_PASTE(free_parent_info_,type_name) *info; \
GstVulkanTrash *trash; \
g_return_val_if_fail (type_name != NULL, NULL); \
info = g_new0 (struct G_PASTE(free_parent_info_,type_name), 1); \
info->parent = gst_object_ref (parent); \
info->resource = (gpointer) type_name; \
trash = gst_vulkan_trash_new (fence, \
(GstVulkanTrashNotify) G_PASTE(_free_,type_name), info); \
return trash; \
}
FREE_WITH_GST_PARENT (vkFreeCommandBuffers, VkCommandBuffer, command_buffer,
GstVulkanCommandPool *,->pool);
#define FREE_WITH_VK_PARENT(func, type, type_name, parent_type) \
struct G_PASTE(free_parent_info_,type_name) \
{ \

View file

@ -105,10 +105,6 @@ GstVulkanTrash * gst_vulkan_trash_new_free_semaphore (GstVulkanFe
VkSemaphore semaphore);
GST_VULKAN_API
GstVulkanTrash * gst_vulkan_trash_new_free_command_buffer (GstVulkanFence * fence,
GstVulkanCommandPool * parent,
VkCommandBuffer command_buffer);
GST_VULKAN_API
GstVulkanTrash * gst_vulkan_trash_new_free_descriptor_set (GstVulkanFence * fence,
VkDescriptorPool parent,
VkDescriptorSet descriptor_set);

View file

@ -6,6 +6,7 @@ endif
vulkan_sources = [
'gstvkbuffermemory.c',
'gstvkbufferpool.c',
'gstvkcommandbuffer.c',
'gstvkcommandpool.c',
'gstvkdevice.c',
'gstvkdebug.c',
@ -30,6 +31,7 @@ vulkan_headers = [
'gstvkbarrier.h',
'gstvkbuffermemory.h',
'gstvkbufferpool.h',
'gstvkcommandbuffer.h',
'gstvkcommandpool.h',
'gstvkdebug.h',
'gstvkdevice.h',

View file

@ -42,6 +42,7 @@
#include <gst/vulkan/gstvkbufferpool.h>
#include <gst/vulkan/gstvkimagebufferpool.h>
#include <gst/vulkan/gstvkutils.h>
#include <gst/vulkan/gstvkcommandbuffer.h>
#include <gst/vulkan/gstvkcommandpool.h>
#include <gst/vulkan/gstvktrash.h>
#include <gst/vulkan/gstvkswapper.h>

View file

@ -44,6 +44,8 @@ typedef struct _GstVulkanCommandPool GstVulkanCommandPool;
typedef struct _GstVulkanCommandPoolClass GstVulkanCommandPoolClass;
typedef struct _GstVulkanCommandPoolPrivate GstVulkanCommandPoolPrivate;
typedef struct _GstVulkanCommandBuffer GstVulkanCommandBuffer;
typedef struct _GstVulkanDisplay GstVulkanDisplay;
typedef struct _GstVulkanDisplayClass GstVulkanDisplayClass;
typedef struct _GstVulkanDisplayPrivate GstVulkanDisplayPrivate;

View file

@ -0,0 +1,127 @@
/* GStreamer
*
* Copyright (C) 2019 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include <gst/check/gstcheck.h>
#include <gst/vulkan/vulkan.h>
static GstVulkanInstance *instance;
static GstVulkanDevice *device;
static GstVulkanQueue *queue;
static void
setup (void)
{
instance = gst_vulkan_instance_new ();
fail_unless (gst_vulkan_instance_open (instance, NULL));
device = gst_vulkan_device_new_with_index (instance, 0);
fail_unless (gst_vulkan_device_open (device, NULL));
/* family and id may be wrong! */
queue = gst_vulkan_device_get_queue (device, 0, 0);
fail_unless (GST_IS_VULKAN_QUEUE (queue));
}
static void
teardown (void)
{
gst_object_unref (instance);
gst_object_unref (device);
gst_object_unref (queue);
}
GST_START_TEST (test_new)
{
GstVulkanCommandPool *pool =
gst_vulkan_queue_create_command_pool (queue, NULL);
fail_unless (GST_IS_VULKAN_COMMAND_POOL (pool));
gst_object_unref (pool);
}
GST_END_TEST;
static void
buffer_destroy_notify (gpointer ptr)
{
gint *counter = ptr;
GST_DEBUG ("buffer destroyed");
*counter += 1;
}
/* Track when a buffer is destroyed. The counter will be increased if the
* buffer is finalized (but not if it was re-surrected in dispose and put
* back into the buffer pool. */
static void
buffer_track_destroy (GstVulkanCommandBuffer * buf, gint * counter)
{
gst_mini_object_set_qdata (GST_MINI_OBJECT (buf),
g_quark_from_static_string ("TestTracker"),
counter, buffer_destroy_notify);
}
GST_START_TEST (test_recycle)
{
GstVulkanCommandPool *pool =
gst_vulkan_queue_create_command_pool (queue, NULL);
GstVulkanCommandBuffer *cmd;
gint dcount = 0;
fail_unless (GST_IS_VULKAN_COMMAND_POOL (pool));
cmd = gst_vulkan_command_pool_create (pool, NULL);
fail_unless (cmd != NULL);
buffer_track_destroy (cmd, &dcount);
gst_vulkan_command_buffer_unref (cmd);
/* buffer should have been recycled */
fail_unless (dcount == 0);
gst_object_unref (pool);
}
GST_END_TEST;
static Suite *
vkcommandpool_suite (void)
{
Suite *s = suite_create ("vkcommandpool");
TCase *tc_basic = tcase_create ("general");
gboolean have_instance;
suite_add_tcase (s, tc_basic);
tcase_add_checked_fixture (tc_basic, setup, teardown);
/* FIXME: CI doesn't have a software vulkan renderer (and none exists currently) */
instance = gst_vulkan_instance_new ();
have_instance = gst_vulkan_instance_open (instance, NULL);
gst_object_unref (instance);
if (have_instance) {
tcase_add_test (tc_basic, test_new);
tcase_add_test (tc_basic, test_recycle);
}
return s;
}
GST_CHECK_MAIN (vkcommandpool);

View file

@ -59,6 +59,7 @@ base_tests = [
[['libs/vkwindow.c'], not gstvulkan_dep.found(), [gstvulkan_dep]],
[['libs/vkdevice.c'], not gstvulkan_dep.found(), [gstvulkan_dep]],
[['elements/vkdeviceprovider.c'], not gstvulkan_dep.found(), [gstvulkan_dep]],
[['libs/vkcommandpool.c'], not gstvulkan_dep.found(), [gstvulkan_dep]],
]
# FIXME: unistd dependency, unstable or not tested yet on windows