2016-12-21 06:20:28 +00:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
2016-12-23 06:07:59 +00:00
|
|
|
static gboolean benchmark = FALSE;
|
|
|
|
static gboolean dump_variant = FALSE;
|
2016-12-22 17:58:55 +00:00
|
|
|
static gboolean fallback = FALSE;
|
2016-12-25 18:51:30 +00:00
|
|
|
static int runs = 1;
|
2016-12-22 17:58:55 +00:00
|
|
|
|
2016-12-21 06:20:28 +00:00
|
|
|
static GOptionEntry options[] = {
|
2016-12-23 06:07:59 +00:00
|
|
|
{ "benchmark", 'b', 0, G_OPTION_ARG_NONE, &benchmark, "Time operations", NULL },
|
|
|
|
{ "dump-variant", 'd', 0, G_OPTION_ARG_NONE, &dump_variant, "Dump GVariant structure", NULL },
|
2016-12-22 17:58:55 +00:00
|
|
|
{ "fallback", '\0', 0, G_OPTION_ARG_NONE, &fallback, "Draw node without a renderer", NULL },
|
2016-12-25 05:18:42 +00:00
|
|
|
{ "runs", 'r', 0, G_OPTION_ARG_INT, &runs, "Render the test N times", "N" },
|
2016-12-21 06:20:28 +00:00
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
2019-04-24 16:30:46 +00:00
|
|
|
static void
|
2020-11-17 03:21:27 +00:00
|
|
|
deserialize_error_func (const GskParseLocation *start,
|
|
|
|
const GskParseLocation *end,
|
|
|
|
const GError *error,
|
|
|
|
gpointer user_data)
|
2019-04-24 16:30:46 +00:00
|
|
|
{
|
2020-11-17 03:21:27 +00:00
|
|
|
GString *string = g_string_new ("<data>");
|
2019-04-24 16:30:46 +00:00
|
|
|
|
2020-11-17 03:21:27 +00:00
|
|
|
g_string_append_printf (string, ":%zu:%zu",
|
|
|
|
start->lines + 1, start->line_chars + 1);
|
|
|
|
if (start->lines != end->lines || start->line_chars != end->line_chars)
|
|
|
|
{
|
|
|
|
g_string_append (string, "-");
|
|
|
|
if (start->lines != end->lines)
|
|
|
|
g_string_append_printf (string, "%zu:", end->lines + 1);
|
|
|
|
g_string_append_printf (string, "%zu", end->line_chars + 1);
|
|
|
|
}
|
2019-04-24 16:30:46 +00:00
|
|
|
|
2020-11-17 03:21:27 +00:00
|
|
|
g_warning ("Error at %s: %s", string->str, error->message);
|
|
|
|
|
|
|
|
g_string_free (string, TRUE);
|
2019-04-24 16:30:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-21 06:20:28 +00:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
cairo_surface_t *surface;
|
|
|
|
GskRenderNode *node;
|
|
|
|
GError *error = NULL;
|
|
|
|
GBytes *bytes;
|
2016-12-23 06:07:59 +00:00
|
|
|
gint64 start, end;
|
2016-12-21 06:20:28 +00:00
|
|
|
char *contents;
|
|
|
|
gsize len;
|
2016-12-25 05:18:42 +00:00
|
|
|
int run;
|
2016-12-28 13:53:22 +00:00
|
|
|
GOptionContext *context;
|
2021-09-15 15:21:24 +00:00
|
|
|
GdkTexture *texture;
|
2016-12-21 06:20:28 +00:00
|
|
|
|
2016-12-28 13:53:22 +00:00
|
|
|
context = g_option_context_new ("NODE-FILE PNG-FILE");
|
|
|
|
g_option_context_add_main_entries (context, options, NULL);
|
|
|
|
if (!g_option_context_parse (context, &argc, &argv, &error))
|
2016-12-21 06:20:28 +00:00
|
|
|
{
|
|
|
|
g_printerr ("Option parsing failed: %s\n", error->message);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-12-28 13:53:22 +00:00
|
|
|
gtk_init ();
|
|
|
|
|
2016-12-25 18:51:30 +00:00
|
|
|
if (runs < 1)
|
|
|
|
{
|
|
|
|
g_printerr ("Number of runs given with -r/--runs must be at least 1 and not %d.\n", runs);
|
|
|
|
return 1;
|
|
|
|
}
|
2016-12-25 05:19:34 +00:00
|
|
|
if (!(argc == 3 || (argc == 2 && (dump_variant || benchmark))))
|
2016-12-21 06:20:28 +00:00
|
|
|
{
|
|
|
|
g_printerr ("Usage: %s [OPTIONS] NODE-FILE PNG-FILE\n", argv[0]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!g_file_get_contents (argv[1], &contents, &len, &error))
|
|
|
|
{
|
|
|
|
g_printerr ("Could not open node file: %s\n", error->message);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytes = g_bytes_new_take (contents, len);
|
2016-12-23 06:07:59 +00:00
|
|
|
if (dump_variant)
|
|
|
|
{
|
|
|
|
GVariant *variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("(suuv)"), bytes, FALSE);
|
2016-12-26 16:07:24 +00:00
|
|
|
char *s;
|
2016-12-23 06:07:59 +00:00
|
|
|
|
2016-12-26 16:07:24 +00:00
|
|
|
s = g_variant_print (variant, FALSE);
|
|
|
|
g_print ("%s\n", s);
|
|
|
|
g_free (s);
|
2016-12-23 06:07:59 +00:00
|
|
|
g_variant_unref (variant);
|
|
|
|
}
|
|
|
|
|
|
|
|
start = g_get_monotonic_time ();
|
2019-04-24 16:30:46 +00:00
|
|
|
node = gsk_render_node_deserialize (bytes, deserialize_error_func, NULL);
|
2016-12-23 06:07:59 +00:00
|
|
|
end = g_get_monotonic_time ();
|
|
|
|
if (benchmark)
|
|
|
|
{
|
|
|
|
char *bytes_string = g_format_size (g_bytes_get_size (bytes));
|
|
|
|
g_print ("Loaded %s in %.4gs\n", bytes_string, (double) (end - start) / G_USEC_PER_SEC);
|
|
|
|
g_free (bytes_string);
|
|
|
|
}
|
2016-12-21 06:20:28 +00:00
|
|
|
g_bytes_unref (bytes);
|
|
|
|
|
|
|
|
if (node == NULL)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-12-23 10:30:09 +00:00
|
|
|
if (fallback)
|
2016-12-22 17:58:55 +00:00
|
|
|
{
|
2016-12-23 10:30:09 +00:00
|
|
|
graphene_rect_t bounds;
|
|
|
|
cairo_t *cr;
|
2021-09-15 15:21:24 +00:00
|
|
|
int width, height, stride;
|
|
|
|
guchar *pixels;
|
2016-12-23 06:07:59 +00:00
|
|
|
|
2016-12-23 10:30:09 +00:00
|
|
|
gsk_render_node_get_bounds (node, &bounds);
|
2021-09-15 15:21:24 +00:00
|
|
|
width = ceil (bounds.size.width);
|
|
|
|
height = ceil (bounds.size.height);
|
|
|
|
stride = width * 4;
|
|
|
|
pixels = g_malloc0_n (stride, height);
|
|
|
|
|
|
|
|
surface = cairo_image_surface_create_for_data (pixels, CAIRO_FORMAT_ARGB32, width, height, stride);
|
2016-12-23 10:30:09 +00:00
|
|
|
cr = cairo_create (surface);
|
2016-12-23 06:07:59 +00:00
|
|
|
|
2016-12-23 10:30:09 +00:00
|
|
|
cairo_translate (cr, - bounds.origin.x, - bounds.origin.y);
|
2016-12-25 05:18:42 +00:00
|
|
|
for (run = 0; run < runs; run++)
|
|
|
|
{
|
|
|
|
if (run > 0)
|
|
|
|
{
|
|
|
|
cairo_save (cr);
|
|
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
|
|
|
cairo_paint (cr);
|
|
|
|
cairo_restore (cr);
|
|
|
|
}
|
|
|
|
start = g_get_monotonic_time ();
|
|
|
|
gsk_render_node_draw (node, cr);
|
|
|
|
end = g_get_monotonic_time ();
|
|
|
|
if (benchmark)
|
|
|
|
g_print ("Run %d: Rendered fallback in %.4gs\n", run, (double) (end - start) / G_USEC_PER_SEC);
|
|
|
|
}
|
2016-12-23 06:07:59 +00:00
|
|
|
|
2016-12-23 10:30:09 +00:00
|
|
|
cairo_destroy (cr);
|
2021-09-15 15:21:24 +00:00
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
|
|
|
|
bytes = g_bytes_new_take (pixels, stride * height);
|
|
|
|
texture = gdk_memory_texture_new (width, height,
|
|
|
|
GDK_MEMORY_DEFAULT,
|
|
|
|
bytes,
|
|
|
|
stride);
|
|
|
|
g_bytes_unref (bytes);
|
2016-12-23 10:30:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GskRenderer *renderer;
|
2018-03-20 10:40:08 +00:00
|
|
|
GdkSurface *window;
|
2016-12-23 10:30:09 +00:00
|
|
|
|
2020-07-30 21:06:59 +00:00
|
|
|
window = gdk_surface_new_toplevel (gdk_display_get_default());
|
2018-03-20 11:05:26 +00:00
|
|
|
renderer = gsk_renderer_new_for_surface (window);
|
2021-09-15 15:21:24 +00:00
|
|
|
texture = NULL; /* poor gcc can't see that runs > 0 */
|
2016-12-23 10:30:09 +00:00
|
|
|
|
2016-12-25 05:18:42 +00:00
|
|
|
for (run = 0; run < runs; run++)
|
|
|
|
{
|
|
|
|
if (run > 0)
|
2017-01-01 12:40:13 +00:00
|
|
|
g_object_unref (texture);
|
2016-12-25 05:18:42 +00:00
|
|
|
start = g_get_monotonic_time ();
|
|
|
|
texture = gsk_renderer_render_texture (renderer, node, NULL);
|
|
|
|
end = g_get_monotonic_time ();
|
|
|
|
if (benchmark)
|
|
|
|
g_print ("Run %u: Rendered using %s in %.4gs\n", run, G_OBJECT_TYPE_NAME (renderer), (double) (end - start) / G_USEC_PER_SEC);
|
|
|
|
}
|
|
|
|
|
2018-02-02 14:34:34 +00:00
|
|
|
gsk_renderer_unrealize (renderer);
|
2016-12-23 10:30:09 +00:00
|
|
|
g_object_unref (window);
|
|
|
|
g_object_unref (renderer);
|
|
|
|
}
|
|
|
|
|
|
|
|
gsk_render_node_unref (node);
|
2016-12-23 06:07:59 +00:00
|
|
|
|
2016-12-23 10:30:09 +00:00
|
|
|
if (argc > 2)
|
|
|
|
{
|
2021-09-15 15:21:24 +00:00
|
|
|
if (!gdk_texture_save_to_png (texture, argv[2]))
|
2016-12-23 06:07:59 +00:00
|
|
|
{
|
2021-09-15 15:21:24 +00:00
|
|
|
g_object_unref (texture);
|
|
|
|
g_print ("Failed to save PNG file\n");
|
2016-12-23 06:07:59 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2016-12-21 06:20:28 +00:00
|
|
|
}
|
|
|
|
|
2021-09-15 15:21:24 +00:00
|
|
|
g_object_unref (texture);
|
2016-12-23 10:30:09 +00:00
|
|
|
|
2016-12-21 06:20:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|