pixman-implementation.c revision 6ca29ff0
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
30pixman_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
57typedef 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
66PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
67
68static void
69dummy_composite_rect (pixman_implementation_t *imp,
70		      pixman_composite_info_t *info)
71{
72}
73
74void
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
164update_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
182static void
183dummy_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
192pixman_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
232pixman_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
263pixman_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
288static uint32_t *
289get_scanline_null (pixman_iter_t *iter, const uint32_t *mask)
290{
291    return NULL;
292}
293
294void
295_pixman_implementation_iter_init (pixman_implementation_t *imp,
296                                  pixman_iter_t           *iter,
297                                  pixman_image_t          *image,
298                                  int                      x,
299                                  int                      y,
300                                  int                      width,
301                                  int                      height,
302                                  uint8_t                 *buffer,
303                                  iter_flags_t             iter_flags,
304                                  uint32_t                 image_flags)
305{
306    pixman_format_code_t format;
307
308    iter->image = image;
309    iter->buffer = (uint32_t *)buffer;
310    iter->x = x;
311    iter->y = y;
312    iter->width = width;
313    iter->height = height;
314    iter->iter_flags = iter_flags;
315    iter->image_flags = image_flags;
316    iter->fini = NULL;
317
318    if (!iter->image)
319    {
320	iter->get_scanline = get_scanline_null;
321	return;
322    }
323
324    format = iter->image->common.extended_format_code;
325
326    while (imp)
327    {
328        if (imp->iter_info)
329        {
330            const pixman_iter_info_t *info;
331
332            for (info = imp->iter_info; info->format != PIXMAN_null; ++info)
333            {
334                if ((info->format == PIXMAN_any || info->format == format) &&
335                    (info->image_flags & image_flags) == info->image_flags &&
336                    (info->iter_flags & iter_flags) == info->iter_flags)
337                {
338                    iter->get_scanline = info->get_scanline;
339                    iter->write_back = info->write_back;
340
341                    if (info->initializer)
342                        info->initializer (iter, info);
343                    return;
344                }
345            }
346        }
347
348        imp = imp->fallback;
349    }
350}
351
352pixman_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
383static const pixman_fast_path_t empty_fast_path[] =
384{
385    { PIXMAN_OP_NONE }
386};
387
388pixman_implementation_t *
389_pixman_choose_implementation (void)
390{
391    pixman_implementation_t *imp;
392
393    imp = _pixman_implementation_create_general();
394
395    if (!_pixman_disabled ("fast"))
396	imp = _pixman_implementation_create_fast_path (imp);
397
398    imp = _pixman_x86_get_implementations (imp);
399    imp = _pixman_arm_get_implementations (imp);
400    imp = _pixman_ppc_get_implementations (imp);
401    imp = _pixman_mips_get_implementations (imp);
402
403    imp = _pixman_implementation_create_noop (imp);
404
405    if (_pixman_disabled ("wholeops"))
406    {
407        pixman_implementation_t *cur;
408
409        /* Disable all whole-operation paths except the general one,
410         * so that optimized iterators are used as much as possible.
411         */
412        for (cur = imp; cur->fallback; cur = cur->fallback)
413            cur->fast_paths = empty_fast_path;
414    }
415
416    return imp;
417}
418