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