1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Intel Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is Red Hat, Inc.
33 * Chris Wilson <chris@chris-wilson.co.uk>
38 #include "cairo-composite-rectangles-private.h"
39 #include "cairo-drm-i965-private.h"
40 #include "cairo-error-private.h"
41 #include "cairo-rtree-private.h"
43 typedef struct _i965_glyphs i965_glyphs_t;
46 (*i965_get_rectangle_func_t) (i965_glyphs_t *glyphs);
49 i965_get_rectangle_func_t get_rectangle;
52 struct i965_vbo head, *tail;
54 unsigned int vbo_offset;
59 i965_glyphs_emit_rectangle (i965_glyphs_t *glyphs)
61 return i965_add_rectangle (glyphs->shader.device);
65 i965_glyphs_accumulate_rectangle (i965_glyphs_t *glyphs)
70 size = glyphs->shader.device->rectangle_size;
71 if (unlikely (glyphs->vbo_offset + size > I965_VERTEX_SIZE)) {
74 vbo = malloc (sizeof (struct i965_vbo));
75 if (unlikely (vbo == NULL)) {
79 glyphs->tail->next = vbo;
83 vbo->bo = intel_bo_create (&glyphs->shader.device->intel,
84 I965_VERTEX_SIZE, I965_VERTEX_SIZE,
85 FALSE, I915_TILING_NONE, 0);
88 glyphs->vbo_offset = 0;
89 glyphs->vbo_base = intel_bo_map (&glyphs->shader.device->intel, vbo->bo);
92 vertices = glyphs->vbo_base + glyphs->vbo_offset;
93 glyphs->vbo_offset += size;
94 glyphs->tail->count += 3;
100 i965_add_glyph_rectangle (i965_glyphs_t *glyphs,
103 intel_glyph_t *glyph)
108 * 2 vertex coordinates
109 * 1 glyph texture coordinate
112 v = glyphs->get_rectangle (glyphs);
115 *v++ = x2; *v++ = y2;
116 *v++ = glyph->texcoord[0];
119 *v++ = x1; *v++ = y2;
120 *v++ = glyph->texcoord[1];
123 *v++ = x1; *v++ = y1;
124 *v++ = glyph->texcoord[2];
127 static cairo_status_t
128 i965_surface_mask_internal (i965_surface_t *dst,
130 const cairo_pattern_t *source,
131 i965_surface_t *mask,
133 const cairo_composite_rectangles_t *extents)
135 i965_device_t *device;
136 i965_shader_t shader;
137 cairo_region_t *clip_region = NULL;
138 cairo_status_t status;
140 i965_shader_init (&shader, dst, op);
142 status = i965_shader_acquire_pattern (&shader, &shader.source,
143 source, &extents->bounded);
144 if (unlikely (status))
147 shader.mask.type.vertex = VS_NONE;
148 shader.mask.type.fragment = FS_SURFACE;
149 shader.mask.base.content = mask->intel.drm.base.content;
150 shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST);
151 shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE);
153 cairo_matrix_init_translate (&shader.mask.base.matrix,
155 -extents->bounded.y);
156 cairo_matrix_scale (&shader.mask.base.matrix,
157 1. / mask->intel.drm.width,
158 1. / mask->intel.drm.height);
160 shader.mask.base.bo = to_intel_bo (mask->intel.drm.bo);
161 shader.mask.base.format = mask->intel.drm.format;
162 shader.mask.base.width = mask->intel.drm.width;
163 shader.mask.base.height = mask->intel.drm.height;
164 shader.mask.base.stride = mask->intel.drm.stride;
167 status = _cairo_clip_get_region (clip, &clip_region);
168 assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
170 if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
173 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
174 i965_shader_set_clip (&shader, clip);
177 status = cairo_device_acquire (dst->intel.drm.base.device);
178 if (unlikely (status))
181 device = i965_device (dst);
183 status = i965_shader_commit (&shader, device);
184 if (unlikely (status))
187 if (clip_region != NULL) {
188 unsigned int n, num_rectangles;
190 num_rectangles = cairo_region_num_rectangles (clip_region);
191 for (n = 0; n < num_rectangles; n++) {
192 cairo_rectangle_int_t rect;
194 cairo_region_get_rectangle (clip_region, n, &rect);
196 i965_shader_add_rectangle (&shader,
198 rect.width, rect.height);
201 i965_shader_add_rectangle (&shader,
204 extents->bounded.width,
205 extents->bounded.height);
208 if (! extents->is_bounded)
209 status = i965_fixup_unbounded (dst, extents, clip);
212 cairo_device_release (&device->intel.base.base);
214 i965_shader_fini (&shader);
219 i965_surface_glyphs (void *abstract_surface,
221 const cairo_pattern_t *source,
224 cairo_scaled_font_t *scaled_font,
228 i965_surface_t *surface = abstract_surface;
229 i965_surface_t *mask = NULL;
230 i965_device_t *device;
231 i965_glyphs_t glyphs;
232 cairo_composite_rectangles_t extents;
233 cairo_clip_t local_clip;
234 cairo_bool_t have_clip = FALSE;
235 cairo_bool_t overlap;
236 cairo_region_t *clip_region = NULL;
237 intel_bo_t *last_bo = NULL;
238 cairo_scaled_glyph_t *glyph_cache[64];
239 cairo_status_t status;
240 int mask_x = 0, mask_y = 0;
244 status = _cairo_composite_rectangles_init_for_glyphs (&extents,
245 surface->intel.drm.width,
246 surface->intel.drm.height,
252 if (unlikely (status))
255 if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents.mask))
258 if (clip != NULL && extents.is_bounded) {
259 clip = _cairo_clip_init_copy (&local_clip, clip);
260 status = _cairo_clip_rectangle (clip, &extents.bounded);
261 if (unlikely (status))
267 if (overlap || ! extents.is_bounded) {
268 cairo_format_t format;
270 format = CAIRO_FORMAT_A8;
271 if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
272 format = CAIRO_FORMAT_ARGB32;
274 mask = (i965_surface_t *)
275 i965_surface_create_internal (&i965_device (surface)->intel.base,
277 extents.bounded.width,
278 extents.bounded.height,
281 if (unlikely (mask->intel.drm.base.status))
282 return mask->intel.drm.base.status;
284 status = _cairo_surface_paint (&mask->intel.drm.base,
285 CAIRO_OPERATOR_CLEAR,
286 &_cairo_pattern_clear.base,
288 if (unlikely (status)) {
289 cairo_surface_destroy (&mask->intel.drm.base);
293 i965_shader_init (&glyphs.shader, mask, CAIRO_OPERATOR_ADD);
295 status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
296 &_cairo_pattern_white.base,
298 if (unlikely (status)) {
299 cairo_surface_destroy (&mask->intel.drm.base);
303 mask_x = -extents.bounded.x;
304 mask_y = -extents.bounded.y;
306 i965_shader_init (&glyphs.shader, surface, op);
308 status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
309 source, &extents.bounded);
310 if (unlikely (status))
314 status = _cairo_clip_get_region (clip, &clip_region);
315 assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
317 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
318 i965_shader_set_clip (&glyphs.shader, clip);
322 glyphs.head.next = NULL;
323 glyphs.head.bo = NULL;
324 glyphs.head.count = 0;
325 glyphs.tail = &glyphs.head;
327 device = i965_device (surface);
328 if (mask != NULL || clip_region == NULL) {
329 glyphs.get_rectangle = i965_glyphs_emit_rectangle;
331 glyphs.get_rectangle = i965_glyphs_accumulate_rectangle;
332 glyphs.head.bo = intel_bo_create (&device->intel,
333 I965_VERTEX_SIZE, I965_VERTEX_SIZE,
334 FALSE, I915_TILING_NONE, 0);
335 if (unlikely (glyphs.head.bo == NULL))
336 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
338 glyphs.vbo_base = intel_bo_map (&device->intel, glyphs.head.bo);
340 glyphs.vbo_offset = 0;
342 status = cairo_device_acquire (&device->intel.base.base);
343 if (unlikely (status))
346 _cairo_scaled_font_freeze_cache (scaled_font);
347 //private = _cairo_scaled_font_get_device (scaled_font, device);
348 if (scaled_font->surface_private == NULL) {
349 scaled_font->surface_private = device;
350 scaled_font->surface_backend = surface->intel.drm.base.backend;
351 cairo_list_add (&scaled_font->link, &device->intel.fonts);
354 memset (glyph_cache, 0, sizeof (glyph_cache));
356 for (i = 0; i < num_glyphs; i++) {
357 cairo_scaled_glyph_t *scaled_glyph;
358 int x, y, x1, x2, y1, y2;
359 int cache_index = g[i].index % ARRAY_LENGTH (glyph_cache);
360 intel_glyph_t *glyph;
362 scaled_glyph = glyph_cache[cache_index];
363 if (scaled_glyph == NULL ||
364 _cairo_scaled_glyph_index (scaled_glyph) != g[i].index)
366 status = _cairo_scaled_glyph_lookup (scaled_font,
368 CAIRO_SCALED_GLYPH_INFO_METRICS,
370 if (unlikely (status))
373 glyph_cache[cache_index] = scaled_glyph;
376 if (unlikely (scaled_glyph->metrics.width == 0 ||
377 scaled_glyph->metrics.height == 0))
382 /* XXX glyph images are snapped to pixel locations */
383 x = _cairo_lround (g[i].x);
384 y = _cairo_lround (g[i].y);
386 x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
387 y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
388 x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
389 y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
391 if (x2 < extents.bounded.x ||
392 y2 < extents.bounded.y ||
393 x1 > extents.bounded.x + extents.bounded.width ||
394 y1 > extents.bounded.y + extents.bounded.height)
399 if (scaled_glyph->surface_private == NULL) {
400 status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph);
401 if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) {
402 status = CAIRO_STATUS_SUCCESS;
405 if (unlikely (status))
408 glyph = intel_glyph_pin (scaled_glyph->surface_private);
410 if (glyph->cache->buffer.bo != last_bo) {
411 intel_buffer_cache_t *cache = glyph->cache;
413 glyphs.shader.mask.type.vertex = VS_GLYPHS;
414 glyphs.shader.mask.type.fragment = FS_GLYPHS;
415 glyphs.shader.mask.type.pattern = PATTERN_BASE;
417 glyphs.shader.mask.base.bo = cache->buffer.bo;
418 glyphs.shader.mask.base.format = cache->buffer.format;
419 glyphs.shader.mask.base.width = cache->buffer.width;
420 glyphs.shader.mask.base.height = cache->buffer.height;
421 glyphs.shader.mask.base.stride = cache->buffer.stride;
422 glyphs.shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST);
423 glyphs.shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE);
424 glyphs.shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */
426 glyphs.shader.committed = FALSE;
427 status = i965_shader_commit (&glyphs.shader, device);
428 if (unlikely (status))
431 last_bo = cache->buffer.bo;
434 x2 = x1 + glyph->width;
435 y2 = y1 + glyph->height;
438 x1 += mask_x, x2 += mask_x;
440 y1 += mask_y, y2 += mask_y;
442 i965_add_glyph_rectangle (&glyphs, x1, y1, x2, y2, glyph);
445 if (mask != NULL && clip_region != NULL)
446 i965_clipped_vertices (device, &glyphs.head, clip_region);
448 status = CAIRO_STATUS_SUCCESS;
450 _cairo_scaled_font_thaw_cache (scaled_font);
451 cairo_device_release (surface->intel.drm.base.device);
453 i965_shader_fini (&glyphs.shader);
455 if (glyphs.head.bo != NULL) {
456 struct i965_vbo *vbo, *next;
458 intel_bo_destroy (&device->intel, glyphs.head.bo);
459 for (vbo = glyphs.head.next; vbo != NULL; vbo = next) {
461 intel_bo_destroy (&device->intel, vbo->bo);
466 if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
467 cairo_path_fixed_t path;
469 _cairo_path_fixed_init (&path);
470 status = _cairo_scaled_font_glyph_path (scaled_font,
471 g + i, num_glyphs - i,
473 if (mask_x | mask_y) {
474 _cairo_path_fixed_translate (&path,
475 _cairo_fixed_from_int (mask_x),
476 _cairo_fixed_from_int (mask_y));
478 if (likely (status == CAIRO_STATUS_SUCCESS)) {
479 status = surface->intel.drm.base.backend->fill (glyphs.shader.target,
481 mask != NULL ? &_cairo_pattern_white.base : source,
483 CAIRO_FILL_RULE_WINDING,
485 scaled_font->options.antialias,
488 _cairo_path_fixed_fini (&path);
492 if (likely (status == CAIRO_STATUS_SUCCESS)) {
493 status = i965_surface_mask_internal (surface, op, source, mask,
496 cairo_surface_finish (&mask->intel.drm.base);
497 cairo_surface_destroy (&mask->intel.drm.base);
501 _cairo_clip_fini (&local_clip);