[mutter/wip/carlosg/clip-regions: 5/6] cogl: Add support for clipping regions
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/carlosg/clip-regions: 5/6] cogl: Add support for clipping regions
- Date: Tue, 30 Jul 2019 21:54:31 +0000 (UTC)
commit 311458f9eeabd306c25738eee16c6b7227c3e03e
Author: Carlos Garnacho <carlosg gnome org>
Date: Tue Jul 30 23:48:45 2019 +0200
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.
cogl/cogl/cogl-clip-stack.c | 33 +++++++++++++++++
cogl/cogl/cogl-clip-stack.h | 18 ++++++++-
cogl/cogl/cogl-framebuffer.c | 17 +++++++++
cogl/cogl/cogl-framebuffer.h | 5 +++
cogl/cogl/driver/gl/cogl-clip-stack-gl.c | 63 ++++++++++++++++++++++++++++++++
5 files changed, 135 insertions(+), 1 deletion(-)
---
diff --git a/cogl/cogl/cogl-clip-stack.c b/cogl/cogl/cogl-clip-stack.c
index 0461687e7..b4e1a03fa 100644
--- a/cogl/cogl/cogl-clip-stack.c
+++ b/cogl/cogl/cogl-clip-stack.c
@@ -296,6 +296,32 @@ _cogl_clip_stack_push_primitive (CoglClipStack *stack,
return (CoglClipStack *) entry;
}
+CoglClipStack *
+_cogl_clip_stack_push_region (CoglClipStack *stack,
+ CoglMatrixEntry *modelview_entry,
+ 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->matrix_entry = cogl_matrix_entry_ref (modelview_entry);
+ entry_region->region = cairo_region_reference (region);
+
+ return entry;
+}
+
CoglClipStack *
_cogl_clip_stack_ref (CoglClipStack *entry)
{
@@ -337,6 +363,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 eb2c43282..fedae3f4f 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,16 @@ struct _CoglClipStackPrimitive
float bounds_y2;
};
+struct _CoglClipStackRegion
+{
+ CoglClipStack _parent_data;
+
+ /* The matrix that was current when the clip was set */
+ CoglMatrixEntry *matrix_entry;
+
+ cairo_region_t *region;
+};
+
CoglClipStack *
_cogl_clip_stack_push_window_rectangle (CoglClipStack *stack,
int x_offset,
@@ -189,6 +201,10 @@ _cogl_clip_stack_push_primitive (CoglClipStack *stack,
CoglMatrixEntry *modelview_entry,
CoglMatrixEntry *projection_entry,
const float *viewport);
+CoglClipStack *
+_cogl_clip_stack_push_region (CoglClipStack *stack,
+ CoglMatrixEntry *modelview_entry,
+ 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 527fd81ea..687d54b5a 100644
--- a/cogl/cogl/cogl-framebuffer.c
+++ b/cogl/cogl/cogl-framebuffer.c
@@ -1817,6 +1817,23 @@ cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer,
COGL_FRAMEBUFFER_STATE_CLIP;
}
+void
+cogl_framebuffer_push_region_clip (CoglFramebuffer *framebuffer,
+ cairo_region_t *region)
+{
+ CoglMatrixEntry *modelview_entry =
+ _cogl_framebuffer_get_modelview_entry (framebuffer);
+
+ framebuffer->clip_stack =
+ _cogl_clip_stack_push_region (framebuffer->clip_stack,
+ modelview_entry,
+ 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 08ed3354b..7cc415ea1 100644
--- a/cogl/cogl/cogl-framebuffer.h
+++ b/cogl/cogl/cogl-framebuffer.h
@@ -56,6 +56,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer;
#include <cogl/cogl-euler.h>
#include <cogl/cogl-texture.h>
#include <glib-object.h>
+#include <cairo.h>
G_BEGIN_DECLS
@@ -639,6 +640,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 f8a471828..200de00a9 100644
--- a/cogl/cogl/driver/gl/cogl-clip-stack-gl.c
+++ b/cogl/cogl/driver/gl/cogl-clip-stack-gl.c
@@ -260,6 +260,59 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
}
+static void
+add_stencil_clip_region (CoglFramebuffer *framebuffer,
+ CoglMatrixEntry *modelview_entry,
+ cairo_region_t *region)
+{
+ CoglMatrixStack *projection_stack =
+ _cogl_framebuffer_get_projection_stack (framebuffer);
+ CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+ int num_rectangles = cairo_region_num_rectangles (region);
+ int width, height, 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);
+
+ GE( ctx, glEnable (GL_STENCIL_TEST) );
+
+ /* Initially disallow everything */
+ GE( ctx, glClearStencil (0) );
+ GE( ctx, glClear (GL_STENCIL_BUFFER_BIT) );
+
+ /* Punch out a hole to allow the rectangles */
+ GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x1) );
+ GE( ctx, glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) );
+
+ width = cogl_framebuffer_get_width (framebuffer);
+ height = cogl_framebuffer_get_height (framebuffer);
+
+ for (i = 0; i < num_rectangles; i++)
+ {
+ cairo_rectangle_int_t rect;
+ float x1, y1, x2, y2;
+
+ cairo_region_get_rectangle (region, i, &rect);
+
+ /* Transform coordinates to identity */
+ x1 = (rect.x * 2.0 / width) - 1;
+ y1 = 1 - (rect.y * 2.0 / height);
+ x2 = ((rect.x + rect.width) * 2.0 / width) -1;
+ y2 = 1 - ((rect.y + rect.height) * 2.0 / height);
+
+ _cogl_rectangle_immediate (framebuffer,
+ ctx->stencil_pipeline,
+ x1, y1, x2, y2);
+ }
+
+ /* Restore the stencil mode */
+ 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);
@@ -572,6 +625,16 @@ _cogl_clip_stack_gl_flush (CoglClipStack *stack,
}
break;
}
+ case COGL_CLIP_STACK_REGION:
+ {
+ CoglClipStackRegion *region = (CoglClipStackRegion *) entry;
+
+ COGL_NOTE (CLIPPING, "Adding stencil clip for region");
+
+ add_stencil_clip_region (framebuffer, region->matrix_entry, region->region);
+ using_stencil_buffer = TRUE;
+ break;
+ }
case COGL_CLIP_STACK_WINDOW_RECT:
break;
/* We don't need to do anything for window space rectangles because
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]