Coverage Report

Created: 2026-10-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aom/aom_dsp/blend_a64_mask.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
3
 *
4
 * This source code is subject to the terms of the BSD 2 Clause License and
5
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6
 * was not distributed with this source code in the LICENSE file, you can
7
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8
 * Media Patent License 1.0 was not distributed with this source code in the
9
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10
 */
11
12
#include <assert.h>
13
14
#include "aom/aom_integer.h"
15
#include "aom_ports/mem.h"
16
#include "aom_dsp/blend.h"
17
#include "aom_dsp/aom_dsp_common.h"
18
19
#include "config/aom_dsp_rtcd.h"
20
21
// Blending with alpha mask. Mask values come from the range [0, 64],
22
// as described for AOM_BLEND_A64 in aom_dsp/blend.h. src0 or src1 can
23
// be the same as dst, or dst can be different from both sources.
24
25
// NOTE(rachelbarker): The input and output of aom_blend_a64_d16_mask_c() are
26
// in a higher intermediate precision, and will later be rounded down to pixel
27
// precision.
28
// Thus, in order to avoid double-rounding, we want to use normal right shifts
29
// within this function, not ROUND_POWER_OF_TWO.
30
// This works because of the identity:
31
// ROUND_POWER_OF_TWO(x >> y, z) == ROUND_POWER_OF_TWO(x, y+z)
32
//
33
// In contrast, the output of the non-d16 functions will not be further rounded,
34
// so we *should* use ROUND_POWER_OF_TWO there.
35
36
void aom_lowbd_blend_a64_d16_mask_c(
37
    uint8_t *dst, uint32_t dst_stride, const CONV_BUF_TYPE *src0,
38
    uint32_t src0_stride, const CONV_BUF_TYPE *src1, uint32_t src1_stride,
39
    const uint8_t *mask, uint32_t mask_stride, int w, int h, int subw, int subh,
40
1.54k
    ConvolveParams *conv_params) {
41
1.54k
  int i, j;
42
1.54k
  const int bd = 8;
43
1.54k
  const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0;
44
1.54k
  const int round_offset = (1 << (offset_bits - conv_params->round_1)) +
45
1.54k
                           (1 << (offset_bits - conv_params->round_1 - 1));
46
1.54k
  const int round_bits =
47
1.54k
      2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1;
48
49
1.54k
  assert(IMPLIES((void *)src0 == dst, src0_stride == dst_stride));
50
1.54k
  assert(IMPLIES((void *)src1 == dst, src1_stride == dst_stride));
51
52
1.54k
  assert(h >= 4);
53
1.54k
  assert(w >= 4);
54
1.54k
  assert(IS_POWER_OF_TWO(h));
55
1.54k
  assert(IS_POWER_OF_TWO(w));
56
57
1.54k
  if (subw == 0 && subh == 0) {
58
19.8k
    for (i = 0; i < h; ++i) {
59
192k
      for (j = 0; j < w; ++j) {
60
174k
        int32_t res;
61
174k
        const int m = mask[i * mask_stride + j];
62
174k
        res = ((m * (int32_t)src0[i * src0_stride + j] +
63
174k
                (AOM_BLEND_A64_MAX_ALPHA - m) *
64
174k
                    (int32_t)src1[i * src1_stride + j]) >>
65
174k
               AOM_BLEND_A64_ROUND_BITS);
66
174k
        res -= round_offset;
67
174k
        dst[i * dst_stride + j] =
68
174k
            clip_pixel(ROUND_POWER_OF_TWO(res, round_bits));
69
174k
      }
70
18.5k
    }
71
1.27k
  } else if (subw == 1 && subh == 1) {
72
430
    for (i = 0; i < h; ++i) {
73
1.72k
      for (j = 0; j < w; ++j) {
74
1.37k
        int32_t res;
75
1.37k
        const int m = ROUND_POWER_OF_TWO(
76
1.37k
            mask[(2 * i) * mask_stride + (2 * j)] +
77
1.37k
                mask[(2 * i + 1) * mask_stride + (2 * j)] +
78
1.37k
                mask[(2 * i) * mask_stride + (2 * j + 1)] +
79
1.37k
                mask[(2 * i + 1) * mask_stride + (2 * j + 1)],
80
1.37k
            2);
81
1.37k
        res = ((m * (int32_t)src0[i * src0_stride + j] +
82
1.37k
                (AOM_BLEND_A64_MAX_ALPHA - m) *
83
1.37k
                    (int32_t)src1[i * src1_stride + j]) >>
84
1.37k
               AOM_BLEND_A64_ROUND_BITS);
85
1.37k
        res -= round_offset;
86
1.37k
        dst[i * dst_stride + j] =
87
1.37k
            clip_pixel(ROUND_POWER_OF_TWO(res, round_bits));
88
1.37k
      }
89
344
    }
90
188
  } else if (subw == 1 && subh == 0) {
91
2.14k
    for (i = 0; i < h; ++i) {
92
28.7k
      for (j = 0; j < w; ++j) {
93
26.8k
        int32_t res;
94
26.8k
        const int m = AOM_BLEND_AVG(mask[i * mask_stride + (2 * j)],
95
26.8k
                                    mask[i * mask_stride + (2 * j + 1)]);
96
26.8k
        res = ((m * (int32_t)src0[i * src0_stride + j] +
97
26.8k
                (AOM_BLEND_A64_MAX_ALPHA - m) *
98
26.8k
                    (int32_t)src1[i * src1_stride + j]) >>
99
26.8k
               AOM_BLEND_A64_ROUND_BITS);
100
26.8k
        res -= round_offset;
101
26.8k
        dst[i * dst_stride + j] =
102
26.8k
            clip_pixel(ROUND_POWER_OF_TWO(res, round_bits));
103
26.8k
      }
104
1.95k
    }
105
188
  } else {
106
0
    for (i = 0; i < h; ++i) {
107
0
      for (j = 0; j < w; ++j) {
108
0
        int32_t res;
109
0
        const int m = AOM_BLEND_AVG(mask[(2 * i) * mask_stride + j],
110
0
                                    mask[(2 * i + 1) * mask_stride + j]);
111
0
        res = ((int32_t)(m * (int32_t)src0[i * src0_stride + j] +
112
0
                         (AOM_BLEND_A64_MAX_ALPHA - m) *
113
0
                             (int32_t)src1[i * src1_stride + j]) >>
114
0
               AOM_BLEND_A64_ROUND_BITS);
115
0
        res -= round_offset;
116
0
        dst[i * dst_stride + j] =
117
0
            clip_pixel(ROUND_POWER_OF_TWO(res, round_bits));
118
0
      }
119
0
    }
120
0
  }
121
1.54k
}
122
123
#if CONFIG_AV1_HIGHBITDEPTH
124
void aom_highbd_blend_a64_d16_mask_c(
125
    uint8_t *dst_8, uint32_t dst_stride, const CONV_BUF_TYPE *src0,
126
    uint32_t src0_stride, const CONV_BUF_TYPE *src1, uint32_t src1_stride,
127
    const uint8_t *mask, uint32_t mask_stride, int w, int h, int subw, int subh,
128
2.46k
    ConvolveParams *conv_params, const int bd) {
129
2.46k
  const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0;
130
2.46k
  const int round_offset = (1 << (offset_bits - conv_params->round_1)) +
131
2.46k
                           (1 << (offset_bits - conv_params->round_1 - 1));
132
2.46k
  const int round_bits =
133
2.46k
      2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1;
134
2.46k
  uint16_t *dst = CONVERT_TO_SHORTPTR(dst_8);
135
136
2.46k
  assert(IMPLIES(src0 == dst, src0_stride == dst_stride));
137
2.46k
  assert(IMPLIES(src1 == dst, src1_stride == dst_stride));
138
139
2.46k
  assert(h >= 1);
140
2.46k
  assert(w >= 1);
141
2.46k
  assert(IS_POWER_OF_TWO(h));
142
2.46k
  assert(IS_POWER_OF_TWO(w));
143
144
  // excerpt from clip_pixel_highbd()
145
  // set saturation_value to (1 << bd) - 1
146
2.46k
  unsigned int saturation_value;
147
2.46k
  switch (bd) {
148
0
    case 8:
149
0
    default: saturation_value = 255; break;
150
2.42k
    case 10: saturation_value = 1023; break;
151
48
    case 12: saturation_value = 4095; break;
152
2.46k
  }
153
154
2.46k
  if (subw == 0 && subh == 0) {
155
25.4k
    for (int i = 0; i < h; ++i) {
156
284k
      for (int j = 0; j < w; ++j) {
157
260k
        int32_t res;
158
260k
        const int m = mask[j];
159
260k
        res = ((m * src0[j] + (AOM_BLEND_A64_MAX_ALPHA - m) * src1[j]) >>
160
260k
               AOM_BLEND_A64_ROUND_BITS);
161
260k
        res -= round_offset;
162
260k
        unsigned int v = negative_to_zero(ROUND_POWER_OF_TWO(res, round_bits));
163
260k
        dst[j] = AOMMIN(v, saturation_value);
164
260k
      }
165
23.7k
      mask += mask_stride;
166
23.7k
      src0 += src0_stride;
167
23.7k
      src1 += src1_stride;
168
23.7k
      dst += dst_stride;
169
23.7k
    }
170
1.66k
  } else if (subw == 1 && subh == 1) {
171
320
    for (int i = 0; i < h; ++i) {
172
1.28k
      for (int j = 0; j < w; ++j) {
173
1.02k
        int32_t res;
174
1.02k
        const int m = ROUND_POWER_OF_TWO(
175
1.02k
            mask[2 * j] + mask[mask_stride + 2 * j] + mask[2 * j + 1] +
176
1.02k
                mask[mask_stride + 2 * j + 1],
177
1.02k
            2);
178
1.02k
        res = (m * src0[j] + (AOM_BLEND_A64_MAX_ALPHA - m) * src1[j]) >>
179
1.02k
              AOM_BLEND_A64_ROUND_BITS;
180
1.02k
        res -= round_offset;
181
1.02k
        unsigned int v = negative_to_zero(ROUND_POWER_OF_TWO(res, round_bits));
182
1.02k
        dst[j] = AOMMIN(v, saturation_value);
183
1.02k
      }
184
256
      mask += 2 * mask_stride;
185
256
      src0 += src0_stride;
186
256
      src1 += src1_stride;
187
256
      dst += dst_stride;
188
256
    }
189
740
  } else if (subw == 1 && subh == 0) {
190
8.00k
    for (int i = 0; i < h; ++i) {
191
106k
      for (int j = 0; j < w; ++j) {
192
98.9k
        int32_t res;
193
98.9k
        const int m = AOM_BLEND_AVG(mask[2 * j], mask[2 * j + 1]);
194
98.9k
        res = (m * src0[j] + (AOM_BLEND_A64_MAX_ALPHA - m) * src1[j]) >>
195
98.9k
              AOM_BLEND_A64_ROUND_BITS;
196
98.9k
        res -= round_offset;
197
98.9k
        unsigned int v = negative_to_zero(ROUND_POWER_OF_TWO(res, round_bits));
198
98.9k
        dst[j] = AOMMIN(v, saturation_value);
199
98.9k
      }
200
7.26k
      mask += mask_stride;
201
7.26k
      src0 += src0_stride;
202
7.26k
      src1 += src1_stride;
203
7.26k
      dst += dst_stride;
204
7.26k
    }
205
740
  } else {
206
0
    for (int i = 0; i < h; ++i) {
207
0
      for (int j = 0; j < w; ++j) {
208
0
        int32_t res;
209
0
        const int m = AOM_BLEND_AVG(mask[j], mask[mask_stride + j]);
210
0
        res = (m * src0[j] + (AOM_BLEND_A64_MAX_ALPHA - m) * src1[j]) >>
211
0
              AOM_BLEND_A64_ROUND_BITS;
212
0
        res -= round_offset;
213
0
        unsigned int v = negative_to_zero(ROUND_POWER_OF_TWO(res, round_bits));
214
0
        dst[j] = AOMMIN(v, saturation_value);
215
0
      }
216
0
      mask += 2 * mask_stride;
217
0
      src0 += src0_stride;
218
0
      src1 += src1_stride;
219
0
      dst += dst_stride;
220
0
    }
221
0
  }
222
2.46k
}
223
#endif  // CONFIG_AV1_HIGHBITDEPTH
224
225
// Blending with alpha mask. Mask values come from the range [0, 64],
226
// as described for AOM_BLEND_A64 in aom_dsp/blend.h. src0 or src1 can
227
// be the same as dst, or dst can be different from both sources.
228
229
void aom_blend_a64_mask_c(uint8_t *dst, uint32_t dst_stride,
230
                          const uint8_t *src0, uint32_t src0_stride,
231
                          const uint8_t *src1, uint32_t src1_stride,
232
                          const uint8_t *mask, uint32_t mask_stride, int w,
233
1.21k
                          int h, int subw, int subh) {
234
1.21k
  int i, j;
235
236
1.21k
  assert(IMPLIES(src0 == dst, src0_stride == dst_stride));
237
1.21k
  assert(IMPLIES(src1 == dst, src1_stride == dst_stride));
238
239
1.21k
  assert(h >= 1);
240
1.21k
  assert(w >= 1);
241
1.21k
  assert(IS_POWER_OF_TWO(h));
242
1.21k
  assert(IS_POWER_OF_TWO(w));
243
244
1.21k
  if (subw == 0 && subh == 0) {
245
12.5k
    for (i = 0; i < h; ++i) {
246
142k
      for (j = 0; j < w; ++j) {
247
130k
        const int m = mask[i * mask_stride + j];
248
130k
        dst[i * dst_stride + j] = AOM_BLEND_A64(m, src0[i * src0_stride + j],
249
130k
                                                src1[i * src1_stride + j]);
250
130k
      }
251
11.4k
    }
252
1.07k
  } else if (subw == 1 && subh == 1) {
253
260
    for (i = 0; i < h; ++i) {
254
1.04k
      for (j = 0; j < w; ++j) {
255
832
        const int m = ROUND_POWER_OF_TWO(
256
832
            mask[(2 * i) * mask_stride + (2 * j)] +
257
832
                mask[(2 * i + 1) * mask_stride + (2 * j)] +
258
832
                mask[(2 * i) * mask_stride + (2 * j + 1)] +
259
832
                mask[(2 * i + 1) * mask_stride + (2 * j + 1)],
260
832
            2);
261
832
        dst[i * dst_stride + j] = AOM_BLEND_A64(m, src0[i * src0_stride + j],
262
832
                                                src1[i * src1_stride + j]);
263
832
      }
264
208
    }
265
84
  } else if (subw == 1 && subh == 0) {
266
772
    for (i = 0; i < h; ++i) {
267
4.33k
      for (j = 0; j < w; ++j) {
268
3.64k
        const int m = AOM_BLEND_AVG(mask[i * mask_stride + (2 * j)],
269
3.64k
                                    mask[i * mask_stride + (2 * j + 1)]);
270
3.64k
        dst[i * dst_stride + j] = AOM_BLEND_A64(m, src0[i * src0_stride + j],
271
3.64k
                                                src1[i * src1_stride + j]);
272
3.64k
      }
273
688
    }
274
84
  } else {
275
0
    for (i = 0; i < h; ++i) {
276
0
      for (j = 0; j < w; ++j) {
277
0
        const int m = AOM_BLEND_AVG(mask[(2 * i) * mask_stride + j],
278
0
                                    mask[(2 * i + 1) * mask_stride + j]);
279
0
        dst[i * dst_stride + j] = AOM_BLEND_A64(m, src0[i * src0_stride + j],
280
0
                                                src1[i * src1_stride + j]);
281
0
      }
282
0
    }
283
0
  }
284
1.21k
}
285
286
#if CONFIG_AV1_HIGHBITDEPTH
287
void aom_highbd_blend_a64_mask_c(uint8_t *dst_8, uint32_t dst_stride,
288
                                 const uint8_t *src0_8, uint32_t src0_stride,
289
                                 const uint8_t *src1_8, uint32_t src1_stride,
290
                                 const uint8_t *mask, uint32_t mask_stride,
291
3.97k
                                 int w, int h, int subw, int subh, int bd) {
292
3.97k
  int i, j;
293
3.97k
  uint16_t *dst = CONVERT_TO_SHORTPTR(dst_8);
294
3.97k
  const uint16_t *src0 = CONVERT_TO_SHORTPTR(src0_8);
295
3.97k
  const uint16_t *src1 = CONVERT_TO_SHORTPTR(src1_8);
296
3.97k
  (void)bd;
297
298
3.97k
  assert(IMPLIES(src0 == dst, src0_stride == dst_stride));
299
3.97k
  assert(IMPLIES(src1 == dst, src1_stride == dst_stride));
300
301
3.97k
  assert(h >= 1);
302
3.97k
  assert(w >= 1);
303
3.97k
  assert(IS_POWER_OF_TWO(h));
304
3.97k
  assert(IS_POWER_OF_TWO(w));
305
306
3.97k
  assert(bd == 8 || bd == 10 || bd == 12);
307
308
3.97k
  if (subw == 0 && subh == 0) {
309
39.2k
    for (i = 0; i < h; ++i) {
310
338k
      for (j = 0; j < w; ++j) {
311
303k
        const int m = mask[i * mask_stride + j];
312
303k
        dst[i * dst_stride + j] = AOM_BLEND_A64(m, src0[i * src0_stride + j],
313
303k
                                                src1[i * src1_stride + j]);
314
303k
      }
315
35.3k
    }
316
3.90k
  } else if (subw == 1 && subh == 1) {
317
330
    for (i = 0; i < h; ++i) {
318
1.32k
      for (j = 0; j < w; ++j) {
319
1.05k
        const int m = ROUND_POWER_OF_TWO(
320
1.05k
            mask[(2 * i) * mask_stride + (2 * j)] +
321
1.05k
                mask[(2 * i + 1) * mask_stride + (2 * j)] +
322
1.05k
                mask[(2 * i) * mask_stride + (2 * j + 1)] +
323
1.05k
                mask[(2 * i + 1) * mask_stride + (2 * j + 1)],
324
1.05k
            2);
325
1.05k
        dst[i * dst_stride + j] = AOM_BLEND_A64(m, src0[i * src0_stride + j],
326
1.05k
                                                src1[i * src1_stride + j]);
327
1.05k
      }
328
264
    }
329
66
  } else if (subw == 1 && subh == 0) {
330
122
    for (i = 0; i < h; ++i) {
331
880
      for (j = 0; j < w; ++j) {
332
768
        const int m = AOM_BLEND_AVG(mask[i * mask_stride + (2 * j)],
333
768
                                    mask[i * mask_stride + (2 * j + 1)]);
334
768
        dst[i * dst_stride + j] = AOM_BLEND_A64(m, src0[i * src0_stride + j],
335
768
                                                src1[i * src1_stride + j]);
336
768
      }
337
112
    }
338
10
  } else {
339
0
    for (i = 0; i < h; ++i) {
340
0
      for (j = 0; j < w; ++j) {
341
0
        const int m = AOM_BLEND_AVG(mask[(2 * i) * mask_stride + j],
342
0
                                    mask[(2 * i + 1) * mask_stride + j]);
343
0
        dst[i * dst_stride + j] = AOM_BLEND_A64(m, src0[i * src0_stride + j],
344
0
                                                src1[i * src1_stride + j]);
345
0
      }
346
0
    }
347
0
  }
348
3.97k
}
349
#endif  // CONFIG_AV1_HIGHBITDEPTH