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-i915-private.h"
40 #include "cairo-error-private.h"
41 #include "cairo-rtree-private.h"
44 i915_emit_glyph_rectangle_zero (i915_device_t *device,
45 i915_shader_t *shader,
53 * 2 vertex coordinates
56 v = i915_add_rectangle (device);
63 i915_emit_glyph_rectangle_constant (i915_device_t *device,
64 i915_shader_t *shader,
72 * 2 vertex coordinates
73 * 2 glyph texture coordinates
76 v = i915_add_rectangle (device);
80 *v++ = glyph->texcoord[0];
84 *v++ = glyph->texcoord[1];
88 *v++ = glyph->texcoord[2];
92 i915_emit_glyph_rectangle_general (i915_device_t *device,
93 i915_shader_t *shader,
102 * 2 vertex coordinates
103 * [0-2] source texture coordinates
104 * 2 glyph texture coordinates
107 v = i915_add_rectangle (device);
110 *v++ = x2; *v++ = y2;
112 switch (shader->source.type.vertex) {
117 *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
120 cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
124 cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
125 *v++ = texcoord_2d_16 (s, t);
128 *v++ = glyph->texcoord[0];
131 *v++ = x1; *v++ = y2;
133 switch (shader->source.type.vertex) {
138 *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
141 cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
145 cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
146 *v++ = texcoord_2d_16 (s, t);
149 *v++ = glyph->texcoord[1];
152 *v++ = x1; *v++ = y1;
154 switch (shader->source.type.vertex) {
159 *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
162 cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
166 cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
167 *v++ = texcoord_2d_16 (s, t);
170 *v++ = glyph->texcoord[2];
174 (*i915_emit_glyph_rectangle_func_t) (i915_device_t *device,
175 i915_shader_t *shader,
178 intel_glyph_t *glyph);
180 static cairo_status_t
181 i915_surface_mask_internal (i915_surface_t *dst,
183 const cairo_pattern_t *source,
184 i915_surface_t *mask,
186 const cairo_composite_rectangles_t *extents)
188 i915_device_t *device;
189 i915_shader_t shader;
190 cairo_region_t *clip_region = NULL;
191 cairo_status_t status;
193 i915_shader_init (&shader, dst, op, 1.);
195 status = i915_shader_acquire_pattern (&shader, &shader.source,
196 source, &extents->bounded);
197 if (unlikely (status))
200 shader.mask.type.vertex = VS_TEXTURE_16;
201 shader.mask.type.pattern = PATTERN_TEXTURE;
202 shader.mask.type.fragment = FS_TEXTURE;
203 shader.mask.base.content = mask->intel.drm.base.content;
204 shader.mask.base.texfmt = TEXCOORDFMT_2D_16;
205 shader.mask.base.n_samplers = 1;
206 shader.mask.base.sampler[0] =
207 (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
208 i915_texture_filter (CAIRO_FILTER_NEAREST);
209 shader.mask.base.sampler[1] =
210 SS3_NORMALIZED_COORDS |
211 i915_texture_extend (CAIRO_EXTEND_NONE);
213 cairo_matrix_init_translate (&shader.mask.base.matrix,
215 -extents->bounded.y);
216 cairo_matrix_scale (&shader.mask.base.matrix,
217 1. / mask->intel.drm.width,
218 1. / mask->intel.drm.height);
220 shader.mask.base.bo = intel_bo_reference (to_intel_bo (mask->intel.drm.bo));
221 shader.mask.base.offset[0] = 0;
222 shader.mask.base.map[0] = mask->map0;
223 shader.mask.base.map[1] = mask->map1;
226 status = _cairo_clip_get_region (clip, &clip_region);
228 if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
231 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
232 i915_shader_set_clip (&shader, clip);
235 status = cairo_device_acquire (dst->intel.drm.base.device);
236 if (unlikely (status))
239 device = i915_device (dst);
241 status = i915_shader_commit (&shader, device);
242 if (unlikely (status))
245 if (clip_region != NULL) {
246 unsigned int n, num_rectangles;
248 num_rectangles = cairo_region_num_rectangles (clip_region);
249 for (n = 0; n < num_rectangles; n++) {
250 cairo_rectangle_int_t rect;
252 cairo_region_get_rectangle (clip_region, n, &rect);
254 shader.add_rectangle (&shader,
256 rect.x + rect.width, rect.y + rect.height);
259 shader.add_rectangle (&shader,
260 extents->bounded.x, extents->bounded.y,
261 extents->bounded.x + extents->bounded.width,
262 extents->bounded.y + extents->bounded.height);
265 if (! extents->is_bounded)
266 status = i915_fixup_unbounded (dst, extents, clip);
269 cairo_device_release (&device->intel.base.base);
271 i915_shader_fini (&shader);
276 i915_surface_glyphs (void *abstract_surface,
278 const cairo_pattern_t *source,
279 cairo_glyph_t *glyphs,
281 cairo_scaled_font_t *scaled_font,
285 i915_surface_t *surface = abstract_surface;
286 i915_surface_t *mask = NULL;
287 i915_device_t *device;
288 i915_shader_t shader;
289 cairo_composite_rectangles_t extents;
290 cairo_clip_t local_clip;
291 cairo_bool_t have_clip = FALSE;
292 cairo_bool_t overlap;
293 cairo_region_t *clip_region = NULL;
294 intel_bo_t *last_bo = NULL;
295 i915_emit_glyph_rectangle_func_t emit_func;
296 cairo_scaled_glyph_t *glyph_cache[64];
297 cairo_status_t status;
298 int mask_x = 0, mask_y = 0;
302 status = _cairo_composite_rectangles_init_for_glyphs (&extents,
303 surface->intel.drm.width,
304 surface->intel.drm.height,
310 if (unlikely (status))
313 if (_cairo_clip_contains_rectangle (clip, &extents.mask))
316 if (clip != NULL && extents.is_bounded) {
317 clip = _cairo_clip_init_copy (&local_clip, clip);
318 status = _cairo_clip_rectangle (clip, &extents.bounded);
319 if (unlikely (status))
326 status = _cairo_clip_get_region (clip, &clip_region);
327 if (unlikely (_cairo_status_is_error (status) ||
328 status == CAIRO_INT_STATUS_NOTHING_TO_DO))
331 _cairo_clip_fini (&local_clip);
336 if (i915_surface_needs_tiling (surface)) {
338 return CAIRO_INT_STATUS_UNSUPPORTED;
341 if (overlap || ! extents.is_bounded) {
342 cairo_format_t format;
344 format = CAIRO_FORMAT_A8;
345 if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
346 format = CAIRO_FORMAT_ARGB32;
348 mask = (i915_surface_t *)
349 i915_surface_create_internal (&i915_device (surface)->intel.base,
351 extents.bounded.width,
352 extents.bounded.height,
355 if (unlikely (mask->intel.drm.base.status))
356 return mask->intel.drm.base.status;
358 status = i915_surface_clear (mask);
359 if (unlikely (status)) {
360 cairo_surface_destroy (&mask->intel.drm.base);
364 i915_shader_init (&shader, mask, CAIRO_OPERATOR_ADD, 1.);
366 status = i915_shader_acquire_pattern (&shader, &shader.source,
367 &_cairo_pattern_white.base,
369 if (unlikely (status)) {
370 cairo_surface_destroy (&mask->intel.drm.base);
374 mask_x = -extents.bounded.x;
375 mask_y = -extents.bounded.y;
377 i915_shader_init (&shader, surface, op, 1.);
379 status = i915_shader_acquire_pattern (&shader, &shader.source,
380 source, &extents.bounded);
381 if (unlikely (status))
385 status = _cairo_clip_get_region (clip, &clip_region);
387 if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
390 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
391 i915_shader_set_clip (&shader, clip);
395 shader.mask.type.fragment = FS_TEXTURE;
396 shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */
397 shader.mask.base.texfmt = TEXCOORDFMT_2D_16;
398 shader.mask.base.n_samplers = 1;
399 shader.mask.base.sampler[0] =
400 (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
401 i915_texture_filter (CAIRO_FILTER_NEAREST);
402 shader.mask.base.sampler[1] =
403 SS3_NORMALIZED_COORDS |
404 i915_texture_extend (CAIRO_EXTEND_NONE);
406 switch (shader.source.type.vertex) {
408 emit_func = i915_emit_glyph_rectangle_zero;
411 emit_func = i915_emit_glyph_rectangle_constant;
417 emit_func = i915_emit_glyph_rectangle_general;
421 status = cairo_device_acquire (surface->intel.drm.base.device);
422 if (unlikely (status))
425 device = i915_device (surface);
427 _cairo_scaled_font_freeze_cache (scaled_font);
428 if (scaled_font->surface_private == NULL) {
429 scaled_font->surface_private = device;
430 scaled_font->surface_backend = surface->intel.drm.base.backend;
431 cairo_list_add (&scaled_font->link, &device->intel.fonts);
434 memset (glyph_cache, 0, sizeof (glyph_cache));
436 for (i = 0; i < num_glyphs; i++) {
437 cairo_scaled_glyph_t *scaled_glyph;
438 int x, y, x1, x2, y1, y2;
439 int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache);
440 intel_glyph_t *glyph;
442 scaled_glyph = glyph_cache[cache_index];
443 if (scaled_glyph == NULL ||
444 _cairo_scaled_glyph_index (scaled_glyph) != glyphs[i].index)
446 status = _cairo_scaled_glyph_lookup (scaled_font,
448 CAIRO_SCALED_GLYPH_INFO_METRICS,
450 if (unlikely (status))
453 glyph_cache[cache_index] = scaled_glyph;
456 if (unlikely (scaled_glyph->metrics.width == 0 ||
457 scaled_glyph->metrics.height == 0))
462 /* XXX glyph images are snapped to pixel locations */
463 x = _cairo_lround (glyphs[i].x);
464 y = _cairo_lround (glyphs[i].y);
466 x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
467 y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
468 x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
469 y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
471 if (x2 < extents.bounded.x ||
472 y2 < extents.bounded.y ||
473 x1 > extents.bounded.x + extents.bounded.width ||
474 y1 > extents.bounded.y + extents.bounded.height)
479 if (scaled_glyph->surface_private == NULL) {
480 status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph);
481 if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) {
482 status = CAIRO_STATUS_SUCCESS;
485 if (unlikely (status))
489 glyph = intel_glyph_pin (scaled_glyph->surface_private);
490 if (glyph->cache->buffer.bo != last_bo) {
491 intel_buffer_cache_t *cache = glyph->cache;
493 shader.mask.base.bo = cache->buffer.bo;
494 shader.mask.base.offset[0] = cache->buffer.offset;
495 shader.mask.base.map[0] = cache->buffer.map0;
496 shader.mask.base.map[1] = cache->buffer.map1;
497 shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */
499 status = i915_shader_commit (&shader, device);
500 if (unlikely (status))
503 last_bo = cache->buffer.bo;
506 x2 = x1 + glyph->width;
507 y2 = y1 + glyph->height;
510 x1 += mask_x, x2 += mask_x;
512 y1 += mask_y, y2 += mask_y;
515 emit_func (device, &shader, x1, y1, x2, y2, glyph);
518 status = CAIRO_STATUS_SUCCESS;
520 _cairo_scaled_font_thaw_cache (scaled_font);
521 cairo_device_release (surface->intel.drm.base.device);
523 i915_shader_fini (&shader);
525 if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
526 cairo_path_fixed_t path;
528 _cairo_path_fixed_init (&path);
529 status = _cairo_scaled_font_glyph_path (scaled_font,
530 glyphs + i, num_glyphs - i,
532 if (mask_x | mask_y) {
533 _cairo_path_fixed_translate (&path,
534 _cairo_fixed_from_int (mask_x),
535 _cairo_fixed_from_int (mask_y));
537 if (likely (status == CAIRO_STATUS_SUCCESS)) {
538 status = surface->intel.drm.base.backend->fill (shader.target,
540 mask != NULL ? &_cairo_pattern_white.base : source,
542 CAIRO_FILL_RULE_WINDING,
544 scaled_font->options.antialias,
547 _cairo_path_fixed_fini (&path);
551 if (likely (status == CAIRO_STATUS_SUCCESS)) {
552 status = i915_surface_mask_internal (surface, op, source, mask,
555 cairo_surface_finish (&mask->intel.drm.base);
556 cairo_surface_destroy (&mask->intel.drm.base);
560 _cairo_clip_fini (&local_clip);