Tizen 2.0 Release
[framework/graphics/cairo.git] / src / drm / cairo-drm-i965-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-i965-private.h"
40 #include "cairo-error-private.h"
41 #include "cairo-rtree-private.h"
42
43 typedef struct _i965_glyphs i965_glyphs_t;
44
45 typedef float *
46 (*i965_get_rectangle_func_t) (i965_glyphs_t *glyphs);
47
48 struct _i965_glyphs {
49     i965_get_rectangle_func_t get_rectangle;
50     i965_shader_t shader;
51
52     struct i965_vbo head, *tail;
53
54     unsigned int vbo_offset;
55     float *vbo_base;
56 };
57
58 static float *
59 i965_glyphs_emit_rectangle (i965_glyphs_t *glyphs)
60 {
61     return i965_add_rectangle (glyphs->shader.device);
62 }
63
64 static float *
65 i965_glyphs_accumulate_rectangle (i965_glyphs_t *glyphs)
66 {
67     float *vertices;
68     uint32_t size;
69
70     size = glyphs->shader.device->rectangle_size;
71     if (unlikely (glyphs->vbo_offset + size > I965_VERTEX_SIZE)) {
72         struct i965_vbo *vbo;
73
74         vbo = malloc (sizeof (struct i965_vbo));
75         if (unlikely (vbo == NULL)) {
76             /* throw error! */
77         }
78
79         glyphs->tail->next = vbo;
80         glyphs->tail = vbo;
81
82         vbo->next = NULL;
83         vbo->bo = intel_bo_create (&glyphs->shader.device->intel,
84                                    I965_VERTEX_SIZE, I965_VERTEX_SIZE,
85                                    FALSE, I915_TILING_NONE, 0);
86         vbo->count = 0;
87
88         glyphs->vbo_offset = 0;
89         glyphs->vbo_base = intel_bo_map (&glyphs->shader.device->intel, vbo->bo);
90     }
91
92     vertices = glyphs->vbo_base + glyphs->vbo_offset;
93     glyphs->vbo_offset += size;
94     glyphs->tail->count += 3;
95
96     return vertices;
97 }
98
99 static void
100 i965_add_glyph_rectangle (i965_glyphs_t *glyphs,
101                           int x1, int y1,
102                           int x2, int y2,
103                           intel_glyph_t *glyph)
104 {
105     float *v;
106
107     /* Each vertex is:
108      *   2 vertex coordinates
109      *   1 glyph texture coordinate
110      */
111
112     v = glyphs->get_rectangle (glyphs);
113
114     /* bottom right */
115     *v++ = x2; *v++ = y2;
116     *v++ = glyph->texcoord[0];
117
118     /* bottom left */
119     *v++ = x1; *v++ = y2;
120     *v++ = glyph->texcoord[1];
121
122     /* top left */
123     *v++ = x1; *v++ = y1;
124     *v++ = glyph->texcoord[2];
125 }
126
127 static cairo_status_t
128 i965_surface_mask_internal (i965_surface_t *dst,
129                             cairo_operator_t             op,
130                             const cairo_pattern_t       *source,
131                             i965_surface_t *mask,
132                             cairo_clip_t                *clip,
133                             const cairo_composite_rectangles_t *extents)
134 {
135     i965_device_t *device;
136     i965_shader_t shader;
137     cairo_region_t *clip_region = NULL;
138     cairo_status_t status;
139
140     i965_shader_init (&shader, dst, op);
141
142     status = i965_shader_acquire_pattern (&shader, &shader.source,
143                                           source, &extents->bounded);
144     if (unlikely (status))
145         return status;
146
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);
152
153     cairo_matrix_init_translate (&shader.mask.base.matrix,
154                                  -extents->bounded.x,
155                                  -extents->bounded.y);
156     cairo_matrix_scale (&shader.mask.base.matrix,
157                         1. / mask->intel.drm.width,
158                         1. / mask->intel.drm.height);
159
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;
165
166     if (clip != NULL) {
167         status = _cairo_clip_get_region (clip, &clip_region);
168         assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
169
170         if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
171             clip_region = NULL;
172
173         if (status == CAIRO_INT_STATUS_UNSUPPORTED)
174             i965_shader_set_clip (&shader, clip);
175     }
176
177     status = cairo_device_acquire (dst->intel.drm.base.device);
178     if (unlikely (status))
179         goto CLEANUP_SHADER;
180
181     device = i965_device (dst);
182
183     status = i965_shader_commit (&shader, device);
184     if (unlikely (status))
185         goto CLEANUP_DEVICE;
186
187     if (clip_region != NULL) {
188         unsigned int n, num_rectangles;
189
190         num_rectangles = cairo_region_num_rectangles (clip_region);
191         for (n = 0; n < num_rectangles; n++) {
192             cairo_rectangle_int_t rect;
193
194             cairo_region_get_rectangle (clip_region, n, &rect);
195
196             i965_shader_add_rectangle (&shader,
197                                        rect.x, rect.y,
198                                        rect.width, rect.height);
199         }
200     } else {
201         i965_shader_add_rectangle (&shader,
202                                    extents->bounded.x,
203                                    extents->bounded.y,
204                                    extents->bounded.width,
205                                    extents->bounded.height);
206     }
207
208     if (! extents->is_bounded)
209         status = i965_fixup_unbounded (dst, extents, clip);
210
211   CLEANUP_DEVICE:
212     cairo_device_release (&device->intel.base.base);
213   CLEANUP_SHADER:
214     i965_shader_fini (&shader);
215     return status;
216 }
217
218 cairo_int_status_t
219 i965_surface_glyphs (void                       *abstract_surface,
220                      cairo_operator_t            op,
221                      const cairo_pattern_t      *source,
222                      cairo_glyph_t              *g,
223                      int                         num_glyphs,
224                      cairo_scaled_font_t        *scaled_font,
225                      cairo_clip_t               *clip,
226                      int *num_remaining)
227 {
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;
241     int i = 0;
242
243     *num_remaining = 0;
244     status = _cairo_composite_rectangles_init_for_glyphs (&extents,
245                                                           surface->intel.drm.width,
246                                                           surface->intel.drm.height,
247                                                           op, source,
248                                                           scaled_font,
249                                                           g, num_glyphs,
250                                                           clip,
251                                                           &overlap);
252     if (unlikely (status))
253         return status;
254
255     if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents.mask))
256         clip = NULL;
257
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))
262             return status;
263
264         have_clip = TRUE;
265     }
266
267     if (overlap || ! extents.is_bounded) {
268         cairo_format_t format;
269
270         format = CAIRO_FORMAT_A8;
271         if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
272             format = CAIRO_FORMAT_ARGB32;
273
274         mask = (i965_surface_t *)
275             i965_surface_create_internal (&i965_device (surface)->intel.base,
276                                           format,
277                                           extents.bounded.width,
278                                           extents.bounded.height,
279                                           I965_TILING_DEFAULT,
280                                           TRUE);
281         if (unlikely (mask->intel.drm.base.status))
282             return mask->intel.drm.base.status;
283
284         status = _cairo_surface_paint (&mask->intel.drm.base,
285                                        CAIRO_OPERATOR_CLEAR,
286                                        &_cairo_pattern_clear.base,
287                                        NULL);
288         if (unlikely (status)) {
289             cairo_surface_destroy (&mask->intel.drm.base);
290             return status;
291         }
292
293         i965_shader_init (&glyphs.shader, mask, CAIRO_OPERATOR_ADD);
294
295         status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
296                                               &_cairo_pattern_white.base,
297                                               &extents.bounded);
298         if (unlikely (status)) {
299             cairo_surface_destroy (&mask->intel.drm.base);
300             return status;
301         }
302
303         mask_x = -extents.bounded.x;
304         mask_y = -extents.bounded.y;
305     } else {
306         i965_shader_init (&glyphs.shader, surface, op);
307
308         status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
309                                               source, &extents.bounded);
310         if (unlikely (status))
311             return status;
312
313         if (clip != NULL) {
314             status = _cairo_clip_get_region (clip, &clip_region);
315             assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
316
317             if (status == CAIRO_INT_STATUS_UNSUPPORTED)
318                 i965_shader_set_clip (&glyphs.shader, clip);
319         }
320     }
321
322     glyphs.head.next = NULL;
323     glyphs.head.bo = NULL;
324     glyphs.head.count = 0;
325     glyphs.tail = &glyphs.head;
326
327     device = i965_device (surface);
328     if (mask != NULL || clip_region == NULL) {
329         glyphs.get_rectangle = i965_glyphs_emit_rectangle;
330     } else {
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);
337
338         glyphs.vbo_base = intel_bo_map (&device->intel, glyphs.head.bo);
339     }
340     glyphs.vbo_offset = 0;
341
342     status = cairo_device_acquire (&device->intel.base.base);
343     if (unlikely (status))
344         goto CLEANUP_GLYPHS;
345
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);
352     }
353
354     memset (glyph_cache, 0, sizeof (glyph_cache));
355
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;
361
362         scaled_glyph = glyph_cache[cache_index];
363         if (scaled_glyph == NULL ||
364             _cairo_scaled_glyph_index (scaled_glyph) != g[i].index)
365         {
366             status = _cairo_scaled_glyph_lookup (scaled_font,
367                                                  g[i].index,
368                                                  CAIRO_SCALED_GLYPH_INFO_METRICS,
369                                                  &scaled_glyph);
370             if (unlikely (status))
371                 goto FINISH;
372
373             glyph_cache[cache_index] = scaled_glyph;
374         }
375
376         if (unlikely (scaled_glyph->metrics.width  == 0 ||
377                       scaled_glyph->metrics.height == 0))
378         {
379             continue;
380         }
381
382         /* XXX glyph images are snapped to pixel locations */
383         x = _cairo_lround (g[i].x);
384         y = _cairo_lround (g[i].y);
385
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);
390
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)
395         {
396             continue;
397         }
398
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;
403                 continue;
404             }
405             if (unlikely (status))
406                 goto FINISH;
407         }
408         glyph = intel_glyph_pin (scaled_glyph->surface_private);
409
410         if (glyph->cache->buffer.bo != last_bo) {
411             intel_buffer_cache_t *cache = glyph->cache;
412
413             glyphs.shader.mask.type.vertex   = VS_GLYPHS;
414             glyphs.shader.mask.type.fragment = FS_GLYPHS;
415             glyphs.shader.mask.type.pattern  = PATTERN_BASE;
416
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 */
425
426             glyphs.shader.committed = FALSE;
427             status = i965_shader_commit (&glyphs.shader, device);
428             if (unlikely (status))
429                 goto FINISH;
430
431             last_bo = cache->buffer.bo;
432         }
433
434         x2 = x1 + glyph->width;
435         y2 = y1 + glyph->height;
436
437         if (mask_x)
438             x1 += mask_x, x2 += mask_x;
439         if (mask_y)
440             y1 += mask_y, y2 += mask_y;
441
442         i965_add_glyph_rectangle (&glyphs, x1, y1, x2, y2, glyph);
443     }
444
445     if (mask != NULL && clip_region != NULL)
446         i965_clipped_vertices (device, &glyphs.head, clip_region);
447
448     status = CAIRO_STATUS_SUCCESS;
449   FINISH:
450     _cairo_scaled_font_thaw_cache (scaled_font);
451     cairo_device_release (surface->intel.drm.base.device);
452   CLEANUP_GLYPHS:
453     i965_shader_fini (&glyphs.shader);
454
455     if (glyphs.head.bo != NULL) {
456         struct i965_vbo *vbo, *next;
457
458         intel_bo_destroy (&device->intel, glyphs.head.bo);
459         for (vbo = glyphs.head.next; vbo != NULL; vbo = next) {
460             next = vbo->next;
461             intel_bo_destroy (&device->intel, vbo->bo);
462             free (vbo);
463         }
464     }
465
466     if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
467         cairo_path_fixed_t path;
468
469         _cairo_path_fixed_init (&path);
470         status = _cairo_scaled_font_glyph_path (scaled_font,
471                                                 g + i, num_glyphs - i,
472                                                 &path);
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));
477         }
478         if (likely (status == CAIRO_STATUS_SUCCESS)) {
479             status = surface->intel.drm.base.backend->fill (glyphs.shader.target,
480                                                             glyphs.shader.op,
481                                                             mask != NULL ? &_cairo_pattern_white.base : source,
482                                                             &path,
483                                                             CAIRO_FILL_RULE_WINDING,
484                                                             0,
485                                                             scaled_font->options.antialias,
486                                                             clip);
487         }
488         _cairo_path_fixed_fini (&path);
489     }
490
491     if (mask != NULL) {
492         if (likely (status == CAIRO_STATUS_SUCCESS)) {
493             status = i965_surface_mask_internal (surface, op, source, mask,
494                                                  clip, &extents);
495         }
496         cairo_surface_finish (&mask->intel.drm.base);
497         cairo_surface_destroy (&mask->intel.drm.base);
498     }
499
500     if (have_clip)
501         _cairo_clip_fini (&local_clip);
502
503     return status;
504 }