static cairo_int_status_t _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup, cairo_gl_context_t *ctx, int vertex_size) { if (! _cairo_gl_context_is_flushed (ctx) && (! cairo_region_equal (ctx->clip_region, setup->clip_region) || ! _cairo_clip_equal (ctx->clip, setup->clip))) _cairo_gl_composite_flush (ctx); cairo_region_destroy (ctx->clip_region); ctx->clip_region = cairo_region_reference (setup->clip_region); _cairo_clip_destroy (ctx->clip); ctx->clip = _cairo_clip_copy (setup->clip); assert (!setup->clip_region || !setup->clip); if (ctx->clip_region) { _disable_stencil_buffer (); glEnable (GL_SCISSOR_TEST); return CAIRO_INT_STATUS_SUCCESS; } if (ctx->clip) return _cairo_gl_composite_setup_painted_clipping (setup, ctx, vertex_size); _disable_stencil_buffer (); glDisable (GL_SCISSOR_TEST); return CAIRO_INT_STATUS_SUCCESS; }
static cairo_int_status_t _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup, cairo_gl_context_t *ctx, int vertex_size) { cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; cairo_gl_surface_t *dst = setup->dst; cairo_clip_t *clip = setup->clip; if (clip->num_boxes == 1 && clip->path == NULL) { _scissor_to_box (dst, &clip->boxes[0]); goto disable_stencil_buffer_and_return; } /* If we cannot reduce the clip to a rectangular region, we clip using the stencil buffer. */ glDisable (GL_SCISSOR_TEST); if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto disable_stencil_buffer_and_return; } glDepthMask (GL_TRUE); glEnable (GL_STENCIL_TEST); glClearStencil (0); glClear (GL_STENCIL_BUFFER_BIT); glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc (GL_EQUAL, 1, 0xffffffff); glColorMask (0, 0, 0, 0); status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip); if (unlikely (status)) { glColorMask (1, 1, 1, 1); goto disable_stencil_buffer_and_return; } /* We want to only render to the stencil buffer, so draw everything now. Flushing also unbinds the VBO, which we want to rebind for regular drawing. */ _cairo_gl_composite_flush (ctx); _cairo_gl_composite_setup_vbo (ctx, vertex_size); glColorMask (1, 1, 1, 1); glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc (GL_EQUAL, 1, 0xffffffff); return CAIRO_INT_STATUS_SUCCESS; disable_stencil_buffer_and_return: _disable_stencil_buffer (); return status; }
static cairo_int_status_t _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup, cairo_gl_context_t *ctx, int vertex_size) { cairo_bool_t clip_changing = TRUE; cairo_bool_t clip_region_changing = TRUE; if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region) goto disable_all_clipping; clip_changing = ! _cairo_clip_equal (ctx->clip, setup->clip); clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region); if (! _cairo_gl_context_is_flushed (ctx) && (clip_region_changing || clip_changing)) _cairo_gl_composite_flush (ctx); assert (!setup->clip_region || !setup->clip); /* setup->clip is only used by the msaa compositor and setup->clip_region * only by the other compositors, so it's safe to wait to clean up obsolete * clips. */ if (clip_region_changing) { cairo_region_destroy (ctx->clip_region); ctx->clip_region = cairo_region_reference (setup->clip_region); } if (clip_changing) { _cairo_clip_destroy (ctx->clip); ctx->clip = _cairo_clip_copy (setup->clip); } /* For clip regions, we scissor right before drawing. */ if (setup->clip_region) goto disable_all_clipping; if (setup->clip) return _cairo_gl_composite_setup_painted_clipping (setup, ctx, vertex_size); disable_all_clipping: _disable_stencil_buffer (); glDisable (GL_SCISSOR_TEST); return CAIRO_INT_STATUS_SUCCESS; }
static cairo_int_status_t _draw_clip_to_stencil_buffer (cairo_gl_context_t *ctx, cairo_gl_composite_t *setup, cairo_clip_t *clip) { cairo_int_status_t status; assert (! _cairo_clip_is_all_clipped (clip)); if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) return CAIRO_INT_STATUS_UNSUPPORTED; glDepthMask (GL_TRUE); glEnable (GL_STENCIL_TEST); glClearStencil (0); glClear (GL_STENCIL_BUFFER_BIT); glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc (GL_EQUAL, 1, 0xffffffff); glColorMask (0, 0, 0, 0); status = _draw_clip (ctx, setup, clip); if (unlikely (status)) { glColorMask (1, 1, 1, 1); _disable_stencil_buffer (); return status; } /* We want to only render to the stencil buffer, so draw everything now. */ _cairo_gl_composite_flush (ctx); glColorMask (1, 1, 1, 1); glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc (GL_EQUAL, 1, 0xffffffff); return status;; }
static cairo_int_status_t _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup, cairo_gl_context_t *ctx, int vertex_size, cairo_bool_t equal_clip) { cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; cairo_gl_surface_t *dst = setup->dst; cairo_clip_t *clip = setup->clip; cairo_traps_t traps; const cairo_rectangle_int_t *clip_extents; if (clip->num_boxes == 1 && clip->path == NULL) { _scissor_to_box (dst, &clip->boxes[0]); goto disable_stencil_buffer_and_return; } if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto disable_stencil_buffer_and_return; } if (! ctx->states_cache.depth_mask ) { glDepthMask (GL_TRUE); ctx->states_cache.depth_mask = TRUE; } glEnable (GL_STENCIL_TEST); clip_extents = _cairo_clip_get_extents ((const cairo_clip_t *)clip); _cairo_gl_scissor_to_extents (dst, clip_extents); if (equal_clip) return CAIRO_INT_STATUS_SUCCESS; glClearStencil (0); glClear (GL_STENCIL_BUFFER_BIT); glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc (GL_EQUAL, 1, 0xffffffff); glColorMask (0, 0, 0, 0); _cairo_traps_init (&traps); status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip, &traps); _cairo_traps_fini (&traps); if (unlikely (status)) { glColorMask (1, 1, 1, 1); goto disable_stencil_buffer_and_return; } /* We want to only render to the stencil buffer, so draw everything now. Flushing also unbinds the VBO, which we want to rebind for regular drawing. */ _cairo_gl_composite_flush (ctx); _cairo_gl_composite_setup_vbo (ctx, vertex_size); glColorMask (1, 1, 1, 1); glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc (GL_EQUAL, 1, 0xffffffff); return CAIRO_INT_STATUS_SUCCESS; disable_stencil_buffer_and_return: _disable_stencil_buffer (); return status; }
static cairo_int_status_t _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_gl_composite_t setup; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; cairo_gl_context_t *ctx = NULL; cairo_int_status_t status; cairo_traps_t traps; cairo_bool_t used_stencil_buffer; if (antialias != CAIRO_ANTIALIAS_NONE) return CAIRO_INT_STATUS_UNSUPPORTED; _cairo_traps_init (&traps); status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (unlikely (status)) goto cleanup_traps; status = _cairo_gl_composite_init (&setup, composite->op, dst, FALSE, /* assume_component_alpha */ &composite->bounded); if (unlikely (status)) goto cleanup_traps; status = _cairo_gl_composite_set_source (&setup, &composite->source_pattern.base, &composite->source_sample_area, &composite->bounded); if (unlikely (status)) goto cleanup_setup; status = _cairo_gl_composite_begin_tristrip (&setup, &ctx); if (unlikely (status)) goto cleanup_setup; status = _scissor_and_clip (ctx, &setup, composite, &used_stencil_buffer); if (unlikely (status)) goto cleanup_setup; status = _draw_traps (ctx, &setup, &traps); if (unlikely (status)) goto cleanup_setup; _cairo_gl_composite_flush (ctx); cleanup_setup: _cairo_gl_composite_fini (&setup); if (ctx) { glDisable (GL_SCISSOR_TEST); _disable_stencil_buffer (); status = _cairo_gl_context_release (ctx, status); } cleanup_traps: _cairo_traps_fini (&traps); return status; }
static cairo_int_status_t _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite, const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias) { cairo_int_status_t status; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; struct _tristrip_composite_info info; cairo_bool_t used_stencil_buffer_for_clip; if (antialias != CAIRO_ANTIALIAS_NONE) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_gl_composite_init (&info.setup, composite->op, dst, FALSE, /* assume_component_alpha */ &composite->bounded); if (unlikely (status)) return status; info.ctx = NULL; status = _cairo_gl_composite_set_source (&info.setup, &composite->source_pattern.base, &composite->source_sample_area, &composite->bounded); if (unlikely (status)) goto finish; status = _cairo_gl_composite_begin_tristrip (&info.setup, &info.ctx); if (unlikely (status)) goto finish; status = _scissor_and_clip (info.ctx, &info.setup, composite, &used_stencil_buffer_for_clip); if (unlikely (status)) goto finish; status = _cairo_path_fixed_stroke_to_shaper ((cairo_path_fixed_t *) path, style, ctm, ctm_inverse, tolerance, _stroke_shaper_add_triangle, _stroke_shaper_add_triangle_fan, _stroke_shaper_add_quad, &info); if (unlikely (status)) goto finish; _cairo_gl_composite_flush (info.ctx); finish: _cairo_gl_composite_fini (&info.setup); if (info.ctx) { glDisable (GL_SCISSOR_TEST); _disable_stencil_buffer (); status = _cairo_gl_context_release (info.ctx, status); } return status; }
static cairo_int_status_t _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup, cairo_gl_context_t *ctx, int vertex_size) { cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; cairo_gl_surface_t *dst = setup->dst; cairo_clip_t *clip = setup->clip; if (clip->num_boxes == 1 && clip->path == NULL) { _scissor_to_box (dst, &clip->boxes[0]); goto disable_stencil_buffer_and_return; } if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto disable_stencil_buffer_and_return; } /* We only want to clear the part of the stencil buffer * that we are about to use. It also does not hurt to * scissor around the painted clip. */ _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (clip)); /* The clip is not rectangular, so use the stencil buffer. */ glDepthMask (GL_TRUE); glEnable (GL_STENCIL_TEST); /* Texture surfaces have private depth/stencil buffers, so we can * rely on any previous clip being cached there. */ if (_cairo_gl_surface_is_texture (setup->dst)) { cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer; if (_cairo_clip_equal (old_clip, setup->clip)) goto activate_stencil_buffer_and_return; if (old_clip) { _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer); } setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip); } glClearStencil (0); glClear (GL_STENCIL_BUFFER_BIT); glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc (GL_EQUAL, 1, 0xffffffff); glColorMask (0, 0, 0, 0); status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip); if (unlikely (status)) { glColorMask (1, 1, 1, 1); goto disable_stencil_buffer_and_return; } /* We want to only render to the stencil buffer, so draw everything now. Flushing also unbinds the VBO, which we want to rebind for regular drawing. */ _cairo_gl_composite_flush (ctx); _cairo_gl_composite_setup_vbo (ctx, vertex_size); activate_stencil_buffer_and_return: glColorMask (1, 1, 1, 1); glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc (GL_EQUAL, 1, 0xffffffff); return CAIRO_INT_STATUS_SUCCESS; disable_stencil_buffer_and_return: _disable_stencil_buffer (); return status; }