forked from AuroraMiddleware/gtk
121e61cf01
Using GtkCssSection in public headers here may be ok from the C perspective, since it all ends up in the same library anyway. But it causes circular dependency problems for our gir files that are still split by namespace. To avoid this problem, copy the GtkCssLocation struct struct as GskParseLocation, and pass take two of them instead of a GtkCssSection in the error callback. Update all users. Fixes: #2454
189 lines
5.5 KiB
C
189 lines
5.5 KiB
C
#include <gtk/gtk.h>
|
|
|
|
static gboolean benchmark = FALSE;
|
|
static gboolean dump_variant = FALSE;
|
|
static gboolean fallback = FALSE;
|
|
static int runs = 1;
|
|
|
|
static GOptionEntry options[] = {
|
|
{ "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 },
|
|
{ "fallback", '\0', 0, G_OPTION_ARG_NONE, &fallback, "Draw node without a renderer", NULL },
|
|
{ "runs", 'r', 0, G_OPTION_ARG_INT, &runs, "Render the test N times", "N" },
|
|
{ NULL }
|
|
};
|
|
|
|
static void
|
|
deserialize_error_func (const GskParseLocation *start,
|
|
const GskParseLocation *end,
|
|
const GError *error,
|
|
gpointer user_data)
|
|
{
|
|
GString *string = g_string_new ("<data>");
|
|
|
|
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);
|
|
}
|
|
|
|
g_warning ("Error at %s: %s", string->str, error->message);
|
|
|
|
g_string_free (string, TRUE);
|
|
}
|
|
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
cairo_surface_t *surface;
|
|
GskRenderNode *node;
|
|
GError *error = NULL;
|
|
GBytes *bytes;
|
|
gint64 start, end;
|
|
char *contents;
|
|
gsize len;
|
|
int run;
|
|
GOptionContext *context;
|
|
|
|
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))
|
|
{
|
|
g_printerr ("Option parsing failed: %s\n", error->message);
|
|
return 1;
|
|
}
|
|
|
|
gtk_init ();
|
|
|
|
if (runs < 1)
|
|
{
|
|
g_printerr ("Number of runs given with -r/--runs must be at least 1 and not %d.\n", runs);
|
|
return 1;
|
|
}
|
|
if (!(argc == 3 || (argc == 2 && (dump_variant || benchmark))))
|
|
{
|
|
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);
|
|
if (dump_variant)
|
|
{
|
|
GVariant *variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("(suuv)"), bytes, FALSE);
|
|
char *s;
|
|
|
|
s = g_variant_print (variant, FALSE);
|
|
g_print ("%s\n", s);
|
|
g_free (s);
|
|
g_variant_unref (variant);
|
|
}
|
|
|
|
start = g_get_monotonic_time ();
|
|
node = gsk_render_node_deserialize (bytes, deserialize_error_func, NULL);
|
|
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);
|
|
}
|
|
g_bytes_unref (bytes);
|
|
|
|
if (node == NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if (fallback)
|
|
{
|
|
graphene_rect_t bounds;
|
|
cairo_t *cr;
|
|
|
|
gsk_render_node_get_bounds (node, &bounds);
|
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ceil (bounds.size.width), ceil (bounds.size.height));
|
|
cr = cairo_create (surface);
|
|
|
|
cairo_translate (cr, - bounds.origin.x, - bounds.origin.y);
|
|
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);
|
|
}
|
|
|
|
cairo_destroy (cr);
|
|
}
|
|
else
|
|
{
|
|
GskRenderer *renderer;
|
|
GdkSurface *window;
|
|
GdkTexture *texture = NULL;
|
|
|
|
window = gdk_surface_new_toplevel (gdk_display_get_default());
|
|
renderer = gsk_renderer_new_for_surface (window);
|
|
|
|
for (run = 0; run < runs; run++)
|
|
{
|
|
if (run > 0)
|
|
g_object_unref (texture);
|
|
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);
|
|
}
|
|
|
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
gdk_texture_get_width (texture),
|
|
gdk_texture_get_height (texture));
|
|
gdk_texture_download (texture,
|
|
cairo_image_surface_get_data (surface),
|
|
cairo_image_surface_get_stride (surface));
|
|
cairo_surface_mark_dirty (surface);
|
|
gsk_renderer_unrealize (renderer);
|
|
g_object_unref (texture);
|
|
g_object_unref (window);
|
|
g_object_unref (renderer);
|
|
}
|
|
|
|
gsk_render_node_unref (node);
|
|
|
|
if (argc > 2)
|
|
{
|
|
cairo_status_t status;
|
|
|
|
status = cairo_surface_write_to_png (surface, argv[2]);
|
|
|
|
if (status != CAIRO_STATUS_SUCCESS)
|
|
{
|
|
cairo_surface_destroy (surface);
|
|
g_print ("Failed to save PNG file: %s\n", cairo_status_to_string (status));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
return 0;
|
|
}
|