dmabuf: Add Wayland information

Add device and scanout information for dmabuf formats.

While this is not a great API, there is no good alternative to
making this information available to applications that want to
negotiate dmabuf formats suitable for graphics offload.

The getters for Wayland-specific information are kept as
Wayland backend apis.

Tests included.
This commit is contained in:
Matthias Clasen
2024-02-07 10:19:02 +00:00
parent f8b9b76a05
commit 8f28b21f2d
9 changed files with 239 additions and 19 deletions

View File

@@ -205,6 +205,8 @@ gdk_dmabuf_formats_contains (GdkDmabufFormats *formats,
* gdk_dmabuf_formats_new:
* @formats: the formats
* @n_formats: the length of @formats
* @device: the DRM device that the compositor uses, or
* 0 if this object doesn't describe compositor formats
*
* Creates a new `GdkDmabufFormats struct for
* the given formats.
@@ -218,7 +220,8 @@ gdk_dmabuf_formats_contains (GdkDmabufFormats *formats,
*/
GdkDmabufFormats *
gdk_dmabuf_formats_new (GdkDmabufFormat *formats,
gsize n_formats)
gsize n_formats,
guint64 device)
{
GdkDmabufFormats *self;
@@ -227,6 +230,7 @@ gdk_dmabuf_formats_new (GdkDmabufFormat *formats,
self->ref_count = 1;
self->n_formats = n_formats;
self->formats = g_new (GdkDmabufFormat, n_formats);
self->device = device;
memcpy (self->formats, formats, n_formats * sizeof (GdkDmabufFormat));
@@ -261,6 +265,9 @@ gdk_dmabuf_formats_equal (const GdkDmabufFormats *formats1,
if (formats1 == NULL || formats2 == NULL)
return FALSE;
if (formats1->device != formats2->device)
return FALSE;
if (formats1->n_formats != formats2->n_formats)
return FALSE;
@@ -271,7 +278,9 @@ gdk_dmabuf_formats_equal (const GdkDmabufFormats *formats1,
if (f1->fourcc != f2->fourcc ||
f1->modifier != f2->modifier ||
f1->next_priority != f2->next_priority)
f1->next_priority != f2->next_priority ||
f1->flags != f2->flags ||
f1->device != f2->device)
return FALSE;
}

View File

@@ -69,7 +69,9 @@ gdk_dmabuf_format_equal (gconstpointer data_a,
const GdkDmabufFormat *b = data_b;
return a->fourcc == b->fourcc &&
a->modifier == b->modifier;
a->flags == b->flags &&
a->modifier == b->modifier &&
a->device == b->device;
}
static void
@@ -82,7 +84,8 @@ gdk_dmabuf_formats_builder_sort (GdkDmabufFormatsBuilder *self)
}
GdkDmabufFormats *
gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self)
gdk_dmabuf_formats_builder_free_to_formats_for_device (GdkDmabufFormatsBuilder *self,
guint64 device)
{
GdkDmabufFormats *formats;
@@ -90,19 +93,28 @@ gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self)
gdk_dmabuf_formats_builder_sort (self);
formats = gdk_dmabuf_formats_new (gdk_dmabuf_formats_builder_get_data (self),
gdk_dmabuf_formats_builder_get_size (self));
gdk_dmabuf_formats_builder_get_size (self),
device);
gdk_dmabuf_formats_builder_clear (self);
g_free (self);
return formats;
}
void
gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self,
guint32 fourcc,
guint64 modifier)
GdkDmabufFormats *
gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self)
{
GdkDmabufFormat format = { fourcc, modifier, G_MAXSIZE };
return gdk_dmabuf_formats_builder_free_to_formats_for_device (self, 0);
}
void
gdk_dmabuf_formats_builder_add_format_for_device (GdkDmabufFormatsBuilder *self,
guint32 fourcc,
guint32 flags,
guint64 modifier,
guint64 device)
{
GdkDmabufFormat format = { fourcc, flags, modifier, device, G_MAXSIZE };
for (gsize i = 0; i < gdk_dmabuf_formats_builder_get_size (self); i++)
{
@@ -113,6 +125,14 @@ gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self,
gdk_dmabuf_formats_builder_append (self, &format);
}
void
gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self,
guint32 fourcc,
guint64 modifier)
{
gdk_dmabuf_formats_builder_add_format_for_device (self, fourcc, 0, modifier, 0);
}
void
gdk_dmabuf_formats_builder_next_priority (GdkDmabufFormatsBuilder *self)
{

View File

@@ -4,13 +4,21 @@
typedef struct GdkDmabufFormatsBuilder GdkDmabufFormatsBuilder;
GdkDmabufFormatsBuilder * gdk_dmabuf_formats_builder_new (void);
GdkDmabufFormats * gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self);
GdkDmabufFormatsBuilder *gdk_dmabuf_formats_builder_new (void);
GdkDmabufFormats * gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self);
void gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self,
guint32 fourcc,
guint64 modifier);
void gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self,
guint32 fourcc,
guint64 modifier);
void gdk_dmabuf_formats_builder_next_priority (GdkDmabufFormatsBuilder *self);
void gdk_dmabuf_formats_builder_add_formats (GdkDmabufFormatsBuilder *self,
GdkDmabufFormats *formats);
GdkDmabufFormats * gdk_dmabuf_formats_builder_free_to_formats_for_device (GdkDmabufFormatsBuilder *self,
guint64 device);
void gdk_dmabuf_formats_builder_add_format_for_device (GdkDmabufFormatsBuilder *self,
guint32 fourcc,
guint32 flags,
guint64 modifier,
guint64 device);
void gdk_dmabuf_formats_builder_next_priority (GdkDmabufFormatsBuilder *self);
void gdk_dmabuf_formats_builder_add_formats (GdkDmabufFormatsBuilder *self,
GdkDmabufFormats *formats);

View File

@@ -6,7 +6,9 @@ typedef struct _GdkDmabufFormat GdkDmabufFormat;
struct _GdkDmabufFormat
{
guint32 fourcc;
guint32 flags;
guint64 modifier;
guint64 device;
gsize next_priority;
};
@@ -16,9 +18,11 @@ struct _GdkDmabufFormats
gsize n_formats;
GdkDmabufFormat *formats;
guint64 device;
};
GdkDmabufFormats * gdk_dmabuf_formats_new (GdkDmabufFormat *formats,
gsize n_formats);
gsize n_formats,
guint64 device);
const GdkDmabufFormat * gdk_dmabuf_formats_peek_formats (GdkDmabufFormats *self);

View File

@@ -0,0 +1,85 @@
#include "config.h"
#include "gdkwaylanddmabufformats.h"
#include "gdkdebugprivate.h"
#include "gdkdmabufformatsprivate.h"
#include "gdkdmabufformatsbuilderprivate.h"
#include "gdkdmabufformatsprivate.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
/**
* gdk_wayland_dmabuf_formats_get_main_device:
* @formats: a `GdkDmabufFormats`
*
* Returns the DRM device that the compositor uses for compositing.
*
* If this information isn't available (e.g. because @formats wasn't
* obtained form the compositor), then 0 is returned.
*
* Returns: the main DRM device that the compositor prefers
*
* Since: 4.14
*/
dev_t
gdk_wayland_dmabuf_formats_get_main_device (GdkDmabufFormats *formats)
{
return formats->device;
}
/**
* gdk_wayland_dmabuf_formats_get_target_device:
* @formats: a `GdkDmabufFormats`
* @idx: the index of the format to return
*
* Returns the target DRM device that should be used for creating buffers
* with this format.
*
* If this information isn't available (e.g. because @formats wasn't
* obtained form the compositor), then 0 is returned.
*
* Returns: the target DRM device for this format
*
* Since: 4.14
*/
dev_t
gdk_wayland_dmabuf_formats_get_target_device (GdkDmabufFormats *formats,
gsize idx)
{
GdkDmabufFormat *format;
g_return_val_if_fail (idx < formats->n_formats, 0);
format = &formats->formats[idx];
return format->device;
}
/**
* gdk_wayland_dmabuf_formats_is_scanout:
* @formats: a `GdkDmabufFormats`
* @idx: the index of the format to return
*
* Returns whether the compositor intents to use buffers with this
* format for scanout.
*
* If this information isn't available (e.g. because @formats wasn't
* obtained form the compositor), then 0 is returned.
*
* Returns: whether the format will be used for scanout
*
* Since: 4.14
*/
gboolean
gdk_wayland_dmabuf_formats_is_scanout (GdkDmabufFormats *formats,
gsize idx)
{
GdkDmabufFormat *format;
g_return_val_if_fail (idx < formats->n_formats, 0);
format = &formats->formats[idx];
return format->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT;
}

View File

@@ -30,6 +30,7 @@
#include <gdk/wayland/gdkwaylanddevice.h>
#include <gdk/wayland/gdkwaylanddisplay.h>
#include <gdk/wayland/gdkwaylanddmabufformats.h>
#include <gdk/wayland/gdkwaylandglcontext.h>
#include <gdk/wayland/gdkwaylandmonitor.h>
#include <gdk/wayland/gdkwaylandpopup.h>

View File

@@ -0,0 +1,40 @@
/* gdkwaylanddmabufformats.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 (__GDKWAYLAND_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/wayland/gdkwayland.h> can be included directly."
#endif
#include <gdk/gdkdmabufformats.h>
G_BEGIN_DECLS
GDK_AVAILABLE_IN_4_14
dev_t gdk_wayland_dmabuf_formats_get_main_device (GdkDmabufFormats *formats);
GDK_AVAILABLE_IN_4_14
dev_t gdk_wayland_dmabuf_formats_get_target_device (GdkDmabufFormats *formats,
gsize idx);
GDK_AVAILABLE_IN_4_14
gboolean gdk_wayland_dmabuf_formats_is_scanout (GdkDmabufFormats *formats,
gsize idx);
G_END_DECLS

View File

@@ -8,6 +8,7 @@ gdk_wayland_sources = files([
'gdkdevice-wayland.c',
'gdkdevicepad-wayland.c',
'gdkdisplay-wayland.c',
'gdkdmabuf-wayland.c',
'gdkdrag-wayland.c',
'gdkdragsurface-wayland.c',
'gdkdrop-wayland.c',
@@ -28,6 +29,7 @@ gdk_wayland_sources = files([
gdk_wayland_public_headers = files([
'gdkwaylanddevice.h',
'gdkwaylanddisplay.h',
'gdkwaylanddmabufformats.h',
'gdkwaylandglcontext.h',
'gdkwaylandmonitor.h',
'gdkwaylandpopup.h',

View File

@@ -11,6 +11,10 @@
#include <drm_fourcc.h>
#endif
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/wayland/gdkwayland.h>
#endif
static void
test_dmabuf_formats_basic (void)
{
@@ -137,6 +141,52 @@ test_priorities (void)
gdk_dmabuf_formats_unref (formats);
}
static void
test_wayland (void)
{
GdkDmabufFormatsBuilder *builder;
GdkDmabufFormats *formats1, *formats2;
builder = gdk_dmabuf_formats_builder_new ();
gdk_dmabuf_formats_builder_add_format_for_device (builder,
DRM_FORMAT_RGBA8888,
0,
DRM_FORMAT_MOD_LINEAR,
0);
gdk_dmabuf_formats_builder_add_format_for_device (builder,
DRM_FORMAT_ARGB8888,
0,
DRM_FORMAT_MOD_LINEAR,
1);
formats1 = gdk_dmabuf_formats_builder_free_to_formats_for_device (builder, 2);
#ifdef GDK_WINDOWING_WAYLAND
g_assert_true (gdk_wayland_dmabuf_formats_get_main_device (formats1) == 2);
g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats1, 0) == 0);
g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats1, 1) == 1);
g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats1, 0));
g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats1, 1));
#endif
builder = gdk_dmabuf_formats_builder_new ();
gdk_dmabuf_formats_builder_add_format (builder, DRM_FORMAT_ARGB8888, DRM_FORMAT_MOD_LINEAR);
gdk_dmabuf_formats_builder_add_format (builder, DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_LINEAR);
formats2 = gdk_dmabuf_formats_builder_free_to_formats (builder);
#ifdef GDK_WINDOWING_WAYLAND
g_assert_true (gdk_wayland_dmabuf_formats_get_main_device (formats2) == 0);
g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats2, 0) == 0);
g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats2, 1) == 0);
g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats2, 0));
g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats2, 1));
#endif
g_assert_false (gdk_dmabuf_formats_equal (formats1, formats2));
gdk_dmabuf_formats_unref (formats1);
gdk_dmabuf_formats_unref (formats2);
}
int
main (int argc, char *argv[])
{
@@ -145,6 +195,7 @@ main (int argc, char *argv[])
g_test_add_func ("/dmabuf/formats/basic", test_dmabuf_formats_basic);
g_test_add_func ("/dmabuf/formats/builder", test_dmabuf_formats_builder);
g_test_add_func ("/dmabuf/formats/priorities", test_priorities);
g_test_add_func ("/dmabuf/formats/wayland", test_wayland);
return g_test_run ();
}