gskrenderer.c 23.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* GSK - The GTK Scene Kit
 *
 * Copyright 2016  Endless
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * SECTION:GskRenderer
21 22
 * @Title: GskRenderer
 * @Short_description: Renders a scene
23
 *
24 25 26 27 28 29 30 31 32 33
 * #GskRenderer is a class that renders a scene graph defined via a
 * tree of #GskRenderNode instances.
 *
 * Typically you will use a #GskRenderer instance with a #GdkDrawingContext
 * associated to a #GdkWindow, and call gsk_renderer_render() with the
 * drawing context and the scene to be rendered.
 *
 * It is necessary to realize a #GskRenderer instance using gsk_renderer_realize()
 * before calling gsk_renderer_render(), in order to create the appropriate
 * windowing system resources needed to render the scene.
34 35 36 37 38 39
 */

#include "config.h"

#include "gskrendererprivate.h"

40
#include "gskcairorendererprivate.h"
41
#include "gskdebugprivate.h"
42
#include "gl/gskglrendererprivate.h"
43
#include "gskprofilerprivate.h"
44 45 46 47 48 49 50 51 52 53 54 55 56 57
#include "gskrendernodeprivate.h"

#include "gskenumtypes.h"

#include <graphene-gobject.h>
#include <cairo-gobject.h>
#include <gdk/gdk.h>

#ifdef GDK_WINDOWING_X11
#include <gdk/x11/gdkx.h>
#endif
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/wayland/gdkwayland.h>
#endif
58 59 60
#ifdef GDK_WINDOWING_BROADWAY
#include "gskbroadwayrendererprivate.h"
#endif
Matthias Clasen's avatar
Matthias Clasen committed
61
#ifdef GDK_RENDERING_VULKAN
62
#include "vulkan/gskvulkanrendererprivate.h"
63
#endif
64 65 66 67 68 69 70 71

typedef struct
{
  GObject parent_instance;

  GskScalingFilter min_filter;
  GskScalingFilter mag_filter;

72 73
  GdkWindow *window;
  GdkDrawingContext *drawing_context;
74
  GskRenderNode *root_node;
75
  GdkDisplay *display;
76

77 78
  GskProfiler *profiler;

79 80
  GskDebugFlags debug_flags;

81 82 83 84 85 86
  gboolean is_realized : 1;
} GskRendererPrivate;

G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GskRenderer, gsk_renderer, G_TYPE_OBJECT)

enum {
87
  PROP_WINDOW = 1,
88
  PROP_DISPLAY,
89
  PROP_DRAWING_CONTEXT,
90 91 92 93 94 95 96 97 98 99

  N_PROPS
};

static GParamSpec *gsk_renderer_properties[N_PROPS];

#define GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD(obj,method) \
  g_critical ("Renderer of type '%s' does not implement GskRenderer::" # method, G_OBJECT_TYPE_NAME (obj))

static gboolean
100 101 102
gsk_renderer_real_realize (GskRenderer  *self,
                           GdkWindow    *window,
                           GError      **error)
103 104 105 106 107 108 109 110 111 112 113
{
  GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, realize);
  return FALSE;
}

static void
gsk_renderer_real_unrealize (GskRenderer *self)
{
  GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, unrealize);
}

Benjamin Otte's avatar
Benjamin Otte committed
114
static GdkTexture *
115 116 117 118 119 120 121 122
gsk_renderer_real_render_texture (GskRenderer           *self,
                                  GskRenderNode         *root,
                                  const graphene_rect_t *viewport)
{
  GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, render_texture);
  return NULL;
}

123 124 125 126 127 128 129
static GdkDrawingContext *
gsk_renderer_real_begin_draw_frame (GskRenderer          *self,
                                    const cairo_region_t *region)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);

  return gdk_window_begin_draw_frame (priv->window,
130
                                      NULL,
131 132 133 134 135 136 137 138 139 140 141 142 143
                                      region);
}

static void
gsk_renderer_real_end_draw_frame (GskRenderer       *self,
                                  GdkDrawingContext *context)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);

  gdk_window_end_draw_frame (priv->window,
                             context);
}

144
static void
145
gsk_renderer_real_render (GskRenderer *self,
146
                          GskRenderNode *root)
147 148 149 150
{
  GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, render);
}

151 152 153 154 155 156 157
static cairo_surface_t *
gsk_renderer_real_create_cairo_surface (GskRenderer    *self,
                                        cairo_format_t  format,
                                        int             width,
                                        int             height)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
158
  int scale_factor = priv->window ? gdk_window_get_scale_factor (priv->window) : 1;
159 160 161 162 163 164 165 166 167 168
  int real_width = width * scale_factor;
  int real_height = height * scale_factor;

  cairo_surface_t *res = cairo_image_surface_create (format, real_width, real_height);

  cairo_surface_set_device_scale (res, scale_factor, scale_factor);

  return res;
}

169 170 171 172 173 174
static void
gsk_renderer_dispose (GObject *gobject)
{
  GskRenderer *self = GSK_RENDERER (gobject);
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);

175 176 177
  /* We can't just unrealize here because superclasses have already run dispose.
   * So we insist that unrealize must be called before unreffing. */
  g_assert (!priv->is_realized);
178

179
  g_clear_object (&priv->profiler);
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
  g_clear_object (&priv->display);

  G_OBJECT_CLASS (gsk_renderer_parent_class)->dispose (gobject);
}

static void
gsk_renderer_set_property (GObject      *gobject,
                           guint         prop_id,
                           const GValue *value,
                           GParamSpec   *pspec)
{
  GskRenderer *self = GSK_RENDERER (gobject);
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);

  switch (prop_id)
    {
    case PROP_DISPLAY:
197
      /* Construct-only */
198 199
      priv->display = g_value_dup_object (value);
      break;
200 201 202 203

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
      break;
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
    }
}

static void
gsk_renderer_get_property (GObject    *gobject,
                           guint       prop_id,
                           GValue     *value,
                           GParamSpec *pspec)
{
  GskRenderer *self = GSK_RENDERER (gobject);
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);

  switch (prop_id)
    {
    case PROP_WINDOW:
      g_value_set_object (value, priv->window);
      break;

222 223 224 225 226 227
    case PROP_DRAWING_CONTEXT:
      g_value_set_object (value, priv->drawing_context);
      break;

    case PROP_DISPLAY:
      g_value_set_object (value, priv->display);
228
      break;
229 230 231 232

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
      break;
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
    }
}

static void
gsk_renderer_constructed (GObject *gobject)
{
  GskRenderer *self = GSK_RENDERER (gobject);
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);

  if (priv->display == NULL)
    {
      GdkDisplayManager *manager = gdk_display_manager_get ();

      priv->display = gdk_display_manager_get_default_display (manager);
      g_assert (priv->display != NULL);
    }

  G_OBJECT_CLASS (gsk_renderer_parent_class)->constructed (gobject);
}

static void
gsk_renderer_class_init (GskRendererClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  klass->realize = gsk_renderer_real_realize;
  klass->unrealize = gsk_renderer_real_unrealize;
260 261
  klass->begin_draw_frame = gsk_renderer_real_begin_draw_frame;
  klass->end_draw_frame = gsk_renderer_real_end_draw_frame;
262
  klass->render = gsk_renderer_real_render;
263
  klass->render_texture = gsk_renderer_real_render_texture;
264
  klass->create_cairo_surface = gsk_renderer_real_create_cairo_surface;
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287

  gobject_class->constructed = gsk_renderer_constructed;
  gobject_class->set_property = gsk_renderer_set_property;
  gobject_class->get_property = gsk_renderer_get_property;
  gobject_class->dispose = gsk_renderer_dispose;

  /**
   * GskRenderer:display:
   *
   * The #GdkDisplay used by the #GskRenderer.
   */
  gsk_renderer_properties[PROP_DISPLAY] =
    g_param_spec_object ("display",
			 "Display",
			 "The GdkDisplay object used by the renderer",
			 GDK_TYPE_DISPLAY,
			 G_PARAM_READWRITE |
			 G_PARAM_CONSTRUCT_ONLY |
			 G_PARAM_STATIC_STRINGS);

  gsk_renderer_properties[PROP_WINDOW] =
    g_param_spec_object ("window",
                         "Window",
288
                         "The window associated to the renderer",
289
                         GDK_TYPE_WINDOW,
290
                         G_PARAM_READABLE |
291 292 293 294 295 296 297 298 299 300 301 302 303 304
                         G_PARAM_STATIC_STRINGS);

  /**
   * GskRenderer:drawing-context:
   *
   * The drawing context used when rendering.
   */
  gsk_renderer_properties[PROP_DRAWING_CONTEXT] =
    g_param_spec_object ("drawing-context",
                         "Drawing Context",
                         "The drawing context used by the renderer",
                         GDK_TYPE_DRAWING_CONTEXT,
                         G_PARAM_READABLE |
                         G_PARAM_STATIC_STRINGS);
305 306 307 308 309 310 311 312 313

  g_object_class_install_properties (gobject_class, N_PROPS, gsk_renderer_properties);
}

static void
gsk_renderer_init (GskRenderer *self)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);

314
  priv->profiler = gsk_profiler_new ();
315
  priv->debug_flags = gsk_get_debug_flags ();
316 317 318
}

/**
319
 * gsk_renderer_get_window:
320 321
 * @renderer: a #GskRenderer
 *
322 323
 * Retrieves the #GdkWindow set using gsk_renderer_realize(). If the renderer
 * has not been realized yet, %NULL will be returned.
324
 *
325
 * Returns: (transfer none) (nullable): a #GdkWindow
326
 */
327 328
GdkWindow *
gsk_renderer_get_window (GskRenderer *renderer)
329 330 331 332 333
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

  g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);

334
  return priv->window;
335 336
}

337
/*< private >
338 339 340
 * gsk_renderer_get_root_node:
 * @renderer: a #GskRenderer
 *
341
 * Retrieves the #GskRenderNode used by @renderer.
342 343 344 345 346 347 348 349 350 351 352 353 354 355
 *
 * Returns: (transfer none) (nullable): a #GskRenderNode
 */
GskRenderNode *
gsk_renderer_get_root_node (GskRenderer *renderer)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

  g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);

  return priv->root_node;
}

/*< private >
356
 * gsk_renderer_get_drawing_context:
357 358
 * @renderer: a #GskRenderer
 *
359
 * Retrieves the #GdkDrawingContext used by @renderer.
360
 *
361
 * Returns: (transfer none) (nullable): a #GdkDrawingContext
362
 */
363 364
GdkDrawingContext *
gsk_renderer_get_drawing_context (GskRenderer *renderer)
365 366 367
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

368
  g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
369

370
  return priv->drawing_context;
371 372 373
}

/**
374
 * gsk_renderer_get_display:
375 376
 * @renderer: a #GskRenderer
 *
377
 * Retrieves the #GdkDisplay used when creating the #GskRenderer.
378
 *
379
 * Returns: (transfer none): a #GdkDisplay
380
 */
381 382
GdkDisplay *
gsk_renderer_get_display (GskRenderer *renderer)
383 384 385
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

386
  g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
387

388
  return priv->display;
389 390
}

391 392
/*< private >
 * gsk_renderer_is_realized:
393 394
 * @renderer: a #GskRenderer
 *
395
 * Checks whether the @renderer is realized or not.
396
 *
397
 * Returns: %TRUE if the #GskRenderer was realized, and %FALSE otherwise
398
 */
399 400
gboolean
gsk_renderer_is_realized (GskRenderer *renderer)
401 402 403
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

404
  g_return_val_if_fail (GSK_IS_RENDERER (renderer), FALSE);
405

406
  return priv->is_realized;
407 408 409 410 411
}

/**
 * gsk_renderer_realize:
 * @renderer: a #GskRenderer
412
 * @window: the #GdkWindow renderer will be used on
413
 * @error: return location for an error
414 415 416 417 418
 *
 * Creates the resources needed by the @renderer to render the scene
 * graph.
 */
gboolean
419 420 421
gsk_renderer_realize (GskRenderer  *renderer,
                      GdkWindow    *window,
                      GError      **error)
422 423 424 425
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

  g_return_val_if_fail (GSK_IS_RENDERER (renderer), FALSE);
426 427
  g_return_val_if_fail (!gsk_renderer_is_realized (renderer), FALSE);
  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
428
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
429

430
  priv->window = g_object_ref (window);
431

432
  if (!GSK_RENDERER_GET_CLASS (renderer)->realize (renderer, window, error))
433 434 435 436
    {
      g_clear_object (&priv->window);
      return FALSE;
    }
437

438 439
  priv->is_realized = TRUE;
  return TRUE;
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
}

/**
 * gsk_renderer_unrealize:
 * @renderer: a #GskRenderer
 *
 * Releases all the resources created by gsk_renderer_realize().
 */
void
gsk_renderer_unrealize (GskRenderer *renderer)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

  g_return_if_fail (GSK_IS_RENDERER (renderer));

  if (!priv->is_realized)
    return;

  GSK_RENDERER_GET_CLASS (renderer)->unrealize (renderer);

  priv->is_realized = FALSE;
}

463 464 465 466 467 468 469
/**
 * gsk_renderer_render_texture:
 * @renderer: a realized #GdkRenderer
 * @root: a #GskRenderNode
 * @viewport: (allow-none): the section to draw or %NULL to use @root's bounds
 *
 * Renders the scene graph, described by a tree of #GskRenderNode instances,
Benjamin Otte's avatar
Benjamin Otte committed
470
 * to a #GdkTexture.
471 472 473 474 475 476 477
 *
 * The @renderer will acquire a reference on the #GskRenderNode tree while
 * the rendering is in progress, and will make the tree immutable.
 *
 * If you want to apply any transformations to @root, you should put it into a 
 * transform node and pass that node instead.
 *
Benjamin Otte's avatar
Benjamin Otte committed
478
 * Returns: (transfer full): a #GdkTexture with the rendered contents of @root.
479
 */
Benjamin Otte's avatar
Benjamin Otte committed
480
GdkTexture *
481 482 483 484 485 486
gsk_renderer_render_texture (GskRenderer           *renderer,
                             GskRenderNode         *root,
                             const graphene_rect_t *viewport)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
  graphene_rect_t real_viewport;
Benjamin Otte's avatar
Benjamin Otte committed
487
  GdkTexture *texture;
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504

  g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
  g_return_val_if_fail (priv->is_realized, NULL);
  g_return_val_if_fail (GSK_IS_RENDER_NODE (root), NULL);
  g_return_val_if_fail (priv->root_node == NULL, NULL);

  priv->root_node = gsk_render_node_ref (root);

  if (viewport == NULL)
    {
      gsk_render_node_get_bounds (root, &real_viewport);
      viewport = &real_viewport;
    }

  texture = GSK_RENDERER_GET_CLASS (renderer)->render_texture (renderer, root, viewport);

#ifdef G_ENABLE_DEBUG
505
  if (GSK_RENDERER_DEBUG_CHECK (renderer, RENDERER))
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
    {
      GString *buf = g_string_new ("*** Texture stats ***\n\n");

      gsk_profiler_append_counters (priv->profiler, buf);
      g_string_append_c (buf, '\n');

      gsk_profiler_append_timers (priv->profiler, buf);
      g_string_append_c (buf, '\n');

      g_print ("%s\n***\n\n", buf->str);

      g_string_free (buf, TRUE);
    }
#endif

  g_clear_pointer (&priv->root_node, gsk_render_node_unref);

  return texture;
}

526 527
/**
 * gsk_renderer_render:
528 529
 * @renderer: a #GskRenderer
 * @root: a #GskRenderNode
530
 * @context: The drawing context created via gsk_renderer_begin_draw_frame()
531 532 533
 *
 * Renders the scene graph, described by a tree of #GskRenderNode instances,
 * using the given #GdkDrawingContext.
534
 *
535
 * The @renderer will acquire a reference on the #GskRenderNode tree while
536
 * the rendering is in progress.
537 538
 */
void
539 540 541
gsk_renderer_render (GskRenderer       *renderer,
                     GskRenderNode     *root,
                     GdkDrawingContext *context)
542 543 544 545 546
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

  g_return_if_fail (GSK_IS_RENDERER (renderer));
  g_return_if_fail (priv->is_realized);
547
  g_return_if_fail (GSK_IS_RENDER_NODE (root));
548
  g_return_if_fail (priv->root_node == NULL);
549
  g_return_if_fail (GDK_IS_DRAWING_CONTEXT (context));
550
  g_return_if_fail (context == priv->drawing_context);
551

552
  priv->root_node = gsk_render_node_ref (root);
553

554
  GSK_RENDERER_GET_CLASS (renderer)->render (renderer, root);
555

556
#ifdef G_ENABLE_DEBUG
557
  if (GSK_RENDERER_DEBUG_CHECK (renderer, RENDERER))
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
    {
      GString *buf = g_string_new ("*** Frame stats ***\n\n");

      gsk_profiler_append_counters (priv->profiler, buf);
      g_string_append_c (buf, '\n');

      gsk_profiler_append_timers (priv->profiler, buf);
      g_string_append_c (buf, '\n');

      g_print ("%s\n***\n\n", buf->str);

      g_string_free (buf, TRUE);
    }
#endif

573
  g_clear_pointer (&priv->root_node, gsk_render_node_unref);
574 575
}

576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
/*< private >
 * gsk_renderer_get_profiler:
 * @renderer: a #GskRenderer
 *
 * Retrieves a pointer to the GskProfiler instance of the renderer.
 *
 * Returns: (transfer none): the profiler
 */
GskProfiler *
gsk_renderer_get_profiler (GskRenderer *renderer)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

  g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);

  return priv->profiler;
}

594 595 596 597 598 599 600 601 602 603 604 605
static GType
get_renderer_for_name (const char *renderer_name)
{
  if (renderer_name == NULL)
    return G_TYPE_INVALID;
  else if (g_ascii_strcasecmp (renderer_name, "cairo") == 0)
    return GSK_TYPE_CAIRO_RENDERER;
  else if (g_ascii_strcasecmp (renderer_name, "opengl") == 0
           || g_ascii_strcasecmp (renderer_name, "gl") == 0)
    return GSK_TYPE_GL_RENDERER;
#ifdef GDK_RENDERING_VULKAN
  else if (g_ascii_strcasecmp (renderer_name, "vulkan") == 0)
606
    return GSK_TYPE_VULKAN_RENDERER;
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
#endif
  else if (g_ascii_strcasecmp (renderer_name, "help") == 0)
    {
      g_print ("Supported arguments for GSK_RENDERER environment variable:\n");
      g_print ("   cairo - Use the Cairo fallback renderer\n");
      g_print ("  opengl - Use the default OpenGL renderer\n");
#ifdef GDK_RENDERING_VULKAN
      g_print ("  vulkan - Use the Vulkan renderer\n");
#endif
      g_print ("    help - Print this help\n\n");
      g_print ("Other arguments will cause a warning and be ignored.\n");
    }
  else
    {
      g_warning ("Unrecognized renderer \"%s\". Try GSK_RENDERER=help", renderer_name);
    }

  return G_TYPE_INVALID;
}

static GType
get_renderer_for_display (GdkWindow *window)
{
  GdkDisplay *display = gdk_window_get_display (window);
  const char *renderer_name;

633
  renderer_name = g_object_get_data (G_OBJECT (display), "gsk-renderer");
634 635 636
  return get_renderer_for_name (renderer_name);
}

637 638
static GType
get_renderer_for_env_var (GdkWindow *window)
639
{
640
  static GType env_var_type = G_TYPE_NONE;
641

642
  if (env_var_type == G_TYPE_NONE)
643
    {
644
      const char *renderer_name = g_getenv ("GSK_RENDERER");
645
      env_var_type = get_renderer_for_name (renderer_name);
646 647
    }

648
  return env_var_type;
649 650 651 652 653
}

static GType
get_renderer_for_backend (GdkWindow *window)
{
654
#ifdef GDK_WINDOWING_X11
655 656
  if (GDK_IS_X11_WINDOW (window))
    return GSK_TYPE_GL_RENDERER; 
657 658
#endif
#ifdef GDK_WINDOWING_WAYLAND
659 660
  if (GDK_IS_WAYLAND_WINDOW (window))
    return GSK_TYPE_GL_RENDERER;
661
#endif
662 663 664 665
#ifdef GDK_WINDOWING_BROADWAY
  if (GDK_IS_BROADWAY_WINDOW (window))
    return GSK_TYPE_BROADWAY_RENDERER;
#endif
666

667 668 669 670 671 672 673 674 675 676
  return G_TYPE_INVALID;
}

static GType
get_renderer_fallback (GdkWindow *window)
{
  return GSK_TYPE_CAIRO_RENDERER;
}

static struct {
677
  gboolean verbose;
678 679
  GType (* get_renderer) (GdkWindow *window);
} renderer_possibilities[] = {
680
  { TRUE,  get_renderer_for_display },
681 682 683
  { TRUE,  get_renderer_for_env_var },
  { FALSE, get_renderer_for_backend },
  { FALSE, get_renderer_fallback },
684
};
685

686 687
/**
 * gsk_renderer_new_for_window:
688
 * @window: a #GdkWindow
689 690 691 692 693 694 695 696 697 698 699 700
 *
 * Creates an appropriate #GskRenderer instance for the given @window.
 *
 * The renderer will be realized when it is returned.
 *
 * Returns: (transfer full) (nullable): a #GskRenderer
 */
GskRenderer *
gsk_renderer_new_for_window (GdkWindow *window)
{
  GType renderer_type;
  GskRenderer *renderer;
701
  GError *error = NULL;
702
  gboolean verbose = FALSE;
703 704 705 706 707 708 709 710 711 712
  guint i;

  g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);

  for (i = 0; i < G_N_ELEMENTS (renderer_possibilities); i++)
    {
      renderer_type = renderer_possibilities[i].get_renderer (window);
      if (renderer_type == G_TYPE_INVALID)
        continue;

713 714 715 716
      /* If a renderer is selected that's marked as verbose, start printing
       * information to stdout.
       */
      verbose |= renderer_possibilities[i].verbose;
717 718 719 720
      renderer = g_object_new (renderer_type,
                               "display", gdk_window_get_display (window),
                               NULL);

721
      if (gsk_renderer_realize (renderer, window, &error))
722
        {
723
          if (verbose || GSK_RENDERER_DEBUG_CHECK (renderer, RENDERER))
724
            {
725
              g_print ("Using renderer of type '%s' for window '%s'\n",
726 727 728
                       G_OBJECT_TYPE_NAME (renderer),
                       G_OBJECT_TYPE_NAME (window));
            }
729 730 731
          return renderer;
        }

732
      if (verbose || GSK_RENDERER_DEBUG_CHECK (renderer, RENDERER))
733 734 735 736 737 738
        {
          g_print ("Failed to realize renderer of type '%s' for window '%s': %s\n",
                   G_OBJECT_TYPE_NAME (renderer),
                   G_OBJECT_TYPE_NAME (window),
                   error->message);
        }
739
      g_object_unref (renderer);
740
      g_clear_error (&error);
741
    }
742

743 744
  g_assert_not_reached ();
  return NULL;
745
}
746

747 748 749 750 751 752 753 754 755 756 757 758
cairo_surface_t *
gsk_renderer_create_cairo_surface (GskRenderer    *renderer,
                                   cairo_format_t  format,
                                   int             width,
                                   int             height)
{
  g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
  g_return_val_if_fail (width > 0 && height > 0, NULL);

  return GSK_RENDERER_GET_CLASS (renderer)->create_cairo_surface (renderer, format, width, height);
}

759 760 761 762 763 764 765 766 767 768 769
/**
 * gsk_renderer_begin_draw_frame:
 * @renderer: a #GskRenderer
 * @region: the #cairo_region_t that you wish to draw
 *
 * Indicates that you are beginning the process of redrawing @region using
 * @renderer, and provides you with a #GdkDrawingContext to use for this.
 *
 * Returns: (transfer none): a #GdkDrawingContext context that should be used to
 * draw the contents of the @renderer. This context is owned by GDK.
 */
770 771 772 773 774 775 776 777 778 779
GdkDrawingContext *
gsk_renderer_begin_draw_frame (GskRenderer          *renderer,
                               const cairo_region_t *region)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

  g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
  g_return_val_if_fail (region != NULL, NULL);
  g_return_val_if_fail (priv->drawing_context == NULL, NULL);

780 781
#ifdef G_ENABLE_DEBUG
  if (GSK_RENDERER_DEBUG_CHECK (renderer, FULL_REDRAW))
782 783
    {
      cairo_region_t *full_window;
784

785 786 787 788 789
      full_window = cairo_region_create_rectangle (&(GdkRectangle) {
                                                       0, 0,
                                                       gdk_window_get_width (priv->window),
                                                       gdk_window_get_height (priv->window)
                                                   });
790

791 792 793 794 795
      priv->drawing_context = GSK_RENDERER_GET_CLASS (renderer)->begin_draw_frame (renderer, full_window);

      cairo_region_destroy (full_window);
    }
  else
796 797
#endif
  priv->drawing_context = GSK_RENDERER_GET_CLASS (renderer)->begin_draw_frame (renderer, region);
798 799 800 801

  return priv->drawing_context;
}

802 803 804 805 806 807 808 809 810 811 812
/**
 * gsk_renderer_end_draw_frame:
 * @renderer: a #GskRenderer
 * @context: the drawing context returned by the matching call to
 *     gsk_renderer_begin_draw_frame()
 *
 * Release the drawning context returned by gsk_renderer_begin_draw_frame().
 *
 * Calls to gsk_renderer_begin_draw_frame() and gsk_renderer_end_draw_frame()
 * must be paired.
 */
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
void
gsk_renderer_end_draw_frame (GskRenderer       *renderer,
                             GdkDrawingContext *context)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

  g_return_if_fail (GSK_IS_RENDERER (renderer));
  g_return_if_fail (GDK_IS_DRAWING_CONTEXT (context));
  g_return_if_fail (priv->drawing_context == context);

  priv->drawing_context = NULL;

  GSK_RENDERER_GET_CLASS (renderer)->end_draw_frame (renderer, context);
}

828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
GskDebugFlags
gsk_renderer_get_debug_flags (GskRenderer *renderer)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

  g_return_val_if_fail (GSK_IS_RENDERER (renderer), 0);

  return priv->debug_flags;
}

void
gsk_renderer_set_debug_flags (GskRenderer   *renderer,
                              GskDebugFlags  flags)
{
  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);

  g_return_if_fail (GSK_IS_RENDERER (renderer));

  priv->debug_flags = flags;
}