Coverage Report

Created: 2025-07-23 06:50

/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
60
{
34
60
    pixman_implementation_t *imp;
35
36
60
    assert (fast_paths);
37
38
60
    if ((imp = malloc (sizeof (pixman_implementation_t))))
39
60
    {
40
60
  pixman_implementation_t *d;
41
42
60
  memset (imp, 0, sizeof *imp);
43
44
60
  imp->fallback = fallback;
45
60
  imp->fast_paths = fast_paths;
46
  
47
  /* Make sure the whole fallback chain has the right toplevel */
48
270
  for (d = imp; d != NULL; d = d->fallback)
49
210
      d->toplevel = imp;
50
60
    }
51
52
60
    return imp;
53
60
}
54
55
95.2k
#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
46.8k
{
86
46.8k
    pixman_implementation_t *imp;
87
46.8k
    cache_t *cache;
88
46.8k
    int i;
89
90
    /* Check cache for fast paths */
91
46.8k
    cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache);
92
93
94.7k
    for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
94
94.3k
    {
95
94.3k
  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
94.3k
  if (info->op == op      &&
103
94.3k
      info->src_format == src_format  &&
104
94.3k
      info->mask_format == mask_format  &&
105
94.3k
      info->dest_format == dest_format  &&
106
94.3k
      info->src_flags == src_flags  &&
107
94.3k
      info->mask_flags == mask_flags  &&
108
94.3k
      info->dest_flags == dest_flags  &&
109
94.3k
      info->func)
110
46.3k
  {
111
46.3k
      *out_imp = cache->cache[i].imp;
112
46.3k
      *out_func = cache->cache[i].fast_path.func;
113
114
46.3k
      goto update_cache;
115
46.3k
  }
116
94.3k
    }
117
118
2.55k
    for (imp = toplevel; imp != NULL; imp = imp->fallback)
119
2.55k
    {
120
2.55k
  const pixman_fast_path_t *info = imp->fast_paths;
121
122
199k
  while (info->op != PIXMAN_OP_NONE)
123
197k
  {
124
197k
      if ((info->op == op || info->op == PIXMAN_OP_any)   &&
125
    /* Formats */
126
197k
    ((info->src_format == src_format) ||
127
89.2k
     (info->src_format == PIXMAN_any))      &&
128
197k
    ((info->mask_format == mask_format) ||
129
19.4k
     (info->mask_format == PIXMAN_any))      &&
130
197k
    ((info->dest_format == dest_format) ||
131
4.55k
     (info->dest_format == PIXMAN_any))      &&
132
    /* Flags */
133
197k
    (info->src_flags & src_flags) == info->src_flags  &&
134
197k
    (info->mask_flags & mask_flags) == info->mask_flags  &&
135
197k
    (info->dest_flags & dest_flags) == info->dest_flags)
136
476
      {
137
476
    *out_imp = imp;
138
476
    *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
476
    i = N_CACHED_FAST_PATHS - 1;
144
145
476
    goto update_cache;
146
476
      }
147
148
197k
      ++info;
149
197k
  }
150
2.55k
    }
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
46.8k
update_cache:
165
46.8k
    if (i)
166
23.0k
    {
167
70.5k
  while (i--)
168
47.4k
      cache->cache[i + 1] = cache->cache[i];
169
170
23.0k
  cache->cache[0].imp = *out_imp;
171
23.0k
  cache->cache[0].fast_path.op = op;
172
23.0k
  cache->cache[0].fast_path.src_format = src_format;
173
23.0k
  cache->cache[0].fast_path.src_flags = src_flags;
174
23.0k
  cache->cache[0].fast_path.mask_format = mask_format;
175
23.0k
  cache->cache[0].fast_path.mask_flags = mask_flags;
176
23.0k
  cache->cache[0].fast_path.dest_format = dest_format;
177
23.0k
  cache->cache[0].fast_path.dest_flags = dest_flags;
178
23.0k
  cache->cache[0].fast_path.func = *out_func;
179
23.0k
    }
180
46.8k
}
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
27.6k
{
198
119k
    while (imp)
199
119k
    {
200
119k
  pixman_combine_32_func_t f = NULL;
201
202
119k
  switch ((narrow << 1) | component_alpha)
203
119k
  {
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
119k
  case 2: /* narrow, not component alpha */
213
119k
      f = imp->combine_32[op];
214
119k
      break;
215
216
0
  case 3: /* narrow, component_alpha */
217
0
      f = imp->combine_32_ca[op];
218
0
      break;
219
119k
  }
220
221
119k
  if (f)
222
27.6k
      return f;
223
224
92.2k
  imp = imp->fallback;
225
92.2k
    }
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
27.6k
}
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
662
{
247
1.98k
    while (imp)
248
1.98k
    {
249
1.98k
  if (imp->blt &&
250
1.98k
      (*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride,
251
662
       src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y,
252
662
       width, height))
253
662
  {
254
662
      return TRUE;
255
662
  }
256
257
1.32k
  imp = imp->fallback;
258
1.32k
    }
259
260
0
    return FALSE;
261
662
}
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
11.2k
{
274
33.6k
    while (imp)
275
33.6k
    {
276
33.6k
  if (imp->fill &&
277
33.6k
      ((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler)))
278
11.2k
  {
279
11.2k
      return TRUE;
280
11.2k
  }
281
282
22.4k
  imp = imp->fallback;
283
22.4k
    }
284
285
0
    return FALSE;
286
11.2k
}
287
288
static uint32_t *
289
get_scanline_null (pixman_iter_t *iter, const uint32_t *mask)
290
764
{
291
764
    return NULL;
292
764
}
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
82.9k
{
306
82.9k
    pixman_format_code_t format;
307
308
82.9k
    iter->image = image;
309
82.9k
    iter->buffer = (uint32_t *)buffer;
310
82.9k
    iter->x = x;
311
82.9k
    iter->y = y;
312
82.9k
    iter->width = width;
313
82.9k
    iter->height = height;
314
82.9k
    iter->iter_flags = iter_flags;
315
82.9k
    iter->image_flags = image_flags;
316
82.9k
    iter->fini = NULL;
317
318
82.9k
    if (!iter->image)
319
764
    {
320
764
  iter->get_scanline = get_scanline_null;
321
764
  return;
322
764
    }
323
324
82.1k
    format = iter->image->common.extended_format_code;
325
326
177k
    while (imp)
327
177k
    {
328
177k
        if (imp->iter_info)
329
177k
        {
330
177k
            const pixman_iter_info_t *info;
331
332
965k
            for (info = imp->iter_info; info->format != PIXMAN_null; ++info)
333
870k
            {
334
870k
                if ((info->format == PIXMAN_any || info->format == format) &&
335
870k
                    (info->image_flags & image_flags) == info->image_flags &&
336
870k
                    (info->iter_flags & iter_flags) == info->iter_flags)
337
82.1k
                {
338
82.1k
                    iter->get_scanline = info->get_scanline;
339
82.1k
                    iter->write_back = info->write_back;
340
341
82.1k
                    if (info->initializer)
342
63.9k
                        info->initializer (iter, info);
343
82.1k
                    return;
344
82.1k
                }
345
870k
            }
346
177k
        }
347
348
95.1k
        imp = imp->fallback;
349
95.1k
    }
350
82.1k
}
351
352
pixman_bool_t
353
_pixman_disabled (const char *name)
354
50
{
355
50
    const char *env;
356
357
50
    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
50
    return FALSE;
381
50
}
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
10
{
391
10
    pixman_implementation_t *imp;
392
393
10
    imp = _pixman_implementation_create_general();
394
395
10
    if (!_pixman_disabled ("fast"))
396
10
  imp = _pixman_implementation_create_fast_path (imp);
397
398
10
    imp = _pixman_x86_get_implementations (imp);
399
10
    imp = _pixman_arm_get_implementations (imp);
400
10
    imp = _pixman_ppc_get_implementations (imp);
401
10
    imp = _pixman_mips_get_implementations (imp);
402
10
    imp = _pixman_riscv_get_implementations (imp);
403
404
10
    imp = _pixman_implementation_create_noop (imp);
405
406
10
    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
10
    return imp;
418
10
}