|
1 /* |
|
2 * Copyright © 2004 Keith Packard |
|
3 * |
|
4 * Permission to use, copy, modify, distribute, and sell this software and its |
|
5 * documentation for any purpose is hereby granted without fee, provided that |
|
6 * the above copyright notice appear in all copies and that both that |
|
7 * copyright notice and this permission notice appear in supporting |
|
8 * documentation, and that the name of Keith Packard not be used in |
|
9 * advertising or publicity pertaining to distribution of the software without |
|
10 * specific, written prior permission. Keith Packard makes no |
|
11 * representations about the suitability of this software for any purpose. It |
|
12 * is provided "as is" without express or implied warranty. |
|
13 * |
|
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
|
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
|
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
|
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
|
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
|
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
|
20 * PERFORMANCE OF THIS SOFTWARE. |
|
21 */ |
|
22 |
|
23 #ifdef HAVE_CONFIG_H |
|
24 #include <config.h> |
|
25 #endif |
|
26 |
|
27 #include <string.h> |
|
28 |
|
29 #include "pixman-private.h" |
|
30 #include "pixman-accessor.h" |
|
31 |
|
32 /* |
|
33 * Step across a small sample grid gap |
|
34 */ |
|
35 #define RENDER_EDGE_STEP_SMALL(edge) \ |
|
36 { \ |
|
37 edge->x += edge->stepx_small; \ |
|
38 edge->e += edge->dx_small; \ |
|
39 if (edge->e > 0) \ |
|
40 { \ |
|
41 edge->e -= edge->dy; \ |
|
42 edge->x += edge->signdx; \ |
|
43 } \ |
|
44 } |
|
45 |
|
46 /* |
|
47 * Step across a large sample grid gap |
|
48 */ |
|
49 #define RENDER_EDGE_STEP_BIG(edge) \ |
|
50 { \ |
|
51 edge->x += edge->stepx_big; \ |
|
52 edge->e += edge->dx_big; \ |
|
53 if (edge->e > 0) \ |
|
54 { \ |
|
55 edge->e -= edge->dy; \ |
|
56 edge->x += edge->signdx; \ |
|
57 } \ |
|
58 } |
|
59 |
|
60 #ifdef PIXMAN_FB_ACCESSORS |
|
61 #define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_accessors |
|
62 #else |
|
63 #define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_no_accessors |
|
64 #endif |
|
65 |
|
66 /* |
|
67 * 4 bit alpha |
|
68 */ |
|
69 |
|
70 #define N_BITS 4 |
|
71 #define RASTERIZE_EDGES rasterize_edges_4 |
|
72 |
|
73 #ifndef WORDS_BIGENDIAN |
|
74 #define SHIFT_4(o) ((o) << 2) |
|
75 #else |
|
76 #define SHIFT_4(o) ((1 - (o)) << 2) |
|
77 #endif |
|
78 |
|
79 #define GET_4(x, o) (((x) >> SHIFT_4 (o)) & 0xf) |
|
80 #define PUT_4(x, o, v) \ |
|
81 (((x) & ~(0xf << SHIFT_4 (o))) | (((v) & 0xf) << SHIFT_4 (o))) |
|
82 |
|
83 #define DEFINE_ALPHA(line, x) \ |
|
84 uint8_t *__ap = (uint8_t *) line + ((x) >> 1); \ |
|
85 int __ao = (x) & 1 |
|
86 |
|
87 #define STEP_ALPHA ((__ap += __ao), (__ao ^= 1)) |
|
88 |
|
89 #define ADD_ALPHA(a) \ |
|
90 { \ |
|
91 uint8_t __o = READ (image, __ap); \ |
|
92 uint8_t __a = (a) + GET_4 (__o, __ao); \ |
|
93 WRITE (image, __ap, PUT_4 (__o, __ao, __a | (0 - ((__a) >> 4)))); \ |
|
94 } |
|
95 |
|
96 #include "pixman-edge-imp.h" |
|
97 |
|
98 #undef ADD_ALPHA |
|
99 #undef STEP_ALPHA |
|
100 #undef DEFINE_ALPHA |
|
101 #undef RASTERIZE_EDGES |
|
102 #undef N_BITS |
|
103 |
|
104 |
|
105 /* |
|
106 * 1 bit alpha |
|
107 */ |
|
108 |
|
109 #define N_BITS 1 |
|
110 #define RASTERIZE_EDGES rasterize_edges_1 |
|
111 |
|
112 #include "pixman-edge-imp.h" |
|
113 |
|
114 #undef RASTERIZE_EDGES |
|
115 #undef N_BITS |
|
116 |
|
117 /* |
|
118 * 8 bit alpha |
|
119 */ |
|
120 |
|
121 static force_inline uint8_t |
|
122 clip255 (int x) |
|
123 { |
|
124 if (x > 255) |
|
125 return 255; |
|
126 |
|
127 return x; |
|
128 } |
|
129 |
|
130 #define ADD_SATURATE_8(buf, val, length) \ |
|
131 do \ |
|
132 { \ |
|
133 int i__ = (length); \ |
|
134 uint8_t *buf__ = (buf); \ |
|
135 int val__ = (val); \ |
|
136 \ |
|
137 while (i__--) \ |
|
138 { \ |
|
139 WRITE (image, (buf__), clip255 (READ (image, (buf__)) + (val__))); \ |
|
140 (buf__)++; \ |
|
141 } \ |
|
142 } while (0) |
|
143 |
|
144 /* |
|
145 * We want to detect the case where we add the same value to a long |
|
146 * span of pixels. The triangles on the end are filled in while we |
|
147 * count how many sub-pixel scanlines contribute to the middle section. |
|
148 * |
|
149 * +--------------------------+ |
|
150 * fill_height =| \ / |
|
151 * +------------------+ |
|
152 * |================| |
|
153 * fill_start fill_end |
|
154 */ |
|
155 static void |
|
156 rasterize_edges_8 (pixman_image_t *image, |
|
157 pixman_edge_t * l, |
|
158 pixman_edge_t * r, |
|
159 pixman_fixed_t t, |
|
160 pixman_fixed_t b) |
|
161 { |
|
162 pixman_fixed_t y = t; |
|
163 uint32_t *line; |
|
164 int fill_start = -1, fill_end = -1; |
|
165 int fill_size = 0; |
|
166 uint32_t *buf = (image)->bits.bits; |
|
167 int stride = (image)->bits.rowstride; |
|
168 int width = (image)->bits.width; |
|
169 |
|
170 line = buf + pixman_fixed_to_int (y) * stride; |
|
171 |
|
172 for (;;) |
|
173 { |
|
174 uint8_t *ap = (uint8_t *) line; |
|
175 pixman_fixed_t lx, rx; |
|
176 int lxi, rxi; |
|
177 |
|
178 /* clip X */ |
|
179 lx = l->x; |
|
180 if (lx < 0) |
|
181 lx = 0; |
|
182 |
|
183 rx = r->x; |
|
184 |
|
185 if (pixman_fixed_to_int (rx) >= width) |
|
186 { |
|
187 /* Use the last pixel of the scanline, covered 100%. |
|
188 * We can't use the first pixel following the scanline, |
|
189 * because accessing it could result in a buffer overrun. |
|
190 */ |
|
191 rx = pixman_int_to_fixed (width) - 1; |
|
192 } |
|
193 |
|
194 /* Skip empty (or backwards) sections */ |
|
195 if (rx > lx) |
|
196 { |
|
197 int lxs, rxs; |
|
198 |
|
199 /* Find pixel bounds for span. */ |
|
200 lxi = pixman_fixed_to_int (lx); |
|
201 rxi = pixman_fixed_to_int (rx); |
|
202 |
|
203 /* Sample coverage for edge pixels */ |
|
204 lxs = RENDER_SAMPLES_X (lx, 8); |
|
205 rxs = RENDER_SAMPLES_X (rx, 8); |
|
206 |
|
207 /* Add coverage across row */ |
|
208 if (lxi == rxi) |
|
209 { |
|
210 WRITE (image, ap + lxi, |
|
211 clip255 (READ (image, ap + lxi) + rxs - lxs)); |
|
212 } |
|
213 else |
|
214 { |
|
215 WRITE (image, ap + lxi, |
|
216 clip255 (READ (image, ap + lxi) + N_X_FRAC (8) - lxs)); |
|
217 |
|
218 /* Move forward so that lxi/rxi is the pixel span */ |
|
219 lxi++; |
|
220 |
|
221 /* Don't bother trying to optimize the fill unless |
|
222 * the span is longer than 4 pixels. */ |
|
223 if (rxi - lxi > 4) |
|
224 { |
|
225 if (fill_start < 0) |
|
226 { |
|
227 fill_start = lxi; |
|
228 fill_end = rxi; |
|
229 fill_size++; |
|
230 } |
|
231 else |
|
232 { |
|
233 if (lxi >= fill_end || rxi < fill_start) |
|
234 { |
|
235 /* We're beyond what we saved, just fill it */ |
|
236 ADD_SATURATE_8 (ap + fill_start, |
|
237 fill_size * N_X_FRAC (8), |
|
238 fill_end - fill_start); |
|
239 fill_start = lxi; |
|
240 fill_end = rxi; |
|
241 fill_size = 1; |
|
242 } |
|
243 else |
|
244 { |
|
245 /* Update fill_start */ |
|
246 if (lxi > fill_start) |
|
247 { |
|
248 ADD_SATURATE_8 (ap + fill_start, |
|
249 fill_size * N_X_FRAC (8), |
|
250 lxi - fill_start); |
|
251 fill_start = lxi; |
|
252 } |
|
253 else if (lxi < fill_start) |
|
254 { |
|
255 ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8), |
|
256 fill_start - lxi); |
|
257 } |
|
258 |
|
259 /* Update fill_end */ |
|
260 if (rxi < fill_end) |
|
261 { |
|
262 ADD_SATURATE_8 (ap + rxi, |
|
263 fill_size * N_X_FRAC (8), |
|
264 fill_end - rxi); |
|
265 fill_end = rxi; |
|
266 } |
|
267 else if (fill_end < rxi) |
|
268 { |
|
269 ADD_SATURATE_8 (ap + fill_end, |
|
270 N_X_FRAC (8), |
|
271 rxi - fill_end); |
|
272 } |
|
273 fill_size++; |
|
274 } |
|
275 } |
|
276 } |
|
277 else |
|
278 { |
|
279 ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8), rxi - lxi); |
|
280 } |
|
281 |
|
282 WRITE (image, ap + rxi, clip255 (READ (image, ap + rxi) + rxs)); |
|
283 } |
|
284 } |
|
285 |
|
286 if (y == b) |
|
287 { |
|
288 /* We're done, make sure we clean up any remaining fill. */ |
|
289 if (fill_start != fill_end) |
|
290 { |
|
291 if (fill_size == N_Y_FRAC (8)) |
|
292 { |
|
293 MEMSET_WRAPPED (image, ap + fill_start, |
|
294 0xff, fill_end - fill_start); |
|
295 } |
|
296 else |
|
297 { |
|
298 ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8), |
|
299 fill_end - fill_start); |
|
300 } |
|
301 } |
|
302 break; |
|
303 } |
|
304 |
|
305 if (pixman_fixed_frac (y) != Y_FRAC_LAST (8)) |
|
306 { |
|
307 RENDER_EDGE_STEP_SMALL (l); |
|
308 RENDER_EDGE_STEP_SMALL (r); |
|
309 y += STEP_Y_SMALL (8); |
|
310 } |
|
311 else |
|
312 { |
|
313 RENDER_EDGE_STEP_BIG (l); |
|
314 RENDER_EDGE_STEP_BIG (r); |
|
315 y += STEP_Y_BIG (8); |
|
316 if (fill_start != fill_end) |
|
317 { |
|
318 if (fill_size == N_Y_FRAC (8)) |
|
319 { |
|
320 MEMSET_WRAPPED (image, ap + fill_start, |
|
321 0xff, fill_end - fill_start); |
|
322 } |
|
323 else |
|
324 { |
|
325 ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8), |
|
326 fill_end - fill_start); |
|
327 } |
|
328 |
|
329 fill_start = fill_end = -1; |
|
330 fill_size = 0; |
|
331 } |
|
332 |
|
333 line += stride; |
|
334 } |
|
335 } |
|
336 } |
|
337 |
|
338 #ifndef PIXMAN_FB_ACCESSORS |
|
339 static |
|
340 #endif |
|
341 void |
|
342 PIXMAN_RASTERIZE_EDGES (pixman_image_t *image, |
|
343 pixman_edge_t * l, |
|
344 pixman_edge_t * r, |
|
345 pixman_fixed_t t, |
|
346 pixman_fixed_t b) |
|
347 { |
|
348 switch (PIXMAN_FORMAT_BPP (image->bits.format)) |
|
349 { |
|
350 case 1: |
|
351 rasterize_edges_1 (image, l, r, t, b); |
|
352 break; |
|
353 |
|
354 case 4: |
|
355 rasterize_edges_4 (image, l, r, t, b); |
|
356 break; |
|
357 |
|
358 case 8: |
|
359 rasterize_edges_8 (image, l, r, t, b); |
|
360 break; |
|
361 |
|
362 default: |
|
363 break; |
|
364 } |
|
365 } |
|
366 |
|
367 #ifndef PIXMAN_FB_ACCESSORS |
|
368 |
|
369 PIXMAN_EXPORT void |
|
370 pixman_rasterize_edges (pixman_image_t *image, |
|
371 pixman_edge_t * l, |
|
372 pixman_edge_t * r, |
|
373 pixman_fixed_t t, |
|
374 pixman_fixed_t b) |
|
375 { |
|
376 return_if_fail (image->type == BITS); |
|
377 return_if_fail (PIXMAN_FORMAT_TYPE (image->bits.format) == PIXMAN_TYPE_A); |
|
378 |
|
379 if (image->bits.read_func || image->bits.write_func) |
|
380 pixman_rasterize_edges_accessors (image, l, r, t, b); |
|
381 else |
|
382 pixman_rasterize_edges_no_accessors (image, l, r, t, b); |
|
383 } |
|
384 |
|
385 #endif |