From 70380661fe9dbd470b81c7430cfcbfebe6ef4fb8 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 9 Feb 2024 20:53:52 -0500 Subject: [PATCH] testdmabuf: Test dmabuf viewports Allow specifying padding via --padding. The argument to --padding is a string of up to 4 comma-separated numbers, for the left, right, top, bottom padding. If less numbers are given, the remaining ones are set to zero. This commit also includes an image that can be used for testing with testdmabuf --padding 20,20,20,20 NV12 padded.png --- tests/gtkclipper.c | 157 ++++++++++++++++++++++++++++++++++++++ tests/gtkclipperprivate.h | 16 ++++ tests/meson.build | 2 +- tests/padded.png | Bin 0 -> 6232 bytes tests/testdmabuf.c | 69 ++++++++++++++--- 5 files changed, 233 insertions(+), 11 deletions(-) create mode 100644 tests/gtkclipper.c create mode 100644 tests/gtkclipperprivate.h create mode 100644 tests/padded.png diff --git a/tests/gtkclipper.c b/tests/gtkclipper.c new file mode 100644 index 0000000000..67211995d2 --- /dev/null +++ b/tests/gtkclipper.c @@ -0,0 +1,157 @@ +#include "gtk/gtk.h" +#include "gtkclipperprivate.h" + +struct _GtkClipper +{ + GObject parent_instance; + + GdkPaintable *paintable; + graphene_rect_t clip; +}; + +struct _GtkClipperClass +{ + GObjectClass parent_class; +}; + +static void +gtk_clipper_paintable_snapshot (GdkPaintable *paintable, + GdkSnapshot *snapshot, + double width, + double height) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + float sx, sy; + + gtk_snapshot_save (snapshot); + + sx = gdk_paintable_get_intrinsic_width (self->paintable) / self->clip.size.width; + sy = gdk_paintable_get_intrinsic_height (self->paintable) / self->clip.size.height; + + gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height)); + + gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (- self->clip.origin.x * width / self->clip.size.width, + - self->clip.origin.y * height / self->clip.size.height)); + gdk_paintable_snapshot (self->paintable, snapshot, width * sx, height * sy); + gtk_snapshot_pop (snapshot); + gtk_snapshot_restore (snapshot); +} + +static GdkPaintable * +gtk_clipper_paintable_get_current_image (GdkPaintable *paintable) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + GdkPaintable *current_paintable, *current_self; + + current_paintable = gdk_paintable_get_current_image (self->paintable); + current_self = gtk_clipper_new (current_paintable, &self->clip); + g_object_unref (current_paintable); + + return current_self; +} + +static GdkPaintableFlags +gtk_clipper_paintable_get_flags (GdkPaintable *paintable) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + + return gdk_paintable_get_flags (self->paintable); +} + +static int +gtk_clipper_paintable_get_intrinsic_width (GdkPaintable *paintable) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + + return self->clip.size.width; +} + +static int +gtk_clipper_paintable_get_intrinsic_height (GdkPaintable *paintable) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + + return self->clip.size.height; +} + +static double gtk_clipper_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + + return self->clip.size.width / (double) self->clip.size.height; +}; + +static void +gtk_clipper_paintable_init (GdkPaintableInterface *iface) +{ + iface->snapshot = gtk_clipper_paintable_snapshot; + iface->get_current_image = gtk_clipper_paintable_get_current_image; + iface->get_flags = gtk_clipper_paintable_get_flags; + iface->get_intrinsic_width = gtk_clipper_paintable_get_intrinsic_width; + iface->get_intrinsic_height = gtk_clipper_paintable_get_intrinsic_height; + iface->get_intrinsic_aspect_ratio = gtk_clipper_paintable_get_intrinsic_aspect_ratio; +} + +G_DEFINE_TYPE_EXTENDED (GtkClipper, gtk_clipper, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, + gtk_clipper_paintable_init)) + +static void +gtk_clipper_dispose (GObject *object) +{ + GtkClipper *self = GTK_CLIPPER (object); + + if (self->paintable) + { + const guint flags = gdk_paintable_get_flags (self->paintable); + + if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0) + g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_contents, self); + + if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0) + g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_size, self); + + g_clear_object (&self->paintable); + } + + G_OBJECT_CLASS (gtk_clipper_parent_class)->dispose (object); +} + +static void +gtk_clipper_class_init (GtkClipperClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = gtk_clipper_dispose; +} + +static void +gtk_clipper_init (GtkClipper *self) +{ +} + +GdkPaintable * +gtk_clipper_new (GdkPaintable *paintable, + const graphene_rect_t *clip) +{ + GtkClipper *self; + guint flags; + + g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), NULL); + g_return_val_if_fail (clip != NULL, NULL); + + self = g_object_new (GTK_TYPE_CLIPPER, NULL); + + self->paintable = g_object_ref (paintable); + flags = gdk_paintable_get_flags (paintable); + + if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0) + g_signal_connect_swapped (paintable, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self); + + if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0) + g_signal_connect_swapped (paintable, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self); + + self->clip = *clip; + + return GDK_PAINTABLE (self); +} diff --git a/tests/gtkclipperprivate.h b/tests/gtkclipperprivate.h new file mode 100644 index 0000000000..2b4a61d0cc --- /dev/null +++ b/tests/gtkclipperprivate.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_CLIPPER (gtk_clipper_get_type ()) + +G_DECLARE_FINAL_TYPE (GtkClipper, gtk_clipper, GTK, CLIPPER, GObject) + +GdkPaintable * gtk_clipper_new (GdkPaintable *paintable, + const graphene_rect_t *clip); + +G_END_DECLS + diff --git a/tests/meson.build b/tests/meson.build index 253640c461..6990712cb7 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -133,7 +133,7 @@ endif if os_linux gtk_tests += [ - ['testdmabuf'], + ['testdmabuf', ['testdmabuf.c', 'gtkclipper.c']], ] endif diff --git a/tests/padded.png b/tests/padded.png new file mode 100644 index 0000000000000000000000000000000000000000..0501851547dacfc629ee249071de294fcaed9fdc GIT binary patch literal 6232 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 Bswe;e literal 0 HcmV?d00001 diff --git a/tests/testdmabuf.c b/tests/testdmabuf.c index df166beea0..d603abe10c 100644 --- a/tests/testdmabuf.c +++ b/tests/testdmabuf.c @@ -9,6 +9,9 @@ #ifdef GDK_RENDERING_VULKAN #include #endif + +#include "gtkclipperprivate.h" + /* For this to work, you may need to give /dev/dma_heap/system * lax permissions. */ @@ -449,13 +452,12 @@ texture_builder_set_planes (GdkDmabufTextureBuilder *builder, } static GdkTexture * -make_dmabuf_texture (const char *filename, +make_dmabuf_texture (GdkTexture *texture, guint32 format, gboolean disjoint, gboolean premultiplied, gboolean flip) { - GdkTexture *texture; GdkTextureDownloader *downloader; int width, height; gsize rgb_stride, rgb_size; @@ -471,8 +473,6 @@ make_dmabuf_texture (const char *filename, else g_print ("Using memfd\n"); - texture = gdk_texture_new_from_filename (filename, NULL); - width = gdk_texture_get_width (texture); height = gdk_texture_get_height (texture); rgb_stride = 4 * width; @@ -490,8 +490,6 @@ make_dmabuf_texture (const char *filename, gdk_texture_downloader_download_into (downloader, rgb_data, rgb_stride); gdk_texture_downloader_free (downloader); - g_object_unref (texture); - if (flip) { for (int y = 0; y < height; y++) @@ -643,7 +641,7 @@ static void usage (void) { char *formats = supported_formats_to_string (); - g_print ("Usage: testdmabuf [--undecorated][--disjoint][--download-to FILE] FORMAT FILE\n" + g_print ("Usage: testdmabuf [--undecorated][--disjoint][--download-to FILE][--padding PADDING] FORMAT FILE\n" "Supported formats: %s\n", formats); g_free (formats); exit (1); @@ -717,6 +715,9 @@ toggle_flip (GtkWidget *widget, { GtkPicture *picture = data; + if (!texture_flipped) + return FALSE; + if (gtk_picture_get_paintable (picture) == GDK_PAINTABLE (texture)) gtk_picture_set_paintable (picture, GDK_PAINTABLE (texture_flipped)); else @@ -756,6 +757,10 @@ main (int argc, char *argv[]) GtkShortcutTrigger *trigger; GtkShortcutAction *action; GtkShortcut *shortcut; + GdkPaintable *paintable; + GdkTexture *orig; + int padding[4] = { 0, }; /* left, right, top, bottom */ + int padding_set = 0; for (i = 1; i < argc; i++) { @@ -775,6 +780,37 @@ main (int argc, char *argv[]) save_filename = argv[i]; } + else if (g_str_equal (argv[i], "--padding")) + { + if (padding_set < 4) + { + char **strv; + + i++; + if (i == argc) + usage (); + + strv = g_strsplit (argv[i], ",", 0); + if (g_strv_length (strv) > 4) + g_error ("Too much padding"); + + for (padding_set = 0; padding_set < 4; padding_set++) + { + guint64 num; + GError *error = NULL; + + if (!strv[padding_set]) + break; + + if (!g_ascii_string_to_unsigned (strv[padding_set], 10, 0, 100, &num, &error)) + g_error ("%s", error->message); + + padding[padding_set] = (int) num; + } + } + else + g_error ("Too much padding"); + } else break; } @@ -793,8 +829,21 @@ main (int argc, char *argv[]) /* Get the list of supported formats with GDK_DEBUG=opengl */ gdk_display_get_dmabuf_formats (gdk_display_get_default ()); - texture = make_dmabuf_texture (filename, format, disjoint, premultiplied, FALSE); - texture_flipped = make_dmabuf_texture (filename, format, disjoint, premultiplied, TRUE); + orig = gdk_texture_new_from_filename (filename, NULL); + texture = make_dmabuf_texture (orig, format, disjoint, premultiplied, FALSE); + texture_flipped = make_dmabuf_texture (orig, format, disjoint, premultiplied, TRUE); + g_object_unref (orig); + + if (padding_set > 0) + { + paintable = gtk_clipper_new (GDK_PAINTABLE (texture), + &GRAPHENE_RECT_INIT (padding[0], + padding[2], + gdk_texture_get_width (texture) - padding[0] - padding[1], + gdk_texture_get_height (texture) - padding[2] - padding[3])); + } + else + paintable = GDK_PAINTABLE (texture); if (save_filename) gdk_texture_save_to_png (texture, save_filename); @@ -804,7 +853,7 @@ main (int argc, char *argv[]) if (fullscreen) gtk_window_fullscreen (GTK_WINDOW (window)); - picture = gtk_picture_new_for_paintable (GDK_PAINTABLE (texture)); + picture = gtk_picture_new_for_paintable (paintable); offload = gtk_graphics_offload_new (picture); gtk_widget_set_halign (offload, GTK_ALIGN_CENTER); gtk_widget_set_valign (offload, GTK_ALIGN_CENTER);