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 *
i965_spans_emit_rectangle(i965_spans_t * spans)75 i965_spans_emit_rectangle (i965_spans_t *spans)
76 {
77 return i965_add_rectangle (spans->device);
78 }
79
80 static float *
i965_spans_accumulate_rectangle(i965_spans_t * spans)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 = _cairo_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
i965_span_rectangle(i965_spans_t * spans,int x0,int x1,int y0,int y1,int alpha)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
i965_bounded_spans_mono(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * half,unsigned num_spans)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
i965_bounded_spans(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * half,unsigned num_spans)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
i965_unbounded_spans(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * half,unsigned num_spans)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
i965_unbounded_spans_mono(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * half,unsigned num_spans)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
i965_spans_init(i965_spans_t * spans,i965_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * pattern,cairo_antialias_t antialias,cairo_clip_t * clip,const cairo_composite_rectangles_t * extents)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
i965_spans_fini(i965_spans_t * spans)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
i965_clip_and_composite_spans(i965_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * pattern,cairo_antialias_t antialias,i965_spans_func_t draw_func,void * draw_closure,const cairo_composite_rectangles_t * extents,cairo_clip_t * clip)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 }
408