Coverage Report

Created: 2026-10-17 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebp/src/dsp/rescaler.c
Line
Count
Source
1
// Copyright 2014 Google Inc. All Rights Reserved.
2
//
3
// Use of this source code is governed by a BSD-style license
4
// that can be found in the COPYING file in the root of the source
5
// tree. An additional intellectual property rights grant can be found
6
// in the file PATENTS. All contributing project authors may
7
// be found in the AUTHORS file in the root of the source tree.
8
// -----------------------------------------------------------------------------
9
//
10
// Rescaling functions
11
//
12
// Author: Skal (pascal.massimino@gmail.com)
13
14
#include <assert.h>
15
#include <stddef.h>
16
17
#include "src/dsp/cpu.h"
18
#include "src/dsp/dsp.h"
19
#include "src/utils/rescaler_utils.h"
20
#include "src/webp/types.h"
21
22
//------------------------------------------------------------------------------
23
// Implementations of critical functions ImportRow / ExportRow
24
25
1.55G
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
26
1.19G
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
27
146M
#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
28
29
//------------------------------------------------------------------------------
30
// Row import
31
WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW void WebPRescalerImportRowExpand_C(
32
1.94M
    WebPRescaler* WEBP_RESTRICT const wrk, const uint8_t* WEBP_RESTRICT src) {
33
1.94M
  const int x_stride = wrk->num_channels;
34
1.94M
  const int x_out_max = wrk->dst_width * wrk->num_channels;
35
1.94M
  int channel;
36
1.94M
  assert(!WebPRescalerInputDone(wrk));
37
1.94M
  assert(wrk->x_expand);
38
6.40M
  for (channel = 0; channel < x_stride; ++channel) {
39
4.45M
    int x_in = channel;
40
4.45M
    int x_out = channel;
41
    // simple bilinear interpolation
42
4.45M
    int accum = wrk->x_add;
43
4.45M
    rescaler_t left = (rescaler_t)src[x_in];
44
4.45M
    rescaler_t right =
45
4.45M
        (wrk->src_width > 1) ? (rescaler_t)src[x_in + x_stride] : left;
46
4.45M
    x_in += x_stride;
47
14.4G
    while (1) {
48
14.4G
      wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
49
14.4G
      x_out += x_stride;
50
14.4G
      if (x_out >= x_out_max) break;
51
14.4G
      accum -= wrk->x_sub;
52
14.4G
      if (accum < 0) {
53
119M
        left = right;
54
119M
        x_in += x_stride;
55
119M
        assert(x_in < wrk->src_width * x_stride);
56
119M
        right = (rescaler_t)src[x_in];
57
119M
        accum += wrk->x_add;
58
119M
      }
59
14.4G
    }
60
4.45M
    assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
61
4.45M
  }
62
1.94M
}
63
64
void WebPRescalerImportRowShrink_C(WebPRescaler* WEBP_RESTRICT const wrk,
65
2.01M
                                   const uint8_t* WEBP_RESTRICT src) {
66
2.01M
  const int x_stride = wrk->num_channels;
67
2.01M
  const int x_out_max = wrk->dst_width * wrk->num_channels;
68
2.01M
  int channel;
69
2.01M
  assert(!WebPRescalerInputDone(wrk));
70
2.01M
  assert(!wrk->x_expand);
71
4.72M
  for (channel = 0; channel < x_stride; ++channel) {
72
2.70M
    int x_in = channel;
73
2.70M
    int x_out = channel;
74
2.70M
    uint32_t sum = 0;
75
2.70M
    int accum = 0;
76
90.1M
    while (x_out < x_out_max) {
77
87.4M
      uint32_t base = 0;
78
87.4M
      accum += wrk->x_add;
79
331M
      while (accum > 0) {
80
243M
        accum -= wrk->x_sub;
81
243M
        assert(x_in < wrk->src_width * x_stride);
82
243M
        base = src[x_in];
83
243M
        sum += base;
84
243M
        x_in += x_stride;
85
243M
      }
86
87.4M
      {  // Emit next horizontal pixel.
87
87.4M
        const rescaler_t frac = base * (-accum);
88
87.4M
        wrk->frow[x_out] = sum * wrk->x_sub - frac;
89
        // fresh fractional start for next pixel
90
87.4M
        sum = (int)MULT_FIX(frac, wrk->fx_scale);
91
87.4M
      }
92
87.4M
      x_out += x_stride;
93
87.4M
    }
94
2.70M
    assert(accum == 0);
95
2.70M
  }
96
2.01M
}
97
98
//------------------------------------------------------------------------------
99
// Row export
100
101
40.2M
void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
102
40.2M
  int x_out;
103
40.2M
  uint8_t* const dst = wrk->dst;
104
40.2M
  rescaler_t* const irow = wrk->irow;
105
40.2M
  const int x_out_max = wrk->dst_width * wrk->num_channels;
106
40.2M
  const rescaler_t* const frow = wrk->frow;
107
40.2M
  assert(!WebPRescalerOutputDone(wrk));
108
40.2M
  assert(wrk->y_accum <= 0);
109
40.2M
  assert(wrk->y_expand);
110
40.2M
  assert(wrk->y_sub != 0);
111
40.2M
  if (wrk->y_accum == 0) {
112
373M
    for (x_out = 0; x_out < x_out_max; ++x_out) {
113
356M
      const uint32_t J = frow[x_out];
114
356M
      const int v = (int)MULT_FIX(J, wrk->fy_scale);
115
356M
      dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
116
356M
    }
117
22.8M
  } else {
118
22.8M
    const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
119
22.8M
    const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
120
383M
    for (x_out = 0; x_out < x_out_max; ++x_out) {
121
360M
      const uint64_t I = (uint64_t)A * frow[x_out] + (uint64_t)B * irow[x_out];
122
360M
      const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
123
360M
      const int v = (int)MULT_FIX(J, wrk->fy_scale);
124
360M
      dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
125
360M
    }
126
22.8M
  }
127
40.2M
}
128
129
#define EXPORT_ROW_SHRINK(IROW_TYPE, IROW)                                   \
130
281k
  do {                                                                       \
131
281k
    int x_out;                                                               \
132
281k
    uint8_t* const dst = wrk->dst;                                           \
133
281k
    IROW_TYPE* const irow = wrk->IROW;                                       \
134
281k
    const int x_out_max = wrk->dst_width * wrk->num_channels;                \
135
281k
    const rescaler_t* const frow = wrk->frow;                                \
136
281k
    const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);                 \
137
281k
    assert(!WebPRescalerOutputDone(wrk));                                    \
138
281k
    assert(wrk->y_accum <= 0);                                               \
139
281k
    assert(!wrk->y_expand);                                                  \
140
281k
    if (yscale) {                                                            \
141
146M
      for (x_out = 0; x_out < x_out_max; ++x_out) {                          \
142
146M
        const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale); \
143
146M
        const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);     \
144
146M
        dst[x_out] = (v > 255) ? 255u : (uint8_t)v;                          \
145
146M
        irow[x_out] = frac; /* new fractional start */                       \
146
146M
      }                                                                      \
147
179k
    } else {                                                                 \
148
241M
      for (x_out = 0; x_out < x_out_max; ++x_out) {                          \
149
241M
        const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);            \
150
241M
        dst[x_out] = (v > 255) ? 255u : (uint8_t)v;                          \
151
241M
        irow[x_out] = 0;                                                     \
152
241M
      }                                                                      \
153
101k
    }                                                                        \
154
281k
  } while (0)
155
156
281k
void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
157
281k
  EXPORT_ROW_SHRINK(rescaler_t, irow);
158
281k
}
159
160
157
static void RescalerExportRowShrink64_C(WebPRescaler* const wrk) {
161
157
  EXPORT_ROW_SHRINK(rescaler_accum_t, irow64);
162
157
}
163
164
#undef EXPORT_ROW_SHRINK
165
166
#undef MULT_FIX_FLOOR
167
#undef MULT_FIX
168
#undef ROUNDER
169
170
//------------------------------------------------------------------------------
171
// Main entry calls
172
173
void WebPRescalerImportRow(WebPRescaler* WEBP_RESTRICT const wrk,
174
6.72M
                           const uint8_t* WEBP_RESTRICT src) {
175
6.72M
  assert(!WebPRescalerInputDone(wrk));
176
6.72M
  if (!wrk->x_expand) {
177
3.80M
    WebPRescalerImportRowShrink(wrk, src);
178
3.80M
  } else {
179
2.91M
    WebPRescalerImportRowExpand(wrk, src);
180
2.91M
  }
181
6.72M
}
182
183
122M
void WebPRescalerExportRow(WebPRescaler* const wrk) {
184
122M
  if (wrk->y_accum <= 0) {
185
122M
    assert(!WebPRescalerOutputDone(wrk));
186
122M
    if (wrk->y_expand) {
187
120M
      WebPRescalerExportRowExpand(wrk);
188
120M
    } else if (wrk->fxy_scale) {
189
1.60M
      if (wrk->use_64bit) {
190
157
        RescalerExportRowShrink64_C(wrk);
191
1.60M
      } else {
192
1.60M
        WebPRescalerExportRowShrink(wrk);
193
1.60M
      }
194
1.60M
    } else {  // special case
195
113k
      int i;
196
113k
      if (wrk->use_64bit) {
197
0
        for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) {
198
0
          wrk->dst[i] = (uint8_t)wrk->irow64[i];
199
0
          wrk->irow64[i] = 0;
200
0
        }
201
113k
      } else {
202
113k
        assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1);
203
113k
        assert(wrk->src_width == 1 && wrk->dst_width <= 2);
204
351k
        for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) {
205
237k
          wrk->dst[i] = (uint8_t)wrk->irow[i];
206
237k
          wrk->irow[i] = 0;
207
237k
        }
208
113k
      }
209
113k
    }
210
122M
    wrk->y_accum += wrk->y_add;
211
122M
    wrk->dst += wrk->dst_stride;
212
122M
    ++wrk->dst_y;
213
122M
  }
214
122M
}
215
216
//------------------------------------------------------------------------------
217
218
WebPRescalerImportRowFunc WebPRescalerImportRowExpand;
219
WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
220
221
WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
222
WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
223
224
extern VP8CPUInfo VP8GetCPUInfo;
225
extern void WebPRescalerDspInitSSE2(void);
226
extern void WebPRescalerDspInitMIPS32(void);
227
extern void WebPRescalerDspInitMIPSdspR2(void);
228
extern void WebPRescalerDspInitMSA(void);
229
extern void WebPRescalerDspInitNEON(void);
230
231
27.0k
WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
232
27.0k
#if !defined(WEBP_REDUCE_SIZE)
233
27.0k
#if !WEBP_NEON_OMIT_C_CODE
234
27.0k
  WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C;
235
27.0k
  WebPRescalerExportRowShrink = WebPRescalerExportRowShrink_C;
236
27.0k
#endif
237
238
27.0k
  WebPRescalerImportRowExpand = WebPRescalerImportRowExpand_C;
239
27.0k
  WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C;
240
241
27.0k
  if (VP8GetCPUInfo != NULL) {
242
27.0k
#if defined(WEBP_HAVE_SSE2)
243
27.0k
    if (VP8GetCPUInfo(kSSE2)) {
244
19.5k
      WebPRescalerDspInitSSE2();
245
19.5k
    }
246
27.0k
#endif
247
#if defined(WEBP_USE_MIPS32)
248
    if (VP8GetCPUInfo(kMIPS32)) {
249
      WebPRescalerDspInitMIPS32();
250
    }
251
#endif
252
#if defined(WEBP_USE_MIPS_DSP_R2)
253
    if (VP8GetCPUInfo(kMIPSdspR2)) {
254
      WebPRescalerDspInitMIPSdspR2();
255
    }
256
#endif
257
#if defined(WEBP_USE_MSA)
258
    if (VP8GetCPUInfo(kMSA)) {
259
      WebPRescalerDspInitMSA();
260
    }
261
#endif
262
27.0k
  }
263
264
#if defined(WEBP_HAVE_NEON)
265
  if (WEBP_NEON_OMIT_C_CODE ||
266
      (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
267
    WebPRescalerDspInitNEON();
268
  }
269
#endif
270
271
27.0k
  assert(WebPRescalerExportRowExpand != NULL);
272
27.0k
  assert(WebPRescalerExportRowShrink != NULL);
273
27.0k
  assert(WebPRescalerImportRowExpand != NULL);
274
  assert(WebPRescalerImportRowShrink != NULL);
275
27.0k
#endif  // WEBP_REDUCE_SIZE
276
27.0k
}