Home | History | Annotate | Download | only in pixman
      1 /*
      2  * Copyright  2009 Red Hat, Inc.
      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 Red Hat not be used in advertising or
      9  * publicity pertaining to distribution of the software without specific,
     10  * written prior permission.  Red Hat makes no representations about the
     11  * suitability of this software for any purpose.  It is provided "as is"
     12  * without express or implied warranty.
     13  *
     14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
     15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
     16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
     17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     19  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     20  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     21  * SOFTWARE.
     22  */
     23 
     24 #ifdef HAVE_CONFIG_H
     25 #include <config.h>
     26 #endif
     27 #include <stdlib.h>
     28 #include "pixman-private.h"
     29 
     30 pixman_implementation_t *
     31 _pixman_implementation_create (pixman_implementation_t *fallback,
     32 			       const pixman_fast_path_t *fast_paths)
     33 {
     34     pixman_implementation_t *imp;
     35 
     36     assert (fast_paths);
     37 
     38     if ((imp = malloc (sizeof (pixman_implementation_t))))
     39     {
     40 	pixman_implementation_t *d;
     41 
     42 	memset (imp, 0, sizeof *imp);
     43 
     44 	imp->fallback = fallback;
     45 	imp->fast_paths = fast_paths;
     46 
     47 	/* Make sure the whole fallback chain has the right toplevel */
     48 	for (d = imp; d != NULL; d = d->fallback)
     49 	    d->toplevel = imp;
     50     }
     51 
     52     return imp;
     53 }
     54 
     55 #define N_CACHED_FAST_PATHS 8
     56 
     57 typedef struct
     58 {
     59     struct
     60     {
     61 	pixman_implementation_t *	imp;
     62 	pixman_fast_path_t		fast_path;
     63     } cache [N_CACHED_FAST_PATHS];
     64 } cache_t;
     65 
     66 PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
     67 
     68 static void
     69 dummy_composite_rect (pixman_implementation_t *imp,
     70 		      pixman_composite_info_t *info)
     71 {
     72 }
     73 
     74 void
     75 _pixman_implementation_lookup_composite (pixman_implementation_t  *toplevel,
     76 					 pixman_op_t               op,
     77 					 pixman_format_code_t      src_format,
     78 					 uint32_t                  src_flags,
     79 					 pixman_format_code_t      mask_format,
     80 					 uint32_t                  mask_flags,
     81 					 pixman_format_code_t      dest_format,
     82 					 uint32_t                  dest_flags,
     83 					 pixman_implementation_t **out_imp,
     84 					 pixman_composite_func_t  *out_func)
     85 {
     86     pixman_implementation_t *imp;
     87     cache_t *cache;
     88     int i;
     89 
     90     /* Check cache for fast paths */
     91     cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache);
     92 
     93     for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
     94     {
     95 	const pixman_fast_path_t *info = &(cache->cache[i].fast_path);
     96 
     97 	/* Note that we check for equality here, not whether
     98 	 * the cached fast path matches. This is to prevent
     99 	 * us from selecting an overly general fast path
    100 	 * when a more specific one would work.
    101 	 */
    102 	if (info->op == op			&&
    103 	    info->src_format == src_format	&&
    104 	    info->mask_format == mask_format	&&
    105 	    info->dest_format == dest_format	&&
    106 	    info->src_flags == src_flags	&&
    107 	    info->mask_flags == mask_flags	&&
    108 	    info->dest_flags == dest_flags	&&
    109 	    info->func)
    110 	{
    111 	    *out_imp = cache->cache[i].imp;
    112 	    *out_func = cache->cache[i].fast_path.func;
    113 
    114 	    goto update_cache;
    115 	}
    116     }
    117 
    118     for (imp = toplevel; imp != NULL; imp = imp->fallback)
    119     {
    120 	const pixman_fast_path_t *info = imp->fast_paths;
    121 
    122 	while (info->op != PIXMAN_OP_NONE)
    123 	{
    124 	    if ((info->op == op || info->op == PIXMAN_OP_any)		&&
    125 		/* Formats */
    126 		((info->src_format == src_format) ||
    127 		 (info->src_format == PIXMAN_any))			&&
    128 		((info->mask_format == mask_format) ||
    129 		 (info->mask_format == PIXMAN_any))			&&
    130 		((info->dest_format == dest_format) ||
    131 		 (info->dest_format == PIXMAN_any))			&&
    132 		/* Flags */
    133 		(info->src_flags & src_flags) == info->src_flags	&&
    134 		(info->mask_flags & mask_flags) == info->mask_flags	&&
    135 		(info->dest_flags & dest_flags) == info->dest_flags)
    136 	    {
    137 		*out_imp = imp;
    138 		*out_func = info->func;
    139 
    140 		/* Set i to the last spot in the cache so that the
    141 		 * move-to-front code below will work
    142 		 */
    143 		i = N_CACHED_FAST_PATHS - 1;
    144 
    145 		goto update_cache;
    146 	    }
    147 
    148 	    ++info;
    149 	}
    150     }
    151 
    152     /* We should never reach this point */
    153     _pixman_log_error (
    154         FUNC,
    155         "No composite function found\n"
    156         "\n"
    157         "The most likely cause of this is that this system has issues with\n"
    158         "thread local storage\n");
    159 
    160     *out_imp = NULL;
    161     *out_func = dummy_composite_rect;
    162     return;
    163 
    164 update_cache:
    165     if (i)
    166     {
    167 	while (i--)
    168 	    cache->cache[i + 1] = cache->cache[i];
    169 
    170 	cache->cache[0].imp = *out_imp;
    171 	cache->cache[0].fast_path.op = op;
    172 	cache->cache[0].fast_path.src_format = src_format;
    173 	cache->cache[0].fast_path.src_flags = src_flags;
    174 	cache->cache[0].fast_path.mask_format = mask_format;
    175 	cache->cache[0].fast_path.mask_flags = mask_flags;
    176 	cache->cache[0].fast_path.dest_format = dest_format;
    177 	cache->cache[0].fast_path.dest_flags = dest_flags;
    178 	cache->cache[0].fast_path.func = *out_func;
    179     }
    180 }
    181 
    182 static void
    183 dummy_combine (pixman_implementation_t *imp,
    184 	       pixman_op_t              op,
    185 	       uint32_t *               pd,
    186 	       const uint32_t *         ps,
    187 	       const uint32_t *         pm,
    188 	       int                      w)
    189 {
    190 }
    191 
    192 pixman_combine_32_func_t
    193 _pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
    194 					pixman_op_t		 op,
    195 					pixman_bool_t		 component_alpha,
    196 					pixman_bool_t		 narrow)
    197 {
    198     while (imp)
    199     {
    200 	pixman_combine_32_func_t f = NULL;
    201 
    202 	switch ((narrow << 1) | component_alpha)
    203 	{
    204 	case 0: /* not narrow, not component alpha */
    205 	    f = (pixman_combine_32_func_t)imp->combine_float[op];
    206 	    break;
    207 
    208 	case 1: /* not narrow, component_alpha */
    209 	    f = (pixman_combine_32_func_t)imp->combine_float_ca[op];
    210 	    break;
    211 
    212 	case 2: /* narrow, not component alpha */
    213 	    f = imp->combine_32[op];
    214 	    break;
    215 
    216 	case 3: /* narrow, component_alpha */
    217 	    f = imp->combine_32_ca[op];
    218 	    break;
    219 	}
    220 
    221 	if (f)
    222 	    return f;
    223 
    224 	imp = imp->fallback;
    225     }
    226 
    227     /* We should never reach this point */
    228     _pixman_log_error (FUNC, "No known combine function\n");
    229     return dummy_combine;
    230 }
    231 
    232 pixman_bool_t
    233 _pixman_implementation_blt (pixman_implementation_t * imp,
    234                             uint32_t *                src_bits,
    235                             uint32_t *                dst_bits,
    236                             int                       src_stride,
    237                             int                       dst_stride,
    238                             int                       src_bpp,
    239                             int                       dst_bpp,
    240                             int                       src_x,
    241                             int                       src_y,
    242                             int                       dest_x,
    243                             int                       dest_y,
    244                             int                       width,
    245                             int                       height)
    246 {
    247     while (imp)
    248     {
    249 	if (imp->blt &&
    250 	    (*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride,
    251 			 src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y,
    252 			 width, height))
    253 	{
    254 	    return TRUE;
    255 	}
    256 
    257 	imp = imp->fallback;
    258     }
    259 
    260     return FALSE;
    261 }
    262 
    263 pixman_bool_t
    264 _pixman_implementation_fill (pixman_implementation_t *imp,
    265                              uint32_t *               bits,
    266                              int                      stride,
    267                              int                      bpp,
    268                              int                      x,
    269                              int                      y,
    270                              int                      width,
    271                              int                      height,
    272                              uint32_t                 filler)
    273 {
    274     while (imp)
    275     {
    276 	if (imp->fill &&
    277 	    ((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler)))
    278 	{
    279 	    return TRUE;
    280 	}
    281 
    282 	imp = imp->fallback;
    283     }
    284 
    285     return FALSE;
    286 }
    287 
    288 pixman_bool_t
    289 _pixman_implementation_src_iter_init (pixman_implementation_t	*imp,
    290 				      pixman_iter_t             *iter,
    291 				      pixman_image_t		*image,
    292 				      int			 x,
    293 				      int			 y,
    294 				      int			 width,
    295 				      int			 height,
    296 				      uint8_t			*buffer,
    297 				      iter_flags_t		 iter_flags,
    298 				      uint32_t                   image_flags)
    299 {
    300     iter->image = image;
    301     iter->buffer = (uint32_t *)buffer;
    302     iter->x = x;
    303     iter->y = y;
    304     iter->width = width;
    305     iter->height = height;
    306     iter->iter_flags = iter_flags;
    307     iter->image_flags = image_flags;
    308 
    309     while (imp)
    310     {
    311 	if (imp->src_iter_init && (*imp->src_iter_init) (imp, iter))
    312 	    return TRUE;
    313 
    314 	imp = imp->fallback;
    315     }
    316 
    317     return FALSE;
    318 }
    319 
    320 pixman_bool_t
    321 _pixman_implementation_dest_iter_init (pixman_implementation_t	*imp,
    322 				       pixman_iter_t            *iter,
    323 				       pixman_image_t		*image,
    324 				       int			 x,
    325 				       int			 y,
    326 				       int			 width,
    327 				       int			 height,
    328 				       uint8_t			*buffer,
    329 				       iter_flags_t		 iter_flags,
    330 				       uint32_t                  image_flags)
    331 {
    332     iter->image = image;
    333     iter->buffer = (uint32_t *)buffer;
    334     iter->x = x;
    335     iter->y = y;
    336     iter->width = width;
    337     iter->height = height;
    338     iter->iter_flags = iter_flags;
    339     iter->image_flags = image_flags;
    340 
    341     while (imp)
    342     {
    343 	if (imp->dest_iter_init && (*imp->dest_iter_init) (imp, iter))
    344 	    return TRUE;
    345 
    346 	imp = imp->fallback;
    347     }
    348 
    349     return FALSE;
    350 }
    351 
    352 pixman_bool_t
    353 _pixman_disabled (const char *name)
    354 {
    355     const char *env;
    356 
    357     if ((env = getenv ("PIXMAN_DISABLE")))
    358     {
    359 	do
    360 	{
    361 	    const char *end;
    362 	    int len;
    363 
    364 	    if ((end = strchr (env, ' ')))
    365 		len = end - env;
    366 	    else
    367 		len = strlen (env);
    368 
    369 	    if (strlen (name) == len && strncmp (name, env, len) == 0)
    370 	    {
    371 		printf ("pixman: Disabled %s implementation\n", name);
    372 		return TRUE;
    373 	    }
    374 
    375 	    env += len;
    376 	}
    377 	while (*env++);
    378     }
    379 
    380     return FALSE;
    381 }
    382 
    383 pixman_implementation_t *
    384 _pixman_choose_implementation (void)
    385 {
    386     pixman_implementation_t *imp;
    387 
    388     imp = _pixman_implementation_create_general();
    389 
    390     if (!_pixman_disabled ("fast"))
    391 	imp = _pixman_implementation_create_fast_path (imp);
    392 
    393     imp = _pixman_x86_get_implementations (imp);
    394     imp = _pixman_arm_get_implementations (imp);
    395     imp = _pixman_ppc_get_implementations (imp);
    396     imp = _pixman_mips_get_implementations (imp);
    397 
    398     imp = _pixman_implementation_create_noop (imp);
    399 
    400     return imp;
    401 }
    402