2013-12-15 09:09:20 +01:00
|
|
|
/*
|
|
|
|
* 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 <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;
|
|
|
|
}
|
|
|
|
|
|
|
|
pixman_bool_t
|
|
|
|
_pixman_implementation_src_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)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
while (imp)
|
|
|
|
{
|
|
|
|
if (imp->src_iter_init && (*imp->src_iter_init) (imp, iter))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
imp = imp->fallback;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
pixman_bool_t
|
|
|
|
_pixman_implementation_dest_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)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
while (imp)
|
|
|
|
{
|
|
|
|
if (imp->dest_iter_init && (*imp->dest_iter_init) (imp, iter))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
imp = imp->fallback;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2016-01-18 06:09:44 +01:00
|
|
|
fprintf (stderr, "pixman: Disabled %s implementation\n", name);
|
2013-12-15 09:09:20 +01:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
env += len;
|
|
|
|
}
|
|
|
|
while (*env++);
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
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_implementation_create_noop (imp);
|
|
|
|
|
|
|
|
return imp;
|
|
|
|
}
|