1#include <gtk/gtk.h>
2
3static gboolean benchmark = FALSE;
4static gboolean dump_variant = FALSE;
5static gboolean fallback = FALSE;
6static int runs = 1;
7
8static GOptionEntry options[] = {
9 { "benchmark", 'b', 0, G_OPTION_ARG_NONE, &benchmark, "Time operations", NULL },
10 { "dump-variant", 'd', 0, G_OPTION_ARG_NONE, &dump_variant, "Dump GVariant structure", NULL },
11 { "fallback", '\0', 0, G_OPTION_ARG_NONE, &fallback, "Draw node without a renderer", NULL },
12 { "runs", 'r', 0, G_OPTION_ARG_INT, &runs, "Render the test N times", "N" },
13 { NULL }
14};
15
16static void
17deserialize_error_func (const GskParseLocation *start,
18 const GskParseLocation *end,
19 const GError *error,
20 gpointer user_data)
21{
22 GString *string = g_string_new (init: "<data>");
23
24 g_string_append_printf (string, format: ":%zu:%zu",
25 start->lines + 1, start->line_chars + 1);
26 if (start->lines != end->lines || start->line_chars != end->line_chars)
27 {
28 g_string_append (string, val: "-");
29 if (start->lines != end->lines)
30 g_string_append_printf (string, format: "%zu:", end->lines + 1);
31 g_string_append_printf (string, format: "%zu", end->line_chars + 1);
32 }
33
34 g_warning ("Error at %s: %s", string->str, error->message);
35
36 g_string_free (string, TRUE);
37}
38
39
40int
41main(int argc, char **argv)
42{
43 cairo_surface_t *surface;
44 GskRenderNode *node;
45 GError *error = NULL;
46 GBytes *bytes;
47 gint64 start, end;
48 char *contents;
49 gsize len;
50 int run;
51 GOptionContext *context;
52 GdkTexture *texture;
53
54 context = g_option_context_new (parameter_string: "NODE-FILE PNG-FILE");
55 g_option_context_add_main_entries (context, entries: options, NULL);
56 if (!g_option_context_parse (context, argc: &argc, argv: &argv, error: &error))
57 {
58 g_printerr (format: "Option parsing failed: %s\n", error->message);
59 return 1;
60 }
61
62 gtk_init ();
63
64 if (runs < 1)
65 {
66 g_printerr (format: "Number of runs given with -r/--runs must be at least 1 and not %d.\n", runs);
67 return 1;
68 }
69 if (!(argc == 3 || (argc == 2 && (dump_variant || benchmark))))
70 {
71 g_printerr (format: "Usage: %s [OPTIONS] NODE-FILE PNG-FILE\n", argv[0]);
72 return 1;
73 }
74
75 if (!g_file_get_contents (filename: argv[1], contents: &contents, length: &len, error: &error))
76 {
77 g_printerr (format: "Could not open node file: %s\n", error->message);
78 return 1;
79 }
80
81 bytes = g_bytes_new_take (data: contents, size: len);
82 if (dump_variant)
83 {
84 GVariant *variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("(suuv)"), bytes, FALSE);
85 char *s;
86
87 s = g_variant_print (value: variant, FALSE);
88 g_print (format: "%s\n", s);
89 g_free (mem: s);
90 g_variant_unref (value: variant);
91 }
92
93 start = g_get_monotonic_time ();
94 node = gsk_render_node_deserialize (bytes, error_func: deserialize_error_func, NULL);
95 end = g_get_monotonic_time ();
96 if (benchmark)
97 {
98 char *bytes_string = g_format_size (size: g_bytes_get_size (bytes));
99 g_print (format: "Loaded %s in %.4gs\n", bytes_string, (double) (end - start) / G_USEC_PER_SEC);
100 g_free (mem: bytes_string);
101 }
102 g_bytes_unref (bytes);
103
104 if (node == NULL)
105 {
106 return 1;
107 }
108
109 if (fallback)
110 {
111 graphene_rect_t bounds;
112 cairo_t *cr;
113 int width, height, stride;
114 guchar *pixels;
115
116 gsk_render_node_get_bounds (node, bounds: &bounds);
117 width = ceil (x: bounds.size.width);
118 height = ceil (x: bounds.size.height);
119 stride = width * 4;
120 pixels = g_malloc0_n (n_blocks: stride, n_block_bytes: height);
121
122 surface = cairo_image_surface_create_for_data (data: pixels, format: CAIRO_FORMAT_ARGB32, width, height, stride);
123 cr = cairo_create (target: surface);
124
125 cairo_translate (cr, tx: - bounds.origin.x, ty: - bounds.origin.y);
126 for (run = 0; run < runs; run++)
127 {
128 if (run > 0)
129 {
130 cairo_save (cr);
131 cairo_set_operator (cr, op: CAIRO_OPERATOR_CLEAR);
132 cairo_paint (cr);
133 cairo_restore (cr);
134 }
135 start = g_get_monotonic_time ();
136 gsk_render_node_draw (node, cr);
137 end = g_get_monotonic_time ();
138 if (benchmark)
139 g_print (format: "Run %d: Rendered fallback in %.4gs\n", run, (double) (end - start) / G_USEC_PER_SEC);
140 }
141
142 cairo_destroy (cr);
143 cairo_surface_destroy (surface);
144
145 bytes = g_bytes_new_take (data: pixels, size: stride * height);
146 texture = gdk_memory_texture_new (width, height,
147 GDK_MEMORY_DEFAULT,
148 bytes,
149 stride);
150 g_bytes_unref (bytes);
151 }
152 else
153 {
154 GskRenderer *renderer;
155 GdkSurface *window;
156
157 window = gdk_surface_new_toplevel (display: gdk_display_get_default());
158 renderer = gsk_renderer_new_for_surface (surface: window);
159 texture = NULL; /* poor gcc can't see that runs > 0 */
160
161 for (run = 0; run < runs; run++)
162 {
163 if (run > 0)
164 g_object_unref (object: texture);
165 start = g_get_monotonic_time ();
166 texture = gsk_renderer_render_texture (renderer, root: node, NULL);
167 end = g_get_monotonic_time ();
168 if (benchmark)
169 g_print (format: "Run %u: Rendered using %s in %.4gs\n", run, G_OBJECT_TYPE_NAME (renderer), (double) (end - start) / G_USEC_PER_SEC);
170 }
171
172 gsk_renderer_unrealize (renderer);
173 g_object_unref (object: window);
174 g_object_unref (object: renderer);
175 }
176
177 gsk_render_node_unref (node);
178
179 if (argc > 2)
180 {
181 if (!gdk_texture_save_to_png (texture, filename: argv[2]))
182 {
183 g_object_unref (object: texture);
184 g_print (format: "Failed to save PNG file\n");
185 return 1;
186 }
187 }
188
189 g_object_unref (object: texture);
190
191 return 0;
192}
193

source code of gtk/tests/rendernode.c