/work/dav1d/src/cdef_tmpl.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright © 2018, VideoLAN and dav1d authors |
3 | | * Copyright © 2018, Two Orioles, LLC |
4 | | * All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions are met: |
8 | | * |
9 | | * 1. Redistributions of source code must retain the above copyright notice, this |
10 | | * list of conditions and the following disclaimer. |
11 | | * |
12 | | * 2. Redistributions in binary form must reproduce the above copyright notice, |
13 | | * this list of conditions and the following disclaimer in the documentation |
14 | | * and/or other materials provided with the distribution. |
15 | | * |
16 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
20 | | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | | */ |
27 | | |
28 | | #include "config.h" |
29 | | |
30 | | #include <stdlib.h> |
31 | | |
32 | | #include "common/intops.h" |
33 | | |
34 | | #include "src/cdef.h" |
35 | | #include "src/tables.h" |
36 | | |
37 | | static inline int constrain(const int diff, const int threshold, |
38 | | const int shift) |
39 | 520M | { |
40 | 520M | const int adiff = abs(diff); |
41 | 520M | return apply_sign(imin(adiff, imax(0, threshold - (adiff >> shift))), diff); |
42 | 520M | } |
43 | | |
44 | | static inline void fill(int16_t *tmp, const ptrdiff_t stride, |
45 | | const int w, const int h) |
46 | 992k | { |
47 | | /* Use a value that's a large positive number when interpreted as unsigned, |
48 | | * and a large negative number when interpreted as signed. */ |
49 | 8.82M | for (int y = 0; y < h; y++) { |
50 | 28.7M | for (int x = 0; x < w; x++) |
51 | 20.8M | tmp[x] = INT16_MIN; |
52 | 7.83M | tmp += stride; |
53 | 7.83M | } |
54 | 992k | } |
55 | | |
56 | | static void padding(int16_t *tmp, const ptrdiff_t tmp_stride, |
57 | | const pixel *src, const ptrdiff_t src_stride, |
58 | | const pixel (*left)[2], |
59 | | const pixel *top, const pixel *bottom, |
60 | | const int w, const int h, const enum CdefEdgeFlags edges) |
61 | 2.17M | { |
62 | | // fill extended input buffer |
63 | 2.17M | int x_start = -2, x_end = w + 2, y_start = -2, y_end = h + 2; |
64 | 2.17M | if (!(edges & CDEF_HAVE_TOP)) { |
65 | 157k | fill(tmp - 2 - 2 * tmp_stride, tmp_stride, w + 4, 2); |
66 | 157k | y_start = 0; |
67 | 157k | } |
68 | 2.17M | if (!(edges & CDEF_HAVE_BOTTOM)) { |
69 | 155k | fill(tmp + h * tmp_stride - 2, tmp_stride, w + 4, 2); |
70 | 155k | y_end -= 2; |
71 | 155k | } |
72 | 2.17M | if (!(edges & CDEF_HAVE_LEFT)) { |
73 | 339k | fill(tmp + y_start * tmp_stride - 2, tmp_stride, 2, y_end - y_start); |
74 | 339k | x_start = 0; |
75 | 339k | } |
76 | 2.17M | if (!(edges & CDEF_HAVE_RIGHT)) { |
77 | 341k | fill(tmp + y_start * tmp_stride + w, tmp_stride, 2, y_end - y_start); |
78 | 341k | x_end -= 2; |
79 | 341k | } |
80 | | |
81 | 6.17M | for (int y = y_start; y < 0; y++) { |
82 | 44.5M | for (int x = x_start; x < x_end; x++) |
83 | 40.5M | tmp[x + y * tmp_stride] = top[x]; |
84 | 3.99M | top += PXSTRIDE(src_stride); |
85 | 3.99M | } |
86 | 16.8M | for (int y = 0; y < h; y++) |
87 | 39.4M | for (int x = x_start; x < 0; x++) |
88 | 24.7M | tmp[x + y * tmp_stride] = left[y][2 + x]; |
89 | 15.8M | for (int y = 0; y < h; y++) { |
90 | 134M | for (int x = (y < h) ? 0 : x_start; x < x_end; x++) |
91 | 120M | tmp[x] = src[x]; |
92 | 13.6M | src += PXSTRIDE(src_stride); |
93 | 13.6M | tmp += tmp_stride; |
94 | 13.6M | } |
95 | 6.09M | for (int y = h; y < y_end; y++) { |
96 | 42.9M | for (int x = x_start; x < x_end; x++) |
97 | 39.0M | tmp[x] = bottom[x]; |
98 | 3.91M | bottom += PXSTRIDE(src_stride); |
99 | 3.91M | tmp += tmp_stride; |
100 | 3.91M | } |
101 | | |
102 | 2.17M | } |
103 | | |
104 | | static NOINLINE void |
105 | | cdef_filter_block_c(pixel *dst, const ptrdiff_t dst_stride, |
106 | | const pixel (*left)[2], |
107 | | const pixel *const top, const pixel *const bottom, |
108 | | const int pri_strength, const int sec_strength, |
109 | | const int dir, const int damping, const int w, int h, |
110 | | const enum CdefEdgeFlags edges HIGHBD_DECL_SUFFIX) |
111 | 2.17M | { |
112 | 2.17M | const ptrdiff_t tmp_stride = 12; |
113 | 2.17M | assert((w == 4 || w == 8) && (h == 4 || h == 8)); |
114 | 2.17M | int16_t tmp_buf[144]; // 12*12 is the maximum value of tmp_stride * (h + 4) |
115 | 2.17M | int16_t *tmp = tmp_buf + 2 * tmp_stride + 2; |
116 | 2.17M | const int8_t (*const cdef_dirs)[2] = &dav1d_cdef_directions[dir]; |
117 | | |
118 | 2.17M | padding(tmp, tmp_stride, dst, dst_stride, left, top, bottom, w, h, edges); |
119 | | |
120 | 2.17M | if (pri_strength) { |
121 | 1.36M | const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8; |
122 | 1.36M | const int pri_tap = 4 - ((pri_strength >> bitdepth_min_8) & 1); |
123 | 1.36M | const int pri_shift = imax(0, damping - ulog2(pri_strength)); |
124 | 1.36M | if (sec_strength) { |
125 | 801k | const int sec_shift = damping - ulog2(sec_strength); |
126 | 4.76M | do { |
127 | 32.3M | for (int x = 0; x < w; x++) { |
128 | 27.6M | const int px = dst[x]; |
129 | 27.6M | int sum = 0; |
130 | 27.6M | int max = px, min = px; |
131 | 27.6M | int pri_tap_k = pri_tap; |
132 | 78.7M | for (int k = 0; k < 2; k++) { |
133 | 51.1M | const int off1 = cdef_dirs[2][k]; // dir |
134 | 51.1M | const int p0 = tmp[x + off1]; |
135 | 51.1M | const int p1 = tmp[x - off1]; |
136 | 51.1M | sum += pri_tap_k * constrain(p0 - px, pri_strength, pri_shift); |
137 | 51.1M | sum += pri_tap_k * constrain(p1 - px, pri_strength, pri_shift); |
138 | | // if pri_tap_k == 4 then it becomes 2 else it remains 3 |
139 | 51.1M | pri_tap_k = (pri_tap_k & 3) | 2; |
140 | 51.1M | min = umin(p0, min); |
141 | 51.1M | max = imax(p0, max); |
142 | 51.1M | min = umin(p1, min); |
143 | 51.1M | max = imax(p1, max); |
144 | 51.1M | const int off2 = cdef_dirs[4][k]; // dir + 2 |
145 | 51.1M | const int off3 = cdef_dirs[0][k]; // dir - 2 |
146 | 51.1M | const int s0 = tmp[x + off2]; |
147 | 51.1M | const int s1 = tmp[x - off2]; |
148 | 51.1M | const int s2 = tmp[x + off3]; |
149 | 51.1M | const int s3 = tmp[x - off3]; |
150 | | // sec_tap starts at 2 and becomes 1 |
151 | 51.1M | const int sec_tap = 2 - k; |
152 | 51.1M | sum += sec_tap * constrain(s0 - px, sec_strength, sec_shift); |
153 | 51.1M | sum += sec_tap * constrain(s1 - px, sec_strength, sec_shift); |
154 | 51.1M | sum += sec_tap * constrain(s2 - px, sec_strength, sec_shift); |
155 | 51.1M | sum += sec_tap * constrain(s3 - px, sec_strength, sec_shift); |
156 | 51.1M | min = umin(s0, min); |
157 | 51.1M | max = imax(s0, max); |
158 | 51.1M | min = umin(s1, min); |
159 | 51.1M | max = imax(s1, max); |
160 | 51.1M | min = umin(s2, min); |
161 | 51.1M | max = imax(s2, max); |
162 | 51.1M | min = umin(s3, min); |
163 | 51.1M | max = imax(s3, max); |
164 | 51.1M | } |
165 | 27.6M | dst[x] = iclip(px + ((sum - (sum < 0) + 8) >> 4), min, max); |
166 | 27.6M | } |
167 | 4.76M | dst += PXSTRIDE(dst_stride); |
168 | 4.76M | tmp += tmp_stride; |
169 | 4.76M | } while (--h); |
170 | 801k | } else { // pri_strength only |
171 | 3.24M | do { |
172 | 21.7M | for (int x = 0; x < w; x++) { |
173 | 18.5M | const int px = dst[x]; |
174 | 18.5M | int sum = 0; |
175 | 18.5M | int pri_tap_k = pri_tap; |
176 | 54.7M | for (int k = 0; k < 2; k++) { |
177 | 36.2M | const int off = cdef_dirs[2][k]; // dir |
178 | 36.2M | const int p0 = tmp[x + off]; |
179 | 36.2M | const int p1 = tmp[x - off]; |
180 | 36.2M | sum += pri_tap_k * constrain(p0 - px, pri_strength, pri_shift); |
181 | 36.2M | sum += pri_tap_k * constrain(p1 - px, pri_strength, pri_shift); |
182 | 36.2M | pri_tap_k = (pri_tap_k & 3) | 2; |
183 | 36.2M | } |
184 | 18.5M | dst[x] = px + ((sum - (sum < 0) + 8) >> 4); |
185 | 18.5M | } |
186 | 3.24M | dst += PXSTRIDE(dst_stride); |
187 | 3.24M | tmp += tmp_stride; |
188 | 3.24M | } while (--h); |
189 | 558k | } |
190 | 1.36M | } else { // sec_strength only |
191 | 814k | assert(sec_strength); |
192 | 814k | const int sec_shift = damping - ulog2(sec_strength); |
193 | 4.72M | do { |
194 | 29.1M | for (int x = 0; x < w; x++) { |
195 | 24.4M | const int px = dst[x]; |
196 | 24.4M | int sum = 0; |
197 | 70.6M | for (int k = 0; k < 2; k++) { |
198 | 46.2M | const int off1 = cdef_dirs[4][k]; // dir + 2 |
199 | 46.2M | const int off2 = cdef_dirs[0][k]; // dir - 2 |
200 | 46.2M | const int s0 = tmp[x + off1]; |
201 | 46.2M | const int s1 = tmp[x - off1]; |
202 | 46.2M | const int s2 = tmp[x + off2]; |
203 | 46.2M | const int s3 = tmp[x - off2]; |
204 | 46.2M | const int sec_tap = 2 - k; |
205 | 46.2M | sum += sec_tap * constrain(s0 - px, sec_strength, sec_shift); |
206 | 46.2M | sum += sec_tap * constrain(s1 - px, sec_strength, sec_shift); |
207 | 46.2M | sum += sec_tap * constrain(s2 - px, sec_strength, sec_shift); |
208 | 46.2M | sum += sec_tap * constrain(s3 - px, sec_strength, sec_shift); |
209 | 46.2M | } |
210 | 24.4M | dst[x] = px + ((sum - (sum < 0) + 8) >> 4); |
211 | 24.4M | } |
212 | 4.72M | dst += PXSTRIDE(dst_stride); |
213 | 4.72M | tmp += tmp_stride; |
214 | 4.72M | } while (--h); |
215 | 814k | } |
216 | 2.17M | } |
217 | | |
218 | | #define cdef_fn(w, h) \ |
219 | | static void cdef_filter_block_##w##x##h##_c(pixel *const dst, \ |
220 | | const ptrdiff_t stride, \ |
221 | | const pixel (*left)[2], \ |
222 | | const pixel *const top, \ |
223 | | const pixel *const bottom, \ |
224 | | const int pri_strength, \ |
225 | | const int sec_strength, \ |
226 | | const int dir, \ |
227 | | const int damping, \ |
228 | | const enum CdefEdgeFlags edges \ |
229 | 2.16M | HIGHBD_DECL_SUFFIX) \ |
230 | 2.16M | { \ |
231 | 2.16M | cdef_filter_block_c(dst, stride, left, top, bottom, \ |
232 | 2.16M | pri_strength, sec_strength, dir, damping, w, h, edges HIGHBD_TAIL_SUFFIX); \ |
233 | 2.16M | } cdef_tmpl.c:cdef_filter_block_8x8_c Line | Count | Source | 229 | 1.48M | HIGHBD_DECL_SUFFIX) \ | 230 | 1.48M | { \ | 231 | 1.48M | cdef_filter_block_c(dst, stride, left, top, bottom, \ | 232 | 1.48M | pri_strength, sec_strength, dir, damping, w, h, edges HIGHBD_TAIL_SUFFIX); \ | 233 | 1.48M | } |
cdef_tmpl.c:cdef_filter_block_4x8_c Line | Count | Source | 229 | 36.0k | HIGHBD_DECL_SUFFIX) \ | 230 | 36.0k | { \ | 231 | 36.0k | cdef_filter_block_c(dst, stride, left, top, bottom, \ | 232 | 36.0k | pri_strength, sec_strength, dir, damping, w, h, edges HIGHBD_TAIL_SUFFIX); \ | 233 | 36.0k | } |
cdef_tmpl.c:cdef_filter_block_4x4_c Line | Count | Source | 229 | 647k | HIGHBD_DECL_SUFFIX) \ | 230 | 647k | { \ | 231 | 647k | cdef_filter_block_c(dst, stride, left, top, bottom, \ | 232 | 647k | pri_strength, sec_strength, dir, damping, w, h, edges HIGHBD_TAIL_SUFFIX); \ | 233 | 647k | } |
|
234 | | |
235 | | cdef_fn(4, 4); |
236 | | cdef_fn(4, 8); |
237 | | cdef_fn(8, 8); |
238 | | |
239 | | static int cdef_find_dir_c(const pixel *img, const ptrdiff_t stride, |
240 | | unsigned *const var HIGHBD_DECL_SUFFIX) |
241 | 1.48M | { |
242 | 1.48M | const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8; |
243 | 1.48M | int partial_sum_hv[2][8] = { { 0 } }; |
244 | 1.48M | int partial_sum_diag[2][15] = { { 0 } }; |
245 | 1.48M | int partial_sum_alt[4][11] = { { 0 } }; |
246 | | |
247 | 13.0M | for (int y = 0; y < 8; y++) { |
248 | 103M | for (int x = 0; x < 8; x++) { |
249 | 92.1M | const int px = (img[x] >> bitdepth_min_8) - 128; |
250 | | |
251 | 92.1M | partial_sum_diag[0][ y + x ] += px; |
252 | 92.1M | partial_sum_alt [0][ y + (x >> 1)] += px; |
253 | 92.1M | partial_sum_hv [0][ y ] += px; |
254 | 92.1M | partial_sum_alt [1][3 + y - (x >> 1)] += px; |
255 | 92.1M | partial_sum_diag[1][7 + y - x ] += px; |
256 | 92.1M | partial_sum_alt [2][3 - (y >> 1) + x ] += px; |
257 | 92.1M | partial_sum_hv [1][ x ] += px; |
258 | 92.1M | partial_sum_alt [3][ (y >> 1) + x ] += px; |
259 | 92.1M | } |
260 | 11.5M | img += PXSTRIDE(stride); |
261 | 11.5M | } |
262 | | |
263 | 1.48M | unsigned cost[8] = { 0 }; |
264 | 13.3M | for (int n = 0; n < 8; n++) { |
265 | 11.8M | cost[2] += partial_sum_hv[0][n] * partial_sum_hv[0][n]; |
266 | 11.8M | cost[6] += partial_sum_hv[1][n] * partial_sum_hv[1][n]; |
267 | 11.8M | } |
268 | 1.48M | cost[2] *= 105; |
269 | 1.48M | cost[6] *= 105; |
270 | | |
271 | 1.48M | static const uint16_t div_table[7] = { 840, 420, 280, 210, 168, 140, 120 }; |
272 | 11.8M | for (int n = 0; n < 7; n++) { |
273 | 10.3M | const int d = div_table[n]; |
274 | 10.3M | cost[0] += (partial_sum_diag[0][n] * partial_sum_diag[0][n] + |
275 | 10.3M | partial_sum_diag[0][14 - n] * partial_sum_diag[0][14 - n]) * d; |
276 | 10.3M | cost[4] += (partial_sum_diag[1][n] * partial_sum_diag[1][n] + |
277 | 10.3M | partial_sum_diag[1][14 - n] * partial_sum_diag[1][14 - n]) * d; |
278 | 10.3M | } |
279 | 1.48M | cost[0] += partial_sum_diag[0][7] * partial_sum_diag[0][7] * 105; |
280 | 1.48M | cost[4] += partial_sum_diag[1][7] * partial_sum_diag[1][7] * 105; |
281 | | |
282 | 7.42M | for (int n = 0; n < 4; n++) { |
283 | 5.93M | unsigned *const cost_ptr = &cost[n * 2 + 1]; |
284 | 35.6M | for (int m = 0; m < 5; m++) |
285 | 29.6M | *cost_ptr += partial_sum_alt[n][3 + m] * partial_sum_alt[n][3 + m]; |
286 | 5.93M | *cost_ptr *= 105; |
287 | 23.7M | for (int m = 0; m < 3; m++) { |
288 | 17.8M | const int d = div_table[2 * m + 1]; |
289 | 17.8M | *cost_ptr += (partial_sum_alt[n][m] * partial_sum_alt[n][m] + |
290 | 17.8M | partial_sum_alt[n][10 - m] * partial_sum_alt[n][10 - m]) * d; |
291 | 17.8M | } |
292 | 5.93M | } |
293 | | |
294 | 1.48M | int best_dir = 0; |
295 | 1.48M | unsigned best_cost = cost[0]; |
296 | 11.8M | for (int n = 1; n < 8; n++) { |
297 | 10.3M | if (cost[n] > best_cost) { |
298 | 737k | best_cost = cost[n]; |
299 | 737k | best_dir = n; |
300 | 737k | } |
301 | 10.3M | } |
302 | | |
303 | 1.48M | *var = (best_cost - (cost[best_dir ^ 4])) >> 10; |
304 | 1.48M | return best_dir; |
305 | 1.48M | } |
306 | | |
307 | | #if HAVE_ASM |
308 | | #if ARCH_AARCH64 || ARCH_ARM |
309 | | #include "src/arm/cdef.h" |
310 | | #elif ARCH_PPC64LE |
311 | | #include "src/ppc/cdef.h" |
312 | | #elif ARCH_RISCV |
313 | | #include "src/riscv/cdef.h" |
314 | | #elif ARCH_X86 |
315 | | #include "src/x86/cdef.h" |
316 | | #elif ARCH_LOONGARCH64 |
317 | | #include "src/loongarch/cdef.h" |
318 | | #endif |
319 | | #endif |
320 | | |
321 | 36.5k | COLD void bitfn(dav1d_cdef_dsp_init)(Dav1dCdefDSPContext *const c) { |
322 | 36.5k | c->dir = cdef_find_dir_c; |
323 | 36.5k | c->fb[0] = cdef_filter_block_8x8_c; |
324 | 36.5k | c->fb[1] = cdef_filter_block_4x8_c; |
325 | 36.5k | c->fb[2] = cdef_filter_block_4x4_c; |
326 | | |
327 | | #if HAVE_ASM |
328 | | #if ARCH_AARCH64 || ARCH_ARM |
329 | | cdef_dsp_init_arm(c); |
330 | | #elif ARCH_PPC64LE |
331 | | cdef_dsp_init_ppc(c); |
332 | | #elif ARCH_RISCV |
333 | | cdef_dsp_init_riscv(c); |
334 | | #elif ARCH_X86 |
335 | | cdef_dsp_init_x86(c); |
336 | | #elif ARCH_LOONGARCH64 |
337 | | cdef_dsp_init_loongarch(c); |
338 | | #endif |
339 | | #endif |
340 | 36.5k | } Line | Count | Source | 321 | 15.9k | COLD void bitfn(dav1d_cdef_dsp_init)(Dav1dCdefDSPContext *const c) { | 322 | 15.9k | c->dir = cdef_find_dir_c; | 323 | 15.9k | c->fb[0] = cdef_filter_block_8x8_c; | 324 | 15.9k | c->fb[1] = cdef_filter_block_4x8_c; | 325 | 15.9k | c->fb[2] = cdef_filter_block_4x4_c; | 326 | | | 327 | | #if HAVE_ASM | 328 | | #if ARCH_AARCH64 || ARCH_ARM | 329 | | cdef_dsp_init_arm(c); | 330 | | #elif ARCH_PPC64LE | 331 | | cdef_dsp_init_ppc(c); | 332 | | #elif ARCH_RISCV | 333 | | cdef_dsp_init_riscv(c); | 334 | | #elif ARCH_X86 | 335 | | cdef_dsp_init_x86(c); | 336 | | #elif ARCH_LOONGARCH64 | 337 | | cdef_dsp_init_loongarch(c); | 338 | | #endif | 339 | | #endif | 340 | 15.9k | } |
dav1d_cdef_dsp_init_16bpc Line | Count | Source | 321 | 20.6k | COLD void bitfn(dav1d_cdef_dsp_init)(Dav1dCdefDSPContext *const c) { | 322 | 20.6k | c->dir = cdef_find_dir_c; | 323 | 20.6k | c->fb[0] = cdef_filter_block_8x8_c; | 324 | 20.6k | c->fb[1] = cdef_filter_block_4x8_c; | 325 | 20.6k | c->fb[2] = cdef_filter_block_4x4_c; | 326 | | | 327 | | #if HAVE_ASM | 328 | | #if ARCH_AARCH64 || ARCH_ARM | 329 | | cdef_dsp_init_arm(c); | 330 | | #elif ARCH_PPC64LE | 331 | | cdef_dsp_init_ppc(c); | 332 | | #elif ARCH_RISCV | 333 | | cdef_dsp_init_riscv(c); | 334 | | #elif ARCH_X86 | 335 | | cdef_dsp_init_x86(c); | 336 | | #elif ARCH_LOONGARCH64 | 337 | | cdef_dsp_init_loongarch(c); | 338 | | #endif | 339 | | #endif | 340 | 20.6k | } |
|