/* * 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 "gdkdebugprivate.h" #include "gdkdisplay.h" #include "gdkenumtypes.h" #include "gdkcolorstate.h" #include "gdkdmabuftextureprivate.h" #include "gdkdmabuftexturebuilderprivate.h" #include struct _GdkDmabufTextureBuilder { GObject parent_instance; GdkDisplay *display; unsigned int width; unsigned int height; gboolean premultiplied; GdkDmabuf dmabuf; GdkColorState *color_state; 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 are 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_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. * * For historical reasons, some producers of dma-bufs don't provide an explicit modifier, but * instead return `DMA_FORMAT_MOD_INVALID` to indicate that their modifier is **_implicit_**. * GTK tries to accommodate this situation by accepting `DMA_FORMAT_MOD_INVALID` as modifier. * * 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. * * For further information, see * * * The Linux kernel [documentation](https://docs.kernel.org/driver-api/dma-buf.html) * * * The header file [drm_fourcc.h](https://gitlab.freedesktop.org/mesa/drm/-/blob/main/include/drm/drm_fourcc.h) * * Since: 4.14 */ enum { PROP_0, PROP_DISPLAY, PROP_WIDTH, PROP_HEIGHT, PROP_FOURCC, PROP_MODIFIER, PROP_PREMULTIPLIED, PROP_N_PLANES, PROP_COLOR_STATE, 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_clear_pointer (&self->color_state, gdk_color_state_unref); 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->dmabuf.fourcc); break; case PROP_MODIFIER: g_value_set_uint64 (value, self->dmabuf.modifier); break; case PROP_PREMULTIPLIED: g_value_set_boolean (value, self->premultiplied); break; case PROP_N_PLANES: g_value_set_uint (value, self->dmabuf.n_planes); break; case PROP_COLOR_STATE: g_value_set_boxed (value, self->color_state); 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_COLOR_STATE: gdk_dmabuf_texture_builder_set_color_state (self, g_value_get_boxed (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.gtk.Property.get=gdk_dmabuf_texture_builder_get_display org.gtk.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.gtk.Property.get=gdk_dmabuf_texture_builder_get_width org.gtk.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.gtk.Property.get=gdk_dmabuf_texture_builder_get_height org.gtk.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.gtk.Property.get=gdk_dmabuf_texture_builder_get_fourcc org.gtk.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.gtk.Property.get=gdk_dmabuf_texture_builder_get_n_planes org.gtk.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, 1, GDK_DMABUF_MAX_PLANES, 1, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); /** * GdkDmabufTextureBuilder:color-state: * * The color state of the texture. * * Since: 4.16 */ properties[PROP_COLOR_STATE] = g_param_spec_boxed ("color-state", NULL, NULL, GDK_TYPE_COLOR_STATE, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); /** * GdkDmabufTextureBuilder:update-region: (attributes org.gtk.Property.get=gdk_dmabuf_texture_builder_get_update_region org.gtk.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.gtk.Property.get=gdk_dmabuf_texture_builder_get_update_texture org.gtk.Property.set=gdk_dmabuf_texture_builder_set_update_texture) * * The texture [property@Gdk.DmabufTextureBuilder: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->premultiplied = TRUE; self->display = gdk_display_get_default (); self->dmabuf.n_planes = 1; for (int i = 0; i < GDK_DMABUF_MAX_PLANES; i++) self->dmabuf.planes[i].fd = -1; self->color_state = NULL; } /** * 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): 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)); g_return_if_fail (GDK_IS_DISPLAY (display)); 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.gtk.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.gtk.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.gtk.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.gtk.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.gtk.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->dmabuf.fourcc; } /** * gdk_dmabuf_texture_builder_set_fourcc: (attributes org.gtk.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->dmabuf.fourcc == fourcc) return; self->dmabuf.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->dmabuf.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->dmabuf.modifier == modifier) return; self->dmabuf.modifier = modifier; g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODIFIER]); } /** * gdk_dmabuf_texture_builder_get_n_planes: (attributes org.gtk.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->dmabuf.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.gtk.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)); g_return_if_fail (n_planes > 0 && n_planes <= GDK_DMABUF_MAX_PLANES); if (self->dmabuf.n_planes == n_planes) return; self->dmabuf.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 < GDK_DMABUF_MAX_PLANES, 0); return self->dmabuf.planes[plane].fd; } /** * 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 < GDK_DMABUF_MAX_PLANES); if (self->dmabuf.planes[plane].fd == fd) return; self->dmabuf.planes[plane].fd = 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 < GDK_DMABUF_MAX_PLANES, 0); return self->dmabuf.planes[plane].stride; } /** * 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 < GDK_DMABUF_MAX_PLANES); if (self->dmabuf.planes[plane].stride == stride) return; self->dmabuf.planes[plane].stride = 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 < GDK_DMABUF_MAX_PLANES, 0); return self->dmabuf.planes[plane].offset; } /** * 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 < GDK_DMABUF_MAX_PLANES); if (self->dmabuf.planes[plane].offset == offset) return; self->dmabuf.planes[plane].offset = offset; } /** * gdk_dmabuf_texture_builder_get_color_state: (attributes org.gtk.Method.get_property=color-state) * @self: a `GdkDmabufTextureBuilder` * * Gets the color state previously set via gdk_dmabuf_texture_builder_set_color_state(). * * Returns: (nullable): the color state * * Since: 4.16 */ GdkColorState * gdk_dmabuf_texture_builder_get_color_state (GdkDmabufTextureBuilder *self) { g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL); return self->color_state; } /** * gdk_dmabuf_texture_builder_set_color_state: (attributes org.gtk.Method.set_property=color-state) * @self: a `GdkDmabufTextureBuilder` * @color_state: (nullable): a `GdkColorState` or `NULL` to unset the colorstate. * * Sets the color state for the texture. * * By default, the colorstate is `NULL`. In that case, GTK will choose the * correct colorstate based on the format. * If you don't know what colorstates are, this is probably the right thing. * * Since: 4.16 */ void gdk_dmabuf_texture_builder_set_color_state (GdkDmabufTextureBuilder *self, GdkColorState *color_state) { g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self)); if (self->color_state == color_state || (self->color_state != NULL && color_state != NULL && gdk_color_state_equal (self->color_state, color_state))) return; g_clear_pointer (&self->color_state, gdk_color_state_unref); self->color_state = color_state; if (color_state) gdk_color_state_ref (color_state); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_STATE]); } /** * gdk_dmabuf_texture_builder_get_update_texture: (attributes org.gtk.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.gtk.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.gtk.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.gtk.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 * @error: Return location for an error * * Builds a new `GdkTexture` with the values set up in the builder. * * It is a programming error to call this function if any mandatory property has not been set. * * 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. If the * format is not supported by GTK, %NULL will be returned and @error will be set. * * The `destroy` function gets called when the returned texture gets released. * * 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). * * It is possible to call this function multiple times to create multiple textures, * possibly with changing properties in between. * * 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, GError **error) { unsigned i; 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 (error == NULL || *error == 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->dmabuf.fourcc != 0, NULL); for (i = 0; i < self->dmabuf.n_planes; i++) g_return_val_if_fail (self->dmabuf.planes[i].fd != -1, NULL); if (GDK_DISPLAY_DEBUG_CHECK (self->display, DMABUF_DISABLE)) { g_set_error_literal (error, GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_NOT_AVAILABLE, "dmabuf support disabled via GDK_DEBUG environment variable"); return NULL; } return gdk_dmabuf_texture_new_from_builder (self, destroy, data, error); } const GdkDmabuf * gdk_dmabuf_texture_builder_get_dmabuf (GdkDmabufTextureBuilder *self) { return &self->dmabuf; } void gdk_dmabuf_texture_builder_set_dmabuf (GdkDmabufTextureBuilder *self, const GdkDmabuf *dmabuf) { gdk_dmabuf_texture_builder_set_fourcc (self, dmabuf->fourcc); gdk_dmabuf_texture_builder_set_modifier (self, dmabuf->modifier); gdk_dmabuf_texture_builder_set_n_planes (self, dmabuf->n_planes); for (unsigned int i = 0; i < dmabuf->n_planes; i++) { gdk_dmabuf_texture_builder_set_fd (self, i, dmabuf->planes[i].fd); gdk_dmabuf_texture_builder_set_stride (self, i, dmabuf->planes[i].stride); gdk_dmabuf_texture_builder_set_offset (self, i, dmabuf->planes[i].offset); } }