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 121static force_inline uint8_t 122clip255 (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 */ 155static void 156rasterize_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 339static 340#endif 341void 342PIXMAN_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 369PIXMAN_EXPORT void 370pixman_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 386