Home | History | Annotate | Download | only in pixman
      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
    386