Compare commits

...

3 Commits

Author SHA1 Message Date
Matthias Clasen
aa91c59bd7 Rewrite compare-render test
Rewrite this to use TAP and do a single invocation for a whole
directory of files.

This uncovers that the GL renderer is mishandling transforms with
offscreens. There is also some randomness in the failures with the
GL renderer that I have yet to track down.
2023-12-21 08:27:12 -05:00
Matthias Clasen
3ee4dba206 testsuite: Run nodeparser tests as one binary
Instead of relaunching the offload test binary for each file,
just run it once and let it iterate over the directory where
all the node files are.
2023-12-21 08:27:01 -05:00
Matthias Clasen
55c2965dc7 testsuite: Run offload tests as one binary
Instead of relaunching the offload test binary for each file,
just run it once and let it iterate over the directory where
all the node files are.
2023-12-21 08:27:01 -05:00
4 changed files with 652 additions and 721 deletions

View File

@@ -4,12 +4,12 @@
#include <stdlib.h>
#include "../reftests/reftest-compare.h"
static char *arg_dir = NULL;
static char *arg_output_dir = NULL;
static gboolean flip = FALSE;
static gboolean rotate = FALSE;
static gboolean repeat = FALSE;
static gboolean mask = FALSE;
static gboolean replay = FALSE;
static char **arg_skip = NULL;
static GskRenderer *renderer;
static GdkSurface *window;
extern void
replay_node (GskRenderNode *node, GtkSnapshot *snapshot);
@@ -114,7 +114,8 @@ save_image (GdkTexture *texture,
char *filename = get_output_file (test_name, ".node", extension);
gboolean result;
g_print ("Storing test result image at %s\n", filename);
if (g_test_verbose ())
g_test_message ("Storing test result image at %s", filename);
result = gdk_texture_save_to_png (texture, filename);
g_assert_true (result);
g_free (filename);
@@ -128,7 +129,8 @@ save_node (GskRenderNode *node,
char *filename = get_output_file (test_name, ".node", extension);
gboolean result;
g_print ("Storing modified nodes at %s\n", filename);
if (g_test_verbose ())
g_test_message ("Storing modified nodes at %s", filename);
result = gsk_render_node_write_to_file (node, filename, NULL);
g_assert_true (result);
g_free (filename);
@@ -157,16 +159,6 @@ deserialize_error_func (const GskParseLocation *start,
g_string_free (string, TRUE);
}
static const GOptionEntry options[] = {
{ "output", 0, 0, G_OPTION_ARG_FILENAME, &arg_output_dir, "Directory to save image files to", "DIR" },
{ "flip", 0, 0, G_OPTION_ARG_NONE, &flip, "Do flipped test", NULL },
{ "rotate", 0, 0, G_OPTION_ARG_NONE, &rotate, "Do rotated test", NULL },
{ "repeat", 0, 0, G_OPTION_ARG_NONE, &repeat, "Do repeated test", NULL },
{ "mask", 0, 0, G_OPTION_ARG_NONE, &mask, "Do masked test", NULL },
{ "replay", 0, 0, G_OPTION_ARG_NONE, &replay, "Do replay test", NULL },
{ NULL }
};
static GskRenderNode *
load_node_file (const char *node_file)
{
@@ -178,7 +170,7 @@ load_node_file (const char *node_file)
if (!g_file_get_contents (node_file, &contents, &len, &error))
{
g_print ("Could not open node file: %s\n", error->message);
g_test_message ("Could not open node file: %s", error->message);
g_clear_error (&error);
return NULL;
}
@@ -215,29 +207,481 @@ apply_mask_to_pixbuf (GdkPixbuf *pixbuf)
return copy;
}
/*
* Non-option arguments:
* 1) .node file to compare
* 2) .png file to compare the rendered .node file to
*/
int
main (int argc, char **argv)
enum {
PLAIN,
FLIP,
REPEAT,
ROTATE,
MASK,
REPLAY
};
static const char *kind[] = {
"plain",
"flip",
"repeat",
"rotate",
"mask",
"replay"
};
typedef struct
{
char *node_file;
char *png_file;
int opt;
} TestCase;
static void
test_case_free (gpointer data)
{
TestCase *c = data;
g_free (c->node_file);
g_free (c->png_file);
g_free (c);
}
static void
test_one_file (gconstpointer data)
{
const TestCase *c = (TestCase *)data;
GdkTexture *reference_texture;
GdkTexture *rendered_texture;
GskRenderer *renderer;
GdkSurface *window;
GskRenderNode *node;
const char *node_file;
const char *png_file;
gboolean success = TRUE;
GError *error = NULL;
GOptionContext *context;
GdkTexture *diff_texture;
GskRenderNode *node;
GError *error = NULL;
if (g_test_verbose ())
{
g_test_message ("Node file: '%s'", c->node_file);
g_test_message ("PNG file: '%s'", c->png_file);
}
/* Load the render node from the given .node file */
node = load_node_file (c->node_file);
if (!node)
{
g_test_fail_printf ("File %s not found", c->node_file);
return;
}
switch (c->opt)
{
case PLAIN:
{
/* Render the .node file and download to cairo surface */
rendered_texture = gsk_renderer_render_texture (renderer, node, NULL);
g_assert_nonnull (rendered_texture);
save_image (rendered_texture, c->node_file, ".out.png");
/* Load the given reference png file */
reference_texture = gdk_texture_new_from_filename (c->png_file, &error);
if (reference_texture == NULL)
{
save_image (rendered_texture, c->node_file, ".out.png");
g_test_fail_printf ("Error loading reference surface: %s", error->message);
g_clear_error (&error);
return;
}
/* Now compare the two */
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_image (diff_texture, c->node_file, ".diff.png");
g_object_unref (diff_texture);
g_test_fail ();
}
g_clear_object (&reference_texture);
g_clear_object (&rendered_texture);
}
break;
case FLIP:
{
GskRenderNode *node2;
GdkPixbuf *pixbuf, *pixbuf2;
GskTransform *transform;
transform = gsk_transform_scale (NULL, -1, 1);
node2 = gsk_transform_node_new (node, transform);
gsk_transform_unref (transform);
save_node (node2, c->node_file, "-flipped.node");
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
save_image (rendered_texture, c->node_file, "-flipped.out.png");
pixbuf = gdk_pixbuf_new_from_file (c->png_file, &error);
g_assert_no_error (error);
pixbuf2 = gdk_pixbuf_flip (pixbuf, TRUE);
reference_texture = gdk_texture_new_for_pixbuf (pixbuf2);
g_object_unref (pixbuf2);
g_object_unref (pixbuf);
save_image (reference_texture, c->node_file, "-flipped.ref.png");
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_image (diff_texture, c->node_file, "-flipped.diff.png");
g_object_unref (diff_texture);
g_test_fail ();
}
g_clear_object (&rendered_texture);
g_clear_object (&reference_texture);
gsk_render_node_unref (node2);
}
break;
case REPEAT:
{
GskRenderNode *node2;
GdkPixbuf *pixbuf, *pixbuf2, *pixbuf3;
int width, height;
graphene_rect_t node_bounds;
graphene_rect_t bounds;
float offset_x, offset_y;
gsk_render_node_get_bounds (node, &node_bounds);
if (node_bounds.size.width > 32768. || node_bounds.size.height > 32768.)
{
g_test_skip_printf ("Avoiding repeat test that exceeds cairo image surface dimensions");
}
else
{
bounds.origin.x = 0.;
bounds.origin.y = 0.;
bounds.size.width = 2 * node_bounds.size.width;
bounds.size.height = 2 * node_bounds.size.height;
offset_x = floorf (fmodf (node_bounds.origin.x, node_bounds.size.width));
offset_y = floorf (fmodf (node_bounds.origin.y, node_bounds.size.height));
if (offset_x < 0)
offset_x += node_bounds.size.width;
if (offset_y < 0)
offset_y += node_bounds.size.height;
node2 = gsk_repeat_node_new (&bounds, node, &node_bounds);
save_node (node2, c->node_file, "-repeated.node");
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
save_image (rendered_texture, c->node_file, "-repeated.out.png");
pixbuf = gdk_pixbuf_new_from_file (c->png_file, &error);
g_assert_no_error (error);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
pixbuf2 = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf),
gdk_pixbuf_get_bits_per_sample (pixbuf),
width * 3,
height * 3);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
gdk_pixbuf_copy_area (pixbuf, 0, 0, width, height, pixbuf2, i * width, j * height);
pixbuf3 = gdk_pixbuf_new_subpixbuf (pixbuf2, width - (int) offset_x, height - (int) offset_y, 2 * width, 2 * height);
reference_texture = gdk_texture_new_for_pixbuf (pixbuf3);
g_object_unref (pixbuf3);
g_object_unref (pixbuf2);
g_object_unref (pixbuf);
save_image (reference_texture, c->node_file, "-repeated.ref.png");
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_image (diff_texture, c->node_file, "-repeated.diff.png");
g_object_unref (diff_texture);
g_test_fail ();
}
g_clear_object (&rendered_texture);
g_clear_object (&reference_texture);
gsk_render_node_unref (node2);
}
}
break;
case ROTATE:
{
GskRenderNode *node2;
GdkPixbuf *pixbuf, *pixbuf2;
GskTransform *transform;
transform = gsk_transform_rotate (NULL, 90);
node2 = gsk_transform_node_new (node, transform);
gsk_transform_unref (transform);
save_node (node2, c->node_file, "-rotated.node");
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
save_image (rendered_texture, c->node_file, "-rotated.out.png");
pixbuf = gdk_pixbuf_new_from_file (c->png_file, &error);
g_assert_no_error (error);
pixbuf2 = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
reference_texture = gdk_texture_new_for_pixbuf (pixbuf2);
g_object_unref (pixbuf2);
g_object_unref (pixbuf);
save_image (reference_texture, c->node_file, "-rotated.ref.png");
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_image (diff_texture, c->node_file, "-rotated.diff.png");
g_object_unref (diff_texture);
g_test_fail ();
}
g_clear_object (&rendered_texture);
g_clear_object (&reference_texture);
gsk_render_node_unref (node2);
}
break;
case MASK:
{
GskRenderNode *node2;
GdkPixbuf *pixbuf, *pixbuf2;
graphene_rect_t bounds;
GskRenderNode *mask_node;
GskRenderNode *nodes[2];
gsk_render_node_get_bounds (node, &bounds);
nodes[0] = gsk_color_node_new (&(GdkRGBA){ 0, 0, 0, 1},
&GRAPHENE_RECT_INIT (bounds.origin.x, bounds.origin.y, 25, 25));
if (bounds.size.width > 25 && bounds.size.height > 25)
{
nodes[1] = gsk_color_node_new (&(GdkRGBA){ 0, 0, 0, 1},
&GRAPHENE_RECT_INIT (bounds.origin.x + 25, bounds.origin.y + 25, bounds.size.width - 25, bounds.size.height - 25));
mask_node = gsk_container_node_new (nodes, G_N_ELEMENTS (nodes));
gsk_render_node_unref (nodes[0]);
gsk_render_node_unref (nodes[1]);
}
else
{
mask_node = nodes[0];
}
node2 = gsk_mask_node_new (node, mask_node, GSK_MASK_MODE_ALPHA);
gsk_render_node_unref (mask_node);
save_node (node2, c->node_file, "-masked.node");
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
save_image (rendered_texture, c->node_file, "-masked.out.png");
pixbuf = gdk_pixbuf_new_from_file (c->png_file, &error);
g_assert_no_error (error);
pixbuf2 = apply_mask_to_pixbuf (pixbuf);
reference_texture = gdk_texture_new_for_pixbuf (pixbuf2);
g_object_unref (pixbuf2);
g_object_unref (pixbuf);
save_image (reference_texture, c->node_file, "-masked.ref.png");
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_image (diff_texture, c->node_file, "-masked.diff.png");
g_object_unref (diff_texture);
g_test_fail ();
}
g_clear_object (&rendered_texture);
g_clear_object (&reference_texture);
gsk_render_node_unref (node2);
}
break;
case REPLAY:
{
GskRenderNode *node2;
GdkTexture *rendered_texture2;
graphene_rect_t node_bounds, node2_bounds;
GtkSnapshot *snapshot = gtk_snapshot_new ();
replay_node (node, snapshot);
node2 = gtk_snapshot_free_to_node (snapshot);
/* If the whole render node tree got eliminated, make sure we have
something to work with nevertheless. */
if (!node2)
node2 = gsk_container_node_new (NULL, 0);
gsk_render_node_get_bounds (node, &node_bounds);
gsk_render_node_get_bounds (node2, &node2_bounds);
/* Check that the node didn't grow. */
if (!graphene_rect_contains_rect (&node_bounds, &node2_bounds))
g_test_fail_printf ("The node grew");
rendered_texture = gsk_renderer_render_texture (renderer, node, &node_bounds);
rendered_texture2 = gsk_renderer_render_texture (renderer, node2, &node_bounds);
g_assert_nonnull (rendered_texture);
g_assert_nonnull (rendered_texture2);
diff_texture = reftest_compare_textures (rendered_texture, rendered_texture2);
if (diff_texture)
{
save_image (diff_texture, c->node_file, "-replayed.diff.png");
save_node (node2, c->node_file, "-replayed.node");
g_object_unref (diff_texture);
g_test_fail ();
}
g_clear_object (&rendered_texture);
g_clear_object (&rendered_texture2);
gsk_render_node_unref (node2);
}
break;
default:
g_assert_not_reached ();
}
gsk_render_node_unref (node);
}
static int
compare_files (gconstpointer a, gconstpointer b)
{
GFile *file1 = G_FILE (a);
GFile *file2 = G_FILE (b);
const char *path1, *path2;
path1 = g_file_peek_path (file1);
path2 = g_file_peek_path (file2);
return strcmp (path1, path2);
}
static gboolean
should_skip (const char *filename)
{
if (arg_skip)
for (int i = 0; arg_skip[i]; i++)
{
if (strstr (filename, arg_skip[i]))
return TRUE;
}
return FALSE;
}
static void
add_files_in_directory (GFile *dir)
{
GFileEnumerator *enumerator;
GFileInfo *info;
GList *l, *files;
GError *error = NULL;
enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
g_assert_no_error (error);
files = NULL;
while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)))
{
const char *filename;
filename = g_file_info_get_name (info);
if (!g_str_has_suffix (filename, ".node"))
{
g_object_unref (info);
continue;
}
if (should_skip (filename))
{
g_object_unref (info);
continue;
}
files = g_list_prepend (files, g_file_get_child (dir, filename));
g_object_unref (info);
}
g_assert_no_error (error);
g_object_unref (enumerator);
files = g_list_sort (files, compare_files);
for (l = files; l; l = l->next)
{
GFile *file = l->data;
char *name;
name = g_file_get_basename (file);
for (int opt = PLAIN; opt <= REPLAY; opt++)
{
TestCase *c;
char *path;
c = g_new0 (TestCase, 1);
c->node_file = g_file_get_path (file);
c->png_file = file_replace_extension (c->node_file, ".node", ".png");
c->opt = opt;
path = g_strconcat ("/gsk/compare/", kind[opt], "/", name, NULL);
g_test_add_data_func_full (path, c, test_one_file, test_case_free);
g_free (path);
}
g_free (name);
}
g_list_free_full (files, g_object_unref);
}
static gboolean flip;
static gboolean rotate;
static gboolean repeat;
static gboolean mask;
static gboolean replay;
static const GOptionEntry options[] = {
{ "dir", 0, 0, G_OPTION_ARG_FILENAME, &arg_dir, "Directory with test files", "DIR" },
{ "output", 0, 0, G_OPTION_ARG_FILENAME, &arg_output_dir, "Directory to save image files to", "DIR" },
{ "skip", 0, 0, G_OPTION_ARG_STRING_ARRAY, &arg_skip, "Files to skip" },
{ "flip", 0, 0, G_OPTION_ARG_NONE, &flip, "Do flipped test", NULL },
{ "rotate", 0, 0, G_OPTION_ARG_NONE, &rotate, "Do rotated test", NULL },
{ "repeat", 0, 0, G_OPTION_ARG_NONE, &repeat, "Do repeated test", NULL },
{ "mask", 0, 0, G_OPTION_ARG_NONE, &mask, "Do masked test", NULL },
{ "replay", 0, 0, G_OPTION_ARG_NONE, &replay, "Do replay test", NULL },
{ NULL }
};
int
main (int argc, char *argv[])
{
GOptionContext *context;
GError *error = NULL;
GFile *file;
int retval;
gtk_init ();
(g_test_init) (&argc, &argv, NULL);
context = g_option_context_new ("NODE REF - run GSK node tests");
context = g_option_context_new ("- run GSK compare tests");
g_option_context_add_main_entries (context, options, NULL);
g_option_context_set_ignore_unknown_options (context, TRUE);
@@ -246,305 +690,54 @@ main (int argc, char **argv)
g_error ("Option parsing failed: %s\n", error->message);
return 1;
}
else if (argc != 3)
else if (argc == 3)
{
char *help = g_option_context_get_help (context, TRUE, NULL);
g_print ("%s", help);
return 1;
TestCase *c;
char *name;
char *path;
c = g_new (TestCase, 1);
c->node_file = g_strdup (argv[1]);
c->png_file = g_strdup (argv[2]);
if (flip)
c->opt = FLIP;
else if (rotate)
c->opt = ROTATE;
else if (repeat)
c->opt = REPEAT;
else if (mask)
c->opt = MASK;
else if (replay)
c->opt = REPLAY;
else
c->opt = PLAIN;
file = g_file_new_for_commandline_arg (argv[1]);
name = g_file_get_basename (file);
path = g_strconcat ("/gsk/compare/", kind[c->opt], "/", name, NULL);
g_test_add_data_func_full (path, c, test_one_file, test_case_free);
g_free (path);
g_free (name);
g_object_unref (file);
}
g_option_context_free (context);
gtk_init ();
node_file = argv[1];
png_file = argv[2];
g_print ("Node file: '%s'\n", node_file);
g_print ("PNG file: '%s'\n", png_file);
if (arg_dir)
{
file = g_file_new_for_commandline_arg (arg_dir);
add_files_in_directory (file);
g_object_unref (file);
}
window = gdk_surface_new_toplevel (gdk_display_get_default());
renderer = gsk_renderer_new_for_surface (window);
/* Load the render node from the given .node file */
node = load_node_file (node_file);
if (!node)
return 1;
/* Render the .node file and download to cairo surface */
rendered_texture = gsk_renderer_render_texture (renderer, node, NULL);
g_assert_nonnull (rendered_texture);
save_image (rendered_texture, node_file, ".out.png");
/* Load the given reference png file */
reference_texture = gdk_texture_new_from_filename (png_file, &error);
if (reference_texture == NULL)
{
g_print ("Error loading reference surface: %s\n", error->message);
g_clear_error (&error);
save_image (rendered_texture, node_file, ".out.png");
return 0;
}
/* Now compare the two */
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_image (diff_texture, node_file, ".diff.png");
g_object_unref (diff_texture);
success = FALSE;
}
g_clear_object (&reference_texture);
g_clear_object (&rendered_texture);
if (flip)
{
GskRenderNode *node2;
GdkPixbuf *pixbuf, *pixbuf2;
GskTransform *transform;
transform = gsk_transform_scale (NULL, -1, 1);
node2 = gsk_transform_node_new (node, transform);
gsk_transform_unref (transform);
save_node (node2, node_file, "-flipped.node");
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
save_image (rendered_texture, node_file, "-flipped.out.png");
pixbuf = gdk_pixbuf_new_from_file (png_file, &error);
pixbuf2 = gdk_pixbuf_flip (pixbuf, TRUE);
reference_texture = gdk_texture_new_for_pixbuf (pixbuf2);
g_object_unref (pixbuf2);
g_object_unref (pixbuf);
save_image (reference_texture, node_file, "-flipped.ref.png");
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_image (diff_texture, node_file, "-flipped.diff.png");
g_object_unref (diff_texture);
success = FALSE;
}
g_clear_object (&rendered_texture);
g_clear_object (&reference_texture);
gsk_render_node_unref (node2);
}
if (repeat)
{
GskRenderNode *node2;
GdkPixbuf *pixbuf, *pixbuf2, *pixbuf3;
int width, height;
graphene_rect_t node_bounds;
graphene_rect_t bounds;
float offset_x, offset_y;
gsk_render_node_get_bounds (node, &node_bounds);
if (node_bounds.size.width > 32768. || node_bounds.size.height > 32768.)
{
g_print ("Avoiding repeat test that exceeds cairo image surface dimensions");
exit (77);
}
bounds.origin.x = 0.;
bounds.origin.y = 0.;
bounds.size.width = 2 * node_bounds.size.width;
bounds.size.height = 2 * node_bounds.size.height;
offset_x = floorf (fmodf (node_bounds.origin.x, node_bounds.size.width));
offset_y = floorf (fmodf (node_bounds.origin.y, node_bounds.size.height));
if (offset_x < 0)
offset_x += node_bounds.size.width;
if (offset_y < 0)
offset_y += node_bounds.size.height;
node2 = gsk_repeat_node_new (&bounds, node, &node_bounds);
save_node (node2, node_file, "-repeated.node");
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
save_image (rendered_texture, node_file, "-repeated.out.png");
pixbuf = gdk_pixbuf_new_from_file (png_file, &error);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
pixbuf2 = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf),
gdk_pixbuf_get_bits_per_sample (pixbuf),
width * 3,
height * 3);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
gdk_pixbuf_copy_area (pixbuf, 0, 0, width, height, pixbuf2, i * width, j * height);
pixbuf3 = gdk_pixbuf_new_subpixbuf (pixbuf2, width - (int) offset_x, height - (int) offset_y, 2 * width, 2 * height);
reference_texture = gdk_texture_new_for_pixbuf (pixbuf3);
g_object_unref (pixbuf3);
g_object_unref (pixbuf2);
g_object_unref (pixbuf);
save_image (reference_texture, node_file, "-repeated.ref.png");
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_image (diff_texture, node_file, "-repeated.diff.png");
g_object_unref (diff_texture);
success = FALSE;
}
g_clear_object (&rendered_texture);
g_clear_object (&reference_texture);
gsk_render_node_unref (node2);
}
if (rotate)
{
GskRenderNode *node2;
GdkPixbuf *pixbuf, *pixbuf2;
GskTransform *transform;
transform = gsk_transform_rotate (NULL, 90);
node2 = gsk_transform_node_new (node, transform);
gsk_transform_unref (transform);
save_node (node2, node_file, "-rotated.node");
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
save_image (rendered_texture, node_file, "-rotated.out.png");
pixbuf = gdk_pixbuf_new_from_file (png_file, &error);
pixbuf2 = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
reference_texture = gdk_texture_new_for_pixbuf (pixbuf2);
g_object_unref (pixbuf2);
g_object_unref (pixbuf);
save_image (reference_texture, node_file, "-rotated.ref.png");
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_image (diff_texture, node_file, "-rotated.diff.png");
g_object_unref (diff_texture);
success = FALSE;
}
g_clear_object (&rendered_texture);
g_clear_object (&reference_texture);
gsk_render_node_unref (node2);
}
if (mask)
{
GskRenderNode *node2;
GdkPixbuf *pixbuf, *pixbuf2;
graphene_rect_t bounds;
GskRenderNode *mask_node;
GskRenderNode *nodes[2];
gsk_render_node_get_bounds (node, &bounds);
nodes[0] = gsk_color_node_new (&(GdkRGBA){ 0, 0, 0, 1},
&GRAPHENE_RECT_INIT (bounds.origin.x, bounds.origin.y, 25, 25));
if (bounds.size.width > 25 && bounds.size.height > 25)
{
nodes[1] = gsk_color_node_new (&(GdkRGBA){ 0, 0, 0, 1},
&GRAPHENE_RECT_INIT (bounds.origin.x + 25, bounds.origin.y + 25, bounds.size.width - 25, bounds.size.height - 25));
mask_node = gsk_container_node_new (nodes, G_N_ELEMENTS (nodes));
gsk_render_node_unref (nodes[0]);
gsk_render_node_unref (nodes[1]);
}
else
{
mask_node = nodes[0];
}
node2 = gsk_mask_node_new (node, mask_node, GSK_MASK_MODE_ALPHA);
gsk_render_node_unref (mask_node);
save_node (node2, node_file, "-masked.node");
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
save_image (rendered_texture, node_file, "-masked.out.png");
pixbuf = gdk_pixbuf_new_from_file (png_file, &error);
pixbuf2 = apply_mask_to_pixbuf (pixbuf);
reference_texture = gdk_texture_new_for_pixbuf (pixbuf2);
g_object_unref (pixbuf2);
g_object_unref (pixbuf);
save_image (reference_texture, node_file, "-masked.ref.png");
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_image (diff_texture, node_file, "-masked.diff.png");
g_object_unref (diff_texture);
success = FALSE;
}
g_clear_object (&rendered_texture);
g_clear_object (&reference_texture);
gsk_render_node_unref (node2);
}
if (replay)
{
GskRenderNode *node2;
GdkTexture *rendered_texture2;
graphene_rect_t node_bounds, node2_bounds;
GtkSnapshot *snapshot = gtk_snapshot_new ();
replay_node (node, snapshot);
node2 = gtk_snapshot_free_to_node (snapshot);
/* If the whole render node tree got eliminated, make sure we have
something to work with nevertheless. */
if (!node2)
node2 = gsk_container_node_new (NULL, 0);
gsk_render_node_get_bounds (node, &node_bounds);
gsk_render_node_get_bounds (node2, &node2_bounds);
/* Check that the node didn't grow. */
success = success && graphene_rect_contains_rect (&node_bounds, &node2_bounds);
rendered_texture = gsk_renderer_render_texture (renderer, node, &node_bounds);
rendered_texture2 = gsk_renderer_render_texture (renderer, node2, &node_bounds);
g_assert_nonnull (rendered_texture);
g_assert_nonnull (rendered_texture2);
diff_texture = reftest_compare_textures (rendered_texture, rendered_texture2);
if (diff_texture)
{
save_image (diff_texture, node_file, "-replayed.diff.png");
save_node (node2, node_file, "-replayed.node");
g_object_unref (diff_texture);
success = FALSE;
}
g_clear_object (&rendered_texture);
g_clear_object (&rendered_texture2);
gsk_render_node_unref (node2);
}
gsk_render_node_unref (node);
retval = g_test_run ();
gsk_renderer_unrealize (renderer);
g_object_unref (renderer);
gdk_surface_destroy (window);
gdk_display_close (gdk_display_get_default ());
return success ? 0 : 1;
return retval;
}

View File

@@ -4,137 +4,32 @@ compare_render = executable('compare-render',
c_args: common_cflags,
)
node_parser = executable('node-parser', 'node-parser.c',
dependencies: libgtk_dep,
c_args: common_cflags,
)
compare_render_tests = [
'big-checkerboard',
'big-checkerboard-scaled-down',
'big-checkerboard-scaled-down-nearest',
'big-checkerboard-scaled-down2',
'blend-difference',
'blend-modes',
'blend-invisible-child',
'blend-in-rotate',
'blend-normal',
'blurred-lines',
'blur-contents-outside-of-clip',
'border-bottom-right',
'border-one-rounded',
'borders-rotated',
'borders-scaled',
'clip-coordinates-2d',
'clip-coordinates-3d',
'clip-in-rounded-clip1',
'clip-in-rounded-clip2',
'clip-in-rounded-clip3',
'clipped-repeat',
'clipped_rounded_clip',
'clip-nested1',
'clip-translate-offscreen',
'color-blur0',
'color-matrix-identity',
'color-matrix-merge',
'color-matrix-parsing',
'crossfade-clip-both-children',
'cross-fade-in-opacity',
'cross-fade-in-rotate',
'css-background',
'empty-blend',
'empty-blur',
'empty-border',
'empty-cairo',
'empty-clip',
'empty-color',
'empty-color-matrix',
'empty-container',
'empty-cross-fade',
'empty-debug',
'empty-inset-shadow',
'empty-linear-gradient',
'empty-mask',
'empty-opacity',
'empty-outset-shadow',
'empty-repeat',
'empty-rounded-clip',
'empty-shadow',
'empty-texture',
'empty-transform',
'fill',
'huge-height',
'huge-width',
'inset-shadow-multiple',
'invalid-transform',
'issue-3615',
'mask',
'mask-clipped-inverted-alpha',
'mask-modes',
'mask-modes-with-alpha',
'mask-texture-color-alpha',
'nested-rounded-clips',
'opacity_clip',
'opacity-colormatrix-combinations',
'opacity-overdraw',
'opacity-overlapping-children',
'outset_shadow_offset_both',
'outset_shadow_offset_x',
'outset_shadow_offset_y',
'outset_shadow_rounded_top',
'outset_shadow_simple',
'repeat',
'repeating-linear-gradient-edge-colors',
'repeating-radial-gradient-edge-colors',
'repeat-no-repeat',
'repeat-empty-child-bounds',
'repeat-negative-coords',
'repeat-texture',
'repeating-gradient-scaled',
'scale-textures-negative-ngl',
'scale-up-down',
'scaled-cairo',
'scaled-texture',
'scaled-texture-scale',
'shadow-behind',
'shadow-clip-contents',
'shadow-in-opacity',
'shadow-opacity',
'shrink-rounded-border',
'stroke',
'texture-coords',
'texture-scale-filters-3d',
'texture-scale-magnify-10000x',
'texture-scale-magnify-rotate',
'texture-scale-nearest-vs-linear',
'texture-scale-offset',
'texture-scale-stripes',
'texture-url',
'transform-in-transform',
'transform-in-transform-in-transform',
'z-transform-clipping-bounds-3d',
]
# these are too sensitive to differences in the renderers
# to run in ci, but still useful to keep around
informative_render_tests = [
'big-glyph',
'empty-text',
'huge-glyph',
'rounded-clip-in-clip-3d', # both cairo and gl fail this one
]
renderers = [
{ 'name': 'gl' },
{ 'name': 'broadway', 'exclude_term': '-3d' },
{ 'name': 'cairo', 'exclude_term': '-3d' },
]
compare_xfails = [
skips = [
# these are too sensitive to differences in the renderers
# to run in ci, but still useful to keep around
'--skip', 'big-glyph.node',
'--skip', 'empty-text.node',
'--skip', 'huge-glyph.node',
'--skip', 'rounded-clip-in-clip-3d.node',
# Both tests fail because of some font rendering issue
'empty-linear-gradient',
'unaligned-offscreen',
'upside-down-label-3d', # not really 3d, but cairo fails it
'--skip', 'empty-linear-gradient.node',
'--skip', 'unaligned-offscreen.node',
# not really 3d, but cairo fails it
'--skip', 'upside-down-label-3d',
]
gl_skips = [
# the GL renderer mishandles transforms with offscreens
'--skip', 'blend-in-rotate',
'--skip', 'cross-fade-in-opacity',
'--skip', 'opacity-overlapping-children',
'--skip', 'scaled-texture-scale',
'--skip', 'shadow-opacity',
'--skip', 'texture-scale-nearest-vs-linear',
#'--skip', 'blend-normal',
#'--skip', 'color-matrix-merge',
#'--skip', 'color-matrix-parsing',
#'--skip', 'empty-debug',
]
compare_xfails_small_texture = [
@@ -143,241 +38,70 @@ compare_xfails_small_texture = [
'big-checkerboard-scaled-down2'
]
foreach renderer : renderers
foreach testname : compare_render_tests
test('comparerender-gl', compare_render,
args: skips + gl_skips + [
'-k',
'--verbose',
'--dir', '@0@/compare'.format(meson.current_source_dir()),
'--output', '@0@/compare/gl'.format(meson.current_build_dir()),
],
env: [
'GSK_RENDERER=gl',
'GTK_A11Y=test',
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
],
protocol: 'tap',
suite: [ 'gsk', 'gsk-compare', 'gsk-gl'],
)
renderer_name = renderer.get('name')
exclude_term = renderer.get('exclude_term', '')
test('comparerender-broadway', compare_render,
args: skips + [
'--skip', '-3d',
'--dir', '@0@/compare'.format(meson.current_source_dir()),
'--output', '@0@/compare/broadway'.format(meson.current_build_dir()),
],
env: [
'GSK_RENDERER=broadway',
'GTK_A11Y=test',
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
],
protocol: 'tap',
suite: [ 'gsk', 'gsk-compare', 'gsk-broadway'],
)
suites = [
'gsk',
'gsk-compare',
'gsk-' + renderer_name,
'gsk-compare-' + renderer_name,
]
test('comparerender-cairo', compare_render,
args: skips + [
'--skip', '-3d',
'--dir', '@0@/compare'.format(meson.current_source_dir()),
'--output', '@0@/compare/cairo'.format(meson.current_build_dir()),
],
env: [
'GSK_RENDERER=cairo',
'GTK_A11Y=test',
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
],
protocol: 'tap',
suite: [ 'gsk', 'gsk-compare', 'gsk-cairo'],
)
if compare_xfails.contains(testname)
suites += 'failing'
endif
node_parser = executable('node-parser', 'node-parser.c',
dependencies: libgtk_dep,
c_args: common_cflags,
)
if compare_xfails_small_texture.contains(testname)
suites += 'wayland_gles2_failing'
endif
test_env = [
'GSK_RENDERER=' + renderer_name,
'GTK_A11Y=test',
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
]
if ((exclude_term == '' or not testname.contains(exclude_term)) and
(renderer_name != 'broadway' or broadway_enabled))
test(renderer_name + ' ' + testname, compare_render,
args: [
'--output', join_paths(meson.current_build_dir(), 'compare', renderer_name),
join_paths(meson.current_source_dir(), 'compare', testname + '.node'),
join_paths(meson.current_source_dir(), 'compare', testname + '.png'),
],
env: test_env,
suite: suites,
)
test(renderer_name + ' ' + testname + ' flipped', compare_render,
args: [
'--flip',
'--output', join_paths(meson.current_build_dir(), 'compare', renderer_name),
join_paths(meson.current_source_dir(), 'compare', testname + '.node'),
join_paths(meson.current_source_dir(), 'compare', testname + '.png'),
],
env: test_env,
suite: suites + [ 'gsk-compare-flipped-' + renderer_name ],
)
test(renderer_name + ' ' + testname + ' repeated', compare_render,
args: [
'--repeat',
'--output', join_paths(meson.current_build_dir(), 'compare', renderer_name),
join_paths(meson.current_source_dir(), 'compare', testname + '.node'),
join_paths(meson.current_source_dir(), 'compare', testname + '.png'),
],
env: test_env,
suite: suites + [ 'gsk-compare-repeated-' + renderer_name ],
)
test(renderer_name + ' ' + testname + ' rotated', compare_render,
args: [
'--rotate',
'--output', join_paths(meson.current_build_dir(), 'compare', renderer_name),
join_paths(meson.current_source_dir(), 'compare', testname + '.node'),
join_paths(meson.current_source_dir(), 'compare', testname + '.png'),
],
env: test_env,
suite: suites + [ 'gsk-compare-rotated-' + renderer_name ],
)
test(renderer_name + ' ' + testname + ' masked', compare_render,
args: [
'--mask',
'--output', join_paths(meson.current_build_dir(), 'compare', renderer_name),
join_paths(meson.current_source_dir(), 'compare', testname + '.node'),
join_paths(meson.current_source_dir(), 'compare', testname + '.png'),
],
env: test_env,
suite: suites + [ 'gsk-compare-masked-' + renderer_name ],
)
test(renderer_name + ' ' + testname + ' replayed', compare_render,
args: [
'--replay',
'--output', join_paths(meson.current_build_dir(), 'compare', renderer_name),
join_paths(meson.current_source_dir(), 'compare', testname + '.node'),
join_paths(meson.current_source_dir(), 'compare', testname + '.png'),
],
env: test_env,
suite: suites + [ 'gsk-compare-replayed-' + renderer_name ],
)
endif
endforeach
endforeach
node_parser_tests = [
'blend.node',
'blend-unknown-mode.errors',
'blend-unknown-mode.node',
'blend-unknown-mode.ref.node',
'border.node',
'color.node',
'conic-gradient.node',
'conic-gradient.ref.node',
'crash1.errors',
'crash1.node',
'crash1.ref.node',
'crash2.errors',
'crash2.node',
'crash2.ref.node',
'crash3.node',
'crash3.ref.node',
'crash4.errors',
'crash4.node',
'crash4.ref.node',
'debug.node',
'debug-fail.node',
'debug-fail.ref.node',
'debug-fail.errors',
'empty-blend.node',
'empty-blend.ref.node',
'empty-blur.node',
'empty-blur.ref.node',
'empty-border.node',
'empty-border.ref.node',
'empty-cairo.node',
'empty-cairo.ref.node',
'empty-clip.node',
'empty-clip.ref.node',
'empty-color.node',
'empty-color.ref.node',
'empty-color-matrix.node',
'empty-color-matrix.ref.node',
'empty-container.node',
'empty-container.ref.node',
'empty-cross-fade.node',
'empty-cross-fade.ref.node',
'empty-debug.node',
'empty-debug.ref.node',
'empty-fill.node',
'empty-fill.ref.node',
'empty-inset-shadow.node',
'empty-inset-shadow.ref.node',
'empty-linear-gradient.node',
'empty-linear-gradient.ref.node',
'empty-mask.node',
'empty-mask.ref.node',
'empty-opacity.node',
'empty-opacity.ref.node',
'empty-outset-shadow.node',
'empty-outset-shadow.ref.node',
'empty-repeat.node',
'empty-repeat.ref.node',
'empty-rounded-clip.node',
'empty-rounded-clip.ref.node',
'empty-shadow.node',
'empty-shadow.ref.node',
'empty-stroke.node',
'empty-stroke.ref.node',
'empty-text.node',
'empty-text.ref.node',
'empty-texture.node',
'empty-texture.ref.node',
'empty-texture-scale.node',
'empty-texture-scale.ref.node',
'empty-transform.node',
'empty-transform.ref.node',
'fill.node',
'fill.ref.node',
'fill2.node',
'fill2.ref.node',
'glshader.node',
'glshader.ref.node',
'glshader.errors',
'gradient-fail.node',
'gradient-fail.ref.node',
'gradient-fail.errors',
'mask-modes.node',
'mask-modes.ref.node',
'node-names.node',
'node-names-everywhere.errors',
'node-names-everywhere.node',
'node-names-everywhere.ref.node',
'radial-gradient.node',
'radial-gradient.ref.node',
'repeating-linear-gradient.node',
'repeating-linear-gradient.ref.node',
'repeating-radial-gradient.node',
'repeating-radial-gradient.ref.node',
'rounded-rect.node',
'shadow.node',
'shadow-fail.node',
'shadow-fail.ref.node',
'shadow-fail.errors',
'string-error.errors',
'string-error.node',
'string-error.ref.node',
'stroke.node',
'stroke.ref.node',
'testswitch.node',
'text-color.node',
'text-fail.node',
'text-fail.ref.node',
'text-fail.errors',
'text-no-color.node',
'texture-fail.node',
'texture-fail.ref.node',
'texture-fail.ref.errors',
'texture-names.node',
'texture-scale-filters.node',
'texture-scale-filters.ref.node',
'texture-scale-unknown-filter.errors',
'texture-scale-unknown-filter.node',
'texture-scale-unknown-filter.ref.node',
'transform-fail.node',
'transform-fail.ref.node',
'transform-fail.errors',
'widgetfactory.node',
]
foreach test : node_parser_tests
if test.endswith('.node') and not test.endswith('.ref.node')
test('parser ' + test, node_parser,
args: [
join_paths(meson.current_source_dir(), 'nodeparser', test)
],
env: [
'GSK_RENDERER=opengl',
'GTK_A11Y=test',
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
],
protocol: 'exitcode',
suite: 'gsk',
)
endif
endforeach
test('nodeparser', node_parser,
env: [
'GSK_RENDERER=opengl',
'GTK_A11Y=test',
'G_TEST_SRCDIR=@0@/nodeparser'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
],
protocol: 'tap',
suite: 'gsk',
)
# offload does not work outside of linux
if os_linux
@@ -386,32 +110,16 @@ if os_linux
c_args: common_cflags,
)
offload_tests = [
'simple.node',
'transforms.node',
'deep.node',
'move.node',
'start_offloading.node',
'stop_offloading.node',
]
foreach test : offload_tests
if test.endswith('.node') and not test.endswith('.out')
test('parser ' + test, offload,
args: [
join_paths(meson.current_source_dir(), 'offload', test)
],
env: [
'GSK_RENDERER=opengl',
'GTK_A11Y=test',
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
],
protocol: 'exitcode',
suite: 'gsk',
)
endif
endforeach
test('offload', offload,
env: [
'GSK_RENDERER=opengl',
'GTK_A11Y=test',
'G_TEST_SRCDIR=@0@/offload'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
],
protocol: 'tap',
suite: 'gsk',
)
endif
tests = [
@@ -449,14 +157,14 @@ foreach t : tests
endforeach
internal_tests = [
[ 'boundingbox'],
[ 'curve' ],
[ 'curve-special-cases' ],
[ 'path-private' ],
[ 'diff' ],
[ 'half-float' ],
[ 'misc'],
[ 'path-private' ],
[ 'rounded-rect'],
['rounded-rect'],
['misc'],
['boundingbox'],
]
foreach t : internal_tests

View File

@@ -246,6 +246,12 @@ test_file (GFile *file)
return parse_node_file (file, FALSE);
}
static void
test_one_file (gconstpointer data)
{
test_file (G_FILE (data));
}
static int
compare_files (gconstpointer a, gconstpointer b)
{
@@ -272,7 +278,6 @@ test_files_in_directory (GFile *dir)
GFileInfo *info;
GList *l, *files;
GError *error = NULL;
gboolean result = TRUE;
enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
g_assert_no_error (error);
@@ -296,18 +301,28 @@ test_files_in_directory (GFile *dir)
g_object_unref (info);
}
g_assert_no_error (error);
g_object_unref (enumerator);
files = g_list_sort (files, compare_files);
for (l = files; l; l = l->next)
{
result &= test_file (l->data);
GFile *file = l->data;
char *name;
char *path;
name = g_file_get_basename (file);
path = g_strconcat ("/gsk/offload/", name, NULL);
g_test_add_data_func_full (path, g_object_ref (file), test_one_file, g_object_unref);
g_free (name);
g_free (path);
}
g_list_free_full (files, g_object_unref);
return result;
return g_test_run ();
}
int
@@ -324,7 +339,7 @@ main (int argc, char **argv)
basedir = g_test_get_dir (G_TEST_DIST);
dir = g_file_new_for_path (basedir);
success = test_files_in_directory (dir);
success = !test_files_in_directory (dir);
g_object_unref (dir);
}

View File

@@ -495,6 +495,12 @@ test_file (GFile *file)
return parse_node_file (file, FALSE);
}
static void
test_one_file (gconstpointer data)
{
test_file (G_FILE (data));
}
static int
compare_files (gconstpointer a, gconstpointer b)
{
@@ -521,7 +527,6 @@ test_files_in_directory (GFile *dir)
GFileInfo *info;
GList *l, *files;
GError *error = NULL;
gboolean result = TRUE;
enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
g_assert_no_error (error);
@@ -550,11 +555,21 @@ test_files_in_directory (GFile *dir)
files = g_list_sort (files, compare_files);
for (l = files; l; l = l->next)
{
result &= test_file (l->data);
GFile *file = l->data;
char *name;
char *path;
name = g_file_get_basename (file);
path = g_strconcat ("/gsk/offload/", name, NULL);
g_test_add_data_func_full (path, g_object_ref (file), test_one_file, g_object_unref);
g_free (name);
g_free (path);
}
g_list_free_full (files, g_object_unref);
return result;
return g_test_run ();
}
int
@@ -571,7 +586,7 @@ main (int argc, char **argv)
basedir = g_test_get_dir (G_TEST_DIST);
dir = g_file_new_for_path (basedir);
success = test_files_in_directory (dir);
success = !test_files_in_directory (dir);
g_object_unref (dir);
}