From a1116bc6c8a9460711e2d4dceb77a90250ec5de0 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Tue, 30 Jul 2019 23:48:45 +0200 Subject: [PATCH 1/6] cogl: Add support for clipping regions This uses the stencil buffer to poke holes in the shape of the given cairo_region_t that we will draw through. https://gitlab.gnome.org/GNOME/mutter/merge_requests/867 --- cogl/cogl/cogl-clip-stack.c | 31 +++++++ cogl/cogl/cogl-clip-stack.h | 14 ++- cogl/cogl/cogl-framebuffer.c | 13 +++ cogl/cogl/cogl-framebuffer.h | 5 + cogl/cogl/driver/gl/cogl-clip-stack-gl.c | 113 +++++++++++++++++++++++ cogl/cogl/meson.build | 2 +- 6 files changed, 176 insertions(+), 2 deletions(-) diff --git a/cogl/cogl/cogl-clip-stack.c b/cogl/cogl/cogl-clip-stack.c index 092510714e8..96eb105a0e8 100644 --- a/cogl/cogl/cogl-clip-stack.c +++ b/cogl/cogl/cogl-clip-stack.c @@ -295,6 +295,30 @@ _cogl_clip_stack_push_primitive (CoglClipStack *stack, return (CoglClipStack *) entry; } +CoglClipStack * +cogl_clip_stack_push_region (CoglClipStack *stack, + cairo_region_t *region) +{ + CoglClipStack *entry; + CoglClipStackRegion *entry_region; + cairo_rectangle_int_t bounds; + + entry_region = _cogl_clip_stack_push_entry (stack, + sizeof (CoglClipStackRegion), + COGL_CLIP_STACK_REGION); + entry = (CoglClipStack *) entry_region; + + cairo_region_get_extents (region, &bounds); + entry->bounds_x0 = bounds.x; + entry->bounds_x1 = bounds.x + bounds.width; + entry->bounds_y0 = bounds.y; + entry->bounds_y1 = bounds.y + bounds.height; + + entry_region->region = cairo_region_reference (region); + + return entry; +} + CoglClipStack * _cogl_clip_stack_ref (CoglClipStack *entry) { @@ -336,6 +360,13 @@ _cogl_clip_stack_unref (CoglClipStack *entry) g_slice_free1 (sizeof (CoglClipStackPrimitive), entry); break; } + case COGL_CLIP_STACK_REGION: + { + CoglClipStackRegion *region = (CoglClipStackRegion *) entry; + cairo_region_destroy (region->region); + g_slice_free1 (sizeof (CoglClipStackRegion), entry); + break; + } default: g_assert_not_reached (); } diff --git a/cogl/cogl/cogl-clip-stack.h b/cogl/cogl/cogl-clip-stack.h index eb2c4328217..372e7347ade 100644 --- a/cogl/cogl/cogl-clip-stack.h +++ b/cogl/cogl/cogl-clip-stack.h @@ -48,12 +48,14 @@ typedef struct _CoglClipStack CoglClipStack; typedef struct _CoglClipStackRect CoglClipStackRect; typedef struct _CoglClipStackWindowRect CoglClipStackWindowRect; typedef struct _CoglClipStackPrimitive CoglClipStackPrimitive; +typedef struct _CoglClipStackRegion CoglClipStackRegion; typedef enum { COGL_CLIP_STACK_RECT, COGL_CLIP_STACK_WINDOW_RECT, - COGL_CLIP_STACK_PRIMITIVE + COGL_CLIP_STACK_PRIMITIVE, + COGL_CLIP_STACK_REGION, } CoglClipStackType; /* A clip stack consists a list of entries. Each entry has a reference @@ -162,6 +164,13 @@ struct _CoglClipStackPrimitive float bounds_y2; }; +struct _CoglClipStackRegion +{ + CoglClipStack _parent_data; + + cairo_region_t *region; +}; + CoglClipStack * _cogl_clip_stack_push_window_rectangle (CoglClipStack *stack, int x_offset, @@ -189,6 +198,9 @@ _cogl_clip_stack_push_primitive (CoglClipStack *stack, CoglMatrixEntry *modelview_entry, CoglMatrixEntry *projection_entry, const float *viewport); +CoglClipStack * +cogl_clip_stack_push_region (CoglClipStack *stack, + cairo_region_t *region); CoglClipStack * _cogl_clip_stack_pop (CoglClipStack *stack); diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c index 602eb0bc022..2bdac109bf1 100644 --- a/cogl/cogl/cogl-framebuffer.c +++ b/cogl/cogl/cogl-framebuffer.c @@ -1761,6 +1761,19 @@ cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer, COGL_FRAMEBUFFER_STATE_CLIP; } +void +cogl_framebuffer_push_region_clip (CoglFramebuffer *framebuffer, + cairo_region_t *region) +{ + framebuffer->clip_stack = + cogl_clip_stack_push_region (framebuffer->clip_stack, + region); + + if (framebuffer->context->current_draw_buffer == framebuffer) + framebuffer->context->current_draw_buffer_changes |= + COGL_FRAMEBUFFER_STATE_CLIP; +} + void cogl_framebuffer_pop_clip (CoglFramebuffer *framebuffer) { diff --git a/cogl/cogl/cogl-framebuffer.h b/cogl/cogl/cogl-framebuffer.h index d78bd007900..9979e9082d3 100644 --- a/cogl/cogl/cogl-framebuffer.h +++ b/cogl/cogl/cogl-framebuffer.h @@ -54,6 +54,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer; #include #include #include +#include #include @@ -624,6 +625,10 @@ cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer, float bounds_x2, float bounds_y2); +void +cogl_framebuffer_push_region_clip (CoglFramebuffer *framebuffer, + cairo_region_t *region); + /** * cogl_framebuffer_pop_clip: * @framebuffer: A #CoglFramebuffer pointer diff --git a/cogl/cogl/driver/gl/cogl-clip-stack-gl.c b/cogl/cogl/driver/gl/cogl-clip-stack-gl.c index 34f809a867c..31f078f93d7 100644 --- a/cogl/cogl/driver/gl/cogl-clip-stack-gl.c +++ b/cogl/cogl/driver/gl/cogl-clip-stack-gl.c @@ -115,6 +115,102 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer, GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) ); } +static void +add_stencil_clip_region (CoglFramebuffer *framebuffer, + cairo_region_t *region, + gboolean merge) +{ + CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); + CoglMatrix matrix; + int num_rectangles = cairo_region_num_rectangles (region); + int i; + + /* NB: This can be called while flushing the journal so we need + * to be very conservative with what state we change. + */ + _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry); + _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry); + + /* The coordinates in the region are meant to be window coordinates, + * make a matrix that translates those across the viewport, and into + * the default [-1, -1, 1, 1] range. + */ + cogl_matrix_init_identity (&matrix); + cogl_matrix_translate (&matrix, -1, 1, 0); + cogl_matrix_scale (&matrix, + 2.0 / framebuffer->viewport_width, + - 2.0 / framebuffer->viewport_height, + 1); + cogl_matrix_translate (&matrix, + - framebuffer->viewport_x, + - framebuffer->viewport_y, + 0); + + GE( ctx, glEnable (GL_STENCIL_TEST) ); + + GE( ctx, glColorMask (FALSE, FALSE, FALSE, FALSE) ); + GE( ctx, glDepthMask (FALSE) ); + + if (merge) + { + GE( ctx, glStencilFunc (GL_ALWAYS, 0x1, 0x3) ); + GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_INCR) ); + } + else + { + /* Initially disallow everything */ + GE( ctx, glClearStencil (0) ); + GE( ctx, glClear (GL_STENCIL_BUFFER_BIT) ); + + /* Punch out holes to allow the rectangles */ + GE( ctx, glStencilFunc (GL_ALWAYS, 0x1, 0x1) ); + GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE) ); + } + + for (i = 0; i < num_rectangles; i++) + { + cairo_rectangle_int_t rect; + float tl[4], br[4]; + + cairo_region_get_rectangle (region, i, &rect); + + tl[0] = rect.x; + tl[1] = rect.y; + tl[2] = 0.; + tl[3] = 1.; + + br[0] = rect.x + rect.width; + br[1] = rect.y + rect.height; + br[2] = 0.; + br[3] = 1.; + + cogl_matrix_transform_point (&matrix, &tl[0], &tl[1], &tl[2], &tl[3]); + cogl_matrix_transform_point (&matrix, &br[0], &br[1], &br[2], &br[3]); + + _cogl_rectangle_immediate (framebuffer, + ctx->stencil_pipeline, + tl[0], tl[1], br[0], br[1]); + } + + if (merge) + { + /* Subtract one from all pixels in the stencil buffer so that + * only pixels where both the original stencil buffer and the + * region are set will be valid + */ + GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_DECR) ); + _cogl_rectangle_immediate (framebuffer, + ctx->stencil_pipeline, + -1.0, -1.0, 1.0, 1.0); + } + + /* Restore the stencil mode */ + GE (ctx, glDepthMask (TRUE)); + GE (ctx, glColorMask (TRUE, TRUE, TRUE, TRUE)); + GE( ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1) ); + GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) ); +} + typedef void (*SilhouettePaintCallback) (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, void *user_data); @@ -382,6 +478,23 @@ _cogl_clip_stack_gl_flush (CoglClipStack *stack, } break; } + case COGL_CLIP_STACK_REGION: + { + CoglClipStackRegion *region = (CoglClipStackRegion *) entry; + + /* If nrectangles <= 1, it can be fully represented with the + * scissor clip. + */ + if (cairo_region_num_rectangles (region->region) > 1) + { + COGL_NOTE (CLIPPING, "Adding stencil clip for region"); + + add_stencil_clip_region (framebuffer, region->region, + using_stencil_buffer); + using_stencil_buffer = TRUE; + } + break; + } case COGL_CLIP_STACK_WINDOW_RECT: break; /* We don't need to do anything for window space rectangles because diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build index 8041e786e47..f6f8c016331 100644 --- a/cogl/cogl/meson.build +++ b/cogl/cogl/meson.build @@ -478,7 +478,7 @@ if have_introspection sources: cogl_introspected_headers, nsversion: libmutter_api_version, namespace: 'Cogl', - includes: ['GL-1.0', 'GObject-2.0', 'Graphene-1.0'], + includes: ['cairo-1.0', 'GL-1.0', 'GObject-2.0', 'Graphene-1.0'], dependencies: [cogl_deps], extra_args: introspection_args + [ '-UCOGL_COMPILATION', -- GitLab From 8598b654ba8e76d6c59b2de9f0bd1238b21e7834 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Tue, 30 Jul 2019 23:50:22 +0200 Subject: [PATCH 2/6] clutter/cogl: Use regions for clipping if necessary Use the new cogl function to perform clipping if the clip area consists of more than a single rectangle. https://gitlab.gnome.org/GNOME/mutter/merge_requests/867 --- clutter/clutter/cogl/clutter-stage-cogl.c | 41 +++++++++++++---------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c index 6dfde0b6bb7..4304db6e1cc 100644 --- a/clutter/clutter/cogl/clutter-stage-cogl.c +++ b/clutter/clutter/cogl/clutter-stage-cogl.c @@ -879,27 +879,34 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window, cairo_rectangle_int_t clip_rect; cairo_rectangle_int_t scissor_rect; - cairo_region_get_extents (fb_clip_region, &clip_rect); + stage_cogl->using_clipped_redraw = TRUE; - calculate_scissor_region (&clip_rect, - subpixel_compensation, - fb_width, fb_height, - &scissor_rect); + if (cairo_region_num_rectangles (fb_clip_region) == 1) + { + cairo_region_get_extents (fb_clip_region, &clip_rect); - CLUTTER_NOTE (CLIPPING, - "Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n", - scissor_rect.x, - scissor_rect.y, - scissor_rect.width, - scissor_rect.height); + calculate_scissor_region (&clip_rect, + subpixel_compensation, + fb_width, fb_height, + &scissor_rect); - stage_cogl->using_clipped_redraw = TRUE; + CLUTTER_NOTE (CLIPPING, + "Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n", + scissor_rect.x, + scissor_rect.y, + scissor_rect.width, + scissor_rect.height); - cogl_framebuffer_push_scissor_clip (fb, - scissor_rect.x, - scissor_rect.y, - scissor_rect.width, - scissor_rect.height); + cogl_framebuffer_push_scissor_clip (fb, + scissor_rect.x, + scissor_rect.y, + scissor_rect.width, + scissor_rect.height); + } + else + { + cogl_framebuffer_push_region_clip (fb, fb_clip_region); + } paint_stage (stage_cogl, view, fb_clip_region); -- GitLab From e44bd2edb4e957a9a787b4d9a68e52ce4e0bbf3d Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sat, 20 Jul 2019 18:33:11 +0200 Subject: [PATCH 3/6] compositor: Use redraw clip region to cull out children This will avoid repainting too much of the background if the bounding box turned out to be too large. https://bugzilla.gnome.org/show_bug.cgi?id=782344 --- src/compositor/meta-window-group.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c index 29ec1e74223..b8a33cc30fa 100644 --- a/src/compositor/meta-window-group.c +++ b/src/compositor/meta-window-group.c @@ -56,7 +56,7 @@ meta_window_group_paint (ClutterActor *actor) { cairo_region_t *clip_region; cairo_region_t *unobscured_region; - cairo_rectangle_int_t visible_rect, clip_rect; + cairo_rectangle_int_t visible_rect; int paint_x_origin, paint_y_origin; int screen_width, screen_height; @@ -112,10 +112,7 @@ meta_window_group_paint (ClutterActor *actor) * sizes, we could intersect this with an accurate union of the * monitors to avoid painting shadows that are visible only in the * holes. */ - clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage), - &clip_rect); - - clip_region = cairo_region_create_rectangle (&clip_rect); + clip_region = clutter_stage_get_redraw_clip (CLUTTER_STAGE (stage)); cairo_region_translate (clip_region, -paint_x_origin, -paint_y_origin); -- GitLab From a586f6a152e35cb05faf2f7290f45436ff0bff26 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 20 Oct 2019 13:14:09 +0200 Subject: [PATCH 4/6] cogl: Drop unused struct field We only ever stored that the current clip uses the stencil buffer, but never read it back. It doesn't seem like we'll have an use for it. https://gitlab.gnome.org/GNOME/mutter/merge_requests/867 --- cogl/cogl/cogl-context-private.h | 5 ----- cogl/cogl/driver/gl/cogl-clip-stack-gl.c | 3 --- 2 files changed, 8 deletions(-) diff --git a/cogl/cogl/cogl-context-private.h b/cogl/cogl/cogl-context-private.h index e497c445149..785295f90de 100644 --- a/cogl/cogl/cogl-context-private.h +++ b/cogl/cogl/cogl-context-private.h @@ -270,11 +270,6 @@ struct _CoglContext same state multiple times. When the clip state is flushed this will hold a reference */ CoglClipStack *current_clip_stack; - /* Whether the stencil buffer was used as part of the current clip - state. If TRUE then any further use of the stencil buffer (such - as for drawing paths) would need to be merged with the existing - stencil buffer */ - gboolean current_clip_stack_uses_stencil; /* This is used as a temporary buffer to fill a CoglBuffer when cogl_buffer_map fails and we only want to map to fill it with new diff --git a/cogl/cogl/driver/gl/cogl-clip-stack-gl.c b/cogl/cogl/driver/gl/cogl-clip-stack-gl.c index 31f078f93d7..2bc754cc063 100644 --- a/cogl/cogl/driver/gl/cogl-clip-stack-gl.c +++ b/cogl/cogl/driver/gl/cogl-clip-stack-gl.c @@ -383,7 +383,6 @@ _cogl_clip_stack_gl_flush (CoglClipStack *stack, { COGL_NOTE (CLIPPING, "Flushed empty clip stack"); - ctx->current_clip_stack_uses_stencil = FALSE; GE (ctx, glDisable (GL_SCISSOR_TEST)); return; } @@ -502,6 +501,4 @@ _cogl_clip_stack_gl_flush (CoglClipStack *stack, * box */ } } - - ctx->current_clip_stack_uses_stencil = using_stencil_buffer; } -- GitLab From 353d7909f6abc0fa717287fc67e387c6c831f9b6 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 20 Oct 2019 13:36:44 +0200 Subject: [PATCH 5/6] clutter: Check updated devices with the current clip We do check the clip area as an optimization to know which input devices might need updating state after a relayout (Assuming that if a device is under a non-painted area, it's actor beneath didn't change). Use the clip region for this, and drop the last usage of the clip region bounds. https://gitlab.gnome.org/GNOME/mutter/merge_requests/867 --- clutter/clutter/clutter-stage.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 4b6f46612cb..1acca69950e 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -1394,11 +1394,10 @@ _clutter_stage_check_updated_pointers (ClutterStage *stage) ClutterDeviceManager *device_manager; GSList *updating = NULL; const GSList *devices; - cairo_rectangle_int_t clip; + cairo_region_t *clip; graphene_point_t point; - gboolean has_clip; - has_clip = _clutter_stage_window_get_redraw_clip_bounds (priv->impl, &clip); + clip = _clutter_stage_window_get_redraw_clip (priv->impl); device_manager = clutter_device_manager_get_default (); devices = clutter_device_manager_peek_devices (device_manager); @@ -1421,9 +1420,7 @@ _clutter_stage_check_updated_pointers (ClutterStage *stage) if (!clutter_input_device_get_coords (dev, NULL, &point)) continue; - if (!has_clip || - (point.x >= clip.x && point.x < clip.x + clip.width && - point.y >= clip.y && point.y < clip.y + clip.height)) + if (!clip || cairo_region_contains_point (clip, point.x, point.y)) updating = g_slist_prepend (updating, dev); break; default: -- GitLab From f4bf48a7d7aaf4805f6ebe434c5f5a8ec421c1cc Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 20 Oct 2019 13:38:28 +0200 Subject: [PATCH 6/6] clutter: Drop unused API clutter_stage_*_get_clip_region_bounds() is no longer used and may be removed. https://gitlab.gnome.org/GNOME/mutter/merge_requests/867 --- clutter/clutter/clutter-stage-window.c | 17 ------------- clutter/clutter/clutter-stage-window.h | 2 -- clutter/clutter/clutter-stage.c | 35 -------------------------- clutter/clutter/clutter-stage.h | 3 --- 4 files changed, 57 deletions(-) diff --git a/clutter/clutter/clutter-stage-window.c b/clutter/clutter/clutter-stage-window.c index c859264b3ea..68a763d445a 100644 --- a/clutter/clutter/clutter-stage-window.c +++ b/clutter/clutter/clutter-stage-window.c @@ -249,23 +249,6 @@ _clutter_stage_window_get_redraw_clip (ClutterStageWindow *window) return NULL; } -gboolean -_clutter_stage_window_get_redraw_clip_bounds (ClutterStageWindow *window, - cairo_rectangle_int_t *stage_clip) -{ - cairo_region_t *redraw_clip; - - g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), FALSE); - - redraw_clip = _clutter_stage_window_get_redraw_clip (window); - if (!redraw_clip) - return FALSE; - - cairo_region_get_extents (redraw_clip, stage_clip); - cairo_region_destroy (redraw_clip); - return TRUE; -} - void _clutter_stage_window_set_accept_focus (ClutterStageWindow *window, gboolean accept_focus) diff --git a/clutter/clutter/clutter-stage-window.h b/clutter/clutter/clutter-stage-window.h index a06c5190d51..c99e9594d58 100644 --- a/clutter/clutter/clutter-stage-window.h +++ b/clutter/clutter/clutter-stage-window.h @@ -98,8 +98,6 @@ void _clutter_stage_window_add_redraw_clip (ClutterStageWin cairo_rectangle_int_t *stage_clip); gboolean _clutter_stage_window_has_redraw_clips (ClutterStageWindow *window); gboolean _clutter_stage_window_ignoring_redraw_clips (ClutterStageWindow *window); -gboolean _clutter_stage_window_get_redraw_clip_bounds (ClutterStageWindow *window, - cairo_rectangle_int_t *clip); cairo_region_t * _clutter_stage_window_get_redraw_clip (ClutterStageWindow *window); void _clutter_stage_window_set_accept_focus (ClutterStageWindow *window, diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 1acca69950e..02377867a8f 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -1629,41 +1629,6 @@ clutter_stage_get_redraw_clip (ClutterStage *stage) return cairo_region_create_rectangle (&clip); } -/** - * clutter_stage_get_redraw_clip_bounds: - * @stage: A #ClutterStage - * @clip: (out caller-allocates): Return location for the clip bounds - * - * Gets the bounds of the current redraw for @stage in stage pixel - * coordinates. E.g., if only a single actor has queued a redraw then - * Clutter may redraw the stage with a clip so that it doesn't have to - * paint every pixel in the stage. This function would then return the - * bounds of that clip. An application can use this information to - * avoid some extra work if it knows that some regions of the stage - * aren't going to be painted. This should only be called while the - * stage is being painted. If there is no current redraw clip then - * this function will set @clip to the full extents of the stage. - * - * Since: 1.8 - */ -void -clutter_stage_get_redraw_clip_bounds (ClutterStage *stage, - cairo_rectangle_int_t *clip) -{ - ClutterStagePrivate *priv; - - g_return_if_fail (CLUTTER_IS_STAGE (stage)); - g_return_if_fail (clip != NULL); - - priv = stage->priv; - - if (!_clutter_stage_window_get_redraw_clip_bounds (priv->impl, clip)) - { - /* Set clip to the full extents of the stage */ - _clutter_stage_window_get_geometry (priv->impl, clip); - } -} - static ClutterActor * _clutter_stage_do_pick_on_view (ClutterStage *stage, float x, diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h index 88cd96ad5ca..5910e614002 100644 --- a/clutter/clutter/clutter-stage.h +++ b/clutter/clutter/clutter-stage.h @@ -206,9 +206,6 @@ guchar * clutter_stage_read_pixels (ClutterStage gint height); CLUTTER_EXPORT -void clutter_stage_get_redraw_clip_bounds (ClutterStage *stage, - cairo_rectangle_int_t *clip); -CLUTTER_EXPORT cairo_region_t * clutter_stage_get_redraw_clip (ClutterStage *stage); CLUTTER_EXPORT void clutter_stage_ensure_viewport (ClutterStage *stage); -- GitLab