Merge branch 'dmabuf-texture-api' into 'main'

Add API for dmabuf textures

See merge request GNOME/gtk!6463
This commit is contained in:
Benjamin Otte 2023-10-11 20:25:50 +00:00
commit e584d17aad
16 changed files with 1904 additions and 0 deletions

View File

@ -42,6 +42,9 @@
#include <gdk/gdkdevicetool.h>
#include <gdk/gdkdisplay.h>
#include <gdk/gdkdisplaymanager.h>
#include <gdk/gdkdmabufformats.h>
#include <gdk/gdkdmabuftexture.h>
#include <gdk/gdkdmabuftexturebuilder.h>
#include <gdk/gdkdrag.h>
#include <gdk/gdkdragsurface.h>
#include <gdk/gdkdragsurfacesize.h>

View File

@ -37,6 +37,8 @@
#include "gdkmonitorprivate.h"
#include "gdkrectangle.h"
#include "gdkvulkancontext.h"
#include "gdkdmabuftextureprivate.h"
#include "gdkdmabufformatsprivate.h"
#ifdef HAVE_EGL
#include <epoxy/egl.h>
@ -69,6 +71,7 @@ enum
PROP_COMPOSITED,
PROP_RGBA,
PROP_INPUT_SHAPES,
PROP_DMABUF_FORMATS,
LAST_PROP
};
@ -138,6 +141,10 @@ gdk_display_get_property (GObject *object,
g_value_set_boolean (value, gdk_display_supports_input_shapes (display));
break;
case PROP_DMABUF_FORMATS:
g_value_set_boxed (value, gdk_display_get_dmabuf_formats (display));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -239,6 +246,11 @@ gdk_display_class_init (GdkDisplayClass *class)
TRUE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
props[PROP_DMABUF_FORMATS] =
g_param_spec_boxed ("dmabuf-formats", NULL, NULL,
GDK_TYPE_DMABUF_FORMATS,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, LAST_PROP, props);
/**
@ -404,6 +416,8 @@ gdk_display_finalize (GObject *object)
g_list_free_full (display->seats, g_object_unref);
g_clear_pointer (&display->dmabuf_formats, gdk_dmabuf_formats_unref);
G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
}
@ -1824,6 +1838,58 @@ gdk_display_get_egl_display (GdkDisplay *self)
#endif
}
/**
* GdkDmabufFormat:
* @fourcc: the format code
* @modifiers: the format modifier
*
* The `GdkDmabufFormat` struct represents a dma-buf format
* as defined in the `drm_fourcc.h` header.
*
* Since: 4.14
*/
/* To support a drm format, we must be able to import it into GL
* using the relevant EGL extensions, and download it into a memory
* texture, possibly doing format conversion with shaders (in GSK).
*/
static void
init_dmabuf_formats (GdkDisplay *display)
{
GdkDmabufFormat *formats;
gsize n_formats;
if (display->dmabuf_formats != NULL)
return;
gdk_display_prepare_gl (display, NULL);
formats = gdk_dmabuf_texture_get_supported_formats (&n_formats);
display->dmabuf_formats = gdk_dmabuf_formats_new (formats, n_formats);
g_free (formats);
}
/**
* gdk_display_get_dmabuf_formats:
* @display: a `GdkDisplay`
*
* Returns the dma-buf formats that are supported on this display.
*
* GTK may use OpenGL or Vulkan to support some formats.
* Calling this function will then initialize them if they aren't yet.
*
* Returns: (transfer none): a `GdkDmabufFormats` object
*
* Since: 4.14
*/
GdkDmabufFormats *
gdk_display_get_dmabuf_formats (GdkDisplay *display)
{
init_dmabuf_formats (display);
return display->dmabuf_formats;
}
GdkDebugFlags
gdk_display_get_debug_flags (GdkDisplay *display)
{

View File

@ -134,6 +134,10 @@ gboolean gdk_display_get_setting (GdkDisplay *display,
const char *name,
GValue *value);
GDK_AVAILABLE_IN_4_14
GdkDmabufFormats *
gdk_display_get_dmabuf_formats (GdkDisplay *display);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDisplay, g_object_unref)
G_END_DECLS

View File

@ -25,6 +25,7 @@
#include "gdksurfaceprivate.h"
#include "gdkkeysprivate.h"
#include "gdkdeviceprivate.h"
#include "gdkdmabufformats.h"
#ifdef GDK_RENDERING_VULKAN
#include <vulkan/vulkan.h>
@ -113,6 +114,8 @@ struct _GdkDisplay
guint have_egl_buffer_age : 1;
guint have_egl_no_config_context : 1;
guint have_egl_pixel_format_float : 1;
GdkDmabufFormats *dmabuf_formats;
};
struct _GdkDisplayClass

209
gdk/gdkdmabufformats.c Normal file
View File

@ -0,0 +1,209 @@
/* gdkdmabufformats.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 <glib-object.h>
#include "gdkdmabufformatsprivate.h"
/**
* GdkDmabufFormats:
*
* The `GdkDmabufFormats struct provides information about
* supported DMA buffer formats.
*
* You can query whether a given format is supported with
* [method@Gdk.DmabufFormats.contains] and you can iterate
* over the list of all supported formats with
* [method@Gdk.DmabufFormats.get_n_formats] and
* [method@Gdk.DmabufFormats.get_format].
*
* The list of supported formats is sorted by preference,
* with the best formats coming first.
*
* See [class@Gdk.DmabufTextureBuilder] for more information
* about DMA buffers.
*
* Note that DMA buffers only exist on Linux.
*
* Since: 4.14
*/
struct _GdkDmabufFormats
{
int ref_count;
gsize n_formats;
GdkDmabufFormat *formats;
};
G_DEFINE_BOXED_TYPE (GdkDmabufFormats, gdk_dmabuf_formats, gdk_dmabuf_formats_ref, gdk_dmabuf_formats_unref)
/**
* gdk_dmabuf_formats_ref:
* @formats: a `GdkDmabufFormats`
*
* Increases the reference count of @formats.
*
* Returns: the passed-in object
*
* Since: 4.14
*/
GdkDmabufFormats *
gdk_dmabuf_formats_ref (GdkDmabufFormats *formats)
{
formats->ref_count++;
return formats;
}
/**
* gdk_dmabuf_formats_unref:
* @formats: a `GdkDmabufFormats`
*
* Decreases the reference count of @formats.
*
* When the reference count reaches zero,
* the object is freed.
*
* Since: 4.14
*/
void
gdk_dmabuf_formats_unref (GdkDmabufFormats *formats)
{
formats->ref_count--;
if (formats->ref_count > 0)
return;
g_free (formats->formats);
g_free (formats);
}
/**
* gdk_dmabuf_formats_get_n_formats:
* @formats: a `GdkDmabufFormats`
*
* Returns the number of formats that the @formats object
* contains.
*
* Note that DMA buffers are a Linux concept, so on other
* platforms, [method@Gdk.DmabufFormats.get_n_formats] will
* always return zero.
*
* Returns: the number of formats
*
* Since: 4.14
*/
gsize
gdk_dmabuf_formats_get_n_formats (GdkDmabufFormats *formats)
{
return formats->n_formats;
}
/**
* gdk_dmabuf_formats_get_format:
* @formats: a `GdkDmabufFormats`
* @idx: the index of the format to return
* @fourcc: (out): return location for the format code
* @modifier: (out): return location for the format modifier
*
* Gets the fourcc code and modifier for a format
* that is contained in @formats.
*
* Since: 4.14
*/
void
gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats,
gsize idx,
guint32 *fourcc,
guint64 *modifier)
{
GdkDmabufFormat *format;
g_return_if_fail (idx < formats->n_formats);
g_return_if_fail (fourcc != NULL);
g_return_if_fail (modifier != NULL);
format = &formats->formats[idx];
*fourcc = format->fourcc;
*modifier = format->modifier;
}
/**
* gdk_dmabuf_format_contains:
* @formats: a `GdkDmabufFormats`
* @fourcc: a format code
* @modfier: a format modifier
*
* Returns whether a given format is contained in @formats.
*
* Returns: `TRUE` if the format specified by the arguments
* is part of @formats
*
* Since: 4.14
*/
gboolean
gdk_dmabuf_formats_contains (GdkDmabufFormats *formats,
guint32 fourcc,
guint64 modifier)
{
for (gsize i = 0; i < formats->n_formats; i++)
{
GdkDmabufFormat *format = &formats->formats[i];
if (format->fourcc == fourcc && format->modifier == modifier)
return TRUE;
}
return FALSE;
}
/*< private >
* gdk_dmabuf_formats_new:
* @formats: the formats
* @n_formats: the length of @formats
*
* Creates a new `GdkDmabufFormats struct for
* the given formats.
*
* The @formats array is expected to be sorted
* by preference.
*
* Returns: (transfer full): the new `GdkDmabufFormats`
*
* Since: 4.14
*/
GdkDmabufFormats *
gdk_dmabuf_formats_new (GdkDmabufFormat *formats,
gsize n_formats)
{
GdkDmabufFormats *self;
self = g_new0 (GdkDmabufFormats, 1);
self->ref_count = 1;
self->n_formats = n_formats;
self->formats = g_new (GdkDmabufFormat, n_formats);
memcpy (self->formats, formats, n_formats * sizeof (GdkDmabufFormat));
return self;
}

54
gdk/gdkdmabufformats.h Normal file
View File

@ -0,0 +1,54 @@
/* gdkdmabufformats.h
*
* 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/>.
*/
#pragma once
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdktypes.h>
G_BEGIN_DECLS
#define GDK_TYPE_DMABUF_FORMATS (gdk_dmabuf_formats_get_type ())
GDK_AVAILABLE_IN_4_14
GType gdk_dmabuf_formats_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_14
GdkDmabufFormats * gdk_dmabuf_formats_ref (GdkDmabufFormats *formats);
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_formats_unref (GdkDmabufFormats *formats);
GDK_AVAILABLE_IN_4_14
gsize gdk_dmabuf_formats_get_n_formats (GdkDmabufFormats *formats);
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats,
gsize idx,
guint32 *fourcc,
guint64 *modifier);
GDK_AVAILABLE_IN_4_14
gboolean gdk_dmabuf_formats_contains (GdkDmabufFormats *formats,
guint32 fourcc,
guint64 modifier);
G_END_DECLS

View File

@ -0,0 +1,13 @@
#pragma once
#include "gdkdmabufformats.h"
typedef struct _GdkDmabufFormat GdkDmabufFormat;
struct _GdkDmabufFormat
{
guint32 fourcc;
guint64 modifier;
};
GdkDmabufFormats *gdk_dmabuf_formats_new (GdkDmabufFormat *formats,
gsize n_formats);

346
gdk/gdkdmabuftexture.c Normal file
View File

@ -0,0 +1,346 @@
/* 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 "gdkdisplayprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
#include <gdk/gdkglcontext.h>
#include <gdk/gdkgltexturebuilder.h>
#include <gdk/gdktexturedownloader.h>
#ifdef HAVE_LINUX_DMA_BUF_H
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/dma-buf.h>
#include <drm/drm_fourcc.h>
#include <epoxy/egl.h>
#endif
/**
* GdkDmabufTexture:
*
* A `GdkTexture` representing a dma-buf object.
*
* To create a `GdkDmabufTexture`, use the auxiliary
* [class@Gdk.DmabufTextureBuilder] object.
*
* Dma-buf textures can only be created on Linux.
*/
struct _GdkDmabufTexture
{
GdkTexture parent_instance;
GdkDisplay *display;
guint32 fourcc;
guint64 modifier;
unsigned int n_planes;
/* Per-plane properties */
int fds[MAX_DMABUF_PLANES];
unsigned int strides[MAX_DMABUF_PLANES];
unsigned int offsets[MAX_DMABUF_PLANES];
GDestroyNotify destroy;
gpointer data;
};
struct _GdkDmabufTextureClass
{
GdkTextureClass parent_class;
};
G_DEFINE_TYPE (GdkDmabufTexture, gdk_dmabuf_texture, GDK_TYPE_TEXTURE)
static void
gdk_dmabuf_texture_init (GdkDmabufTexture *self)
{
self->fds[0] = self->fds[1] = self->fds[2] = self->fds[3] = -1;
}
static void
gdk_dmabuf_texture_dispose (GObject *object)
{
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (object);
if (self->destroy)
self->destroy (self->data);
G_OBJECT_CLASS (gdk_dmabuf_texture_parent_class)->dispose (object);
}
static void gdk_dmabuf_texture_download (GdkTexture *texture,
GdkMemoryFormat format,
guchar *data,
gsize stride);
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;
}
guint32
gdk_dmabuf_texture_get_fourcc (GdkDmabufTexture *texture)
{
return texture->fourcc;
}
guint64
gdk_dmabuf_texture_get_modifier (GdkDmabufTexture *texture)
{
return texture->modifier;
}
unsigned int
gdk_dmabuf_texture_get_n_planes (GdkDmabufTexture *texture)
{
return texture->n_planes;
}
int *
gdk_dmabuf_texture_get_fds (GdkDmabufTexture *texture)
{
return texture->fds;
}
unsigned int *
gdk_dmabuf_texture_get_strides (GdkDmabufTexture *texture)
{
return texture->strides;
}
unsigned int *
gdk_dmabuf_texture_get_offsets (GdkDmabufTexture *texture)
{
return texture->offsets;
}
#ifdef HAVE_LINUX_DMA_BUF_H
typedef struct _GdkDrmFormatInfo GdkDrmFormatInfo;
struct _GdkDrmFormatInfo
{
guint32 fourcc;
GdkMemoryFormat premultiplied_memory_format;
GdkMemoryFormat unpremultiplied_memory_format;
};
static GdkDrmFormatInfo supported_formats[] = {
{ DRM_FORMAT_ARGB8888, GDK_MEMORY_A8R8G8B8_PREMULTIPLIED, GDK_MEMORY_A8R8G8B8 },
{ DRM_FORMAT_RGBA8888, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, GDK_MEMORY_R8G8B8A8 },
{ DRM_FORMAT_BGRA8888, GDK_MEMORY_B8G8R8A8_PREMULTIPLIED, GDK_MEMORY_B8G8R8A8 },
{ DRM_FORMAT_ABGR16161616F, GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, GDK_MEMORY_R16G16B16A16_FLOAT },
{ DRM_FORMAT_RGB888, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8 },
{ DRM_FORMAT_BGR888, GDK_MEMORY_B8G8R8, GDK_MEMORY_B8G8R8 },
};
static GdkDrmFormatInfo *
get_drm_format_info (guint32 fourcc)
{
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
{
if (supported_formats[i].fourcc == fourcc)
return &supported_formats[i];
}
return NULL;
}
static void
do_direct_download (GdkDmabufTexture *self,
guchar *data,
gsize stride)
{
gsize size;
unsigned int height;
gsize src_stride;
guchar *src_data;
int bpp;
GDK_DEBUG (MISC, "Using mmap() and memcpy() for downloading a dmabuf");
height = gdk_texture_get_height (GDK_TEXTURE (self));
bpp = gdk_memory_format_bytes_per_pixel (gdk_texture_get_format (GDK_TEXTURE (self)));
src_stride = self->strides[0];
size = self->strides[0] * height;
if (ioctl (self->fds[0], DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_START|DMA_BUF_SYNC_READ }) < 0)
g_warning ("Failed to sync dma-buf: %s", g_strerror (errno));
src_data = mmap (NULL, size, PROT_READ, MAP_SHARED, self->fds[0], self->offsets[0]);
if (stride == src_stride)
memcpy (data, src_data, size);
else
{
for (unsigned int i = 0; i < height; i++)
memcpy (data + i * stride, src_data + i * src_stride, height * bpp);
}
munmap (src_data, size);
if (ioctl (self->fds[0], DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_END|DMA_BUF_SYNC_READ }) < 0)
g_warning ("Failed to sync dma-buf: %s", g_strerror (errno));
}
#endif /* HAVE_LINUX_DMA_BUF_H */
GdkDmabufFormat *
gdk_dmabuf_texture_get_supported_formats (gsize *n_formats)
{
#ifdef HAVE_LINUX_DMA_BUF_H
GdkDmabufFormat *formats;
*n_formats = G_N_ELEMENTS (supported_formats);
formats = g_new (GdkDmabufFormat, sizeof (GdkDmabufFormat) * *n_formats);
for (gsize i = 0; i < *n_formats; i++)
{
formats[i].fourcc = supported_formats[i].fourcc;
formats[i].modifier = DRM_FORMAT_MOD_LINEAR;
}
return formats;
#else
*n_formats = 0;
return NULL;
#endif
}
static void
gdk_dmabuf_texture_download (GdkTexture *texture,
GdkMemoryFormat format,
guchar *data,
gsize stride)
{
#ifdef HAVE_LINUX_DMA_BUF_H
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (texture);
GdkMemoryFormat src_format = gdk_texture_get_format (texture);
if (format == src_format)
do_direct_download (self, data, stride);
else
{
unsigned int width, height;
guchar *src_data;
gsize src_stride;
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
src_stride = self->strides[0];
src_data = g_new (guchar, src_stride * height);
do_direct_download (self, src_data, src_stride);
gdk_memory_convert (data, stride, format,
src_data, src_stride, src_format,
width, height);
g_free (src_data);
}
#endif /* HAVE_LINUX_DMA_BUF_H */
}
GdkTexture *
gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
GDestroyNotify destroy,
gpointer data)
{
#ifdef HAVE_LINUX_DMA_BUF_H
GdkDmabufTexture *self;
GdkTexture *update_texture;
GdkDisplay *display = gdk_dmabuf_texture_builder_get_display (builder);
guint32 fourcc = gdk_dmabuf_texture_builder_get_fourcc (builder);
guint64 modifier = gdk_dmabuf_texture_builder_get_modifier (builder);
gboolean premultiplied = gdk_dmabuf_texture_builder_get_premultiplied (builder);
unsigned int n_planes = gdk_dmabuf_texture_builder_get_n_planes (builder);
GdkDrmFormatInfo *info;
info = get_drm_format_info (fourcc);
if (!info || modifier != DRM_FORMAT_MOD_LINEAR || n_planes > 1)
{
g_warning ("Unsupported dmabuf format %c%c%c%c:%#lx",
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
return NULL;
}
GDK_DEBUG (MISC, "Dmabuf texture in format %c%c%c%c:%#lx",
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
self = g_object_new (GDK_TYPE_DMABUF_TEXTURE,
"width", gdk_dmabuf_texture_builder_get_width (builder),
"height", gdk_dmabuf_texture_builder_get_height (builder),
NULL);
self->destroy = destroy;
self->data = data;
GDK_TEXTURE (self)->format = premultiplied ? info->premultiplied_memory_format
: info->unpremultiplied_memory_format;
g_set_object (&self->display, display);
self->fourcc = fourcc;
self->modifier = modifier;
self->n_planes = n_planes;
memcpy (self->fds, gdk_dmabuf_texture_builder_get_fds (builder), sizeof (int) * MAX_DMABUF_PLANES);
memcpy (self->strides, gdk_dmabuf_texture_builder_get_strides (builder), sizeof (unsigned int) * MAX_DMABUF_PLANES);
memcpy (self->offsets, gdk_dmabuf_texture_builder_get_offsets (builder), sizeof (unsigned int) * MAX_DMABUF_PLANES);
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_LINUX_DMA_BUF_H */
return NULL;
#endif
}

43
gdk/gdkdmabuftexture.h Normal file
View File

@ -0,0 +1,43 @@
/* gdkdmabuftexture.h
*
* 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/>.
*/
#pragma once
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdktypes.h>
#include <gdk/gdktexture.h>
G_BEGIN_DECLS
#define GDK_TYPE_DMABUF_TEXTURE (gdk_dmabuf_texture_get_type ())
#define GDK_DMABUF_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_DMABUF_TEXTURE, GdkDmabufTexture))
#define GDK_IS_DMABUF_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_DMABUF_TEXTURE))
typedef struct _GdkDmabufTexture GdkDmabufTexture;
typedef struct _GdkDmabufTextureClass GdkDmabufTextureClass;
GDK_AVAILABLE_IN_4_14
GType gdk_dmabuf_texture_get_type (void) G_GNUC_CONST;
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDmabufTexture, g_object_unref)
G_END_DECLS

View File

@ -0,0 +1,992 @@
/*
* 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.1 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/>.
*
* Authors: Matthias Clasen <mclasen@redhat.com>
*/
#include "config.h"
#include "gdkdmabuftexturebuilder.h"
#include "gdkdisplay.h"
#include "gdkenumtypes.h"
#include "gdkdmabuftextureprivate.h"
#include <cairo-gobject.h>
struct _GdkDmabufTextureBuilder
{
GObject parent_instance;
GdkDisplay *display;
unsigned int width;
unsigned int height;
guint32 fourcc;
guint64 modifier;
gboolean premultiplied;
unsigned int n_planes;
/* per-plane properties */
int fds[MAX_DMABUF_PLANES];
unsigned int strides[MAX_DMABUF_PLANES];
unsigned int offsets[MAX_DMABUF_PLANES];
GdkTexture *update_texture;
cairo_region_t *update_region;
};
struct _GdkDmabufTextureBuilderClass
{
GObjectClass parent_class;
};
/**
* GdkDmabufTextureBuilder:
*
* `GdkDmabufTextureBuilder` is a builder used to construct [class@Gdk.Texture]
* objects from DMA buffers.
*
* DMA buffers are commonly called **_dma-bufs_**.
*
* DMA buffers a feature of the Linux kernel to enable efficient buffer and
* memory sharing between hardware such as codecs, GPUs, displays, cameras and the
* kernel drivers controlling them. For example, a decoder may want its output to
* be directly shared with the display server for rendering without a copy.
*
* Any device driver which participates in DMA buffer sharing, can do so as either
* the exporter or importer of buffers (or both).
*
* The memory that is shared via DMA buffers is usually stored in non-system memory
* (maybe in device's local memory or something else not directly accessible by the
* CPU), and accessing this memory from the CPU may have higher than usual overhead.
*
* In particular for graphics data, it is not uncommon that data consists of multiple
* separate blocks of memory, for example one block for each of the red, green and
* blue channels. These blocks are called **_planes_**. DMA buffers can have up to
* four planes. Even if the memory is a single block, the data can be organized in
* multiple planes, by specifying offsets from the beginning of the data.
*
* DMA buffers are exposed to user-space as file descriptors allowing to pass them
* between processes. If a DMA buffer has multiple planes, there is one file
* descriptor per plane.
*
* The format of the data (for graphics data, essentially its colorspace) is described
* by a 32-bit integer. These format identifiers are defined in the header file
* [drm/drm_fourcc.h](https://github.com/torvalds/linux/blob/master/include/uapi/drm/drm_fourcc.h)
* and commonly referred to as **_fourcc_** values, since they are identified by 4 ASCII
* characters. Additionally, each DMA buffer has a **_modifier_**, which is a 64-bit integer
* that describes driver-specific details of the memory layout, such as tiling or compression.
*
* The operation of `GdkDmabufTextureBuilder` is quite simple: Create a texture builder,
* set all the necessary properties, and then call [method@Gdk.DmabufTextureBuilder.build]
* to create the new texture.
*
* The required properties for a dma-buf texture are
* - The width and height in pixels
* - The `fourcc` code and `modifier` which identify the format and memory layout of the dma-buf
* - The file descriptor, offset and stride for each of the planes
*
* `GdkDmabufTextureBuilder` can be used for quick one-shot construction of
* textures as well as kept around and reused to construct multiple textures.
*
* Since: 4.14
*/
enum
{
PROP_0,
PROP_DISPLAY,
PROP_WIDTH,
PROP_HEIGHT,
PROP_FOURCC,
PROP_MODIFIER,
PROP_PREMULTIPLIED,
PROP_N_PLANES,
PROP_UPDATE_REGION,
PROP_UPDATE_TEXTURE,
N_PROPS
};
G_DEFINE_TYPE (GdkDmabufTextureBuilder, gdk_dmabuf_texture_builder, G_TYPE_OBJECT)
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
gdk_dmabuf_texture_builder_dispose (GObject *object)
{
GdkDmabufTextureBuilder *self = GDK_DMABUF_TEXTURE_BUILDER (object);
g_clear_object (&self->update_texture);
g_clear_pointer (&self->update_region, cairo_region_destroy);
G_OBJECT_CLASS (gdk_dmabuf_texture_builder_parent_class)->dispose (object);
}
static void
gdk_dmabuf_texture_builder_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GdkDmabufTextureBuilder *self = GDK_DMABUF_TEXTURE_BUILDER (object);
switch (property_id)
{
case PROP_DISPLAY:
g_value_set_object (value, self->display);
break;
case PROP_WIDTH:
g_value_set_uint (value, self->width);
break;
case PROP_HEIGHT:
g_value_set_uint (value, self->height);
break;
case PROP_FOURCC:
g_value_set_uint (value, self->fourcc);
break;
case PROP_MODIFIER:
g_value_set_uint64 (value, self->modifier);
break;
case PROP_PREMULTIPLIED:
g_value_set_boolean (value, self->premultiplied);
break;
case PROP_N_PLANES:
g_value_set_uint (value, self->n_planes);
break;
case PROP_UPDATE_REGION:
g_value_set_boxed (value, self->update_region);
break;
case PROP_UPDATE_TEXTURE:
g_value_set_object (value, self->update_texture);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gdk_dmabuf_texture_builder_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GdkDmabufTextureBuilder *self = GDK_DMABUF_TEXTURE_BUILDER (object);
switch (property_id)
{
case PROP_DISPLAY:
gdk_dmabuf_texture_builder_set_display (self, g_value_get_object (value));
break;
case PROP_WIDTH:
gdk_dmabuf_texture_builder_set_width (self, g_value_get_uint (value));
break;
case PROP_HEIGHT:
gdk_dmabuf_texture_builder_set_height (self, g_value_get_uint (value));
break;
case PROP_FOURCC:
gdk_dmabuf_texture_builder_set_fourcc (self, g_value_get_uint (value));
break;
case PROP_MODIFIER:
gdk_dmabuf_texture_builder_set_modifier (self, g_value_get_uint64 (value));
break;
case PROP_PREMULTIPLIED:
gdk_dmabuf_texture_builder_set_premultiplied (self, g_value_get_boolean (value));
break;
case PROP_N_PLANES:
gdk_dmabuf_texture_builder_set_n_planes (self, g_value_get_uint (value));
break;
case PROP_UPDATE_REGION:
gdk_dmabuf_texture_builder_set_update_region (self, g_value_get_boxed (value));
break;
case PROP_UPDATE_TEXTURE:
gdk_dmabuf_texture_builder_set_update_texture (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gdk_dmabuf_texture_builder_class_init (GdkDmabufTextureBuilderClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = gdk_dmabuf_texture_builder_dispose;
gobject_class->get_property = gdk_dmabuf_texture_builder_get_property;
gobject_class->set_property = gdk_dmabuf_texture_builder_set_property;
/**
* GdkDmabufTextureBuilder:display: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_display org.gdk.Property.set=gdk_dmabuf_texture_builder_set_display)
*
* The display that this texture will be used on.
*
* Since: 4.14
*/
properties[PROP_DISPLAY] =
g_param_spec_object ("display", NULL, NULL,
GDK_TYPE_DISPLAY,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:width: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_width org.gdk.Property.set=gdk_dmabuf_texture_builder_set_width)
*
* The width of the texture.
*
* Since: 4.14
*/
properties[PROP_WIDTH] =
g_param_spec_uint ("width", NULL, NULL,
0, G_MAXUINT, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:height: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_height org.gdk.Property.set=gdk_dmabuf_texture_builder_set_height)
*
* The height of the texture.
*
* Since: 4.14
*/
properties[PROP_HEIGHT] =
g_param_spec_uint ("height", NULL, NULL,
0, G_MAXUINT, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:fourcc: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_fourcc org.gdk.Property.set=gdk_dmabuf_texture_builder_set_fourcc)
*
* The format of the texture, as a fourcc value.
*
* Since: 4.14
*/
properties[PROP_FOURCC] =
g_param_spec_uint ("fourcc", NULL, NULL,
0, 0xffffffff, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:modifier:
*
* The modifier.
*
* Since: 4.14
*/
properties[PROP_MODIFIER] =
g_param_spec_uint64 ("modifier", NULL, NULL,
0, G_MAXUINT, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:premultiplied:
*
* Whether the alpha channel is premultiplied into the others.
*
* Only relevant if the format has alpha.
*
* Since: 4.14
*/
properties[PROP_PREMULTIPLIED] =
g_param_spec_boolean ("premultiplied", NULL, NULL,
TRUE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:n-planes: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_n_planes org.gdk.Property.set=gdk_dmabuf_texture_builder_set_n_planes)
*
* The number of planes of the texture.
*
* Note that you can set properties for other planes,
* but they will be ignored when constructing the texture.
*
* Since: 4.14
*/
properties[PROP_N_PLANES] =
g_param_spec_uint ("n-planes", NULL, NULL,
0, 4, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:update-region: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_update_region org.gdk.Property.set=gdk_dmabuf_texture_builder_set_update_region)
*
* The update region for [property@Gdk.GLTextureBuilder:update-texture].
*
* Since: 4.14
*/
properties[PROP_UPDATE_REGION] =
g_param_spec_boxed ("update-region", NULL, NULL,
CAIRO_GOBJECT_TYPE_REGION,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:update-texture: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_update_texture org.gdk.Property.set=gdk_dmabuf_texture_builder_set_update_texture)
*
* The texture [property@Gdk.GLTextureBuilder:update-region] is an update for.
*
* Since: 4.14
*/
properties[PROP_UPDATE_TEXTURE] =
g_param_spec_object ("update-texture", NULL, NULL,
GDK_TYPE_TEXTURE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gdk_dmabuf_texture_builder_init (GdkDmabufTextureBuilder *self)
{
self->fds[0] = self->fds[1] = self->fds[2] = self->fds[3] = -1;
self->premultiplied = TRUE;
}
/**
* gdk_dmabuf_texture_builder_new: (constructor):
*
* Creates a new texture builder.
*
* Returns: the new `GdkTextureBuilder`
*
* Since: 4.14
**/
GdkDmabufTextureBuilder *
gdk_dmabuf_texture_builder_new (void)
{
return g_object_new (GDK_TYPE_DMABUF_TEXTURE_BUILDER, NULL);
}
/**
* gdk_dmabuf_texture_builder_get_display:
* @self: a `GdkDmabufTextureBuilder
*
* Returns the display that this texture builder is
* associated with.
*
* Returns: (transfer none) (nullable): the display
*
* Since: 4.14
*/
GdkDisplay *
gdk_dmabuf_texture_builder_get_display (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL);
return self->display;
}
/**
* gdk_dmabuf_texture_builder_set_display:
* @self: a `GdkDmabufTextureBuilder
* @display: the display
*
* Sets the display that this texture builder is
* associated with.
*
* The display is used to determine the supported
* dma-buf formats.
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_display (GdkDmabufTextureBuilder *self,
GdkDisplay *display)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
if (g_set_object (&self->display, display))
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DISPLAY]);
}
/**
* gdk_dmabuf_texture_builder_get_width: (attributes org.gdk.Method.get_property=width)
* @self: a `GdkDmabufTextureBuilder`
*
* Gets the width previously set via gdk_dmabuf_texture_builder_set_width() or
* 0 if the width wasn't set.
*
* Returns: The width
*
* Since: 4.14
*/
unsigned int
gdk_dmabuf_texture_builder_get_width (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
return self->width;
}
/**
* gdk_dmabuf_texture_builder_set_width: (attributes org.gdk.Method.set_property=width)
* @self: a `GdkDmabufTextureBuilder`
* @width: The texture's width or 0 to unset
*
* Sets the width of the texture.
*
* The width must be set before calling [method@Gdk.GLTextureBuilder.build].
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_width (GdkDmabufTextureBuilder *self,
unsigned int width)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
if (self->width == width)
return;
self->width = width;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WIDTH]);
}
/**
* gdk_dmabuf_texture_builder_get_height: (attributes org.gdk.Method.get_property=height)
* @self: a `GdkDmabufTextureBuilder`
*
* Gets the height previously set via gdk_dmabuf_texture_builder_set_height() or
* 0 if the height wasn't set.
*
* Returns: The height
*
* Since: 4.14
*/
unsigned int
gdk_dmabuf_texture_builder_get_height (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
return self->height;
}
/**
* gdk_dmabuf_texture_builder_set_height: (attributes org.gdk.Method.set_property=height)
* @self: a `GdkDmabufTextureBuilder`
* @height: the texture's height or 0 to unset
*
* Sets the height of the texture.
*
* The height must be set before calling [method@Gdk.GLTextureBuilder.build].
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_height (GdkDmabufTextureBuilder *self,
unsigned int height)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
if (self->height == height)
return;
self->height = height;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEIGHT]);
}
/**
* gdk_dmabuf_texture_builder_get_fourcc: (attributes org.gdk.Method.get_property=fourcc)
* @self: a `GdkDmabufTextureBuilder`
*
* Gets the format previously set via gdk_dmabuf_texture_builder_set_fourcc()
* or 0 if the format wasn't set.
*
* The format is specified as a fourcc code.
*
* Returns: The format
*
* Since: 4.14
*/
guint32
gdk_dmabuf_texture_builder_get_fourcc (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
return self->fourcc;
}
/**
* gdk_dmabuf_texture_builder_set_fourcc: (attributes org.gdk.Method.set_property=fourcc)
* @self: a `GdkDmabufTextureBuilder`
* @fourcc: the texture's format or 0 to unset
*
* Sets the format of the texture.
*
* The format is specified as a fourcc code.
*
* The format must be set before calling [method@Gdk.GLTextureBuilder.build].
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_fourcc (GdkDmabufTextureBuilder *self,
guint32 fourcc)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
if (self->fourcc == fourcc)
return;
self->fourcc = fourcc;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FOURCC]);
}
/**
* gdk_dmabuf_texture_builder_get_modifier:
* @self: a `GdkDmabufTextureBuilder`
*
* Gets the modifier value.
*
* Returns: the modifier
*
* Since: 4.14
*/
guint64
gdk_dmabuf_texture_builder_get_modifier (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
return self->modifier;
}
/**
* gdk_dmabuf_texture_builder_set_modifier:
* @self: a `GdkDmabufTextureBuilder`
* @modifier: the modifier value
*
* Sets the modifier.
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_modifier (GdkDmabufTextureBuilder *self,
guint64 modifier)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
if (self->modifier == modifier)
return;
self->modifier = modifier;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODIFIER]);
}
/**
* gdk_dmabuf_texture_builder_get_n_planes: (attributes org.gdk.Method.get_property=n-planes)
* @self: a `GdkDmabufTextureBuilder`
*
* Gets the number of planes.
*
* Returns: The number of planes
*
* Since: 4.14
*/
unsigned int
gdk_dmabuf_texture_builder_get_n_planes (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
return self->n_planes;
}
/**
* gdk_dmabuf_texture_builder_get_premultiplied:
* @self: a `GdkDmabufTextureBuilder`
*
* Whether the data is premultiplied.
*
* Returns: whether the data is premultiplied
*
* Since: 4.14
*/
gboolean
gdk_dmabuf_texture_builder_get_premultiplied (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), TRUE);
return self->premultiplied;
}
/**
* gdk_dmabuf_texture_builder_set_premultiplied:
* @self: a `GdkDmabufTextureBuilder`
* @premultiplied: whether the data is premultiplied
*
* Sets whether the data is premultiplied.
*
* Unless otherwise specified, all formats including alpha channels are assumed
* to be premultiplied.
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_premultiplied (GdkDmabufTextureBuilder *self,
gboolean premultiplied)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
if (self->premultiplied == premultiplied)
return;
self->premultiplied = premultiplied;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PREMULTIPLIED]);
}
/**
* gdk_dmabuf_texture_builder_set_n_planes: (attributes org.gdk.Method.set_property=n-planes)
* @self: a `GdkDmabufTextureBuilder`
* @n_planes: the number of planes
*
* Sets the number of planes of the texture.
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_n_planes (GdkDmabufTextureBuilder *self,
unsigned int n_planes)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
if (self->n_planes == n_planes)
return;
self->n_planes = n_planes;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_N_PLANES]);
}
/**
* gdk_dmabuf_texture_builder_get_fd:
* @self: a `GdkDmabufTextureBuilder`
* @plane: the plane to get the fd for
*
* Gets the file descriptor for a plane.
*
* Returns: the file descriptor
*
* Since: 4.14
*/
int
gdk_dmabuf_texture_builder_get_fd (GdkDmabufTextureBuilder *self,
unsigned int plane)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
g_return_val_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES, 0);
return self->fds[plane];
}
/**
* gdk_dmabuf_texture_builder_set_fd:
* @self: a `GdkDmabufTextureBuilder`
* @plane: the plane to set the fd for
* @fd: the file descriptor
*
* Sets the file descriptor for a plane.
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_fd (GdkDmabufTextureBuilder *self,
unsigned int plane,
int fd)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
g_return_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES);
if (self->fds[plane] == fd)
return;
self->fds[plane] = fd;
}
/**
* gdk_dmabuf_texture_builder_get_stride:
* @self: a `GdkDmabufTextureBuilder`
* @plane: the plane to get the stride for
*
* Gets the stride value for a plane.
*
* Returns: the stride
*
* Since: 4.14
*/
unsigned int
gdk_dmabuf_texture_builder_get_stride (GdkDmabufTextureBuilder *self,
unsigned int plane)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
g_return_val_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES, 0);
return self->strides[plane];
}
/**
* gdk_dmabuf_texture_builder_set_stride:
* @self: a `GdkDmabufTextureBuilder`
* @plane: the plane to set the stride for
* @stride: the stride value
*
* Sets the stride for a plane.
*
* The stride must be set for all planes before calling [method@Gdk.GLTextureBuilder.build].
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_stride (GdkDmabufTextureBuilder *self,
unsigned int plane,
unsigned int stride)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
g_return_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES);
if (self->strides[plane] == stride)
return;
self->strides[plane] = stride;
}
/**
* gdk_dmabuf_texture_builder_get_offset:
* @self: a `GdkDmabufTextureBuilder`
* @plane: the plane to get the offset for
*
* Gets the offset value for a plane.
*
* Returns: the offset
*
* Since: 4.14
*/
unsigned int
gdk_dmabuf_texture_builder_get_offset (GdkDmabufTextureBuilder *self,
unsigned int plane)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
g_return_val_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES, 0);
return self->offsets[plane];
}
/**
* gdk_dmabuf_texture_builder_set_offset:
* @self: a `GdkDmabufTextureBuilder`
* @plane: the plane to set the offset for
* @offset: the offset value
*
* Sets the offset for a plane.
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_offset (GdkDmabufTextureBuilder *self,
unsigned int plane,
unsigned int offset)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
g_return_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES);
if (self->offsets[plane] == offset)
return;
self->offsets[plane] = offset;
}
/**
* gdk_dmabuf_texture_builder_get_update_texture: (attributes org.gdk.Method.get_property=update_texture)
* @self: a `GdkDmabufTextureBuilder`
*
* Gets the texture previously set via gdk_dmabuf_texture_builder_set_update_texture() or
* %NULL if none was set.
*
* Returns: (transfer none) (nullable): The texture
*
* Since: 4.14
*/
GdkTexture *
gdk_dmabuf_texture_builder_get_update_texture (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL);
return self->update_texture;
}
/**
* gdk_dmabuf_texture_builder_set_update_texture: (attributes org.gdk.Method.set_property=update_texture)
* @self: a `GdkDmabufTextureBuilder`
* @texture: (nullable): the texture to update
*
* Sets the texture to be updated by this texture. See
* [method@Gdk.DmabufTextureBuilder.set_update_region] for an explanation.
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_update_texture (GdkDmabufTextureBuilder *self,
GdkTexture *texture)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
g_return_if_fail (texture == NULL || GDK_IS_TEXTURE (texture));
if (!g_set_object (&self->update_texture, texture))
return;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_TEXTURE]);
}
/**
* gdk_dmabuf_texture_builder_get_update_region: (attributes org.gdk.Method.get_property=update_region)
* @self: a `GdkDmabufTextureBuilder`
*
* Gets the region previously set via gdk_dmabuf_texture_builder_set_update_region() or
* %NULL if none was set.
*
* Returns: (transfer none) (nullable): The region
*
* Since: 4.14
*/
cairo_region_t *
gdk_dmabuf_texture_builder_get_update_region (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL);
return self->update_region;
}
/**
* gdk_dmabuf_texture_builder_set_update_region: (attributes org.gdk.Method.set_property=update_region)
* @self: a `GdkDmabufTextureBuilder`
* @region: (nullable): the region to update
*
* Sets the region to be updated by this texture. Together with
* [property@Gdk.DmabufTextureBuilder:update-texture] this describes an
* update of a previous texture.
*
* When rendering animations of large textures, it is possible that
* consecutive textures are only updating contents in parts of the texture.
* It is then possible to describe this update via these two properties,
* so that GTK can avoid rerendering parts that did not change.
*
* An example would be a screen recording where only the mouse pointer moves.
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_update_region (GdkDmabufTextureBuilder *self,
cairo_region_t *region)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
if (self->update_region == region)
return;
g_clear_pointer (&self->update_region, cairo_region_destroy);
if (region)
self->update_region = cairo_region_reference (region);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_REGION]);
}
/**
* gdk_dmabuf_texture_builder_build:
* @self: a `GdkDmabufTextureBuilder`
* @destroy: (nullable): destroy function to be called when the texture is
* released
* @data: user data to pass to the destroy function
*
* Builds a new `GdkTexture` with the values set up in the builder.
*
* The `destroy` function gets called when the returned texture gets released.
*
* Note that it is a programming error to call this function if any mandatory
* property has not been set.
*
* It is possible to call this function multiple times to create multiple textures,
* possibly with changing properties in between.
*
* It is the responsibility of the caller to keep the file descriptors for the planes
* open until the created texture is no longer used, and close them afterwards (possibly
* using the @destroy notify).
*
* Not all formats defined in the `drm_fourcc.h` header are supported. You can use
* [method@Gdk.Display.get_dmabuf_formats] to get a list of supported formats.
*
* Returns: (transfer full) (nullable): a newly built `GdkTexture` or `NULL`
* if the format is not supported
*
* Since: 4.14
*/
GdkTexture *
gdk_dmabuf_texture_builder_build (GdkDmabufTextureBuilder *self,
GDestroyNotify destroy,
gpointer data)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL);
g_return_val_if_fail (destroy == NULL || data != NULL, NULL);
g_return_val_if_fail (self->width > 0, NULL);
g_return_val_if_fail (self->height > 0, NULL);
g_return_val_if_fail (self->fourcc != 0, NULL);
g_return_val_if_fail (self->n_planes > 0, NULL);
for (int i = 0; i < self->n_planes; i++)
g_return_val_if_fail (self->fds[i] != -1 || self->offsets[i] != 0, NULL);
return gdk_dmabuf_texture_new_from_builder (self, destroy, data);
}
int *
gdk_dmabuf_texture_builder_get_fds (GdkDmabufTextureBuilder *self)
{
return self->fds;
}
unsigned int *
gdk_dmabuf_texture_builder_get_strides (GdkDmabufTextureBuilder *self)
{
return self->strides;
}
unsigned int *
gdk_dmabuf_texture_builder_get_offsets (GdkDmabufTextureBuilder *self)
{
return self->offsets;
}

View File

@ -0,0 +1,121 @@
/*
* 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.1 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/>.
*
* Authors: Matthias Clasen <mclasen@redhat.com>
*/
#pragma once
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdktypes.h>
G_BEGIN_DECLS
#define GDK_TYPE_DMABUF_TEXTURE_BUILDER (gdk_dmabuf_texture_builder_get_type ())
GDK_AVAILABLE_IN_4_14
GDK_DECLARE_INTERNAL_TYPE (GdkDmabufTextureBuilder, gdk_dmabuf_texture_builder, GDK, DMABUF_TEXTURE_BUILDER, GObject)
GDK_AVAILABLE_IN_4_14
GdkDmabufTextureBuilder *gdk_dmabuf_texture_builder_new (void);
GDK_AVAILABLE_IN_4_14
GdkDisplay * gdk_dmabuf_texture_builder_get_display (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_display (GdkDmabufTextureBuilder *self,
GdkDisplay *display);
GDK_AVAILABLE_IN_4_14
unsigned int gdk_dmabuf_texture_builder_get_width (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_width (GdkDmabufTextureBuilder *self,
unsigned int width);
GDK_AVAILABLE_IN_4_14
unsigned int gdk_dmabuf_texture_builder_get_height (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_height (GdkDmabufTextureBuilder *self,
unsigned int height);
GDK_AVAILABLE_IN_4_14
guint32 gdk_dmabuf_texture_builder_get_fourcc (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_fourcc (GdkDmabufTextureBuilder *self,
guint32 fourcc);
GDK_AVAILABLE_IN_4_14
guint64 gdk_dmabuf_texture_builder_get_modifier (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_modifier (GdkDmabufTextureBuilder *self,
guint64 modifier);
GDK_AVAILABLE_IN_4_14
gboolean gdk_dmabuf_texture_builder_get_premultiplied (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_premultiplied (GdkDmabufTextureBuilder *self,
gboolean premultiplied);
GDK_AVAILABLE_IN_4_14
unsigned int gdk_dmabuf_texture_builder_get_n_planes (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_n_planes (GdkDmabufTextureBuilder *self,
unsigned int n_planes);
GDK_AVAILABLE_IN_4_14
int gdk_dmabuf_texture_builder_get_fd (GdkDmabufTextureBuilder *self,
unsigned int plane) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_fd (GdkDmabufTextureBuilder *self,
unsigned int plane,
int fd);
GDK_AVAILABLE_IN_4_14
unsigned int gdk_dmabuf_texture_builder_get_stride (GdkDmabufTextureBuilder *self,
unsigned int plane) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_stride (GdkDmabufTextureBuilder *self,
unsigned int plane,
unsigned int stride);
GDK_AVAILABLE_IN_4_14
unsigned int gdk_dmabuf_texture_builder_get_offset (GdkDmabufTextureBuilder *self,
unsigned int plane) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_offset (GdkDmabufTextureBuilder *self,
unsigned int plane,
unsigned int offset);
GDK_AVAILABLE_IN_4_14
GdkTexture * gdk_dmabuf_texture_builder_get_update_texture (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_update_texture (GdkDmabufTextureBuilder *self,
GdkTexture *texture);
GDK_AVAILABLE_IN_4_14
cairo_region_t * gdk_dmabuf_texture_builder_get_update_region (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_update_region (GdkDmabufTextureBuilder *self,
cairo_region_t *region);
GDK_AVAILABLE_IN_4_14
GdkTexture * gdk_dmabuf_texture_builder_build (GdkDmabufTextureBuilder *self,
GDestroyNotify destroy,
gpointer data);
G_END_DECLS

View File

@ -0,0 +1,33 @@
#pragma once
#include "gdkdmabuftexture.h"
#include "gdkdmabuftexturebuilder.h"
#include "gdkdmabufformatsprivate.h"
#include "gdktextureprivate.h"
#include "gdkdisplay.h"
G_BEGIN_DECLS
#define MAX_DMABUF_PLANES 4
int * gdk_dmabuf_texture_builder_get_fds (GdkDmabufTextureBuilder *builder);
unsigned int * gdk_dmabuf_texture_builder_get_offsets (GdkDmabufTextureBuilder *builder);
unsigned int * gdk_dmabuf_texture_builder_get_strides (GdkDmabufTextureBuilder *builder);
GdkTexture * gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
GDestroyNotify destroy,
gpointer data);
guint32 gdk_dmabuf_texture_get_fourcc (GdkDmabufTexture *texture);
guint64 gdk_dmabuf_texture_get_modifier (GdkDmabufTexture *texture);
unsigned int gdk_dmabuf_texture_get_n_planes (GdkDmabufTexture *texture);
int * gdk_dmabuf_texture_get_fds (GdkDmabufTexture *texture);
unsigned int * gdk_dmabuf_texture_get_offsets (GdkDmabufTexture *texture);
unsigned int * gdk_dmabuf_texture_get_strides (GdkDmabufTexture *texture);
GdkDmabufFormat * gdk_dmabuf_texture_get_supported_formats (gsize *n_formats);
G_END_DECLS

View File

@ -96,6 +96,8 @@ typedef struct _GdkCairoContext GdkCairoContext;
typedef struct _GdkGLContext GdkGLContext;
typedef struct _GdkVulkanContext GdkVulkanContext;
typedef struct _GdkDmabufFormats GdkDmabufFormats;
/*
* GDK_DECLARE_INTERNAL_TYPE:
* @ModuleObjName: The name of the new type, in camel case (like GtkWidget)

View File

@ -17,6 +17,9 @@ gdk_public_sources = files([
'gdkdevicetool.c',
'gdkdisplay.c',
'gdkdisplaymanager.c',
'gdkdmabufformats.c',
'gdkdmabuftexture.c',
'gdkdmabuftexturebuilder.c',
'gdkdrag.c',
'gdkdragsurface.c',
'gdkdragsurfacesize.c',
@ -79,6 +82,9 @@ gdk_public_headers = files([
'gdkdisplay.h',
'gdkdisplaymanager.h',
'gdkdrag.h',
'gdkdmabufformats.h',
'gdkdmabuftexture.h',
'gdkdmabuftexturebuilder.h',
'gdkdragsurfacesize.h',
'gdkdrawcontext.h',
'gdkdrop.h',

View File

@ -162,6 +162,7 @@ check_headers = [
'inttypes.h',
'linux/input.h',
'linux/memfd.h',
'linux/dma-buf.h',
'locale.h',
'memory.h',
'stdint.h',
@ -185,6 +186,10 @@ foreach h : check_headers
endif
endforeach
if os_linux and not cc.has_header('linux/dma-buf.h')
error('OS is Linux, but linux/dma-buf.h not found.')
endif
# Maths functions might be implemented in libm
libm = cc.find_library('m', required: false)

View File

@ -217,6 +217,10 @@ test_type (gconstpointer data)
(strcmp (pspec->name, "default-display") == 0))
check = FALSE;
if (g_type_is_a (type, GDK_TYPE_DISPLAY) &&
(strcmp (pspec->name, "dmabuf-formats") == 0))
check = FALSE;
if (g_type_is_a (type, GDK_TYPE_MONITOR) &&
(strcmp (pspec->name, "geometry") == 0))
check = FALSE;