mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-08 09:40:10 +00:00
ff0045b8c9
Change things from picking a download method at creation time to trying all methods at download time until one succeeds.
305 lines
9.4 KiB
C
305 lines
9.4 KiB
C
/* gdkdmabuftexture.c
|
|
*
|
|
* Copyright 2023 Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gdkdmabuftextureprivate.h"
|
|
|
|
#include "gdkcolorstateprivate.h"
|
|
#include "gdkdisplayprivate.h"
|
|
#include "gdkdmabufdownloaderprivate.h"
|
|
#include "gdkdmabufformatsbuilderprivate.h"
|
|
#include "gdkdmabuffourccprivate.h"
|
|
#include "gdkdmabufprivate.h"
|
|
#include "gdkdmabuftexturebuilderprivate.h"
|
|
#include "gdktextureprivate.h"
|
|
#include <gdk/gdkglcontext.h>
|
|
#include <gdk/gdkgltexturebuilder.h>
|
|
#include <gdk/gdktexturedownloader.h>
|
|
|
|
/**
|
|
* GdkDmabufTexture:
|
|
*
|
|
* A `GdkTexture` representing a DMA buffer.
|
|
*
|
|
* To create a `GdkDmabufTexture`, use the auxiliary
|
|
* [class@Gdk.DmabufTextureBuilder] object.
|
|
*
|
|
* Dma-buf textures can only be created on Linux.
|
|
*
|
|
* Since: 4.14
|
|
*/
|
|
|
|
struct _GdkDmabufTexture
|
|
{
|
|
GdkTexture parent_instance;
|
|
|
|
GdkDisplay *display;
|
|
|
|
GdkDmabuf dmabuf;
|
|
|
|
GDestroyNotify destroy;
|
|
gpointer data;
|
|
};
|
|
|
|
struct _GdkDmabufTextureClass
|
|
{
|
|
GdkTextureClass parent_class;
|
|
};
|
|
|
|
/**
|
|
* gdk_dmabuf_error_quark:
|
|
*
|
|
* Registers an error quark for [class@Gdk.DmabufTexture] errors.
|
|
*
|
|
* Returns: the error quark
|
|
**/
|
|
G_DEFINE_QUARK (gdk-dmabuf-error-quark, gdk_dmabuf_error)
|
|
|
|
G_DEFINE_TYPE (GdkDmabufTexture, gdk_dmabuf_texture, GDK_TYPE_TEXTURE)
|
|
|
|
static void
|
|
gdk_dmabuf_texture_dispose (GObject *object)
|
|
{
|
|
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (object);
|
|
|
|
if (self->destroy)
|
|
{
|
|
self->destroy (self->data);
|
|
self->destroy = NULL;
|
|
}
|
|
|
|
g_clear_object (&self->display);
|
|
|
|
G_OBJECT_CLASS (gdk_dmabuf_texture_parent_class)->dispose (object);
|
|
}
|
|
|
|
typedef struct _Download Download;
|
|
|
|
struct _Download
|
|
{
|
|
GdkDmabufTexture *texture;
|
|
GdkMemoryFormat format;
|
|
GdkColorState *color_state;
|
|
guchar *data;
|
|
gsize stride;
|
|
volatile int spinlock;
|
|
};
|
|
|
|
static gboolean
|
|
gdk_dmabuf_texture_invoke_callback (gpointer data)
|
|
{
|
|
Download *download = data;
|
|
GdkDisplay *display = download->texture->display;
|
|
|
|
if (display->egl_downloader &&
|
|
gdk_dmabuf_downloader_download (display->egl_downloader,
|
|
download->texture,
|
|
download->format,
|
|
download->color_state,
|
|
download->data,
|
|
download->stride))
|
|
{
|
|
/* Successfully downloaded using EGL */
|
|
}
|
|
else if (display->vk_downloader &&
|
|
gdk_dmabuf_downloader_download (display->vk_downloader,
|
|
download->texture,
|
|
download->format,
|
|
download->color_state,
|
|
download->data,
|
|
download->stride))
|
|
{
|
|
/* Successfully downloaded using Vulkan */
|
|
}
|
|
#ifdef HAVE_DMABUF
|
|
else if (gdk_dmabuf_download_mmap (GDK_TEXTURE (download->texture),
|
|
download->format,
|
|
download->color_state,
|
|
download->data,
|
|
download->stride))
|
|
{
|
|
/* Successfully downloaded using mmap */
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
const GdkDmabuf *dmabuf = gdk_dmabuf_texture_get_dmabuf (download->texture);
|
|
|
|
g_critical ("Failed to download %dx%d dmabuf texture (format %.4s:%#" G_GINT64_MODIFIER "x)",
|
|
gdk_texture_get_width (GDK_TEXTURE (download->texture)),
|
|
gdk_texture_get_height (GDK_TEXTURE (download->texture)),
|
|
(char *)&(dmabuf->fourcc), dmabuf->modifier);
|
|
}
|
|
|
|
g_atomic_int_set (&download->spinlock, 1);
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gdk_dmabuf_texture_download (GdkTexture *texture,
|
|
GdkMemoryFormat format,
|
|
GdkColorState *color_state,
|
|
guchar *data,
|
|
gsize stride)
|
|
{
|
|
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (texture);
|
|
Download download = { self, format, color_state, data, stride, 0 };
|
|
|
|
g_main_context_invoke (NULL, gdk_dmabuf_texture_invoke_callback, &download);
|
|
|
|
while (g_atomic_int_get (&download.spinlock) == 0);
|
|
}
|
|
|
|
static void
|
|
gdk_dmabuf_texture_class_init (GdkDmabufTextureClass *klass)
|
|
{
|
|
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
texture_class->download = gdk_dmabuf_texture_download;
|
|
|
|
gobject_class->dispose = gdk_dmabuf_texture_dispose;
|
|
}
|
|
|
|
static void
|
|
gdk_dmabuf_texture_init (GdkDmabufTexture *self)
|
|
{
|
|
}
|
|
|
|
GdkDisplay *
|
|
gdk_dmabuf_texture_get_display (GdkDmabufTexture *self)
|
|
{
|
|
return self->display;
|
|
}
|
|
|
|
const GdkDmabuf *
|
|
gdk_dmabuf_texture_get_dmabuf (GdkDmabufTexture *self)
|
|
{
|
|
return &self->dmabuf;
|
|
}
|
|
|
|
GdkTexture *
|
|
gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
|
GDestroyNotify destroy,
|
|
gpointer data,
|
|
GError **error)
|
|
{
|
|
#ifdef HAVE_DMABUF
|
|
GdkDmabufTexture *self;
|
|
GdkTexture *update_texture;
|
|
GdkDisplay *display;
|
|
GdkDmabuf dmabuf;
|
|
GdkColorState *color_state;
|
|
int width, height;
|
|
gboolean premultiplied;
|
|
|
|
display = gdk_dmabuf_texture_builder_get_display (builder);
|
|
width = gdk_dmabuf_texture_builder_get_width (builder);
|
|
height = gdk_dmabuf_texture_builder_get_height (builder);
|
|
premultiplied = gdk_dmabuf_texture_builder_get_premultiplied (builder);
|
|
|
|
if (!gdk_dmabuf_sanitize (&dmabuf,
|
|
width,
|
|
height,
|
|
gdk_dmabuf_texture_builder_get_dmabuf (builder),
|
|
error))
|
|
return NULL;
|
|
|
|
gdk_display_init_dmabuf (display);
|
|
|
|
color_state = gdk_dmabuf_texture_builder_get_color_state (builder);
|
|
if (color_state == NULL)
|
|
{
|
|
gboolean is_yuv;
|
|
|
|
if (gdk_dmabuf_fourcc_is_yuv (dmabuf.fourcc, &is_yuv) && is_yuv)
|
|
{
|
|
g_warning_once ("FIXME: Implement the proper colorstate for YUV dmabufs");
|
|
color_state = gdk_color_state_get_srgb ();
|
|
}
|
|
else
|
|
color_state = gdk_color_state_get_srgb ();
|
|
}
|
|
|
|
self = g_object_new (GDK_TYPE_DMABUF_TEXTURE,
|
|
"width", width,
|
|
"height", height,
|
|
"color-state", color_state,
|
|
NULL);
|
|
|
|
g_set_object (&self->display, display);
|
|
self->dmabuf = dmabuf;
|
|
|
|
if (!gdk_dmabuf_get_memory_format (dmabuf.fourcc, premultiplied, &(GDK_TEXTURE (self)->format)))
|
|
{
|
|
GDK_DISPLAY_DEBUG (display, DMABUF,
|
|
"Falling back to generic RGBA for dmabuf format %.4s",
|
|
(char *) &dmabuf.fourcc);
|
|
GDK_TEXTURE (self)->format = premultiplied ? GDK_MEMORY_R8G8B8A8_PREMULTIPLIED
|
|
: GDK_MEMORY_R8G8B8A8;
|
|
}
|
|
|
|
if (!gdk_dmabuf_formats_contains (display->dmabuf_formats, dmabuf.fourcc, dmabuf.modifier))
|
|
{
|
|
g_set_error (error,
|
|
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
|
|
"Unsupported dmabuf format: %.4s:%#" G_GINT64_MODIFIER "x",
|
|
(char *) &dmabuf.fourcc, dmabuf.modifier);
|
|
g_object_unref (self);
|
|
return NULL;
|
|
}
|
|
|
|
GDK_DISPLAY_DEBUG (display, DMABUF,
|
|
"Creating dmabuf texture, format %.4s:%#" G_GINT64_MODIFIER "x, %s%u planes, memory format %u",
|
|
(char *) &dmabuf.fourcc, dmabuf.modifier,
|
|
gdk_dmabuf_texture_builder_get_premultiplied (builder) ? " premultiplied, " : "",
|
|
dmabuf.n_planes,
|
|
GDK_TEXTURE (self)->format);
|
|
|
|
/* Set this only once we know that the texture will be created.
|
|
* Otherwise dispose() will run the callback */
|
|
self->destroy = destroy;
|
|
self->data = data;
|
|
|
|
update_texture = gdk_dmabuf_texture_builder_get_update_texture (builder);
|
|
if (update_texture)
|
|
{
|
|
cairo_region_t *update_region = gdk_dmabuf_texture_builder_get_update_region (builder);
|
|
if (update_region)
|
|
{
|
|
update_region = cairo_region_copy (update_region);
|
|
cairo_region_intersect_rectangle (update_region,
|
|
&(cairo_rectangle_int_t) {
|
|
0, 0,
|
|
update_texture->width, update_texture->height
|
|
});
|
|
gdk_texture_set_diff (GDK_TEXTURE (self), update_texture, update_region);
|
|
}
|
|
}
|
|
|
|
return GDK_TEXTURE (self);
|
|
|
|
#else /* !HAVE_DMABUF */
|
|
g_set_error_literal (error, GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_NOT_AVAILABLE,
|
|
"dmabuf support disabled at compile-time.");
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|