1 /* GSK - The GTK Scene Kit
2 *
3 * Copyright 2016 Endless
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20 * GskRenderer:
21 *
22 * `GskRenderer` is a class that renders a scene graph defined via a
23 * tree of [class@Gsk.RenderNode] instances.
24 *
25 * Typically you will use a `GskRenderer` instance to repeatedly call
26 * [method@Gsk.Renderer.render] to update the contents of its associated
27 * [class@Gdk.Surface].
28 *
29 * It is necessary to realize a `GskRenderer` instance using
30 * [method@Gsk.Renderer.realize] before calling [method@Gsk.Renderer.render],
31 * in order to create the appropriate windowing system resources needed
32 * to render the scene.
33 */
34
35 #include "config.h"
36
37 #include "gskrendererprivate.h"
38
39 #include "gskcairorenderer.h"
40 #include "gskdebugprivate.h"
41 #include "gl/gskglrenderer.h"
42 #include "ngl/gsknglrenderer.h"
43 #include "gskprofilerprivate.h"
44 #include "gskrendernodeprivate.h"
45
46 #include "gskenumtypes.h"
47
48 #include <graphene-gobject.h>
49 #include <cairo-gobject.h>
50 #include <gdk/gdk.h>
51
52 #ifdef GDK_WINDOWING_X11
53 #include <gdk/x11/gdkx.h>
54 #endif
55 #ifdef GDK_WINDOWING_WAYLAND
56 #include <gdk/wayland/gdkwayland.h>
57 #endif
58 #ifdef GDK_WINDOWING_BROADWAY
59 #include "broadway/gskbroadwayrenderer.h"
60 #endif
61 #ifdef GDK_RENDERING_VULKAN
62 #include "vulkan/gskvulkanrenderer.h"
63 #endif
64 #ifdef GDK_WINDOWING_MACOS
65 #include <gdk/macos/gdkmacos.h>
66 #endif
67 #ifdef GDK_WINDOWING_WIN32
68 #include <gdk/win32/gdkwin32.h>
69
70 /* Remove these lines when OpenGL/ES 2.0 shader is ready */
71 #include "win32/gdkprivate-win32.h"
72 #include "win32/gdkdisplay-win32.h"
73 #endif
74
75 typedef struct
76 {
77 GObject parent_instance;
78
79 GdkSurface *surface;
80 GskRenderNode *prev_node;
81 GskRenderNode *root_node;
82
83 GskProfiler *profiler;
84
85 GskDebugFlags debug_flags;
86
87 gboolean is_realized : 1;
88 } GskRendererPrivate;
89
90 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GskRenderer, gsk_renderer, G_TYPE_OBJECT)
91
92 enum {
93 PROP_0,
94 PROP_REALIZED,
95 PROP_SURFACE,
96
97 N_PROPS
98 };
99
100 static GParamSpec *gsk_renderer_properties[N_PROPS];
101
102 #define GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD(obj,method) \
103 g_critical ("Renderer of type '%s' does not implement GskRenderer::" # method, G_OBJECT_TYPE_NAME (obj))
104
105 static gboolean
gsk_renderer_real_realize(GskRenderer * self,GdkSurface * surface,GError ** error)106 gsk_renderer_real_realize (GskRenderer *self,
107 GdkSurface *surface,
108 GError **error)
109 {
110 GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, realize);
111 return FALSE;
112 }
113
114 static void
gsk_renderer_real_unrealize(GskRenderer * self)115 gsk_renderer_real_unrealize (GskRenderer *self)
116 {
117 GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, unrealize);
118 }
119
120 static GdkTexture *
gsk_renderer_real_render_texture(GskRenderer * self,GskRenderNode * root,const graphene_rect_t * viewport)121 gsk_renderer_real_render_texture (GskRenderer *self,
122 GskRenderNode *root,
123 const graphene_rect_t *viewport)
124 {
125 GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, render_texture);
126 return NULL;
127 }
128
129 static void
gsk_renderer_real_render(GskRenderer * self,GskRenderNode * root,const cairo_region_t * region)130 gsk_renderer_real_render (GskRenderer *self,
131 GskRenderNode *root,
132 const cairo_region_t *region)
133 {
134 GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, render);
135 }
136
137 static void
gsk_renderer_dispose(GObject * gobject)138 gsk_renderer_dispose (GObject *gobject)
139 {
140 GskRenderer *self = GSK_RENDERER (gobject);
141 GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
142
143 /* We can't just unrealize here because superclasses have already run dispose.
144 * So we insist that unrealize must be called before unreffing. */
145 g_assert (!priv->is_realized);
146
147 g_clear_object (&priv->profiler);
148
149 G_OBJECT_CLASS (gsk_renderer_parent_class)->dispose (gobject);
150 }
151
152 static void
gsk_renderer_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * pspec)153 gsk_renderer_get_property (GObject *gobject,
154 guint prop_id,
155 GValue *value,
156 GParamSpec *pspec)
157 {
158 GskRenderer *self = GSK_RENDERER (gobject);
159 GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
160
161 switch (prop_id)
162 {
163 case PROP_REALIZED:
164 g_value_set_boolean (value, priv->is_realized);
165 break;
166
167 case PROP_SURFACE:
168 g_value_set_object (value, priv->surface);
169 break;
170
171 default:
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
173 break;
174 }
175 }
176
177 static void
gsk_renderer_class_init(GskRendererClass * klass)178 gsk_renderer_class_init (GskRendererClass *klass)
179 {
180 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
181
182 klass->realize = gsk_renderer_real_realize;
183 klass->unrealize = gsk_renderer_real_unrealize;
184 klass->render = gsk_renderer_real_render;
185 klass->render_texture = gsk_renderer_real_render_texture;
186
187 gobject_class->get_property = gsk_renderer_get_property;
188 gobject_class->dispose = gsk_renderer_dispose;
189
190 /**
191 * GskRenderer:realized: (attributes org.gtk.Property.get=gsk_renderer_is_realized)
192 *
193 * Whether the renderer has been associated with a surface.
194 */
195 gsk_renderer_properties[PROP_REALIZED] =
196 g_param_spec_boolean ("realized",
197 "Realized",
198 "The renderer has been associated with a surface",
199 FALSE,
200 G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
201
202 /**
203 * GskRenderer:surface: (attributes org.gtk.Property.get=gsk_renderer_get_surface)
204 *
205 * The surface associated with renderer.
206 */
207 gsk_renderer_properties[PROP_SURFACE] =
208 g_param_spec_object ("surface",
209 "Surface",
210 "The surface associated to the renderer",
211 GDK_TYPE_SURFACE,
212 G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
213
214 g_object_class_install_properties (gobject_class, N_PROPS, gsk_renderer_properties);
215 }
216
217 static void
gsk_renderer_init(GskRenderer * self)218 gsk_renderer_init (GskRenderer *self)
219 {
220 GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
221
222 priv->profiler = gsk_profiler_new ();
223 priv->debug_flags = gsk_get_debug_flags ();
224 }
225
226 /**
227 * gsk_renderer_get_surface: (attributes org.gtk.Method.get_property=surface)
228 * @renderer: a `GskRenderer`
229 *
230 * Retrieves the `GdkSurface` set using gsk_enderer_realize().
231 *
232 * If the renderer has not been realized yet, %NULL will be returned.
233 *
234 * Returns: (transfer none) (nullable): a `GdkSurface`
235 */
236 GdkSurface *
gsk_renderer_get_surface(GskRenderer * renderer)237 gsk_renderer_get_surface (GskRenderer *renderer)
238 {
239 GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
240
241 g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
242
243 return priv->surface;
244 }
245
246 /*< private >
247 * gsk_renderer_get_root_node:
248 * @renderer: a `GskRenderer`
249 *
250 * Retrieves the `GskRenderNode` used by @renderer.
251 *
252 * Returns: (transfer none) (nullable): a `GskRenderNode`
253 */
254 GskRenderNode *
gsk_renderer_get_root_node(GskRenderer * renderer)255 gsk_renderer_get_root_node (GskRenderer *renderer)
256 {
257 GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
258
259 g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
260
261 return priv->root_node;
262 }
263
264 /**
265 * gsk_renderer_is_realized: (attributes org.gtk.Method.get_property=realized)
266 * @renderer: a `GskRenderer`
267 *
268 * Checks whether the @renderer is realized or not.
269 *
270 * Returns: %TRUE if the `GskRenderer` was realized, and %FALSE otherwise
271 */
272 gboolean
gsk_renderer_is_realized(GskRenderer * renderer)273 gsk_renderer_is_realized (GskRenderer *renderer)
274 {
275 GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
276
277 g_return_val_if_fail (GSK_IS_RENDERER (renderer), FALSE);
278
279 return priv->is_realized;
280 }
281
282 /**
283 * gsk_renderer_realize:
284 * @renderer: a `GskRenderer`
285 * @surface: the `GdkSurface` renderer will be used on
286 * @error: return location for an error
287 *
288 * Creates the resources needed by the @renderer to render the scene
289 * graph.
290 */
291 gboolean
gsk_renderer_realize(GskRenderer * renderer,GdkSurface * surface,GError ** error)292 gsk_renderer_realize (GskRenderer *renderer,
293 GdkSurface *surface,
294 GError **error)
295 {
296 GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
297
298 g_return_val_if_fail (GSK_IS_RENDERER (renderer), FALSE);
299 g_return_val_if_fail (!gsk_renderer_is_realized (renderer), FALSE);
300 g_return_val_if_fail (GDK_IS_SURFACE (surface), FALSE);
301 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
302
303 priv->surface = g_object_ref (surface);
304
305 if (!GSK_RENDERER_GET_CLASS (renderer)->realize (renderer, surface, error))
306 {
307 g_clear_object (&priv->surface);
308 return FALSE;
309 }
310
311 priv->is_realized = TRUE;
312 return TRUE;
313 }
314
315 /**
316 * gsk_renderer_unrealize:
317 * @renderer: a `GskRenderer`
318 *
319 * Releases all the resources created by gsk_renderer_realize().
320 */
321 void
gsk_renderer_unrealize(GskRenderer * renderer)322 gsk_renderer_unrealize (GskRenderer *renderer)
323 {
324 GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
325
326 g_return_if_fail (GSK_IS_RENDERER (renderer));
327
328 if (!priv->is_realized)
329 return;
330
331 GSK_RENDERER_GET_CLASS (renderer)->unrealize (renderer);
332
333 g_clear_pointer (&priv->prev_node, gsk_render_node_unref);
334
335 priv->is_realized = FALSE;
336 }
337
338 /**
339 * gsk_renderer_render_texture:
340 * @renderer: a realized `GskRenderer`
341 * @root: a `GskRenderNode`
342 * @viewport: (nullable): the section to draw or %NULL to use @root's bounds
343 *
344 * Renders the scene graph, described by a tree of `GskRenderNode` instances,
345 * to a `GdkTexture`.
346 *
347 * The @renderer will acquire a reference on the `GskRenderNode` tree while
348 * the rendering is in progress.
349 *
350 * If you want to apply any transformations to @root, you should put it into a
351 * transform node and pass that node instead.
352 *
353 * Returns: (transfer full): a `GdkTexture` with the rendered contents of @root.
354 */
355 GdkTexture *
gsk_renderer_render_texture(GskRenderer * renderer,GskRenderNode * root,const graphene_rect_t * viewport)356 gsk_renderer_render_texture (GskRenderer *renderer,
357 GskRenderNode *root,
358 const graphene_rect_t *viewport)
359 {
360 GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
361 graphene_rect_t real_viewport;
362 GdkTexture *texture;
363
364 g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
365 g_return_val_if_fail (priv->is_realized, NULL);
366 g_return_val_if_fail (GSK_IS_RENDER_NODE (root), NULL);
367 g_return_val_if_fail (priv->root_node == NULL, NULL);
368
369 priv->root_node = gsk_render_node_ref (root);
370
371 if (viewport == NULL)
372 {
373 gsk_render_node_get_bounds (root, &real_viewport);
374 viewport = &real_viewport;
375 }
376
377 texture = GSK_RENDERER_GET_CLASS (renderer)->render_texture (renderer, root, viewport);
378
379 #ifdef G_ENABLE_DEBUG
380 if (GSK_RENDERER_DEBUG_CHECK (renderer, RENDERER))
381 {
382 GString *buf = g_string_new ("*** Texture stats ***\n\n");
383
384 gsk_profiler_append_counters (priv->profiler, buf);
385 g_string_append_c (buf, '\n');
386
387 gsk_profiler_append_timers (priv->profiler, buf);
388 g_string_append_c (buf, '\n');
389
390 g_print ("%s\n***\n\n", buf->str);
391
392 g_string_free (buf, TRUE);
393 }
394 #endif
395
396 g_clear_pointer (&priv->root_node, gsk_render_node_unref);
397
398 return texture;
399 }
400
401 /**
402 * gsk_renderer_render:
403 * @renderer: a `GskRenderer`
404 * @root: a `GskRenderNode`
405 * @region: (nullable): the `cairo_region_t` that must be redrawn or %NULL
406 * for the whole window
407 *
408 * Renders the scene graph, described by a tree of `GskRenderNode` instances,
409 * ensuring that the given @region gets redrawn.
410 *
411 * Renderers must ensure that changes of the contents given by the @root
412 * node as well as the area given by @region are redrawn. They are however
413 * free to not redraw any pixel outside of @region if they can guarantee that
414 * it didn't change.
415 *
416 * The @renderer will acquire a reference on the `GskRenderNode` tree while
417 * the rendering is in progress.
418 */
419 void
gsk_renderer_render(GskRenderer * renderer,GskRenderNode * root,const cairo_region_t * region)420 gsk_renderer_render (GskRenderer *renderer,
421 GskRenderNode *root,
422 const cairo_region_t *region)
423 {
424 GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
425 cairo_region_t *clip;
426
427 g_return_if_fail (GSK_IS_RENDERER (renderer));
428 g_return_if_fail (priv->is_realized);
429 g_return_if_fail (GSK_IS_RENDER_NODE (root));
430 g_return_if_fail (priv->root_node == NULL);
431
432 if (region == NULL || priv->prev_node == NULL || GSK_RENDERER_DEBUG_CHECK (renderer, FULL_REDRAW))
433 {
434 clip = cairo_region_create_rectangle (&(GdkRectangle) {
435 0, 0,
436 gdk_surface_get_width (priv->surface),
437 gdk_surface_get_height (priv->surface)
438 });
439 }
440 else
441 {
442 clip = cairo_region_copy (region);
443 gsk_render_node_diff (priv->prev_node, root, clip);
444
445 if (cairo_region_is_empty (clip))
446 {
447 cairo_region_destroy (clip);
448 return;
449 }
450 }
451
452 priv->root_node = gsk_render_node_ref (root);
453
454 GSK_RENDERER_GET_CLASS (renderer)->render (renderer, root, clip);
455
456 #ifdef G_ENABLE_DEBUG
457 if (GSK_RENDERER_DEBUG_CHECK (renderer, RENDERER))
458 {
459 GString *buf = g_string_new ("*** Frame stats ***\n\n");
460
461 gsk_profiler_append_counters (priv->profiler, buf);
462 g_string_append_c (buf, '\n');
463
464 gsk_profiler_append_timers (priv->profiler, buf);
465 g_string_append_c (buf, '\n');
466
467 g_print ("%s\n***\n\n", buf->str);
468
469 g_string_free (buf, TRUE);
470 }
471 #endif
472
473 g_clear_pointer (&priv->prev_node, gsk_render_node_unref);
474 cairo_region_destroy (clip);
475 priv->prev_node = priv->root_node;
476 priv->root_node = NULL;
477 }
478
479 /*< private >
480 * gsk_renderer_get_profiler:
481 * @renderer: a `GskRenderer`
482 *
483 * Retrieves a pointer to the `GskProfiler` instance of the renderer.
484 *
485 * Returns: (transfer none): the profiler
486 */
487 GskProfiler *
gsk_renderer_get_profiler(GskRenderer * renderer)488 gsk_renderer_get_profiler (GskRenderer *renderer)
489 {
490 GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
491
492 g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
493
494 return priv->profiler;
495 }
496
497 static GType
get_renderer_for_name(const char * renderer_name)498 get_renderer_for_name (const char *renderer_name)
499 {
500 if (renderer_name == NULL)
501 return G_TYPE_INVALID;
502 #ifdef GDK_WINDOWING_BROADWAY
503 else if (g_ascii_strcasecmp (renderer_name, "broadway") == 0)
504 return GSK_TYPE_BROADWAY_RENDERER;
505 #endif
506 else if (g_ascii_strcasecmp (renderer_name, "cairo") == 0)
507 return GSK_TYPE_CAIRO_RENDERER;
508 else if (g_ascii_strcasecmp (renderer_name, "opengl") == 0 ||
509 g_ascii_strcasecmp (renderer_name, "ngl") == 0)
510 return GSK_TYPE_NGL_RENDERER;
511 else if (g_ascii_strcasecmp (renderer_name, "gl") == 0)
512 return GSK_TYPE_GL_RENDERER;
513 #ifdef GDK_RENDERING_VULKAN
514 else if (g_ascii_strcasecmp (renderer_name, "vulkan") == 0)
515 return GSK_TYPE_VULKAN_RENDERER;
516 #endif
517 else if (g_ascii_strcasecmp (renderer_name, "help") == 0)
518 {
519 g_print ("Supported arguments for GSK_RENDERER environment variable:\n");
520 #ifdef GDK_WINDOWING_BROADWAY
521 g_print ("broadway - Use the Broadway specific renderer\n");
522 #else
523 g_print ("broadway - disabled during GTK build\n");
524 #endif
525 g_print (" cairo - Use the Cairo fallback renderer\n");
526 g_print (" opengl - Use the default OpenGL renderer\n");
527 g_print (" gl - An OpenGL renderer\n");
528 g_print (" ngl - Another OpenGL renderer\n");
529 #ifdef GDK_RENDERING_VULKAN
530 g_print (" vulkan - Use the Vulkan renderer\n");
531 #else
532 g_print (" vulkan - Disabled during GTK build\n");
533 #endif
534 g_print (" help - Print this help\n\n");
535 g_print ("Other arguments will cause a warning and be ignored.\n");
536 }
537 else
538 {
539 g_warning ("Unrecognized renderer \"%s\". Try GSK_RENDERER=help", renderer_name);
540 }
541
542 return G_TYPE_INVALID;
543 }
544
545 static GType
get_renderer_for_display(GdkSurface * surface)546 get_renderer_for_display (GdkSurface *surface)
547 {
548 GdkDisplay *display = gdk_surface_get_display (surface);
549 const char *renderer_name;
550
551 renderer_name = g_object_get_data (G_OBJECT (display), "gsk-renderer");
552 return get_renderer_for_name (renderer_name);
553 }
554
555 static GType
get_renderer_for_env_var(GdkSurface * surface)556 get_renderer_for_env_var (GdkSurface *surface)
557 {
558 static GType env_var_type = G_TYPE_NONE;
559
560 if (env_var_type == G_TYPE_NONE)
561 {
562 const char *renderer_name = g_getenv ("GSK_RENDERER");
563 env_var_type = get_renderer_for_name (renderer_name);
564 }
565
566 return env_var_type;
567 }
568
569 static GType
get_renderer_for_backend(GdkSurface * surface)570 get_renderer_for_backend (GdkSurface *surface)
571 {
572 #ifdef GDK_WINDOWING_X11
573 if (GDK_IS_X11_SURFACE (surface))
574 return GSK_TYPE_NGL_RENDERER;
575 #endif
576 #ifdef GDK_WINDOWING_WAYLAND
577 if (GDK_IS_WAYLAND_SURFACE (surface))
578 return GSK_TYPE_NGL_RENDERER;
579 #endif
580 #ifdef GDK_WINDOWING_BROADWAY
581 if (GDK_IS_BROADWAY_SURFACE (surface))
582 return GSK_TYPE_BROADWAY_RENDERER;
583 #endif
584 #ifdef GDK_WINDOWING_MACOS
585 if (GDK_IS_MACOS_SURFACE (surface))
586 return GSK_TYPE_NGL_RENDERER;
587 #endif
588 #ifdef GDK_WINDOWING_WIN32
589 if (GDK_IS_WIN32_SURFACE (surface))
590 /* remove check for OpenGL/ES when OpenGL/ES 2.0 shader is ready */
591 {
592 GdkDisplay *display = gdk_surface_get_display (surface);
593
594 if (!(GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) ||
595 GDK_WIN32_DISPLAY (display)->running_on_arm64))
596 return GSK_TYPE_NGL_RENDERER;
597 }
598 #endif
599
600 return G_TYPE_INVALID;
601 }
602
603 static GType
get_renderer_fallback(GdkSurface * surface)604 get_renderer_fallback (GdkSurface *surface)
605 {
606 return GSK_TYPE_CAIRO_RENDERER;
607 }
608
609 static struct {
610 GType (* get_renderer) (GdkSurface *surface);
611 } renderer_possibilities[] = {
612 { get_renderer_for_display },
613 { get_renderer_for_env_var },
614 { get_renderer_for_backend },
615 { get_renderer_fallback },
616 };
617
618 /**
619 * gsk_renderer_new_for_surface:
620 * @surface: a `GdkSurface`
621 *
622 * Creates an appropriate `GskRenderer` instance for the given @surface.
623 *
624 * If the `GSK_RENDERER` environment variable is set, GSK will
625 * try that renderer first, before trying the backend-specific
626 * default. The ultimate fallback is the cairo renderer.
627 *
628 * The renderer will be realized before it is returned.
629 *
630 * Returns: (transfer full) (nullable): a `GskRenderer`
631 */
632 GskRenderer *
gsk_renderer_new_for_surface(GdkSurface * surface)633 gsk_renderer_new_for_surface (GdkSurface *surface)
634 {
635 GType renderer_type;
636 GskRenderer *renderer;
637 GError *error = NULL;
638 guint i;
639
640 g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
641
642 for (i = 0; i < G_N_ELEMENTS (renderer_possibilities); i++)
643 {
644 renderer_type = renderer_possibilities[i].get_renderer (surface);
645 if (renderer_type == G_TYPE_INVALID)
646 continue;
647
648 renderer = g_object_new (renderer_type, NULL);
649
650 if (gsk_renderer_realize (renderer, surface, &error))
651 {
652 GSK_RENDERER_NOTE (renderer, RENDERER,
653 g_message ("Using renderer of type '%s' for surface '%s'\n",
654 G_OBJECT_TYPE_NAME (renderer),
655 G_OBJECT_TYPE_NAME (surface)));
656 return renderer;
657 }
658
659 g_message ("Failed to realize renderer of type '%s' for surface '%s': %s\n",
660 G_OBJECT_TYPE_NAME (renderer),
661 G_OBJECT_TYPE_NAME (surface),
662 error->message);
663 g_object_unref (renderer);
664 g_clear_error (&error);
665 }
666
667 g_assert_not_reached ();
668 return NULL;
669 }
670
671 GskDebugFlags
gsk_renderer_get_debug_flags(GskRenderer * renderer)672 gsk_renderer_get_debug_flags (GskRenderer *renderer)
673 {
674 GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
675
676 g_return_val_if_fail (GSK_IS_RENDERER (renderer), 0);
677
678 return priv->debug_flags;
679 }
680
681 void
gsk_renderer_set_debug_flags(GskRenderer * renderer,GskDebugFlags flags)682 gsk_renderer_set_debug_flags (GskRenderer *renderer,
683 GskDebugFlags flags)
684 {
685 GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
686
687 g_return_if_fail (GSK_IS_RENDERER (renderer));
688
689 priv->debug_flags = flags;
690 }
691