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