mirror of
https://github.com/brl/mutter.git
synced 2025-02-17 21:54:10 +00:00
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
This commit is contained in:
parent
8e172aeecb
commit
a1116bc6c8
@ -295,6 +295,30 @@ _cogl_clip_stack_push_primitive (CoglClipStack *stack,
|
|||||||
return (CoglClipStack *) entry;
|
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 *
|
CoglClipStack *
|
||||||
_cogl_clip_stack_ref (CoglClipStack *entry)
|
_cogl_clip_stack_ref (CoglClipStack *entry)
|
||||||
{
|
{
|
||||||
@ -336,6 +360,13 @@ _cogl_clip_stack_unref (CoglClipStack *entry)
|
|||||||
g_slice_free1 (sizeof (CoglClipStackPrimitive), entry);
|
g_slice_free1 (sizeof (CoglClipStackPrimitive), entry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case COGL_CLIP_STACK_REGION:
|
||||||
|
{
|
||||||
|
CoglClipStackRegion *region = (CoglClipStackRegion *) entry;
|
||||||
|
cairo_region_destroy (region->region);
|
||||||
|
g_slice_free1 (sizeof (CoglClipStackRegion), entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
@ -48,12 +48,14 @@ typedef struct _CoglClipStack CoglClipStack;
|
|||||||
typedef struct _CoglClipStackRect CoglClipStackRect;
|
typedef struct _CoglClipStackRect CoglClipStackRect;
|
||||||
typedef struct _CoglClipStackWindowRect CoglClipStackWindowRect;
|
typedef struct _CoglClipStackWindowRect CoglClipStackWindowRect;
|
||||||
typedef struct _CoglClipStackPrimitive CoglClipStackPrimitive;
|
typedef struct _CoglClipStackPrimitive CoglClipStackPrimitive;
|
||||||
|
typedef struct _CoglClipStackRegion CoglClipStackRegion;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
COGL_CLIP_STACK_RECT,
|
COGL_CLIP_STACK_RECT,
|
||||||
COGL_CLIP_STACK_WINDOW_RECT,
|
COGL_CLIP_STACK_WINDOW_RECT,
|
||||||
COGL_CLIP_STACK_PRIMITIVE
|
COGL_CLIP_STACK_PRIMITIVE,
|
||||||
|
COGL_CLIP_STACK_REGION,
|
||||||
} CoglClipStackType;
|
} CoglClipStackType;
|
||||||
|
|
||||||
/* A clip stack consists a list of entries. Each entry has a reference
|
/* A clip stack consists a list of entries. Each entry has a reference
|
||||||
@ -162,6 +164,13 @@ struct _CoglClipStackPrimitive
|
|||||||
float bounds_y2;
|
float bounds_y2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _CoglClipStackRegion
|
||||||
|
{
|
||||||
|
CoglClipStack _parent_data;
|
||||||
|
|
||||||
|
cairo_region_t *region;
|
||||||
|
};
|
||||||
|
|
||||||
CoglClipStack *
|
CoglClipStack *
|
||||||
_cogl_clip_stack_push_window_rectangle (CoglClipStack *stack,
|
_cogl_clip_stack_push_window_rectangle (CoglClipStack *stack,
|
||||||
int x_offset,
|
int x_offset,
|
||||||
@ -189,6 +198,9 @@ _cogl_clip_stack_push_primitive (CoglClipStack *stack,
|
|||||||
CoglMatrixEntry *modelview_entry,
|
CoglMatrixEntry *modelview_entry,
|
||||||
CoglMatrixEntry *projection_entry,
|
CoglMatrixEntry *projection_entry,
|
||||||
const float *viewport);
|
const float *viewport);
|
||||||
|
CoglClipStack *
|
||||||
|
cogl_clip_stack_push_region (CoglClipStack *stack,
|
||||||
|
cairo_region_t *region);
|
||||||
|
|
||||||
CoglClipStack *
|
CoglClipStack *
|
||||||
_cogl_clip_stack_pop (CoglClipStack *stack);
|
_cogl_clip_stack_pop (CoglClipStack *stack);
|
||||||
|
@ -1761,6 +1761,19 @@ cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer,
|
|||||||
COGL_FRAMEBUFFER_STATE_CLIP;
|
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
|
void
|
||||||
cogl_framebuffer_pop_clip (CoglFramebuffer *framebuffer)
|
cogl_framebuffer_pop_clip (CoglFramebuffer *framebuffer)
|
||||||
{
|
{
|
||||||
|
@ -54,6 +54,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer;
|
|||||||
#include <cogl/cogl-bitmap.h>
|
#include <cogl/cogl-bitmap.h>
|
||||||
#include <cogl/cogl-texture.h>
|
#include <cogl/cogl-texture.h>
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
#include <cairo.h>
|
||||||
|
|
||||||
#include <graphene.h>
|
#include <graphene.h>
|
||||||
|
|
||||||
@ -624,6 +625,10 @@ cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer,
|
|||||||
float bounds_x2,
|
float bounds_x2,
|
||||||
float bounds_y2);
|
float bounds_y2);
|
||||||
|
|
||||||
|
void
|
||||||
|
cogl_framebuffer_push_region_clip (CoglFramebuffer *framebuffer,
|
||||||
|
cairo_region_t *region);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cogl_framebuffer_pop_clip:
|
* cogl_framebuffer_pop_clip:
|
||||||
* @framebuffer: A #CoglFramebuffer pointer
|
* @framebuffer: A #CoglFramebuffer pointer
|
||||||
|
@ -115,6 +115,102 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
|
|||||||
GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
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,
|
typedef void (*SilhouettePaintCallback) (CoglFramebuffer *framebuffer,
|
||||||
CoglPipeline *pipeline,
|
CoglPipeline *pipeline,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
@ -382,6 +478,23 @@ _cogl_clip_stack_gl_flush (CoglClipStack *stack,
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case COGL_CLIP_STACK_WINDOW_RECT:
|
||||||
break;
|
break;
|
||||||
/* We don't need to do anything for window space rectangles because
|
/* We don't need to do anything for window space rectangles because
|
||||||
|
@ -478,7 +478,7 @@ if have_introspection
|
|||||||
sources: cogl_introspected_headers,
|
sources: cogl_introspected_headers,
|
||||||
nsversion: libmutter_api_version,
|
nsversion: libmutter_api_version,
|
||||||
namespace: 'Cogl',
|
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],
|
dependencies: [cogl_deps],
|
||||||
extra_args: introspection_args + [
|
extra_args: introspection_args + [
|
||||||
'-UCOGL_COMPILATION',
|
'-UCOGL_COMPILATION',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user