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 inline void _cairo_gl_composite_draw (cairo_gl_context_t *ctx, unsigned int count) { if (! ctx->pre_shader) { glDrawArrays (GL_TRIANGLES, 0, count); } else { cairo_gl_shader_t *prev_shader = ctx->current_shader; _cairo_gl_set_shader (ctx, ctx->pre_shader); _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE); glDrawArrays (GL_TRIANGLES, 0, count); _cairo_gl_set_shader (ctx, prev_shader); _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE); glDrawArrays (GL_TRIANGLES, 0, count); } }
static inline void _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx) { cairo_array_t* indices = &ctx->tristrip_indices; const unsigned short *indices_array = _cairo_array_index_const (indices, 0); if (ctx->pre_shader) { cairo_gl_shader_t *prev_shader = ctx->current_shader; _cairo_gl_set_shader (ctx, ctx->pre_shader); _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE); glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array); _cairo_gl_set_shader (ctx, prev_shader); _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE); } glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array); _cairo_array_truncate (indices, 0); }
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; }
static cairo_status_t _render_glyphs (cairo_gl_surface_t *dst, int dst_x, int dst_y, cairo_operator_t op, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, const cairo_rectangle_int_t *glyph_extents, cairo_scaled_font_t *scaled_font, cairo_region_t *clip_region, int *remaining_glyphs) { cairo_format_t last_format = (cairo_format_t) -1; cairo_gl_glyph_cache_t *cache = NULL; cairo_gl_context_t *ctx; cairo_gl_glyphs_setup_t setup; cairo_gl_composite_setup_t composite_setup; cairo_status_t status; int i = 0; GLuint vbo = 0; status = _cairo_gl_operand_init (&composite_setup.src, source, dst, glyph_extents->x, glyph_extents->y, dst_x, dst_y, glyph_extents->width, glyph_extents->height); if (unlikely (status)) return status; ctx = _cairo_gl_context_acquire (dst->ctx); /* Set up the mask to source from the incoming vertex color. */ glActiveTexture (GL_TEXTURE1); glEnable (GL_TEXTURE_2D); /* IN: dst.argb = src.argb * mask.aaaa */ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1); glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1); glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA); glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); _cairo_gl_set_destination (dst); _cairo_gl_set_operator (dst, op); _cairo_gl_set_src_operand (ctx, &composite_setup); _cairo_scaled_font_freeze_cache (scaled_font); if (! _cairo_gl_surface_owns_font (dst, scaled_font)) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto CLEANUP_FONT; } if (scaled_font->surface_private == NULL) { /* XXX couple into list to remove on context destruction */ scaled_font->surface_private = ctx; scaled_font->surface_backend = &_cairo_gl_surface_backend; } /* Create our VBO so that we can accumulate a bunch of glyph primitives * into one giant DrawArrays. */ memset(&setup, 0, sizeof(setup)); setup.composite = &composite_setup; setup.clip = clip_region; setup.dst = dst; setup.vertex_size = 4; if (composite_setup.src.type == OPERAND_TEXTURE) setup.vertex_size += 2; setup.vbo_size = num_glyphs * 4 * setup.vertex_size; if (setup.vbo_size > 4096) setup.vbo_size = 4096; glGenBuffersARB (1, &vbo); glBindBufferARB (GL_ARRAY_BUFFER_ARB, vbo); glVertexPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat), (void *)(uintptr_t)(0)); glEnableClientState (GL_VERTEX_ARRAY); if (composite_setup.src.type == OPERAND_TEXTURE) { /* Note that we're packing texcoord 0 after texcoord 1, for * convenience. */ glClientActiveTexture (GL_TEXTURE0); glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat), (void *)(uintptr_t)(4 * sizeof (GLfloat))); glEnableClientState (GL_TEXTURE_COORD_ARRAY); } glClientActiveTexture (GL_TEXTURE1); glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat), (void *)(uintptr_t)(2 * sizeof (GLfloat))); glEnableClientState (GL_TEXTURE_COORD_ARRAY); for (i = 0; i < num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; double x_offset, y_offset; double x1, x2, y1, y2; status = _cairo_scaled_glyph_lookup (scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); if (unlikely (status)) goto FINISH; if (scaled_glyph->surface->width == 0 || scaled_glyph->surface->height == 0) { continue; } if (scaled_glyph->surface->width > GLYPH_CACHE_MAX_SIZE || scaled_glyph->surface->height > GLYPH_CACHE_MAX_SIZE) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto FINISH; } if (scaled_glyph->surface->format != last_format) { /* Switching textures, so flush any queued prims. */ _cairo_gl_flush_glyphs (ctx, &setup); glActiveTexture (GL_TEXTURE1); cache = cairo_gl_context_get_glyph_cache (ctx, scaled_glyph->surface->format); glBindTexture (GL_TEXTURE_2D, cache->tex); last_format = scaled_glyph->surface->format; } if (scaled_glyph->surface_private == NULL) { status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph); if (unlikely (_cairo_status_is_error (status))) goto FINISH; if (status == CAIRO_INT_STATUS_UNSUPPORTED) { /* Cache is full, so flush existing prims and try again. */ _cairo_gl_flush_glyphs (ctx, &setup); _cairo_gl_glyph_cache_unlock (cache); } status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph); if (unlikely (status)) goto FINISH; } x_offset = scaled_glyph->surface->base.device_transform.x0; y_offset = scaled_glyph->surface->base.device_transform.y0; x1 = _cairo_lround (glyphs[i].x - x_offset); y1 = _cairo_lround (glyphs[i].y - y_offset); x2 = x1 + scaled_glyph->surface->width; y2 = y1 + scaled_glyph->surface->height; _cairo_gl_emit_glyph_rectangle (ctx, &setup, x1, y1, x2, y2, _cairo_gl_glyph_cache_lock (cache, scaled_glyph)); } status = CAIRO_STATUS_SUCCESS; FINISH: _cairo_gl_flush_glyphs (ctx, &setup); CLEANUP_FONT: _cairo_scaled_font_thaw_cache (scaled_font); glDisable (GL_BLEND); glDisable (GL_SCISSOR_TEST); glDisableClientState (GL_VERTEX_ARRAY); glClientActiveTexture (GL_TEXTURE0); glDisableClientState (GL_TEXTURE_COORD_ARRAY); glActiveTexture (GL_TEXTURE0); glDisable (GL_TEXTURE_2D); glClientActiveTexture (GL_TEXTURE1); glDisableClientState (GL_TEXTURE_COORD_ARRAY); glActiveTexture (GL_TEXTURE1); glDisable (GL_TEXTURE_2D); if (vbo != 0) { glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0); glDeleteBuffersARB (1, &vbo); } _cairo_gl_context_release (ctx); _cairo_gl_operand_destroy (&composite_setup.src); *remaining_glyphs = num_glyphs - i; 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; }