rendernode tool: Add a compare command

This command can be used to compare the rendering of a node
to a reference image. It can also be used to compare the
renderings of two nodes, or to compare two images.
This commit is contained in:
Matthias Clasen 2024-02-21 22:22:30 -05:00
parent c93fa922dc
commit c9c6b7bb2a
5 changed files with 169 additions and 1 deletions

View File

@ -13,6 +13,7 @@ SYNOPSIS
| **gtk4-rendernode-tool** <COMMAND> [OPTIONS...] <FILE> | **gtk4-rendernode-tool** <COMMAND> [OPTIONS...] <FILE>
| |
| **gtk4-rendernode-tool** benchmark [OPTIONS...] <FILE> | **gtk4-rendernode-tool** benchmark [OPTIONS...] <FILE>
| **gtk4-rendernode-tool** compare [OPTIONS...] <FILE1> <FILE2>
| **gtk4-rendernode-tool** info [OPTIONS...] <FILE> | **gtk4-rendernode-tool** info [OPTIONS...] <FILE>
| **gtk4-rendernode-tool** render [OPTIONS...] <FILE> [<FILE>] | **gtk4-rendernode-tool** render [OPTIONS...] <FILE> [<FILE>]
| **gtk4-rendernode-tool** show [OPTIONS...] <FILE> | **gtk4-rendernode-tool** show [OPTIONS...] <FILE>
@ -75,7 +76,21 @@ and prints the runtimes.
the execution of the commands on the GPU. It can be useful to use this flag to test the execution of the commands on the GPU. It can be useful to use this flag to test
command submission performance. command submission performance.
Compare
^^^^^^^
The ``compare`` command compares the rendering of a node with a reference image,
or the renderings of two nodes, or two images. If any differences are found, the
exit code is 1. If the images are identical, it is 0.
``--renderer=RENDERER``
Use the given renderer.
``--output=FILE``
Save the differences as a png image in ``FILE``.
``--quiet``
Don't write results to stdout.`

View File

@ -0,0 +1,147 @@
/* Copyright 2024 Red Hat, Inc.
*
* GTK 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.
*
* GTK 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 GTK; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <glib/gi18n-lib.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include "gtk-rendernode-tool.h"
#include "testsuite/reftests/reftest-compare.h"
static GdkTexture *
texture_from_file (const char *filename,
GskRenderer *renderer,
GError **error)
{
GdkTexture *texture;
if (g_str_has_suffix (filename, ".node"))
{
GskRenderNode *node = load_node_file (filename);
texture = gsk_renderer_render_texture (renderer, node, NULL);
gsk_render_node_unref (node);
}
else
{
texture = gdk_texture_new_from_filename (filename, error);
}
return texture;
}
void
do_compare (int *argc,
const char ***argv)
{
GOptionContext *context;
char *opt_filename = NULL;
gboolean opt_quiet = FALSE;
char **filenames = NULL;
char *renderer_name = NULL;
const GOptionEntry entries[] = {
{ "renderer", 0, 0, G_OPTION_ARG_STRING, &renderer_name, N_("Renderer to use"), N_("RENDERER") },
{ "output", 'o', 0, G_OPTION_ARG_FILENAME, &opt_filename, N_("Output file"), N_("FILE") },
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &opt_quiet, "Don't talk", NULL },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, N_("FILE1 FILE2") },
{ NULL, }
};
GskRenderer *renderer;
GdkTexture *texture[2];
GdkTexture *diff;
GError *error = NULL;
g_set_prgname ("gtk4-rendernode-tool compare");
context = g_option_context_new (NULL);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_set_summary (context, _("Compare .node or .png files."));
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
{
g_printerr ("%s\n", error->message);
g_error_free (error);
exit (1);
}
g_option_context_free (context);
if (filenames == NULL || g_strv_length (filenames) != 2)
{
g_printerr (_("Must specify two files\n"));
exit (1);
}
renderer = create_renderer (renderer_name, &error);
if (renderer == NULL)
{
g_printerr (_("Failed to create renderer: %s\n"), error->message);
exit (1);
}
for (int i = 0; i < 2; i++)
{
texture[i] = texture_from_file (filenames[i], renderer, &error);
if (texture[i] == NULL)
{
g_printerr (_("Failed to load %s: %s\n"), filenames[i], error->message);
exit (1);
}
}
diff = reftest_compare_textures (texture[0], texture[1]);
if (opt_filename && diff)
{
if (!gdk_texture_save_to_png (diff, opt_filename))
{
g_printerr (_("Could not save diff image to %s\n"), opt_filename);
exit (1);
}
}
if (!opt_quiet)
{
if (diff)
{
if (opt_filename)
g_print (_("Differences witten to %s.\n"), opt_filename);
else
g_print (_("The images are different.\n"));
}
else
g_print (_("No differences.\n"));
}
if (diff)
exit (1);
g_strfreev (filenames);
g_object_unref (texture[0]);
g_object_unref (texture[1]);
g_object_unref (renderer);
}

View File

@ -39,6 +39,7 @@ usage (void)
"\n" "\n"
"Commands:\n" "Commands:\n"
" benchmark Benchmark rendering of a node\n" " benchmark Benchmark rendering of a node\n"
" compare Compare nodes or images\n"
" info Provide information about the node\n" " info Provide information about the node\n"
" show Show the node\n" " show Show the node\n"
" render Take a screenshot of the node\n" " render Take a screenshot of the node\n"
@ -116,6 +117,8 @@ main (int argc, const char *argv[])
do_info (&argc, &argv); do_info (&argc, &argv);
else if (strcmp (argv[0], "benchmark") == 0) else if (strcmp (argv[0], "benchmark") == 0)
do_benchmark (&argc, &argv); do_benchmark (&argc, &argv);
else if (strcmp (argv[0], "compare") == 0)
do_compare (&argc, &argv);
else else
usage (); usage ();

View File

@ -2,6 +2,7 @@
#pragma once #pragma once
void do_benchmark (int *argc, const char ***argv); void do_benchmark (int *argc, const char ***argv);
void do_compare (int *argc, const char ***argv);
void do_info (int *argc, const char ***argv); void do_info (int *argc, const char ***argv);
void do_show (int *argc, const char ***argv); void do_show (int *argc, const char ***argv);
void do_render (int *argc, const char ***argv); void do_render (int *argc, const char ***argv);

View File

@ -42,10 +42,12 @@ gtk_tools = [
'fake-scope.c'], [libgtk_dep] ], 'fake-scope.c'], [libgtk_dep] ],
['gtk4-rendernode-tool', ['gtk-rendernode-tool.c', ['gtk4-rendernode-tool', ['gtk-rendernode-tool.c',
'gtk-rendernode-tool-benchmark.c', 'gtk-rendernode-tool-benchmark.c',
'gtk-rendernode-tool-compare.c',
'gtk-rendernode-tool-info.c', 'gtk-rendernode-tool-info.c',
'gtk-rendernode-tool-render.c', 'gtk-rendernode-tool-render.c',
'gtk-rendernode-tool-show.c', 'gtk-rendernode-tool-show.c',
'gtk-rendernode-tool-utils.c'], [libgtk_dep] ], 'gtk-rendernode-tool-utils.c',
'../testsuite/reftests/reftest-compare.c'], [libgtk_dep] ],
['gtk4-update-icon-cache', ['updateiconcache.c', '../gtk/gtkiconcachevalidator.c' ] + extra_update_icon_cache_objs, [ libgtk_dep ] ], ['gtk4-update-icon-cache', ['updateiconcache.c', '../gtk/gtkiconcachevalidator.c' ] + extra_update_icon_cache_objs, [ libgtk_dep ] ],
['gtk4-encode-symbolic-svg', ['encodesymbolic.c'], [ libgtk_static_dep ] ], ['gtk4-encode-symbolic-svg', ['encodesymbolic.c'], [ libgtk_static_dep ] ],
] ]