From d23e13aced21af8ef464af60867b9c960675f9c6 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 9 Oct 2023 16:11:04 -0400 Subject: [PATCH] Add GdkDmabufTextureBuilder Add a builder for a new GdkTexture subclass that wraps dmabuf buffers on Linux. For now, this is just an API. The implementation will follow in subsequent commits. --- gdk/gdk.h | 1 + gdk/gdkdmabufformats.c | 8 +- gdk/gdkdmabuftexturebuilder.c | 992 ++++++++++++++++++++++++++++++++++ gdk/gdkdmabuftexturebuilder.h | 121 +++++ gdk/gdkdmabuftextureprivate.h | 15 + gdk/meson.build | 2 + 6 files changed, 1135 insertions(+), 4 deletions(-) create mode 100644 gdk/gdkdmabuftexturebuilder.c create mode 100644 gdk/gdkdmabuftexturebuilder.h create mode 100644 gdk/gdkdmabuftextureprivate.h diff --git a/gdk/gdk.h b/gdk/gdk.h index 462682be48..20add23cd5 100644 --- a/gdk/gdk.h +++ b/gdk/gdk.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include diff --git a/gdk/gdkdmabufformats.c b/gdk/gdkdmabufformats.c index 5f79aae988..67c8dd9150 100644 --- a/gdk/gdkdmabufformats.c +++ b/gdk/gdkdmabufformats.c @@ -130,10 +130,10 @@ gdk_dmabuf_formats_get_n_formats (GdkDmabufFormats *formats) * Since: 4.14 */ void -gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats, - gsize idx, - guint32 *fourcc, - guint64 *modifier) +gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats, + gsize idx, + guint32 *fourcc, + guint64 *modifier) { GdkDmabufFormat *format; diff --git a/gdk/gdkdmabuftexturebuilder.c b/gdk/gdkdmabuftexturebuilder.c new file mode 100644 index 0000000000..e49f6412e7 --- /dev/null +++ b/gdk/gdkdmabuftexturebuilder.c @@ -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 . + * + * Authors: Matthias Clasen + */ + +#include "config.h" + +#include "gdkdmabuftexturebuilder.h" + +#include "gdkdisplay.h" +#include "gdkenumtypes.h" +#include "gdkdmabuftextureprivate.h" + +#include + + +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 NULL; +} + +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; +} diff --git a/gdk/gdkdmabuftexturebuilder.h b/gdk/gdkdmabuftexturebuilder.h new file mode 100644 index 0000000000..0570aa8d73 --- /dev/null +++ b/gdk/gdkdmabuftexturebuilder.h @@ -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 . + * + * Authors: Matthias Clasen + */ + +#pragma once + +#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +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 + diff --git a/gdk/gdkdmabuftextureprivate.h b/gdk/gdkdmabuftextureprivate.h new file mode 100644 index 0000000000..01c2c655bc --- /dev/null +++ b/gdk/gdkdmabuftextureprivate.h @@ -0,0 +1,15 @@ +#pragma once + +#include "gdkdmabuftexturebuilder.h" +#include "gdktextureprivate.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); + +G_END_DECLS + diff --git a/gdk/meson.build b/gdk/meson.build index 3d0d0cc77d..9d5eb4ca46 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -18,6 +18,7 @@ gdk_public_sources = files([ 'gdkdisplay.c', 'gdkdisplaymanager.c', 'gdkdmabufformats.c', + 'gdkdmabuftexturebuilder.c', 'gdkdrag.c', 'gdkdragsurface.c', 'gdkdragsurfacesize.c', @@ -81,6 +82,7 @@ gdk_public_headers = files([ 'gdkdisplaymanager.h', 'gdkdrag.h', 'gdkdmabufformats.h', + 'gdkdmabuftexturebuilder.h', 'gdkdragsurfacesize.h', 'gdkdrawcontext.h', 'gdkdrop.h',