void _cairo_gl_context_set_destination (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface, cairo_bool_t multisampling) { /* OpenGL ES surfaces are always in MSAA mode once it's been turned on, * so we don't need to check whether we are switching modes for that * surface type. */ if (ctx->current_target == surface && ! surface->needs_update && (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES || surface->msaa_active == multisampling)) return; _cairo_gl_composite_flush (ctx); ctx->current_target = surface; surface->needs_update = FALSE; if (_cairo_gl_surface_is_texture (surface)) { if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) { _cairo_gl_ensure_framebuffer (ctx, surface); ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb); #if CAIRO_HAS_GL_SURFACE } else if (multisampling) _cairo_gl_activate_surface_as_multisampling (ctx, surface); else { _cairo_gl_activate_surface_as_nonmultisampling (ctx, surface); #endif } } else { ctx->make_current (ctx, surface); #if CAIRO_HAS_GL_SURFACE if (multisampling) glEnable(GL_MULTISAMPLE); else glDisable(GL_MULTISAMPLE); #endif ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0); #if CAIRO_HAS_GL_SURFACE glDrawBuffer (GL_BACK_LEFT); glReadBuffer (GL_BACK_LEFT); #endif } glViewport (0, 0, surface->width, surface->height); if (_cairo_gl_surface_is_texture (surface)) _gl_identity_ortho (ctx->modelviewprojection_matrix, 0, surface->width, 0, surface->height); else _gl_identity_ortho (ctx->modelviewprojection_matrix, 0, surface->width, surface->height, 0); }
void _cairo_gl_context_set_destination (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface, cairo_bool_t multisampling) { cairo_bool_t changing_surface, changing_sampling; /* The decision whether or not to use multisampling happens when * we create an OpenGL ES surface, so we can never switch modes. */ if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) multisampling = surface->msaa_active; changing_surface = ctx->current_target != surface || surface->needs_update; changing_sampling = surface->msaa_active != multisampling; if (! changing_surface && ! changing_sampling) return; if (! changing_surface) { _cairo_gl_composite_flush (ctx); _cairo_gl_context_bind_framebuffer (ctx, surface, multisampling); return; } _cairo_gl_composite_flush (ctx); ctx->current_target = surface; surface->needs_update = FALSE; if (! _cairo_gl_surface_is_texture (surface)) { ctx->make_current (ctx, surface); } _cairo_gl_context_bind_framebuffer (ctx, surface, multisampling); if (! _cairo_gl_surface_is_texture (surface)) { #if CAIRO_HAS_GL_SURFACE glDrawBuffer (GL_BACK_LEFT); glReadBuffer (GL_BACK_LEFT); #endif } glDisable (GL_DITHER); glViewport (0, 0, surface->width, surface->height); if (_cairo_gl_surface_is_texture (surface)) _gl_identity_ortho (ctx->modelviewprojection_matrix, 0, surface->width, 0, surface->height); else _gl_identity_ortho (ctx->modelviewprojection_matrix, 0, surface->width, surface->height, 0); }
void cairo_gl_surface_set_size (cairo_surface_t *abstract_surface, int width, int height) { cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface; if (unlikely (abstract_surface->status)) return; if (unlikely (abstract_surface->finished)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } if (! _cairo_surface_is_gl (abstract_surface) || _cairo_gl_surface_is_texture (surface)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; } if (surface->width != width || surface->height != height) { surface->needs_update = TRUE; surface->width = width; surface->height = height; } }
static void _wgl_acquire (void *abstract_ctx) { cairo_wgl_context_t *ctx = abstract_ctx; HDC current_dc; ctx->prev_dc = wglGetCurrentDC (); ctx->prev_rc = wglGetCurrentContext (); if (ctx->base.current_target == NULL || _cairo_gl_surface_is_texture (ctx->base.current_target)) { current_dc = ctx->dummy_dc; } else { cairo_wgl_surface_t *surface = (cairo_wgl_surface_t *) ctx->base.current_target; current_dc = surface->dc; } if (ctx->prev_dc != current_dc || (ctx->prev_rc != ctx->rc && current_dc != ctx->dummy_dc)) { wglMakeCurrent (current_dc, ctx->rc); } }
void _cairo_gl_context_bind_framebuffer (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface, cairo_bool_t multisampling) { if (_cairo_gl_surface_is_texture (surface)) { /* OpenGL ES surfaces only have either a multisample framebuffer or a * singlesample framebuffer, so we cannot switch back and forth. */ if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) { _cairo_gl_ensure_framebuffer (ctx, surface); ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb); return; } #if CAIRO_HAS_GL_SURFACE if (multisampling) bind_multisample_framebuffer (ctx, surface); else bind_singlesample_framebuffer (ctx, surface); #endif } else { ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0); #if CAIRO_HAS_GL_SURFACE if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) { if (multisampling) glEnable (GL_MULTISAMPLE); else glDisable (GL_MULTISAMPLE); } #endif } surface->msaa_active = multisampling; }
static void query_surface_capabilities (cairo_gl_surface_t *surface) { GLint samples, stencil_bits; cairo_gl_context_t *ctx; cairo_int_status_t status; /* Texture surfaces are create in such a way that they always have stencil and multisample bits if possible, so we don't need to query their capabilities lazily. */ if (_cairo_gl_surface_is_texture (surface)) return; if (surface->stencil_and_msaa_caps_initialized) return; surface->stencil_and_msaa_caps_initialized = TRUE; surface->supports_stencil = FALSE; surface->supports_msaa = FALSE; status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) return; _cairo_gl_context_set_destination (ctx, surface, FALSE); glGetIntegerv(GL_SAMPLES, &samples); glGetIntegerv(GL_STENCIL_BITS, &stencil_bits); surface->supports_stencil = stencil_bits > 0; surface->supports_msaa = samples > 1; status = _cairo_gl_context_release (ctx, status); }
static cairo_status_t _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand, const cairo_pattern_t *_src, cairo_gl_surface_t *dst, const cairo_rectangle_int_t *sample, const cairo_rectangle_int_t *extents, cairo_bool_t use_texgen) { const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src; cairo_surface_subsurface_t *sub; cairo_gl_surface_t *surface; cairo_surface_attributes_t *attributes; cairo_int_status_t status; sub = (cairo_surface_subsurface_t *) src->surface; if (sample->x < 0 || sample->y < 0 || sample->x + sample->width > sub->extents.width || sample->y + sample->height > sub->extents.height) { return _cairo_gl_subsurface_clone_operand_init (operand, _src, dst, sample, extents, use_texgen); } surface = (cairo_gl_surface_t *) sub->target; if (surface->base.device && surface->base.device != dst->base.device) return CAIRO_INT_STATUS_UNSUPPORTED; if (! _cairo_gl_surface_is_texture (surface)) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_gl_surface_resolve_multisampling (surface); if (unlikely (status)) return status; /* Translate the matrix from * (unnormalized src -> unnormalized src) to * (unnormalized dst -> unnormalized src) */ _cairo_gl_operand_copy(operand, &surface->operand); attributes = &operand->texture.attributes; attributes->matrix = src->base.matrix; attributes->matrix.x0 += sub->extents.x; attributes->matrix.y0 += sub->extents.y; cairo_matrix_multiply (&attributes->matrix, &attributes->matrix, &surface->operand.texture.attributes.matrix); attributes->extend = src->base.extend; attributes->filter = src->base.filter; attributes->has_component_alpha = src->base.has_component_alpha; operand->texture.texgen = use_texgen; return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_gl_surface_clone_similar (void *abstract_surface, cairo_surface_t *src, int src_x, int src_y, int width, int height, int *clone_offset_x, int *clone_offset_y, cairo_surface_t **clone_out) { cairo_gl_surface_t *surface = abstract_surface; cairo_int_status_t status; /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */ if (src->device == surface->base.device && _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) { status = _cairo_gl_surface_deferred_clear ((cairo_gl_surface_t *)src); if (unlikely (status)) return status; *clone_offset_x = 0; *clone_offset_y = 0; *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } else if (_cairo_surface_is_image (src)) { cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; cairo_gl_surface_t *clone; clone = (cairo_gl_surface_t *) _cairo_gl_surface_create_similar (&surface->base, src->content, width, height); if (clone == NULL) return UNSUPPORTED ("create_similar failed"); if (clone->base.status) return clone->base.status; status = _cairo_gl_surface_draw_image (clone, image_src, src_x, src_y, width, height, 0, 0); if (status) { cairo_surface_destroy (&clone->base); return status; } *clone_out = &clone->base; *clone_offset_x = src_x; *clone_offset_y = src_y; return CAIRO_STATUS_SUCCESS; } return UNSUPPORTED ("unknown src surface type in clone_similar"); }
static GLXDrawable _glx_get_current_drawable (cairo_glx_context_t *ctx) { if (ctx->base.current_target == NULL || _cairo_gl_surface_is_texture (ctx->base.current_target)) { return ctx->dummy_window; } return ((cairo_glx_surface_t *) ctx->base.current_target)->win; }
static void _scissor_to_rectangle (cairo_gl_surface_t *surface, const cairo_rectangle_int_t *r) { int y = r->y; if (_cairo_gl_surface_is_texture (surface) == FALSE) y = surface->height - (r->y + r->height); glScissor (r->x, y, r->width, r->height); glEnable (GL_SCISSOR_TEST); }
static EGLSurface _egl_get_current_surface (cairo_egl_context_t *ctx) { if (ctx->base.current_target == NULL || _cairo_gl_surface_is_texture (ctx->base.current_target)) { return ctx->dummy_surface; } return ((cairo_egl_surface_t *) ctx->base.current_target)->egl; }
static void _scissor_to_doubles (cairo_gl_surface_t *surface, double x1, double y1, double x2, double y2) { double height; height = y2 - y1; if (_cairo_gl_surface_is_texture (surface) == FALSE) y1 = surface->height - (y1 + height); glScissor (x1, y1, x2 - x1, height); glEnable (GL_SCISSOR_TEST); }
static cairo_status_t _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand, const cairo_pattern_t *_src, cairo_gl_surface_t *dst, const cairo_rectangle_int_t *sample, const cairo_rectangle_int_t *extents, cairo_bool_t use_texgen) { const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src; cairo_gl_surface_t *surface; cairo_surface_attributes_t *attributes; cairo_int_status_t status; surface = (cairo_gl_surface_t *) src->surface; if (surface->base.type != CAIRO_SURFACE_TYPE_GL) return CAIRO_INT_STATUS_UNSUPPORTED; if (surface->base.backend->type != CAIRO_SURFACE_TYPE_GL) { if (_cairo_surface_is_subsurface (&surface->base)) return _cairo_gl_subsurface_operand_init (operand, _src, dst, sample, extents, use_texgen); return CAIRO_INT_STATUS_UNSUPPORTED; } if (surface->base.device && surface->base.device != dst->base.device) return CAIRO_INT_STATUS_UNSUPPORTED; if (surface->base.device && ! _cairo_gl_surface_is_texture (surface)) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_gl_surface_resolve_multisampling (surface); if (unlikely (status)) return status; _cairo_gl_operand_copy(operand, &surface->operand); attributes = &operand->texture.attributes; cairo_matrix_multiply (&attributes->matrix, &src->base.matrix, &attributes->matrix); attributes->extend = src->base.extend; attributes->filter = src->base.filter; attributes->has_component_alpha = src->base.has_component_alpha; operand->texture.texgen = use_texgen; return CAIRO_STATUS_SUCCESS; }
cairo_bool_t _cairo_gl_ensure_stencil (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface) { if (! _cairo_gl_surface_is_texture (surface)) return TRUE; /* best guess for now, will check later */ if (! ctx->has_packed_depth_stencil) return FALSE; if (surface->msaa_active) return _cairo_gl_ensure_msaa_depth_stencil_buffer (ctx, surface); else return _cairo_gl_ensure_depth_stencil_buffer (ctx, surface); }
void _cairo_gl_scissor_to_extents (cairo_gl_surface_t *surface, const cairo_rectangle_int_t *extents) { int x1, y1, height; x1 = extents->x; y1 = extents->y; height = extents->height; if (_cairo_gl_surface_is_texture (surface) == FALSE) y1 = surface->height - (y1 + height); glScissor (x1, y1, extents->width, height); glEnable (GL_SCISSOR_TEST); }
void cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface) { cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface; if (unlikely (abstract_surface->status)) return; if (unlikely (abstract_surface->finished)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } if (! _cairo_surface_is_gl (abstract_surface)) { _cairo_surface_set_error (abstract_surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return; } if (! _cairo_gl_surface_is_texture (surface)) { cairo_gl_context_t *ctx; cairo_status_t status; status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) return; /* For swapping on EGL, at least, we need a valid context/target. */ _cairo_gl_context_set_destination (ctx, surface); /* And in any case we should flush any pending operations. */ _cairo_gl_composite_flush (ctx); ctx->swap_buffers (ctx, surface); status = _cairo_gl_context_release (ctx, status); if (status) status = _cairo_surface_set_error (abstract_surface, status); } }
static cairo_surface_t * _cairo_gl_surface_map_to_image (void *abstract_surface, const cairo_rectangle_int_t *extents) { cairo_gl_surface_t *surface = abstract_surface; cairo_image_surface_t *image; cairo_gl_context_t *ctx; GLenum format, type; pixman_format_code_t pixman_format; unsigned int cpp; cairo_bool_t invert; cairo_status_t status; /* Want to use a switch statement here but the compiler gets whiny. */ if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) { format = GL_BGRA; pixman_format = PIXMAN_a8r8g8b8; type = GL_UNSIGNED_INT_8_8_8_8_REV; cpp = 4; } else if (surface->base.content == CAIRO_CONTENT_COLOR) { format = GL_BGRA; pixman_format = PIXMAN_x8r8g8b8; type = GL_UNSIGNED_INT_8_8_8_8_REV; cpp = 4; } else if (surface->base.content == CAIRO_CONTENT_ALPHA) { format = GL_ALPHA; pixman_format = PIXMAN_a8; type = GL_UNSIGNED_BYTE; cpp = 1; } else { ASSERT_NOT_REACHED; return NULL; } /* * GLES2 supports only RGBA, UNSIGNED_BYTE so use that. * We are also using this format for ALPHA as GLES2 does not * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the * pixman image that is created has row_stride = row_width * bpp. */ if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES) { format = GL_RGBA; if (! _cairo_is_little_endian ()) { if (surface->base.content == CAIRO_CONTENT_COLOR) pixman_format = PIXMAN_r8g8b8x8; else pixman_format = PIXMAN_r8g8b8a8; } else { if (surface->base.content == CAIRO_CONTENT_COLOR) pixman_format = PIXMAN_x8b8g8r8; else pixman_format = PIXMAN_a8b8g8r8; } type = GL_UNSIGNED_BYTE; cpp = 4; } image = (cairo_image_surface_t*) _cairo_image_surface_create_with_pixman_format (NULL, pixman_format, extents->width, extents->height, -1); if (unlikely (image->base.status)) return &image->base; if (surface->base.serial == 0) return &image->base; status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) { cairo_surface_destroy (&image->base); return _cairo_surface_create_in_error (status); } cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y); /* This is inefficient, as we'd rather just read the thing without making * it the destination. But then, this is the fallback path, so let's not * fall back instead. */ _cairo_gl_composite_flush (ctx); _cairo_gl_context_set_destination (ctx, surface); invert = ! _cairo_gl_surface_is_texture (surface) && ctx->has_mesa_pack_invert; glPixelStorei (GL_PACK_ALIGNMENT, 4); if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp); if (invert) glPixelStorei (GL_PACK_INVERT_MESA, 1); glReadPixels (extents->x, extents->y, extents->width, extents->height, format, type, image->data); if (invert) glPixelStorei (GL_PACK_INVERT_MESA, 0); status = _cairo_gl_context_release (ctx, status); if (unlikely (status)) { cairo_surface_destroy (&image->base); image = (cairo_image_surface_t *) _cairo_surface_create_in_error (status); } return &image->base; }
cairo_status_t _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, cairo_image_surface_t *src, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { GLenum internal_format, format, type; cairo_bool_t has_alpha, needs_swap; cairo_image_surface_t *clone = NULL; cairo_gl_context_t *ctx; int cpp; cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; status = _cairo_gl_context_acquire (dst->base.device, &ctx); if (unlikely (status)) return status; if (! _cairo_gl_get_image_format_and_type (ctx->gl_flavor, src->pixman_format, &internal_format, &format, &type, &has_alpha, &needs_swap)) { cairo_bool_t is_supported; clone = _cairo_image_surface_coerce (src); if (unlikely (status = clone->base.status)) goto FAIL; is_supported = _cairo_gl_get_image_format_and_type (ctx->gl_flavor, clone->pixman_format, &internal_format, &format, &type, &has_alpha, &needs_swap); assert (is_supported); assert (!needs_swap); src = clone; } cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8; status = _cairo_gl_surface_flush (&dst->base); if (unlikely (status)) goto FAIL; if (_cairo_gl_surface_is_texture (dst)) { void *data_start = src->data + src_y * src->stride + src_x * cpp; void *data_start_gles2 = NULL; /* * Due to GL_UNPACK_ROW_LENGTH missing in GLES2 we have to extract the * image data ourselves in some cases. In particular, we must extract * the pixels if: * a. we don't want full-length lines or * b. the row stride cannot be handled by GL itself using a 4 byte * alignment constraint */ if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES && (src->width * cpp < src->stride - 3 || width != src->width)) { glPixelStorei (GL_UNPACK_ALIGNMENT, 1); status = _cairo_gl_surface_extract_image_data (src, src_x, src_y, width, height, &data_start_gles2); if (unlikely (status)) goto FAIL; data_start = data_start_gles2; } else { glPixelStorei (GL_UNPACK_ALIGNMENT, 4); if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp); } _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); glBindTexture (ctx->tex_target, dst->tex); glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexSubImage2D (ctx->tex_target, 0, dst_x, dst_y, width, height, format, type, data_start); free (data_start_gles2); /* If we just treated some rgb-only data as rgba, then we have to * go back and fix up the alpha channel where we filled in this * texture data. */ if (!has_alpha) { _cairo_gl_surface_fill_alpha_channel (dst, ctx, dst_x, dst_y, width, height); } } else { cairo_surface_t *tmp; tmp = _cairo_gl_surface_create_scratch (ctx, dst->base.content, width, height); if (unlikely (tmp->status)) goto FAIL; status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *) tmp, src, src_x, src_y, width, height, 0, 0); if (status == CAIRO_INT_STATUS_SUCCESS) { cairo_surface_pattern_t tmp_pattern; cairo_rectangle_int_t r; cairo_clip_t *clip; _cairo_pattern_init_for_surface (&tmp_pattern, tmp); cairo_matrix_init_translate (&tmp_pattern.base.matrix, -dst_x, -dst_y); tmp_pattern.base.filter = CAIRO_FILTER_NEAREST; tmp_pattern.base.extend = CAIRO_EXTEND_NONE; r.x = dst_x; r.y = dst_y; r.width = width; r.height = height; clip = _cairo_clip_intersect_rectangle (NULL, &r); status = _cairo_surface_paint (&dst->base, CAIRO_OPERATOR_SOURCE, &tmp_pattern.base, clip); _cairo_clip_destroy (clip); _cairo_pattern_fini (&tmp_pattern.base); } cairo_surface_destroy (tmp); } FAIL: status = _cairo_gl_context_release (ctx, status); if (clone) cairo_surface_destroy (&clone->base); 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; }