/src/cairo/subprojects/pixman-0.44.2/pixman/pixman-implementation.c
Line | Count | Source (jump to first uncovered line) |
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 <pixman-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 | 72 | { |
34 | 72 | pixman_implementation_t *imp; |
35 | | |
36 | 72 | assert (fast_paths); |
37 | | |
38 | 72 | if ((imp = malloc (sizeof (pixman_implementation_t)))) |
39 | 72 | { |
40 | 72 | pixman_implementation_t *d; |
41 | | |
42 | 72 | memset (imp, 0, sizeof *imp); |
43 | | |
44 | 72 | imp->fallback = fallback; |
45 | 72 | imp->fast_paths = fast_paths; |
46 | | |
47 | | /* Make sure the whole fallback chain has the right toplevel */ |
48 | 324 | for (d = imp; d != NULL; d = d->fallback) |
49 | 252 | d->toplevel = imp; |
50 | 72 | } |
51 | | |
52 | 72 | return imp; |
53 | 72 | } |
54 | | |
55 | 276 | #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 | 0 | { |
72 | 0 | } |
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 | 188 | { |
86 | 188 | pixman_implementation_t *imp; |
87 | 188 | cache_t *cache; |
88 | 188 | int i; |
89 | | |
90 | | /* Check cache for fast paths */ |
91 | 188 | cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache); |
92 | | |
93 | 269 | for (i = 0; i < N_CACHED_FAST_PATHS; ++i) |
94 | 262 | { |
95 | 262 | 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 | 262 | if (info->op == op && |
103 | 262 | info->src_format == src_format && |
104 | 262 | info->mask_format == mask_format && |
105 | 262 | info->dest_format == dest_format && |
106 | 262 | info->src_flags == src_flags && |
107 | 262 | info->mask_flags == mask_flags && |
108 | 262 | info->dest_flags == dest_flags && |
109 | 262 | info->func) |
110 | 181 | { |
111 | 181 | *out_imp = cache->cache[i].imp; |
112 | 181 | *out_func = cache->cache[i].fast_path.func; |
113 | | |
114 | 181 | goto update_cache; |
115 | 181 | } |
116 | 262 | } |
117 | | |
118 | 33 | for (imp = toplevel; imp != NULL; imp = imp->fallback) |
119 | 33 | { |
120 | 33 | const pixman_fast_path_t *info = imp->fast_paths; |
121 | | |
122 | 2.09k | while (info->op != PIXMAN_OP_NONE) |
123 | 2.06k | { |
124 | 2.06k | if ((info->op == op || info->op == PIXMAN_OP_any) && |
125 | | /* Formats */ |
126 | 2.06k | ((info->src_format == src_format) || |
127 | 739 | (info->src_format == PIXMAN_any)) && |
128 | 2.06k | ((info->mask_format == mask_format) || |
129 | 64 | (info->mask_format == PIXMAN_any)) && |
130 | 2.06k | ((info->dest_format == dest_format) || |
131 | 14 | (info->dest_format == PIXMAN_any)) && |
132 | | /* Flags */ |
133 | 2.06k | (info->src_flags & src_flags) == info->src_flags && |
134 | 2.06k | (info->mask_flags & mask_flags) == info->mask_flags && |
135 | 2.06k | (info->dest_flags & dest_flags) == info->dest_flags) |
136 | 7 | { |
137 | 7 | *out_imp = imp; |
138 | 7 | *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 | 7 | i = N_CACHED_FAST_PATHS - 1; |
144 | | |
145 | 7 | goto update_cache; |
146 | 7 | } |
147 | | |
148 | 2.05k | ++info; |
149 | 2.05k | } |
150 | 33 | } |
151 | | |
152 | | /* We should never reach this point */ |
153 | 0 | _pixman_log_error ( |
154 | 0 | FUNC, |
155 | 0 | "No composite function found\n" |
156 | 0 | "\n" |
157 | 0 | "The most likely cause of this is that this system has issues with\n" |
158 | 0 | "thread local storage\n"); |
159 | |
|
160 | 0 | *out_imp = NULL; |
161 | 0 | *out_func = dummy_composite_rect; |
162 | 0 | return; |
163 | | |
164 | 188 | update_cache: |
165 | 188 | if (i) |
166 | 17 | { |
167 | 91 | while (i--) |
168 | 74 | cache->cache[i + 1] = cache->cache[i]; |
169 | | |
170 | 17 | cache->cache[0].imp = *out_imp; |
171 | 17 | cache->cache[0].fast_path.op = op; |
172 | 17 | cache->cache[0].fast_path.src_format = src_format; |
173 | 17 | cache->cache[0].fast_path.src_flags = src_flags; |
174 | 17 | cache->cache[0].fast_path.mask_format = mask_format; |
175 | 17 | cache->cache[0].fast_path.mask_flags = mask_flags; |
176 | 17 | cache->cache[0].fast_path.dest_format = dest_format; |
177 | 17 | cache->cache[0].fast_path.dest_flags = dest_flags; |
178 | 17 | cache->cache[0].fast_path.func = *out_func; |
179 | 17 | } |
180 | 188 | } |
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 | 0 | { |
190 | 0 | } |
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 | 174 | { |
198 | 1.04k | while (imp) |
199 | 1.04k | { |
200 | 1.04k | pixman_combine_32_func_t f = NULL; |
201 | | |
202 | 1.04k | switch ((narrow << 1) | component_alpha) |
203 | 1.04k | { |
204 | 0 | case 0: /* not narrow, not component alpha */ |
205 | 0 | f = (pixman_combine_32_func_t)imp->combine_float[op]; |
206 | 0 | break; |
207 | | |
208 | 0 | case 1: /* not narrow, component_alpha */ |
209 | 0 | f = (pixman_combine_32_func_t)imp->combine_float_ca[op]; |
210 | 0 | break; |
211 | | |
212 | 1.04k | case 2: /* narrow, not component alpha */ |
213 | 1.04k | f = imp->combine_32[op]; |
214 | 1.04k | break; |
215 | | |
216 | 0 | case 3: /* narrow, component_alpha */ |
217 | 0 | f = imp->combine_32_ca[op]; |
218 | 0 | break; |
219 | 1.04k | } |
220 | | |
221 | 1.04k | if (f) |
222 | 174 | return f; |
223 | | |
224 | 870 | imp = imp->fallback; |
225 | 870 | } |
226 | | |
227 | | /* We should never reach this point */ |
228 | 0 | _pixman_log_error (FUNC, "No known combine function\n"); |
229 | 0 | return dummy_combine; |
230 | 174 | } |
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 | 0 | { |
247 | 0 | while (imp) |
248 | 0 | { |
249 | 0 | if (imp->blt && |
250 | 0 | (*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride, |
251 | 0 | src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y, |
252 | 0 | width, height)) |
253 | 0 | { |
254 | 0 | return TRUE; |
255 | 0 | } |
256 | | |
257 | 0 | imp = imp->fallback; |
258 | 0 | } |
259 | | |
260 | 0 | return FALSE; |
261 | 0 | } |
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 | 8 | { |
274 | 24 | while (imp) |
275 | 24 | { |
276 | 24 | if (imp->fill && |
277 | 24 | ((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler))) |
278 | 8 | { |
279 | 8 | return TRUE; |
280 | 8 | } |
281 | | |
282 | 16 | imp = imp->fallback; |
283 | 16 | } |
284 | | |
285 | 0 | return FALSE; |
286 | 8 | } |
287 | | |
288 | | static uint32_t * |
289 | | get_scanline_null (pixman_iter_t *iter, const uint32_t *mask) |
290 | 0 | { |
291 | 0 | return NULL; |
292 | 0 | } |
293 | | |
294 | | void |
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 | 522 | { |
306 | 522 | pixman_format_code_t format; |
307 | | |
308 | 522 | iter->image = image; |
309 | 522 | iter->buffer = (uint32_t *)buffer; |
310 | 522 | iter->x = x; |
311 | 522 | iter->y = y; |
312 | 522 | iter->width = width; |
313 | 522 | iter->height = height; |
314 | 522 | iter->iter_flags = iter_flags; |
315 | 522 | iter->image_flags = image_flags; |
316 | 522 | iter->fini = NULL; |
317 | | |
318 | 522 | if (!iter->image) |
319 | 0 | { |
320 | 0 | iter->get_scanline = get_scanline_null; |
321 | 0 | return; |
322 | 0 | } |
323 | | |
324 | 522 | format = iter->image->common.extended_format_code; |
325 | | |
326 | 1.74k | while (imp) |
327 | 1.74k | { |
328 | 1.74k | if (imp->iter_info) |
329 | 1.74k | { |
330 | 1.74k | const pixman_iter_info_t *info; |
331 | | |
332 | 15.6k | for (info = imp->iter_info; info->format != PIXMAN_null; ++info) |
333 | 14.4k | { |
334 | 14.4k | if ((info->format == PIXMAN_any || info->format == format) && |
335 | 14.4k | (info->image_flags & image_flags) == info->image_flags && |
336 | 14.4k | (info->iter_flags & iter_flags) == info->iter_flags) |
337 | 522 | { |
338 | 522 | iter->get_scanline = info->get_scanline; |
339 | 522 | iter->write_back = info->write_back; |
340 | | |
341 | 522 | if (info->initializer) |
342 | 522 | info->initializer (iter, info); |
343 | 522 | return; |
344 | 522 | } |
345 | 14.4k | } |
346 | 1.74k | } |
347 | | |
348 | 1.21k | imp = imp->fallback; |
349 | 1.21k | } |
350 | 522 | } |
351 | | |
352 | | pixman_bool_t |
353 | | _pixman_disabled (const char *name) |
354 | 60 | { |
355 | 60 | const char *env; |
356 | | |
357 | 60 | if ((env = getenv ("PIXMAN_DISABLE"))) |
358 | 0 | { |
359 | 0 | do |
360 | 0 | { |
361 | 0 | const char *end; |
362 | 0 | int len; |
363 | |
|
364 | 0 | if ((end = strchr (env, ' '))) |
365 | 0 | len = end - env; |
366 | 0 | else |
367 | 0 | len = strlen (env); |
368 | |
|
369 | 0 | if (strlen (name) == len && strncmp (name, env, len) == 0) |
370 | 0 | { |
371 | 0 | printf ("pixman: Disabled %s implementation\n", name); |
372 | 0 | return TRUE; |
373 | 0 | } |
374 | | |
375 | 0 | env += len; |
376 | 0 | } |
377 | 0 | while (*env++); |
378 | 0 | } |
379 | | |
380 | 60 | return FALSE; |
381 | 60 | } |
382 | | |
383 | | static const pixman_fast_path_t empty_fast_path[] = |
384 | | { |
385 | | { PIXMAN_OP_NONE } |
386 | | }; |
387 | | |
388 | | pixman_implementation_t * |
389 | | _pixman_choose_implementation (void) |
390 | 12 | { |
391 | 12 | pixman_implementation_t *imp; |
392 | | |
393 | 12 | imp = _pixman_implementation_create_general(); |
394 | | |
395 | 12 | if (!_pixman_disabled ("fast")) |
396 | 12 | imp = _pixman_implementation_create_fast_path (imp); |
397 | | |
398 | 12 | imp = _pixman_x86_get_implementations (imp); |
399 | 12 | imp = _pixman_arm_get_implementations (imp); |
400 | 12 | imp = _pixman_ppc_get_implementations (imp); |
401 | 12 | imp = _pixman_mips_get_implementations (imp); |
402 | 12 | imp = _pixman_riscv_get_implementations (imp); |
403 | | |
404 | 12 | imp = _pixman_implementation_create_noop (imp); |
405 | | |
406 | 12 | if (_pixman_disabled ("wholeops")) |
407 | 0 | { |
408 | 0 | pixman_implementation_t *cur; |
409 | | |
410 | | /* Disable all whole-operation paths except the general one, |
411 | | * so that optimized iterators are used as much as possible. |
412 | | */ |
413 | 0 | for (cur = imp; cur->fallback; cur = cur->fallback) |
414 | 0 | cur->fast_paths = empty_fast_path; |
415 | 0 | } |
416 | | |
417 | 12 | return imp; |
418 | 12 | } |