Tizen 2.0 Release
[profile/ivi/cairo.git] / src / drm / cairo-drm-i965-spans.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-boxes-private.h"
40 #include "cairo-error-private.h"
41 #include "cairo-drm-i965-private.h"
42
43 /* Operates in either immediate or retained mode.
44  * When given a clip region we record the sequence of vbo and then
45  * replay them for each clip rectangle, otherwise we simply emit
46  * the vbo straight into the command stream.
47  */
48
49 typedef struct _i965_spans i965_spans_t;
50
51 typedef float *
52 (*i965_get_rectangle_func_t) (i965_spans_t *spans);
53
54 struct _i965_spans {
55     cairo_span_renderer_t renderer;
56
57     i965_device_t *device;
58
59     int xmin, xmax;
60     cairo_bool_t is_bounded;
61     const cairo_rectangle_int_t *extents;
62
63     i965_get_rectangle_func_t get_rectangle;
64     i965_shader_t shader;
65
66     cairo_region_t *clip_region;
67
68     struct i965_vbo head, *tail;
69
70     unsigned int vbo_offset;
71     float *vbo_base;
72 };
73
74 static float *
75 i965_spans_emit_rectangle (i965_spans_t *spans)
76 {
77     return i965_add_rectangle (spans->device);
78 }
79
80 static float *
81 i965_spans_accumulate_rectangle (i965_spans_t *spans)
82 {
83     float *vertices;
84     uint32_t size;
85
86     size = spans->device->rectangle_size;
87     if (unlikely (spans->vbo_offset + size > I965_VERTEX_SIZE)) {
88         struct i965_vbo *vbo;
89
90         vbo = malloc (sizeof (struct i965_vbo));
91         if (unlikely (vbo == NULL)) {
92             /* throw error! */
93         }
94
95         spans->tail->next = vbo;
96         spans->tail = vbo;
97
98         vbo->next = NULL;
99         vbo->bo = intel_bo_create (&spans->device->intel,
100                                    I965_VERTEX_SIZE, I965_VERTEX_SIZE,
101                                    FALSE, I915_TILING_NONE, 0);
102         vbo->count = 0;
103
104         spans->vbo_offset = 0;
105         spans->vbo_base = intel_bo_map (&spans->device->intel, vbo->bo);
106     }
107
108     vertices = spans->vbo_base + spans->vbo_offset;
109     spans->vbo_offset += size;
110     spans->tail->count += 3;
111
112     return vertices;
113 }
114
115 static void
116 i965_span_rectangle (i965_spans_t *spans,
117                      int x0, int x1, int y0, int y1,
118                      int alpha)
119 {
120     float *vertices;
121     float a = alpha / 255.;
122
123     vertices = spans->get_rectangle (spans);
124
125     *vertices++ = x1;
126     *vertices++ = y1;
127     *vertices++ = a;
128
129     *vertices++ = x0;
130     *vertices++ = y1;
131     *vertices++ = a;
132
133     *vertices++ = x0;
134     *vertices++ = y0;
135     *vertices++ = a;
136 }
137
138 static cairo_status_t
139 i965_bounded_spans_mono (void *abstract_renderer,
140                          int y, int height,
141                          const cairo_half_open_span_t *half,
142                          unsigned num_spans)
143 {
144     i965_spans_t *spans = abstract_renderer;
145
146     if (num_spans == 0)
147         return CAIRO_STATUS_SUCCESS;
148
149     do {
150         if (half[0].coverage >= 128) {
151             i965_span_rectangle (spans,
152                                  half[0].x, half[1].x,
153                                  y, y + height,
154                                  255);
155         }
156         half++;
157     } while (--num_spans > 1);
158
159     return CAIRO_STATUS_SUCCESS;
160 }
161
162 static cairo_status_t
163 i965_bounded_spans (void *abstract_renderer,
164                     int y, int height,
165                     const cairo_half_open_span_t *half,
166                     unsigned num_spans)
167 {
168     i965_spans_t *spans = abstract_renderer;
169
170     if (num_spans == 0)
171         return CAIRO_STATUS_SUCCESS;
172
173     do {
174         if (half[0].coverage) {
175             i965_span_rectangle (spans,
176                                  half[0].x, half[1].x,
177                                  y, y + height,
178                                  half[0].coverage);
179         }
180         half++;
181     } while (--num_spans > 1);
182
183     return CAIRO_STATUS_SUCCESS;
184 }
185
186 static cairo_status_t
187 i965_unbounded_spans (void *abstract_renderer,
188                       int y, int height,
189                       const cairo_half_open_span_t *half,
190                       unsigned num_spans)
191 {
192     i965_spans_t *spans = abstract_renderer;
193
194     if (num_spans == 0) {
195         i965_span_rectangle (spans,
196                              spans->xmin, spans->xmax,
197                              y, y + height,
198                              0);
199         return CAIRO_STATUS_SUCCESS;
200     }
201
202     if (half[0].x != spans->xmin) {
203         i965_span_rectangle (spans,
204                              spans->xmin, half[0].x,
205                              y, y + height,
206                              0);
207     }
208
209     do {
210         i965_span_rectangle (spans,
211                              half[0].x, half[1].x,
212                              y, y + height,
213                              half[0].coverage);
214         half++;
215     } while (--num_spans > 1);
216
217     if (half[0].x != spans->xmax) {
218         i965_span_rectangle (spans,
219                              half[0].x, spans->xmax,
220                              y, y + height,
221                              0);
222     }
223
224     return CAIRO_STATUS_SUCCESS;
225 }
226
227 static cairo_status_t
228 i965_unbounded_spans_mono (void *abstract_renderer,
229                            int y, int height,
230                            const cairo_half_open_span_t *half,
231                            unsigned num_spans)
232 {
233     i965_spans_t *spans = abstract_renderer;
234
235     if (num_spans == 0) {
236         i965_span_rectangle (spans,
237                              spans->xmin, spans->xmax,
238                              y, y + height,
239                              0);
240         return CAIRO_STATUS_SUCCESS;
241     }
242
243     if (half[0].x != spans->xmin) {
244         i965_span_rectangle (spans,
245                              spans->xmin, half[0].x,
246                              y, y + height,
247                              0);
248     }
249
250     do {
251         int alpha = 0;
252         if (half[0].coverage >= 128)
253             alpha = 255;
254         i965_span_rectangle (spans,
255                              half[0].x, half[1].x,
256                              y, y + height,
257                              alpha);
258         half++;
259     } while (--num_spans > 1);
260
261     if (half[0].x != spans->xmax) {
262         i965_span_rectangle (spans,
263                              half[0].x, spans->xmax,
264                              y, y + height,
265                              0);
266     }
267
268     return CAIRO_STATUS_SUCCESS;
269 }
270
271 static cairo_status_t
272 i965_spans_init (i965_spans_t *spans,
273                  i965_surface_t *dst,
274                  cairo_operator_t op,
275                  const cairo_pattern_t *pattern,
276                  cairo_antialias_t antialias,
277                  cairo_clip_t *clip,
278                  const cairo_composite_rectangles_t *extents)
279 {
280     cairo_status_t status;
281
282     spans->device = i965_device (dst);
283     i965_shader_init (&spans->shader, dst, op);
284
285     spans->is_bounded = extents->is_bounded;
286     if (extents->is_bounded) {
287         if (antialias == CAIRO_ANTIALIAS_NONE)
288             spans->renderer.render_rows = i965_bounded_spans_mono;
289         else
290             spans->renderer.render_rows = i965_bounded_spans;
291
292         spans->extents = &extents->bounded;
293     } else {
294         if (antialias == CAIRO_ANTIALIAS_NONE)
295             spans->renderer.render_rows = i965_unbounded_spans_mono;
296         else
297             spans->renderer.render_rows = i965_unbounded_spans;
298
299         spans->extents = &extents->unbounded;
300     }
301     spans->xmin = spans->extents->x;
302     spans->xmax = spans->extents->x + spans->extents->width;
303
304     spans->clip_region = NULL;
305     if (clip != NULL) {
306         cairo_region_t *clip_region = NULL;
307
308         status = _cairo_clip_get_region (clip, &clip_region);
309         assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
310
311         if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
312             clip_region = NULL;
313
314         spans->clip_region = clip_region;
315         if (status == CAIRO_INT_STATUS_UNSUPPORTED)
316             i965_shader_set_clip (&spans->shader, clip);
317     }
318
319     spans->head.next  = NULL;
320     spans->head.bo    = NULL;
321     spans->head.count = 0;
322     spans->tail = &spans->head;
323
324     if (spans->clip_region == NULL) {
325         spans->get_rectangle = i965_spans_emit_rectangle;
326     } else {
327         spans->get_rectangle = i965_spans_accumulate_rectangle;
328         spans->head.bo = intel_bo_create (&spans->device->intel,
329                                           I965_VERTEX_SIZE, I965_VERTEX_SIZE,
330                                           FALSE, I915_TILING_NONE, 0);
331         if (unlikely (spans->head.bo == NULL))
332             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
333
334         spans->vbo_base = intel_bo_map (&spans->device->intel, spans->head.bo);
335     }
336     spans->vbo_offset = 0;
337
338     return i965_shader_acquire_pattern (&spans->shader,
339                                         &spans->shader.source,
340                                         pattern, &extents->bounded);
341 }
342
343 static void
344 i965_spans_fini (i965_spans_t *spans)
345 {
346     i965_shader_fini (&spans->shader);
347
348     if (spans->head.bo != NULL) {
349         struct i965_vbo *vbo, *next;
350
351         intel_bo_destroy (&spans->device->intel, spans->head.bo);
352         for (vbo = spans->head.next; vbo != NULL; vbo = next) {
353             next = vbo->next;
354             intel_bo_destroy (&spans->device->intel, vbo->bo);
355             free (vbo);
356         }
357     }
358 }
359
360 cairo_status_t
361 i965_clip_and_composite_spans (i965_surface_t           *dst,
362                                cairo_operator_t          op,
363                                const cairo_pattern_t    *pattern,
364                                cairo_antialias_t         antialias,
365                                i965_spans_func_t         draw_func,
366                                void                     *draw_closure,
367                                const cairo_composite_rectangles_t*extents,
368                                cairo_clip_t             *clip)
369 {
370     i965_spans_t spans;
371     i965_device_t *device;
372     cairo_status_t status;
373
374     if (op == CAIRO_OPERATOR_CLEAR) {
375         pattern = &_cairo_pattern_white.base;
376         op = CAIRO_OPERATOR_DEST_OUT;
377     }
378
379     status = i965_spans_init (&spans, dst, op, pattern, antialias, clip, extents);
380     if (unlikely (status))
381         return status;
382
383     spans.shader.mask.base.content  = CAIRO_CONTENT_ALPHA;
384     spans.shader.mask.type.fragment = FS_SPANS;
385     spans.shader.mask.type.vertex   = VS_SPANS;
386     spans.shader.mask.type.pattern  = PATTERN_BASE;
387
388     status = cairo_device_acquire (dst->intel.drm.base.device);
389     if (unlikely (status))
390         goto CLEANUP_SPANS;
391
392     device = i965_device (dst);
393     status = i965_shader_commit (&spans.shader, device);
394     if (unlikely (status))
395         goto CLEANUP_DEVICE;
396
397     status = draw_func (draw_closure, &spans.renderer, spans.extents);
398     if (spans.clip_region != NULL && status == CAIRO_STATUS_SUCCESS)
399         i965_clipped_vertices (device, &spans.head, spans.clip_region);
400
401   CLEANUP_DEVICE:
402     cairo_device_release (dst->intel.drm.base.device);
403   CLEANUP_SPANS:
404     i965_spans_fini (&spans);
405
406     return status;
407 }