gpu: Add a gsk_gpu_download_into_op()

... and use it for the dmabuf downloader

Splits the download op into 2 separate ops: One for downloading textures
and one for downloading into preallocated memory.

The download into memory is the fallback for the texture downloading op,
so they need to share code.

But keeping them separate ensures that the different codepaths for
dmabuf download and render_texture() don't get mixed up in weird ways
that potentially call into each other.

By passing the emory down into the op we can also avoid an extra memcpy
which can lead to quite large speedups for big textures.
This commit is contained in:
Benjamin Otte
2024-09-25 02:43:25 +02:00
parent ccb993d87b
commit 52df3481d6
3 changed files with 176 additions and 78 deletions

View File

@@ -37,10 +37,8 @@ struct _GskGpuDownloadOp
GdkColorState *color_state;
gboolean allow_dmabuf;
GdkGpuDownloadOpCreateFunc create_func;
GskGpuDownloadFunc func;
gpointer user_data;
GdkTexture **texture;
GdkTexture *texture;
GskGpuBuffer *buffer;
#ifdef GDK_RENDERING_VULKAN
VkSemaphore vk_semaphore;
@@ -55,9 +53,6 @@ gsk_gpu_download_op_finish (GskGpuOp *op)
if (self->create_func)
self->create_func (self);
self->func (self->user_data, self->texture);
g_object_unref (self->texture);
g_object_unref (self->image);
g_clear_object (&self->buffer);
}
@@ -160,8 +155,8 @@ gsk_gpu_download_op_vk_sync_semaphore (GskGpuDownloadOp *self)
int fd, sync_file_fd;
/* Don't look at where I store my variables plz */
display = gdk_dmabuf_texture_get_display (GDK_DMABUF_TEXTURE (self->texture));
fd = gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (self->texture))->planes[0].fd;
display = gdk_dmabuf_texture_get_display (GDK_DMABUF_TEXTURE (*self->texture));
fd = gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (*self->texture))->planes[0].fd;
func_vkGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR) vkGetDeviceProcAddr (display->vk_device, "vkGetSemaphoreFdKHR");
/* vkGetSemaphoreFdKHR implicitly resets the semaphore.
@@ -206,7 +201,7 @@ gsk_gpu_download_op_vk_create (GskGpuDownloadOp *self)
gdk_memory_texture_builder_set_bytes (builder, bytes);
gdk_memory_texture_builder_set_stride (builder, stride);
gdk_memory_texture_builder_set_color_state (builder, self->color_state);
self->texture = gdk_memory_texture_builder_build (builder);
*self->texture = gdk_memory_texture_builder_build (builder);
g_object_unref (builder);
g_bytes_unref (bytes);
@@ -219,19 +214,18 @@ gsk_gpu_download_op_vk_command (GskGpuOp *op,
GskVulkanCommandState *state)
{
GskGpuDownloadOp *self = (GskGpuDownloadOp *) op;
gsize width, height, stride;
#ifdef HAVE_DMABUF
if (self->allow_dmabuf)
self->texture = gsk_vulkan_image_to_dmabuf_texture (GSK_VULKAN_IMAGE (self->image),
*self->texture = gsk_vulkan_image_to_dmabuf_texture (GSK_VULKAN_IMAGE (self->image),
self->color_state);
if (self->texture)
if (*self->texture)
{
GskGpuDevice *device = gsk_gpu_frame_get_device (frame);
GskGpuCache *cache = gsk_gpu_device_get_cache (device);
VkDevice vk_device = gsk_vulkan_device_get_vk_device (GSK_VULKAN_DEVICE (device));
gsk_gpu_cache_cache_texture_image (cache, self->texture, self->image, NULL);
gsk_gpu_cache_cache_texture_image (cache, *self->texture, self->image, NULL);
if (gsk_vulkan_device_has_feature (GSK_VULKAN_DEVICE (device), GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT))
{
@@ -339,11 +333,11 @@ gsk_gpu_download_op_gl_command (GskGpuOp *op,
gdk_dmabuf_texture_builder_set_height (db, gsk_gpu_image_get_height (self->image));
gdk_dmabuf_texture_builder_set_color_state (db, self->color_state);
self->texture = gdk_dmabuf_texture_builder_build (db, release_dmabuf_texture, texture, NULL);
*self->texture = gdk_dmabuf_texture_builder_build (db, release_dmabuf_texture, texture, NULL);
g_object_unref (db);
if (self->texture)
if (*self->texture)
return op->next;
gdk_dmabuf_close_fds (&texture->dmabuf);
@@ -369,11 +363,11 @@ gsk_gpu_download_op_gl_command (GskGpuOp *op,
gdk_gl_texture_builder_set_height (builder, gsk_gpu_image_get_height (self->image));
gdk_gl_texture_builder_set_sync (builder, data->sync);
self->texture = gdk_gl_texture_builder_build (builder,
gsk_gl_texture_data_free,
data);
*self->texture = gdk_gl_texture_builder_build (builder,
gsk_gl_texture_data_free,
data);
gsk_gpu_image_toggle_ref_texture (self->image, self->texture);
gsk_gpu_image_toggle_ref_texture (self->image, *self->texture);
gsk_gl_image_steal_texture_ownership (GSK_GL_IMAGE (self->image));
g_object_unref (builder);
@@ -396,17 +390,158 @@ void
gsk_gpu_download_op (GskGpuFrame *frame,
GskGpuImage *image,
GdkColorState *color_state,
gboolean allow_dmabuf,
GskGpuDownloadFunc func,
gpointer user_data)
GdkTexture **out_texture)
{
GskGpuDownloadOp *self;
g_assert (out_texture != NULL && *out_texture == NULL);
self = (GskGpuDownloadOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_DOWNLOAD_OP_CLASS);
self->image = g_object_ref (image);
self->color_state = gdk_color_state_ref (color_state);
self->allow_dmabuf = allow_dmabuf;
self->func = func,
self->user_data = user_data;
self->texture = out_texture;
}
typedef struct _GskGpuDownloadIntoOp GskGpuDownloadIntoOp;
typedef void (* GdkGpuDownloadIntoOpCreateFunc) (GskGpuDownloadIntoOp *);
struct _GskGpuDownloadIntoOp
{
GskGpuOp op;
GdkGpuDownloadIntoOpCreateFunc create_func;
GskGpuBuffer *buffer;
GskGpuImage *image;
GdkColorState *image_color_state;
GdkMemoryFormat format;
GdkColorState *color_state;
guchar *data;
gsize stride;
};
static void
gsk_gpu_download_into_op_finish (GskGpuOp *op)
{
GskGpuDownloadIntoOp *self = (GskGpuDownloadIntoOp *) op;
if (self->create_func)
self->create_func (self);
g_object_unref (self->image);
gdk_color_state_unref (self->image_color_state);
gdk_color_state_unref (self->color_state);
g_clear_object (&self->buffer);
}
static void
gsk_gpu_download_into_op_print (GskGpuOp *op,
GskGpuFrame *frame,
GString *string,
guint indent)
{
GskGpuDownloadIntoOp *self = (GskGpuDownloadIntoOp *) op;
gsk_gpu_print_op (string, indent, "download-into");
gsk_gpu_print_image (string, self->image);
g_string_append_printf (string, "%s ", gdk_color_state_get_name (self->image_color_state));
g_string_append_printf (string, "%s ", gdk_memory_format_get_name (self->format));
g_string_append_printf (string, "%s ", gdk_color_state_get_name (self->color_state));
gsk_gpu_print_newline (string);
}
#ifdef GDK_RENDERING_VULKAN
static void
gsk_gpu_download_into_op_vk_create (GskGpuDownloadIntoOp *self)
{
guchar *data;
GdkMemoryFormat format;
gsize width, height;
data = gsk_gpu_buffer_map (self->buffer);
format = gsk_gpu_image_get_format (self->image);
width = gsk_gpu_image_get_width (self->image);
height = gsk_gpu_image_get_height (self->image);
gdk_memory_convert (self->data,
self->stride,
self->format,
self->color_state,
data,
width * gdk_memory_format_bytes_per_pixel (format),
format,
self->image_color_state,
width,
height);
}
static GskGpuOp *
gsk_gpu_download_into_op_vk_command (GskGpuOp *op,
GskGpuFrame *frame,
GskVulkanCommandState *state)
{
GskGpuDownloadIntoOp *self = (GskGpuDownloadIntoOp *) op;
self->buffer = gsk_gpu_download_vk_start (frame, state, self->image);
self->create_func = gsk_gpu_download_into_op_vk_create;
return op->next;
}
#endif
static GskGpuOp *
gsk_gpu_download_into_op_gl_command (GskGpuOp *op,
GskGpuFrame *frame,
GskGLCommandState *state)
{
GskGpuDownloadIntoOp *self = (GskGpuDownloadIntoOp *) op;
gdk_gl_context_download (GDK_GL_CONTEXT (gsk_gpu_frame_get_context (frame)),
gsk_gl_image_get_texture_id (GSK_GL_IMAGE (self->image)),
gsk_gpu_image_get_format (self->image),
self->image_color_state,
self->data,
self->stride,
self->format,
self->color_state,
gsk_gpu_image_get_width (self->image),
gsk_gpu_image_get_height (self->image));
return op->next;
}
static const GskGpuOpClass GSK_GPU_DOWNLOAD_INTO_OP_CLASS = {
GSK_GPU_OP_SIZE (GskGpuDownloadIntoOp),
GSK_GPU_STAGE_COMMAND,
gsk_gpu_download_into_op_finish,
gsk_gpu_download_into_op_print,
#ifdef GDK_RENDERING_VULKAN
gsk_gpu_download_into_op_vk_command,
#endif
gsk_gpu_download_into_op_gl_command
};
void
gsk_gpu_download_into_op (GskGpuFrame *frame,
GskGpuImage *image,
GdkColorState *image_color_state,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride)
{
GskGpuDownloadIntoOp *self;
self = (GskGpuDownloadIntoOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_DOWNLOAD_INTO_OP_CLASS);
self->image = g_object_ref (image);
self->image_color_state = gdk_color_state_ref (image_color_state);
self->format = format;
self->color_state = gdk_color_state_ref (color_state);
self->data = data;
self->stride = stride;
}

View File

@@ -4,15 +4,17 @@
G_BEGIN_DECLS
typedef void (* GskGpuDownloadFunc) (gpointer user_data,
GdkTexture *texture);
void gsk_gpu_download_op (GskGpuFrame *frame,
GskGpuImage *image,
GdkColorState *color_state,
gboolean allow_dmabuf,
GskGpuDownloadFunc func,
gpointer user_data);
GdkTexture **out_texture);
void gsk_gpu_download_into_op (GskGpuFrame *frame,
GskGpuImage *image,
GdkColorState *image_color_state,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride);
G_END_DECLS

View File

@@ -651,15 +651,6 @@ gsk_gpu_frame_wait (GskGpuFrame *self)
gsk_gpu_frame_cleanup (self);
}
static void
copy_texture (gpointer user_data,
GdkTexture *texture)
{
GdkTexture **target = (GdkTexture **) user_data;
*target = g_object_ref (texture);
}
static void
gsk_gpu_frame_record (GskGpuFrame *self,
gint64 timestamp,
@@ -679,7 +670,7 @@ gsk_gpu_frame_record (GskGpuFrame *self,
gsk_gpu_node_processor_process (self, target, target_color_state, clip, node, viewport, pass_type);
if (texture)
gsk_gpu_download_op (self, target, target_color_state, TRUE, copy_texture, texture);
gsk_gpu_download_op (self, target, target_color_state, texture);
}
static void
@@ -732,32 +723,6 @@ gsk_gpu_frame_render (GskGpuFrame *self,
gsk_gpu_frame_submit (self, pass_type);
}
typedef struct _Download Download;
struct _Download
{
GdkMemoryFormat format;
GdkColorState *color_state;
guchar *data;
gsize stride;
};
static void
do_download (gpointer user_data,
GdkTexture *texture)
{
Download *download = user_data;
GdkTextureDownloader downloader;
gdk_texture_downloader_init (&downloader, texture);
gdk_texture_downloader_set_format (&downloader, download->format);
gdk_texture_downloader_set_color_state (&downloader, download->color_state);
gdk_texture_downloader_download_into (&downloader, download->data, download->stride);
gdk_texture_downloader_finish (&downloader);
g_free (download);
}
void
gsk_gpu_frame_download_texture (GskGpuFrame *self,
gint64 timestamp,
@@ -785,17 +750,13 @@ gsk_gpu_frame_download_texture (GskGpuFrame *self,
gsk_gpu_frame_cleanup (self);
gsk_gpu_download_op (self,
image,
gdk_texture_get_color_state (texture),
FALSE,
do_download,
g_memdup2 (&(Download) {
.format = format,
.color_state = color_state,
.data = data,
.stride = stride
}, sizeof (Download)));
gsk_gpu_download_into_op (self,
image,
gdk_texture_get_color_state (texture),
format,
color_state,
data,
stride);
gsk_gpu_frame_submit (self, GSK_RENDER_PASS_EXPORT);
g_object_unref (image);