void _cairo_gl_composite_flush (cairo_gl_context_t *ctx) { unsigned int count; int i; if (_cairo_gl_context_is_flushed (ctx)) return; count = ctx->vb_offset / ctx->vertex_size; _cairo_gl_composite_unmap_vertex_buffer (ctx); if (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS) { if (ctx->draw_mode == CAIRO_GL_LINE_STRIP || ctx->draw_mode == CAIRO_GL_LINES) _cairo_gl_composite_draw_line (ctx); else _cairo_gl_composite_draw_tristrip (ctx); } else { assert (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES); _cairo_gl_composite_draw_triangles_with_clip_region (ctx, count); } for (i = 0; i < ARRAY_LENGTH (&ctx->glyph_cache); i++) _cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]); _cairo_gl_image_cache_unlock (ctx); }
void _cairo_gl_composite_flush (cairo_gl_context_t *ctx) { unsigned int count; int i; if (_cairo_gl_context_is_flushed (ctx)) return; count = ctx->vb_offset / ctx->vertex_size; _cairo_gl_composite_unmap_vertex_buffer (ctx); if ( _cairo_array_num_elements (&ctx->tristrip_indices) > 0) { _cairo_gl_composite_draw_tristrip (ctx); } else if (ctx->clip_region) { int i, num_rectangles = cairo_region_num_rectangles (ctx->clip_region); for (i = 0; i < num_rectangles; i++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (ctx->clip_region, i, &rect); glScissor (rect.x, rect.y, rect.width, rect.height); _cairo_gl_composite_draw (ctx, count); } } else { _cairo_gl_composite_draw (ctx, count); } for (i = 0; i < ARRAY_LENGTH (&ctx->glyph_cache); i++) _cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]); }
void _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx, cairo_gl_tex_t tex_unit) { cairo_gl_dispatch_t *dispatch = &ctx->dispatch; if (!_cairo_gl_context_is_flushed (ctx)) _cairo_gl_composite_flush (ctx); switch (ctx->operands[tex_unit].type) { default: case CAIRO_GL_OPERAND_COUNT: ASSERT_NOT_REACHED; case CAIRO_GL_OPERAND_NONE: break; /* fall through */ case CAIRO_GL_OPERAND_CONSTANT: break; case CAIRO_GL_OPERAND_TEXTURE: dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit); break; case CAIRO_GL_OPERAND_LINEAR_GRADIENT: case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit); break; } memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t)); }
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; }
cairo_status_t _cairo_gl_composite_begin_tristrip (cairo_gl_composite_t *setup, cairo_gl_context_t **ctx_out) { cairo_gl_context_t *ctx; cairo_status_t status; cairo_gl_shader_t *shader; int src_size, dst_size; cairo_gl_operand_t default_mask; memset (&default_mask, 0, sizeof (cairo_gl_operand_t)); assert (setup->dst); status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx); if (unlikely (status)) return status; *ctx_out = ctx; /* Finish any pending operations from other GL compositors. */ if (! _cairo_gl_context_is_flushed (ctx)) _cairo_gl_composite_flush (ctx); glEnable (GL_BLEND); status = _cairo_gl_get_shader_by_type (ctx, &setup->src, &default_mask, setup->spans, CAIRO_GL_SHADER_IN_NORMAL, &shader); if (unlikely (status)) { status = _cairo_gl_context_release (ctx, status); return status; } _cairo_gl_context_set_destination (ctx, setup->dst); _cairo_gl_set_operator (ctx, setup->op, FALSE); _cairo_gl_set_shader (ctx, shader); _cairo_gl_composite_bind_to_shader (ctx, setup); dst_size = 2 * sizeof (GLfloat); src_size = _cairo_gl_operand_get_vertex_size (setup->src.type); ctx->vertex_size = dst_size + src_size; ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo); ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2, GL_FLOAT, GL_FALSE, ctx->vertex_size, NULL); ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, ctx->vertex_size, dst_size); return status; }
static void _cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx, unsigned int size_per_vertex) { if (ctx->vertex_size != size_per_vertex) _cairo_gl_composite_flush (ctx); if (_cairo_gl_context_is_flushed (ctx)) { ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2, GL_FLOAT, GL_FALSE, size_per_vertex, ctx->vb); ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX); } ctx->vertex_size = size_per_vertex; }
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_bool_t _cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx, unsigned int size_per_vertex) { cairo_bool_t vertex_size_changed = ctx->vertex_size != size_per_vertex; if (vertex_size_changed) { ctx->vertex_size = size_per_vertex; _cairo_gl_composite_flush (ctx); } if (_cairo_gl_context_is_flushed (ctx)) { ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2, GL_FLOAT, GL_FALSE, size_per_vertex, ctx->vb); ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX); } return vertex_size_changed; }
cairo_status_t _cairo_gl_composite_begin (cairo_gl_composite_t *setup, cairo_gl_context_t **ctx_out) { unsigned int dst_size, src_size, mask_size, vertex_size; cairo_gl_context_t *ctx; cairo_status_t status; cairo_bool_t component_alpha; cairo_gl_shader_t *shader; assert (setup->dst); status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx); if (unlikely (status)) return status; glEnable (GL_BLEND); component_alpha = setup->mask.type == CAIRO_GL_OPERAND_TEXTURE && setup->mask.texture.attributes.has_component_alpha; /* Do various magic for component alpha */ if (component_alpha) { status = _cairo_gl_composite_begin_component_alpha (ctx, setup); if (unlikely (status)) goto FAIL; } else { if (ctx->pre_shader) { _cairo_gl_composite_flush (ctx); ctx->pre_shader = NULL; } } status = _cairo_gl_get_shader_by_type (ctx, &setup->src, &setup->mask, setup->spans, component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE : CAIRO_GL_SHADER_IN_NORMAL, &shader); if (unlikely (status)) { ctx->pre_shader = NULL; goto FAIL; } if (ctx->current_shader != shader) _cairo_gl_composite_flush (ctx); status = CAIRO_STATUS_SUCCESS; dst_size = 2 * sizeof (GLfloat); src_size = _cairo_gl_operand_get_vertex_size (setup->src.type); mask_size = _cairo_gl_operand_get_vertex_size (setup->mask.type); vertex_size = dst_size + src_size + mask_size; if (setup->spans) vertex_size += sizeof (GLfloat); if (ctx->vertex_size != vertex_size) _cairo_gl_composite_flush (ctx); _cairo_gl_context_set_destination (ctx, setup->dst); if (_cairo_gl_context_is_flushed (ctx)) { ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo); ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2, GL_FLOAT, GL_FALSE, vertex_size, NULL); ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX); } _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size); if (setup->spans) _cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size + mask_size); else ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX); _cairo_gl_set_operator (ctx, setup->op, component_alpha); ctx->vertex_size = vertex_size; if (_cairo_gl_context_is_flushed (ctx)) { if (ctx->pre_shader) { _cairo_gl_set_shader (ctx, ctx->pre_shader); _cairo_gl_composite_bind_to_shader (ctx, setup); } _cairo_gl_set_shader (ctx, shader); _cairo_gl_composite_bind_to_shader (ctx, setup); } if (! _cairo_gl_context_is_flushed (ctx) && ! cairo_region_equal (ctx->clip_region, setup->clip_region)) _cairo_gl_composite_flush (ctx); cairo_region_destroy (ctx->clip_region); ctx->clip_region = cairo_region_reference (setup->clip_region); if (ctx->clip_region) glEnable (GL_SCISSOR_TEST); else glDisable (GL_SCISSOR_TEST); *ctx_out = ctx; FAIL: if (unlikely (status)) status = _cairo_gl_context_release (ctx, status); return status; }
cairo_status_t _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup, cairo_gl_context_t **ctx_out, cairo_bool_t multisampling) { unsigned int dst_size, src_size, mask_size, vertex_size; cairo_gl_context_t *ctx; cairo_status_t status; cairo_bool_t component_alpha; cairo_gl_shader_t *shader; cairo_operator_t op = setup->op; cairo_surface_t *mask_surface = NULL; assert (setup->dst); status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx); if (unlikely (status)) return status; _cairo_gl_context_set_destination (ctx, setup->dst, multisampling); if (ctx->states_cache.blend_enabled == FALSE) { glEnable (GL_BLEND); ctx->states_cache.blend_enabled = TRUE; } component_alpha = setup->mask.type == CAIRO_GL_OPERAND_TEXTURE && setup->mask.texture.attributes.has_component_alpha; /* Do various magic for component alpha */ if (component_alpha) { status = _cairo_gl_composite_begin_component_alpha (ctx, setup); if (unlikely (status)) goto FAIL; } else { if (ctx->pre_shader) { _cairo_gl_composite_flush (ctx); ctx->pre_shader = NULL; } } status = _cairo_gl_get_shader_by_type (ctx, &setup->src, &setup->mask, setup->spans, component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE : CAIRO_GL_SHADER_IN_NORMAL, &shader); if (unlikely (status)) { ctx->pre_shader = NULL; goto FAIL; } if (ctx->current_shader != shader) _cairo_gl_composite_flush (ctx); status = CAIRO_STATUS_SUCCESS; dst_size = 2 * sizeof (GLfloat); src_size = _cairo_gl_operand_get_vertex_size (&setup->src); mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask); vertex_size = dst_size + src_size + mask_size; if (setup->spans) vertex_size += sizeof (GLfloat); _cairo_gl_composite_setup_vbo (ctx, vertex_size); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size); if (setup->spans) _cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size + mask_size); else { ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COVERAGE_ATTRIB_INDEX); ctx->spans = FALSE; } /* XXX: Shoot me - we have converted CLEAR to DEST_OUT, so the dst_factor would be GL_ONE_MINUS_SRC_ALPHA, if the mask is a surface and mask content not content_alpha, we want to use GL_ONE_MINUS_SRC_COLOR, otherwise, we use GL_ONE_MINUS_SRC_ALPHA */ if (setup->mask.type == CAIRO_GL_OPERAND_TEXTURE) mask_surface = &setup->mask.texture.surface->base; if (op == CAIRO_OPERATOR_CLEAR && component_alpha && mask_surface != NULL && cairo_surface_get_content (mask_surface) == CAIRO_CONTENT_ALPHA) component_alpha = FALSE; _cairo_gl_set_operator (ctx, setup->op, component_alpha); if (_cairo_gl_context_is_flushed (ctx)) { if (ctx->pre_shader) { _cairo_gl_set_shader (ctx, ctx->pre_shader); _cairo_gl_composite_bind_to_shader (ctx, setup); } _cairo_gl_set_shader (ctx, shader); _cairo_gl_composite_bind_to_shader (ctx, setup); } status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size); if (unlikely (status)) goto FAIL; *ctx_out = ctx; FAIL: if (unlikely (status)) status = _cairo_gl_context_release (ctx, status); return status; }
cairo_status_t _cairo_gl_composite_begin (cairo_gl_composite_t *setup, cairo_gl_context_t **ctx_out) { unsigned int dst_size, src_size, mask_size, vertex_size; cairo_gl_context_t *ctx; cairo_status_t status; cairo_bool_t component_alpha; cairo_gl_shader_t *shader; assert (setup->dst); status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx); if (unlikely (status)) return status; _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample); glEnable (GL_BLEND); component_alpha = setup->mask.type == CAIRO_GL_OPERAND_TEXTURE && setup->mask.texture.attributes.has_component_alpha; /* Do various magic for component alpha */ if (component_alpha) { status = _cairo_gl_composite_begin_component_alpha (ctx, setup); if (unlikely (status)) goto FAIL; } else { if (ctx->pre_shader) { _cairo_gl_composite_flush (ctx); ctx->pre_shader = NULL; } } status = _cairo_gl_get_shader_by_type (ctx, &setup->src, &setup->mask, setup->spans, component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE : CAIRO_GL_SHADER_IN_NORMAL, &shader); if (unlikely (status)) { ctx->pre_shader = NULL; goto FAIL; } if (ctx->current_shader != shader) _cairo_gl_composite_flush (ctx); status = CAIRO_STATUS_SUCCESS; dst_size = 2 * sizeof (GLfloat); src_size = _cairo_gl_operand_get_vertex_size (setup->src.type); mask_size = _cairo_gl_operand_get_vertex_size (setup->mask.type); vertex_size = dst_size + src_size + mask_size; if (setup->spans) vertex_size += sizeof (GLfloat); _cairo_gl_composite_setup_vbo (ctx, vertex_size); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size); _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size, dst_size + src_size + mask_size); _cairo_gl_set_operator (ctx, setup->op, component_alpha); if (_cairo_gl_context_is_flushed (ctx)) { if (ctx->pre_shader) { _cairo_gl_set_shader (ctx, ctx->pre_shader); _cairo_gl_composite_bind_to_shader (ctx, setup); } _cairo_gl_set_shader (ctx, shader); _cairo_gl_composite_bind_to_shader (ctx, setup); } status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size); if (unlikely (status)) goto FAIL; *ctx_out = ctx; FAIL: if (unlikely (status)) status = _cairo_gl_context_release (ctx, status); return status; }
cairo_status_t _cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup, cairo_gl_context_t *ctx) { unsigned int dst_size, src_size, mask_size, vertex_size; cairo_status_t status; cairo_gl_shader_t *shader; cairo_bool_t component_alpha; cairo_bool_t vertex_size_changed; component_alpha = setup->mask.type == CAIRO_GL_OPERAND_TEXTURE && setup->mask.texture.attributes.has_component_alpha; /* Do various magic for component alpha */ if (component_alpha) { status = _cairo_gl_composite_begin_component_alpha (ctx, setup); if (unlikely (status)) return status; } else { if (ctx->pre_shader) { _cairo_gl_composite_flush (ctx); ctx->pre_shader = NULL; } } status = _cairo_gl_get_shader_by_type (ctx, &setup->src, &setup->mask, setup->spans, component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE : CAIRO_GL_SHADER_IN_NORMAL, &shader); if (unlikely (status)) { ctx->pre_shader = NULL; return status; } if (ctx->current_shader != shader) _cairo_gl_composite_flush (ctx); status = CAIRO_STATUS_SUCCESS; dst_size = 2 * sizeof (GLfloat); src_size = _cairo_gl_operand_get_vertex_size (&setup->src); mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask); vertex_size = dst_size + src_size + mask_size; if (setup->spans) vertex_size += sizeof (GLfloat); vertex_size_changed = _cairo_gl_composite_setup_vbo (ctx, vertex_size); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size, vertex_size_changed); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size, vertex_size_changed); _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size, dst_size + src_size + mask_size); _cairo_gl_set_operator (ctx, setup->op, component_alpha); if (_cairo_gl_context_is_flushed (ctx)) { if (ctx->pre_shader) { _cairo_gl_set_shader (ctx, ctx->pre_shader); _cairo_gl_composite_bind_to_shader (ctx, setup); } _cairo_gl_set_shader (ctx, shader); _cairo_gl_composite_bind_to_shader (ctx, setup); } return status; }