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
This commit is contained in:
Matthias Clasen 2024-02-09 20:53:52 -05:00
parent d91d0f1c0a
commit 70380661fe
5 changed files with 233 additions and 11 deletions

157
tests/gtkclipper.c Normal file
View File

@ -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);
}

16
tests/gtkclipperprivate.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <gdk/gdk.h>
#include <graphene.h>
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

View File

@ -133,7 +133,7 @@ endif
if os_linux
gtk_tests += [
['testdmabuf'],
['testdmabuf', ['testdmabuf.c', 'gtkclipper.c']],
]
endif

BIN
tests/padded.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -9,6 +9,9 @@
#ifdef GDK_RENDERING_VULKAN
#include <vulkan/vulkan.h>
#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);