Coverage Report

Created: 2025-07-23 08:13

/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
}