diff options
Diffstat (limited to 'libs/cairo-1.16.0/src/drm/cairo-drm-i915-glyphs.c')
-rw-r--r-- | libs/cairo-1.16.0/src/drm/cairo-drm-i915-glyphs.c | 564 |
1 files changed, 564 insertions, 0 deletions
diff --git a/libs/cairo-1.16.0/src/drm/cairo-drm-i915-glyphs.c b/libs/cairo-1.16.0/src/drm/cairo-drm-i915-glyphs.c new file mode 100644 index 0000000..3b0efc2 --- /dev/null +++ b/libs/cairo-1.16.0/src/drm/cairo-drm-i915-glyphs.c @@ -0,0 +1,564 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairoint.h" + +#include "cairo-composite-rectangles-private.h" +#include "cairo-drm-i915-private.h" +#include "cairo-error-private.h" +#include "cairo-rtree-private.h" +#include "cairo-clip-inline.h" + +static void +i915_emit_glyph_rectangle_zero (i915_device_t *device, + i915_shader_t *shader, + int x1, int y1, + int x2, int y2, + intel_glyph_t *glyph) +{ + float *v; + + /* Each vertex is: + * 2 vertex coordinates + */ + + v = i915_add_rectangle (device); + *v++ = x2; *v++ = y2; + *v++ = x1; *v++ = y2; + *v++ = x1; *v++ = y1; +} + +static void +i915_emit_glyph_rectangle_constant (i915_device_t *device, + i915_shader_t *shader, + int x1, int y1, + int x2, int y2, + intel_glyph_t *glyph) +{ + float *v; + + /* Each vertex is: + * 2 vertex coordinates + * 2 glyph texture coordinates + */ + + v = i915_add_rectangle (device); + + /* bottom right */ + *v++ = x2; *v++ = y2; + *v++ = glyph->texcoord[0]; + + /* bottom left */ + *v++ = x1; *v++ = y2; + *v++ = glyph->texcoord[1]; + + /* top left */ + *v++ = x1; *v++ = y1; + *v++ = glyph->texcoord[2]; +} + +static void +i915_emit_glyph_rectangle_general (i915_device_t *device, + i915_shader_t *shader, + int x1, int y1, + int x2, int y2, + intel_glyph_t *glyph) +{ + double s, t; + float *v; + + /* Each vertex is: + * 2 vertex coordinates + * [0-2] source texture coordinates + * 2 glyph texture coordinates + */ + + v = i915_add_rectangle (device); + + /* bottom right */ + *v++ = x2; *v++ = y2; + s = x2, t = y2; + switch (shader->source.type.vertex) { + case VS_ZERO: + case VS_CONSTANT: + break; + case VS_LINEAR: + *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t); + break; + case VS_TEXTURE: + cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t); + *v++ = s; *v++ = t; + break; + case VS_TEXTURE_16: + cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t); + *v++ = texcoord_2d_16 (s, t); + break; + } + *v++ = glyph->texcoord[0]; + + /* bottom left */ + *v++ = x1; *v++ = y2; + s = x1, t = y2; + switch (shader->source.type.vertex) { + case VS_ZERO: + case VS_CONSTANT: + break; + case VS_LINEAR: + *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t); + break; + case VS_TEXTURE: + cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t); + *v++ = s; *v++ = t; + break; + case VS_TEXTURE_16: + cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t); + *v++ = texcoord_2d_16 (s, t); + break; + } + *v++ = glyph->texcoord[1]; + + /* top left */ + *v++ = x1; *v++ = y1; + s = x1, t = y2; + switch (shader->source.type.vertex) { + case VS_ZERO: + case VS_CONSTANT: + break; + case VS_LINEAR: + *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t); + break; + case VS_TEXTURE: + cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t); + *v++ = s; *v++ = t; + break; + case VS_TEXTURE_16: + cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t); + *v++ = texcoord_2d_16 (s, t); + break; + } + *v++ = glyph->texcoord[2]; +} + +typedef void +(*i915_emit_glyph_rectangle_func_t) (i915_device_t *device, + i915_shader_t *shader, + int x1, int y1, + int x2, int y2, + intel_glyph_t *glyph); + +static cairo_status_t +i915_surface_mask_internal (i915_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *source, + i915_surface_t *mask, + cairo_clip_t *clip, + const cairo_composite_rectangles_t *extents) +{ + i915_device_t *device; + i915_shader_t shader; + cairo_region_t *clip_region = NULL; + cairo_status_t status; + + i915_shader_init (&shader, dst, op, 1.); + + status = i915_shader_acquire_pattern (&shader, &shader.source, + source, &extents->bounded); + if (unlikely (status)) + return status; + + shader.mask.type.vertex = VS_TEXTURE_16; + shader.mask.type.pattern = PATTERN_TEXTURE; + shader.mask.type.fragment = FS_TEXTURE; + shader.mask.base.content = mask->intel.drm.base.content; + shader.mask.base.texfmt = TEXCOORDFMT_2D_16; + shader.mask.base.n_samplers = 1; + shader.mask.base.sampler[0] = + (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) | + i915_texture_filter (CAIRO_FILTER_NEAREST); + shader.mask.base.sampler[1] = + SS3_NORMALIZED_COORDS | + i915_texture_extend (CAIRO_EXTEND_NONE); + + cairo_matrix_init_translate (&shader.mask.base.matrix, + -extents->bounded.x, + -extents->bounded.y); + cairo_matrix_scale (&shader.mask.base.matrix, + 1. / mask->intel.drm.width, + 1. / mask->intel.drm.height); + + shader.mask.base.bo = intel_bo_reference (to_intel_bo (mask->intel.drm.bo)); + shader.mask.base.offset[0] = 0; + shader.mask.base.map[0] = mask->map0; + shader.mask.base.map[1] = mask->map1; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + + if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + i915_shader_set_clip (&shader, clip); + } + + status = cairo_device_acquire (dst->intel.drm.base.device); + if (unlikely (status)) + goto CLEANUP_SHADER; + + device = i915_device (dst); + + status = i915_shader_commit (&shader, device); + if (unlikely (status)) + goto CLEANUP_DEVICE; + + if (clip_region != NULL) { + unsigned int n, num_rectangles; + + num_rectangles = cairo_region_num_rectangles (clip_region); + for (n = 0; n < num_rectangles; n++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (clip_region, n, &rect); + + shader.add_rectangle (&shader, + rect.x, rect.y, + rect.x + rect.width, rect.y + rect.height); + } + } else { + shader.add_rectangle (&shader, + extents->bounded.x, extents->bounded.y, + extents->bounded.x + extents->bounded.width, + extents->bounded.y + extents->bounded.height); + } + + if (! extents->is_bounded) + status = i915_fixup_unbounded (dst, extents, clip); + +CLEANUP_DEVICE: + cairo_device_release (&device->intel.base.base); +CLEANUP_SHADER: + i915_shader_fini (&shader); + return status; +} + +cairo_int_status_t +i915_surface_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip, + int *num_remaining) +{ + i915_surface_t *surface = abstract_surface; + i915_surface_t *mask = NULL; + i915_device_t *device; + i915_shader_t shader; + cairo_composite_rectangles_t extents; + cairo_clip_t local_clip; + cairo_bool_t have_clip = FALSE; + cairo_bool_t overlap; + cairo_region_t *clip_region = NULL; + intel_bo_t *last_bo = NULL; + i915_emit_glyph_rectangle_func_t emit_func; + cairo_scaled_glyph_t *glyph_cache[64]; + cairo_status_t status; + int mask_x = 0, mask_y = 0; + int i = 0; + + *num_remaining = 0; + status = _cairo_composite_rectangles_init_for_glyphs (&extents, + surface->intel.drm.width, + surface->intel.drm.height, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, + &overlap); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_rectangle (clip, &extents.mask)) + clip = NULL; + + if (clip != NULL && extents.is_bounded) { + clip = _cairo_clip_init_copy (&local_clip, clip); + status = _cairo_clip_rectangle (clip, &extents.bounded); + if (unlikely (status)) + return status; + + have_clip = TRUE; + } + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + if (unlikely (_cairo_status_is_error (status) || + status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + { + if (have_clip) + _cairo_clip_fini (&local_clip); + return status; + } + } + + if (i915_surface_needs_tiling (surface)) { + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (overlap || ! extents.is_bounded) { + cairo_format_t format; + + format = CAIRO_FORMAT_A8; + if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL) + format = CAIRO_FORMAT_ARGB32; + + mask = (i915_surface_t *) + i915_surface_create_internal (&i915_device (surface)->intel.base, + format, + extents.bounded.width, + extents.bounded.height, + I915_TILING_DEFAULT, + TRUE); + if (unlikely (mask->intel.drm.base.status)) + return mask->intel.drm.base.status; + + status = i915_surface_clear (mask); + if (unlikely (status)) { + cairo_surface_destroy (&mask->intel.drm.base); + return status; + } + + i915_shader_init (&shader, mask, CAIRO_OPERATOR_ADD, 1.); + + status = i915_shader_acquire_pattern (&shader, &shader.source, + &_cairo_pattern_white.base, + &extents.bounded); + if (unlikely (status)) { + cairo_surface_destroy (&mask->intel.drm.base); + return status; + } + + mask_x = -extents.bounded.x; + mask_y = -extents.bounded.y; + } else { + i915_shader_init (&shader, surface, op, 1.); + + status = i915_shader_acquire_pattern (&shader, &shader.source, + source, &extents.bounded); + if (unlikely (status)) + return status; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + + if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + i915_shader_set_clip (&shader, clip); + } + } + + shader.mask.type.fragment = FS_TEXTURE; + shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */ + shader.mask.base.texfmt = TEXCOORDFMT_2D_16; + shader.mask.base.n_samplers = 1; + shader.mask.base.sampler[0] = + (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) | + i915_texture_filter (CAIRO_FILTER_NEAREST); + shader.mask.base.sampler[1] = + SS3_NORMALIZED_COORDS | + i915_texture_extend (CAIRO_EXTEND_NONE); + + switch (shader.source.type.vertex) { + case VS_ZERO: + emit_func = i915_emit_glyph_rectangle_zero; + break; + case VS_CONSTANT: + emit_func = i915_emit_glyph_rectangle_constant; + break; + default: + case VS_LINEAR: + case VS_TEXTURE: + case VS_TEXTURE_16: + emit_func = i915_emit_glyph_rectangle_general; + break; + } + + status = cairo_device_acquire (surface->intel.drm.base.device); + if (unlikely (status)) + goto CLEANUP_SHADER; + + device = i915_device (surface); + + _cairo_scaled_font_freeze_cache (scaled_font); + if (scaled_font->surface_private == NULL) { + scaled_font->surface_private = device; + scaled_font->surface_backend = surface->intel.drm.base.backend; + cairo_list_add (&scaled_font->link, &device->intel.fonts); + } + + memset (glyph_cache, 0, sizeof (glyph_cache)); + + for (i = 0; i < num_glyphs; i++) { + cairo_scaled_glyph_t *scaled_glyph; + int x, y, x1, x2, y1, y2; + int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache); + intel_glyph_t *glyph; + + scaled_glyph = glyph_cache[cache_index]; + if (scaled_glyph == NULL || + _cairo_scaled_glyph_index (scaled_glyph) != glyphs[i].index) + { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[i].index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + &scaled_glyph); + if (unlikely (status)) + goto FINISH; + + glyph_cache[cache_index] = scaled_glyph; + } + + if (unlikely (scaled_glyph->metrics.width == 0 || + scaled_glyph->metrics.height == 0)) + { + continue; + } + + /* XXX glyph images are snapped to pixel locations */ + x = _cairo_lround (glyphs[i].x); + y = _cairo_lround (glyphs[i].y); + + x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); + y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); + x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x); + y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y); + + if (x2 < extents.bounded.x || + y2 < extents.bounded.y || + x1 > extents.bounded.x + extents.bounded.width || + y1 > extents.bounded.y + extents.bounded.height) + { + continue; + } + + if (scaled_glyph->surface_private == NULL) { + status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph); + if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) { + status = CAIRO_STATUS_SUCCESS; + continue; + } + if (unlikely (status)) + goto FINISH; + } + + glyph = intel_glyph_pin (scaled_glyph->surface_private); + if (glyph->cache->buffer.bo != last_bo) { + intel_buffer_cache_t *cache = glyph->cache; + + shader.mask.base.bo = cache->buffer.bo; + shader.mask.base.offset[0] = cache->buffer.offset; + shader.mask.base.map[0] = cache->buffer.map0; + shader.mask.base.map[1] = cache->buffer.map1; + shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */ + + status = i915_shader_commit (&shader, device); + if (unlikely (status)) + goto FINISH; + + last_bo = cache->buffer.bo; + } + + x2 = x1 + glyph->width; + y2 = y1 + glyph->height; + + if (mask_x) + x1 += mask_x, x2 += mask_x; + if (mask_y) + y1 += mask_y, y2 += mask_y; + + /* XXX clip glyph */ + emit_func (device, &shader, x1, y1, x2, y2, glyph); + } + + status = CAIRO_STATUS_SUCCESS; + FINISH: + _cairo_scaled_font_thaw_cache (scaled_font); + cairo_device_release (surface->intel.drm.base.device); + CLEANUP_SHADER: + i915_shader_fini (&shader); + + if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) { + cairo_path_fixed_t path; + + _cairo_path_fixed_init (&path); + status = _cairo_scaled_font_glyph_path (scaled_font, + glyphs + i, num_glyphs - i, + &path); + if (mask_x | mask_y) { + _cairo_path_fixed_translate (&path, + _cairo_fixed_from_int (mask_x), + _cairo_fixed_from_int (mask_y)); + } + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = surface->intel.drm.base.backend->fill (shader.target, + shader.op, + mask != NULL ? &_cairo_pattern_white.base : source, + &path, + CAIRO_FILL_RULE_WINDING, + 0, + scaled_font->options.antialias, + clip); + } + _cairo_path_fixed_fini (&path); + } + + if (mask != NULL) { + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = i915_surface_mask_internal (surface, op, source, mask, + clip, &extents); + } + cairo_surface_finish (&mask->intel.drm.base); + cairo_surface_destroy (&mask->intel.drm.base); + } + + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; +} |