Tizen 2.0 Release
[framework/graphics/cairo.git] / src / drm / cairo-drm-i915-glyphs.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2009 Intel Corporation
4  *
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.
12  *
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
18  *
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/
23  *
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.
27  *
28  * The Original Code is the cairo graphics library.
29  *
30  * The Initial Developer of the Original Code is Red Hat, Inc.
31  *
32  * Contributor(s):
33  *      Chris Wilson <chris@chris-wilson.co.uk>
34  */
35
36 #include "cairoint.h"
37
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"
42
43 static void
44 i915_emit_glyph_rectangle_zero (i915_device_t *device,
45                                 i915_shader_t *shader,
46                                 int x1, int y1,
47                                 int x2, int y2,
48                                 intel_glyph_t *glyph)
49 {
50     float *v;
51
52     /* Each vertex is:
53      *   2 vertex coordinates
54      */
55
56     v = i915_add_rectangle (device);
57     *v++ = x2; *v++ = y2;
58     *v++ = x1; *v++ = y2;
59     *v++ = x1; *v++ = y1;
60 }
61
62 static void
63 i915_emit_glyph_rectangle_constant (i915_device_t *device,
64                                     i915_shader_t *shader,
65                                     int x1, int y1,
66                                     int x2, int y2,
67                                     intel_glyph_t *glyph)
68 {
69     float *v;
70
71     /* Each vertex is:
72      *   2 vertex coordinates
73      *   2 glyph texture coordinates
74      */
75
76     v = i915_add_rectangle (device);
77
78     /* bottom right */
79     *v++ = x2; *v++ = y2;
80     *v++ = glyph->texcoord[0];
81
82     /* bottom left */
83     *v++ = x1; *v++ = y2;
84     *v++ = glyph->texcoord[1];
85
86     /* top left */
87     *v++ = x1; *v++ = y1;
88     *v++ = glyph->texcoord[2];
89 }
90
91 static void
92 i915_emit_glyph_rectangle_general (i915_device_t *device,
93                                    i915_shader_t *shader,
94                                    int x1, int y1,
95                                    int x2, int y2,
96                                    intel_glyph_t *glyph)
97 {
98     double s, t;
99     float *v;
100
101     /* Each vertex is:
102      *   2 vertex coordinates
103      *   [0-2] source texture coordinates
104      *   2 glyph texture coordinates
105      */
106
107     v = i915_add_rectangle (device);
108
109     /* bottom right */
110     *v++ = x2; *v++ = y2;
111     s = x2, t = y2;
112     switch (shader->source.type.vertex) {
113     case VS_ZERO:
114     case VS_CONSTANT:
115         break;
116     case VS_LINEAR:
117         *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
118         break;
119     case VS_TEXTURE:
120         cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
121         *v++ = s; *v++ = t;
122         break;
123     case VS_TEXTURE_16:
124         cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
125         *v++ = texcoord_2d_16 (s, t);
126         break;
127     }
128     *v++ = glyph->texcoord[0];
129
130     /* bottom left */
131     *v++ = x1; *v++ = y2;
132     s = x1, t = y2;
133     switch (shader->source.type.vertex) {
134     case VS_ZERO:
135     case VS_CONSTANT:
136         break;
137     case VS_LINEAR:
138         *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
139         break;
140     case VS_TEXTURE:
141         cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
142         *v++ = s; *v++ = t;
143         break;
144     case VS_TEXTURE_16:
145         cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
146         *v++ = texcoord_2d_16 (s, t);
147         break;
148     }
149     *v++ = glyph->texcoord[1];
150
151     /* top left */
152     *v++ = x1; *v++ = y1;
153     s = x1, t = y2;
154     switch (shader->source.type.vertex) {
155     case VS_ZERO:
156     case VS_CONSTANT:
157         break;
158     case VS_LINEAR:
159         *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
160         break;
161     case VS_TEXTURE:
162         cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
163         *v++ = s; *v++ = t;
164         break;
165     case VS_TEXTURE_16:
166         cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
167         *v++ = texcoord_2d_16 (s, t);
168         break;
169     }
170     *v++ = glyph->texcoord[2];
171 }
172
173 typedef void
174 (*i915_emit_glyph_rectangle_func_t) (i915_device_t *device,
175                                      i915_shader_t *shader,
176                                      int x1, int y1,
177                                      int x2, int y2,
178                                      intel_glyph_t *glyph);
179
180 static cairo_status_t
181 i915_surface_mask_internal (i915_surface_t *dst,
182                             cairo_operator_t             op,
183                             const cairo_pattern_t       *source,
184                             i915_surface_t *mask,
185                             cairo_clip_t                *clip,
186                             const cairo_composite_rectangles_t *extents)
187 {
188     i915_device_t *device;
189     i915_shader_t shader;
190     cairo_region_t *clip_region = NULL;
191     cairo_status_t status;
192
193     i915_shader_init (&shader, dst, op, 1.);
194
195     status = i915_shader_acquire_pattern (&shader, &shader.source,
196                                           source, &extents->bounded);
197     if (unlikely (status))
198         return status;
199
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);
212
213     cairo_matrix_init_translate (&shader.mask.base.matrix,
214                                  -extents->bounded.x,
215                                  -extents->bounded.y);
216     cairo_matrix_scale (&shader.mask.base.matrix,
217                         1. / mask->intel.drm.width,
218                         1. / mask->intel.drm.height);
219
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;
224
225     if (clip != NULL) {
226         status = _cairo_clip_get_region (clip, &clip_region);
227
228         if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
229             clip_region = NULL;
230
231         if (status == CAIRO_INT_STATUS_UNSUPPORTED)
232             i915_shader_set_clip (&shader, clip);
233     }
234
235     status = cairo_device_acquire (dst->intel.drm.base.device);
236     if (unlikely (status))
237         goto CLEANUP_SHADER;
238
239     device = i915_device (dst);
240
241     status = i915_shader_commit (&shader, device);
242     if (unlikely (status))
243         goto CLEANUP_DEVICE;
244
245     if (clip_region != NULL) {
246         unsigned int n, num_rectangles;
247
248         num_rectangles = cairo_region_num_rectangles (clip_region);
249         for (n = 0; n < num_rectangles; n++) {
250             cairo_rectangle_int_t rect;
251
252             cairo_region_get_rectangle (clip_region, n, &rect);
253
254             shader.add_rectangle (&shader,
255                                   rect.x, rect.y,
256                                   rect.x + rect.width, rect.y + rect.height);
257         }
258     } else {
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);
263     }
264
265     if (! extents->is_bounded)
266         status = i915_fixup_unbounded (dst, extents, clip);
267
268 CLEANUP_DEVICE:
269     cairo_device_release (&device->intel.base.base);
270 CLEANUP_SHADER:
271     i915_shader_fini (&shader);
272     return status;
273 }
274
275 cairo_int_status_t
276 i915_surface_glyphs (void                       *abstract_surface,
277                      cairo_operator_t            op,
278                      const cairo_pattern_t      *source,
279                      cairo_glyph_t              *glyphs,
280                      int                         num_glyphs,
281                      cairo_scaled_font_t        *scaled_font,
282                      cairo_clip_t               *clip,
283                      int *num_remaining)
284 {
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;
299     int i = 0;
300
301     *num_remaining = 0;
302     status = _cairo_composite_rectangles_init_for_glyphs (&extents,
303                                                           surface->intel.drm.width,
304                                                           surface->intel.drm.height,
305                                                           op, source,
306                                                           scaled_font,
307                                                           glyphs, num_glyphs,
308                                                           clip,
309                                                           &overlap);
310     if (unlikely (status))
311         return status;
312
313     if (_cairo_clip_contains_rectangle (clip, &extents.mask))
314         clip = NULL;
315
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))
320             return status;
321
322         have_clip = TRUE;
323     }
324
325     if (clip != NULL) {
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))
329         {
330             if (have_clip)
331                 _cairo_clip_fini (&local_clip);
332             return status;
333         }
334     }
335
336     if (i915_surface_needs_tiling (surface)) {
337         ASSERT_NOT_REACHED;
338         return CAIRO_INT_STATUS_UNSUPPORTED;
339     }
340
341     if (overlap || ! extents.is_bounded) {
342         cairo_format_t format;
343
344         format = CAIRO_FORMAT_A8;
345         if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
346             format = CAIRO_FORMAT_ARGB32;
347
348         mask = (i915_surface_t *)
349             i915_surface_create_internal (&i915_device (surface)->intel.base,
350                                           format,
351                                           extents.bounded.width,
352                                           extents.bounded.height,
353                                           I915_TILING_DEFAULT,
354                                           TRUE);
355         if (unlikely (mask->intel.drm.base.status))
356             return mask->intel.drm.base.status;
357
358         status = i915_surface_clear (mask);
359         if (unlikely (status)) {
360             cairo_surface_destroy (&mask->intel.drm.base);
361             return status;
362         }
363
364         i915_shader_init (&shader, mask, CAIRO_OPERATOR_ADD, 1.);
365
366         status = i915_shader_acquire_pattern (&shader, &shader.source,
367                                               &_cairo_pattern_white.base,
368                                               &extents.bounded);
369         if (unlikely (status)) {
370             cairo_surface_destroy (&mask->intel.drm.base);
371             return status;
372         }
373
374         mask_x = -extents.bounded.x;
375         mask_y = -extents.bounded.y;
376     } else {
377         i915_shader_init (&shader, surface, op, 1.);
378
379         status = i915_shader_acquire_pattern (&shader, &shader.source,
380                                               source, &extents.bounded);
381         if (unlikely (status))
382             return status;
383
384         if (clip != NULL) {
385             status = _cairo_clip_get_region (clip, &clip_region);
386
387             if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
388                 clip_region = NULL;
389
390             if (status == CAIRO_INT_STATUS_UNSUPPORTED)
391                 i915_shader_set_clip (&shader, clip);
392         }
393     }
394
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);
405
406     switch (shader.source.type.vertex) {
407     case VS_ZERO:
408         emit_func = i915_emit_glyph_rectangle_zero;
409         break;
410     case VS_CONSTANT:
411         emit_func = i915_emit_glyph_rectangle_constant;
412         break;
413     default:
414     case VS_LINEAR:
415     case VS_TEXTURE:
416     case VS_TEXTURE_16:
417         emit_func = i915_emit_glyph_rectangle_general;
418         break;
419     }
420
421     status = cairo_device_acquire (surface->intel.drm.base.device);
422     if (unlikely (status))
423         goto CLEANUP_SHADER;
424
425     device = i915_device (surface);
426
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);
432     }
433
434     memset (glyph_cache, 0, sizeof (glyph_cache));
435
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;
441
442         scaled_glyph = glyph_cache[cache_index];
443         if (scaled_glyph == NULL ||
444             _cairo_scaled_glyph_index (scaled_glyph) != glyphs[i].index)
445         {
446             status = _cairo_scaled_glyph_lookup (scaled_font,
447                                                  glyphs[i].index,
448                                                  CAIRO_SCALED_GLYPH_INFO_METRICS,
449                                                  &scaled_glyph);
450             if (unlikely (status))
451                 goto FINISH;
452
453             glyph_cache[cache_index] = scaled_glyph;
454         }
455
456         if (unlikely (scaled_glyph->metrics.width  == 0 ||
457                       scaled_glyph->metrics.height == 0))
458         {
459             continue;
460         }
461
462         /* XXX glyph images are snapped to pixel locations */
463         x = _cairo_lround (glyphs[i].x);
464         y = _cairo_lround (glyphs[i].y);
465
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);
470
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)
475         {
476             continue;
477         }
478
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;
483                 continue;
484             }
485             if (unlikely (status))
486                 goto FINISH;
487         }
488
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;
492
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 */
498
499             status = i915_shader_commit (&shader, device);
500             if (unlikely (status))
501                 goto FINISH;
502
503             last_bo = cache->buffer.bo;
504         }
505
506         x2 = x1 + glyph->width;
507         y2 = y1 + glyph->height;
508
509         if (mask_x)
510             x1 += mask_x, x2 += mask_x;
511         if (mask_y)
512             y1 += mask_y, y2 += mask_y;
513
514         /* XXX clip glyph */
515         emit_func (device, &shader, x1, y1, x2, y2, glyph);
516     }
517
518     status = CAIRO_STATUS_SUCCESS;
519   FINISH:
520     _cairo_scaled_font_thaw_cache (scaled_font);
521     cairo_device_release (surface->intel.drm.base.device);
522   CLEANUP_SHADER:
523     i915_shader_fini (&shader);
524
525     if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
526         cairo_path_fixed_t path;
527
528         _cairo_path_fixed_init (&path);
529         status = _cairo_scaled_font_glyph_path (scaled_font,
530                                                 glyphs + i, num_glyphs - i,
531                                                 &path);
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));
536         }
537         if (likely (status == CAIRO_STATUS_SUCCESS)) {
538             status = surface->intel.drm.base.backend->fill (shader.target,
539                                                             shader.op,
540                                                             mask != NULL ? &_cairo_pattern_white.base : source,
541                                                             &path,
542                                                             CAIRO_FILL_RULE_WINDING,
543                                                             0,
544                                                             scaled_font->options.antialias,
545                                                             clip);
546         }
547         _cairo_path_fixed_fini (&path);
548     }
549
550     if (mask != NULL) {
551         if (likely (status == CAIRO_STATUS_SUCCESS)) {
552             status = i915_surface_mask_internal (surface, op, source, mask,
553                                                  clip, &extents);
554         }
555         cairo_surface_finish (&mask->intel.drm.base);
556         cairo_surface_destroy (&mask->intel.drm.base);
557     }
558
559     if (have_clip)
560         _cairo_clip_fini (&local_clip);
561
562     return status;
563 }