Source code

Revision control

Copy as Markdown

Other Tools

/*
* Copyright © 2009 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Red Hat not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Red Hat makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <pixman-config.h>
#endif
#include <stdlib.h>
#include "pixman-private.h"
pixman_implementation_t *
_pixman_implementation_create (pixman_implementation_t *fallback,
const pixman_fast_path_t *fast_paths)
{
pixman_implementation_t *imp;
assert (fast_paths);
if ((imp = malloc (sizeof (pixman_implementation_t))))
{
pixman_implementation_t *d;
memset (imp, 0, sizeof *imp);
imp->fallback = fallback;
imp->fast_paths = fast_paths;
/* Make sure the whole fallback chain has the right toplevel */
for (d = imp; d != NULL; d = d->fallback)
d->toplevel = imp;
}
return imp;
}
#define N_CACHED_FAST_PATHS 8
typedef struct
{
struct
{
pixman_implementation_t * imp;
pixman_fast_path_t fast_path;
} cache [N_CACHED_FAST_PATHS];
} cache_t;
PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache)
static void
dummy_composite_rect (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
}
void
_pixman_implementation_lookup_composite (pixman_implementation_t *toplevel,
pixman_op_t op,
pixman_format_code_t src_format,
uint32_t src_flags,
pixman_format_code_t mask_format,
uint32_t mask_flags,
pixman_format_code_t dest_format,
uint32_t dest_flags,
pixman_implementation_t **out_imp,
pixman_composite_func_t *out_func)
{
pixman_implementation_t *imp;
cache_t *cache;
int i;
/* Check cache for fast paths */
cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache);
for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
{
const pixman_fast_path_t *info = &(cache->cache[i].fast_path);
/* Note that we check for equality here, not whether
* the cached fast path matches. This is to prevent
* us from selecting an overly general fast path
* when a more specific one would work.
*/
if (info->op == op &&
info->src_format == src_format &&
info->mask_format == mask_format &&
info->dest_format == dest_format &&
info->src_flags == src_flags &&
info->mask_flags == mask_flags &&
info->dest_flags == dest_flags &&
info->func)
{
*out_imp = cache->cache[i].imp;
*out_func = cache->cache[i].fast_path.func;
goto update_cache;
}
}
for (imp = toplevel; imp != NULL; imp = imp->fallback)
{
const pixman_fast_path_t *info = imp->fast_paths;
while (info->op != PIXMAN_OP_NONE)
{
if ((info->op == op || info->op == PIXMAN_OP_any) &&
/* Formats */
((info->src_format == src_format) ||
(info->src_format == PIXMAN_any)) &&
((info->mask_format == mask_format) ||
(info->mask_format == PIXMAN_any)) &&
((info->dest_format == dest_format) ||
(info->dest_format == PIXMAN_any)) &&
/* Flags */
(info->src_flags & src_flags) == info->src_flags &&
(info->mask_flags & mask_flags) == info->mask_flags &&
(info->dest_flags & dest_flags) == info->dest_flags)
{
*out_imp = imp;
*out_func = info->func;
/* Set i to the last spot in the cache so that the
* move-to-front code below will work
*/
i = N_CACHED_FAST_PATHS - 1;
goto update_cache;
}
++info;
}
}
/* We should never reach this point */
_pixman_log_error (
FUNC,
"No composite function found\n"
"\n"
"The most likely cause of this is that this system has issues with\n"
"thread local storage\n");
*out_imp = NULL;
*out_func = dummy_composite_rect;
return;
update_cache:
if (i)
{
while (i--)
cache->cache[i + 1] = cache->cache[i];
cache->cache[0].imp = *out_imp;
cache->cache[0].fast_path.op = op;
cache->cache[0].fast_path.src_format = src_format;
cache->cache[0].fast_path.src_flags = src_flags;
cache->cache[0].fast_path.mask_format = mask_format;
cache->cache[0].fast_path.mask_flags = mask_flags;
cache->cache[0].fast_path.dest_format = dest_format;
cache->cache[0].fast_path.dest_flags = dest_flags;
cache->cache[0].fast_path.func = *out_func;
}
}
static void
dummy_combine (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
}
pixman_combine_32_func_t
_pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
pixman_op_t op,
pixman_bool_t component_alpha,
pixman_bool_t narrow)
{
while (imp)
{
pixman_combine_32_func_t f = NULL;
switch ((narrow << 1) | component_alpha)
{
case 0: /* not narrow, not component alpha */
f = (pixman_combine_32_func_t)imp->combine_float[op];
break;
case 1: /* not narrow, component_alpha */
f = (pixman_combine_32_func_t)imp->combine_float_ca[op];
break;
case 2: /* narrow, not component alpha */
f = imp->combine_32[op];
break;
case 3: /* narrow, component_alpha */
f = imp->combine_32_ca[op];
break;
}
if (f)
return f;
imp = imp->fallback;
}
/* We should never reach this point */
_pixman_log_error (FUNC, "No known combine function\n");
return dummy_combine;
}
pixman_bool_t
_pixman_implementation_blt (pixman_implementation_t * imp,
uint32_t * src_bits,
uint32_t * dst_bits,
int src_stride,
int dst_stride,
int src_bpp,
int dst_bpp,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height)
{
while (imp)
{
if (imp->blt &&
(*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride,
src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y,
width, height))
{
return TRUE;
}
imp = imp->fallback;
}
return FALSE;
}
pixman_bool_t
_pixman_implementation_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t filler)
{
while (imp)
{
if (imp->fill &&
((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler)))
{
return TRUE;
}
imp = imp->fallback;
}
return FALSE;
}
static uint32_t *
get_scanline_null (pixman_iter_t *iter, const uint32_t *mask)
{
return NULL;
}
void
_pixman_implementation_iter_init (pixman_implementation_t *imp,
pixman_iter_t *iter,
pixman_image_t *image,
int x,
int y,
int width,
int height,
uint8_t *buffer,
iter_flags_t iter_flags,
uint32_t image_flags)
{
pixman_format_code_t format;
iter->image = image;
iter->buffer = (uint32_t *)buffer;
iter->x = x;
iter->y = y;
iter->width = width;
iter->height = height;
iter->iter_flags = iter_flags;
iter->image_flags = image_flags;
iter->fini = NULL;
if (!iter->image)
{
iter->get_scanline = get_scanline_null;
return;
}
format = iter->image->common.extended_format_code;
while (imp)
{
if (imp->iter_info)
{
const pixman_iter_info_t *info;
for (info = imp->iter_info; info->format != PIXMAN_null; ++info)
{
if ((info->format == PIXMAN_any || info->format == format) &&
(info->image_flags & image_flags) == info->image_flags &&
(info->iter_flags & iter_flags) == info->iter_flags)
{
iter->get_scanline = info->get_scanline;
iter->write_back = info->write_back;
if (info->initializer)
info->initializer (iter, info);
return;
}
}
}
imp = imp->fallback;
}
}
pixman_bool_t
_pixman_disabled (const char *name)
{
const char *env;
if ((env = getenv ("PIXMAN_DISABLE")))
{
do
{
const char *end;
int len;
if ((end = strchr (env, ' ')))
len = end - env;
else
len = strlen (env);
if (strlen (name) == len && strncmp (name, env, len) == 0)
{
printf ("pixman: Disabled %s implementation\n", name);
return TRUE;
}
env += len;
}
while (*env++);
}
return FALSE;
}
static const pixman_fast_path_t empty_fast_path[] =
{
{ PIXMAN_OP_NONE }
};
pixman_implementation_t *
_pixman_choose_implementation (void)
{
pixman_implementation_t *imp;
imp = _pixman_implementation_create_general();
if (!_pixman_disabled ("fast"))
imp = _pixman_implementation_create_fast_path (imp);
imp = _pixman_x86_get_implementations (imp);
imp = _pixman_arm_get_implementations (imp);
imp = _pixman_ppc_get_implementations (imp);
imp = _pixman_mips_get_implementations (imp);
imp = _pixman_implementation_create_noop (imp);
if (_pixman_disabled ("wholeops"))
{
pixman_implementation_t *cur;
/* Disable all whole-operation paths except the general one,
* so that optimized iterators are used as much as possible.
*/
for (cur = imp; cur->fallback; cur = cur->fallback)
cur->fast_paths = empty_fast_path;
}
return imp;
}