/src/ffmpeg/libswscale/uops_tmpl.c
Line | Count | Source |
1 | | /** |
2 | | * Copyright (C) 2026 Niklas Haas |
3 | | * |
4 | | * This file is part of FFmpeg. |
5 | | * |
6 | | * FFmpeg is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * FFmpeg is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with FFmpeg; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #include <libavutil/bswap.h> |
22 | | |
23 | | #include "uops_tmpl.h" |
24 | | |
25 | | #ifndef BIT_DEPTH |
26 | | # define BIT_DEPTH 8 |
27 | | #endif |
28 | | |
29 | | #if IS_FLOAT && BIT_DEPTH == 32 |
30 | | # define PIXEL_TYPE SWS_PIXEL_F32 |
31 | 0 | # define pixel_t float |
32 | 0 | # define inter_t float |
33 | | # define uinter_t float |
34 | 0 | # define vec3_t v3f32_t |
35 | | # define PX F32 |
36 | 0 | # define px f32 |
37 | | #elif BIT_DEPTH == 32 |
38 | 0 | # define PIXEL_MAX 0xFFFFFFFFu |
39 | 0 | # define PIXEL_SWAP av_bswap32 |
40 | 0 | # define pixel_t uint32_t |
41 | | # define inter_t int64_t |
42 | | # define uinter_t uint64_t |
43 | | # define PX U32 |
44 | 0 | # define px u32 |
45 | | #elif BIT_DEPTH == 16 |
46 | 0 | # define PIXEL_MAX 0xFFFFu |
47 | 0 | # define PIXEL_SWAP av_bswap16 |
48 | 0 | # define pixel_t uint16_t |
49 | 0 | # define inter_t int64_t |
50 | | # define uinter_t uint64_t |
51 | | # define PX U16 |
52 | 0 | # define px u16 |
53 | | #elif BIT_DEPTH == 8 |
54 | 0 | # define PIXEL_MAX 0xFFu |
55 | 0 | # define pixel_t uint8_t |
56 | 0 | # define inter_t int32_t |
57 | | # define uinter_t uint32_t |
58 | | # define PX U8 |
59 | 0 | # define px u8 |
60 | | #else |
61 | | # error Invalid BIT_DEPTH |
62 | | #endif |
63 | | |
64 | | /********************************* |
65 | | * Generic read/write operations * |
66 | | *********************************/ |
67 | | |
68 | | DECL_READ(read_planar, const SwsCompMask mask) |
69 | 0 | { |
70 | 0 | SWS_LOOP |
71 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
72 | 0 | if (X) x[i] = in0[i]; |
73 | 0 | if (Y) y[i] = in1[i]; |
74 | 0 | if (Z) z[i] = in2[i]; |
75 | 0 | if (W) w[i] = in3[i]; |
76 | 0 | } |
77 | |
|
78 | 0 | if (X) iter->in[0] += SIZEOF_BLOCK; |
79 | 0 | if (Y) iter->in[1] += SIZEOF_BLOCK; |
80 | 0 | if (Z) iter->in[2] += SIZEOF_BLOCK; |
81 | 0 | if (W) iter->in[3] += SIZEOF_BLOCK; |
82 | |
|
83 | 0 | CONTINUE(x, y, z, w); |
84 | 0 | } Unexecuted instantiation: uops_backend.c:read_planar_U8 Unexecuted instantiation: uops_backend.c:read_planar_U16 Unexecuted instantiation: uops_backend.c:read_planar_U32 Unexecuted instantiation: uops_backend.c:read_planar_F32 |
85 | | |
86 | | DECL_READ(read_packed, const SwsCompMask mask) |
87 | 0 | { |
88 | 0 | const int elems = W ? 4 : Z ? 3 : Y ? 2 : 1; |
89 | |
|
90 | 0 | SWS_LOOP |
91 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
92 | 0 | if (X) x[i] = in0[elems * i + 0]; |
93 | 0 | if (Y) y[i] = in0[elems * i + 1]; |
94 | 0 | if (Z) z[i] = in0[elems * i + 2]; |
95 | 0 | if (W) w[i] = in0[elems * i + 3]; |
96 | 0 | } |
97 | |
|
98 | 0 | iter->in[0] += SIZEOF_BLOCK * elems; |
99 | 0 | CONTINUE(x, y, z, w); |
100 | 0 | } Unexecuted instantiation: uops_backend.c:read_packed_U8 Unexecuted instantiation: uops_backend.c:read_packed_U16 Unexecuted instantiation: uops_backend.c:read_packed_U32 Unexecuted instantiation: uops_backend.c:read_packed_F32 |
101 | | |
102 | | DECL_WRITE(write_planar, const SwsCompMask mask) |
103 | 0 | { |
104 | 0 | SWS_LOOP |
105 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
106 | 0 | if (X) out0[i] = x[i]; |
107 | 0 | if (Y) out1[i] = y[i]; |
108 | 0 | if (Z) out2[i] = z[i]; |
109 | 0 | if (W) out3[i] = w[i]; |
110 | 0 | } |
111 | |
|
112 | 0 | if (X) iter->out[0] += SIZEOF_BLOCK; |
113 | 0 | if (Y) iter->out[1] += SIZEOF_BLOCK; |
114 | 0 | if (Z) iter->out[2] += SIZEOF_BLOCK; |
115 | 0 | if (W) iter->out[3] += SIZEOF_BLOCK; |
116 | 0 | } Unexecuted instantiation: uops_backend.c:write_planar_U8 Unexecuted instantiation: uops_backend.c:write_planar_U16 Unexecuted instantiation: uops_backend.c:write_planar_U32 Unexecuted instantiation: uops_backend.c:write_planar_F32 |
117 | | |
118 | | DECL_WRITE(write_packed, const SwsCompMask mask) |
119 | 0 | { |
120 | 0 | const int elems = W ? 4 : Z ? 3 : Y ? 2 : 1; |
121 | |
|
122 | 0 | SWS_LOOP |
123 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
124 | 0 | if (X) out0[elems * i + 0] = x[i]; |
125 | 0 | if (Y) out0[elems * i + 1] = y[i]; |
126 | 0 | if (Z) out0[elems * i + 2] = z[i]; |
127 | 0 | if (W) out0[elems * i + 3] = w[i]; |
128 | 0 | } |
129 | |
|
130 | 0 | iter->out[0] += SIZEOF_BLOCK * elems; |
131 | 0 | } Unexecuted instantiation: uops_backend.c:write_packed_U8 Unexecuted instantiation: uops_backend.c:write_packed_U16 Unexecuted instantiation: uops_backend.c:write_packed_U32 Unexecuted instantiation: uops_backend.c:write_packed_F32 |
132 | | |
133 | | #if BIT_DEPTH == 8 |
134 | | |
135 | | DECL_READ(read_bit, const SwsCompMask mask) |
136 | 0 | { |
137 | 0 | av_assert2(mask == SWS_COMP_ELEMS(1)); |
138 | |
|
139 | 0 | SWS_LOOP |
140 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i += 8) { |
141 | 0 | const pixel_t val = ((const pixel_t *) in0)[i >> 3]; |
142 | 0 | x[i + 0] = (val >> 7) & 1; |
143 | 0 | x[i + 1] = (val >> 6) & 1; |
144 | 0 | x[i + 2] = (val >> 5) & 1; |
145 | 0 | x[i + 3] = (val >> 4) & 1; |
146 | 0 | x[i + 4] = (val >> 3) & 1; |
147 | 0 | x[i + 5] = (val >> 2) & 1; |
148 | 0 | x[i + 6] = (val >> 1) & 1; |
149 | 0 | x[i + 7] = (val >> 0) & 1; |
150 | 0 | } |
151 | |
|
152 | 0 | iter->in[0] += SIZEOF_BLOCK >> 3; |
153 | 0 | CONTINUE(x, y, z, w); |
154 | 0 | } |
155 | | |
156 | | DECL_READ(read_nibble, const SwsCompMask mask) |
157 | 0 | { |
158 | 0 | av_assert2(mask == SWS_COMP_ELEMS(1)); |
159 | |
|
160 | 0 | SWS_LOOP |
161 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i += 2) { |
162 | 0 | const pixel_t val = in0[i >> 1]; |
163 | 0 | x[i + 0] = val >> 4; /* high nibble */ |
164 | 0 | x[i + 1] = val & 0xF; /* low nibble */ |
165 | 0 | } |
166 | |
|
167 | 0 | iter->in[0] += SIZEOF_BLOCK >> 1; |
168 | 0 | CONTINUE(x, y, z, w); |
169 | 0 | } |
170 | | |
171 | | DECL_READ(read_palette, const SwsCompMask mask) |
172 | 0 | { |
173 | 0 | av_assert2(mask == SWS_COMP_ELEMS(4)); |
174 | |
|
175 | 0 | SWS_LOOP |
176 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
177 | 0 | const pixel_t index = in0[i]; |
178 | 0 | const pixel_t *value = &in1[index * 4]; |
179 | 0 | x[i] = value[0]; |
180 | 0 | y[i] = value[1]; |
181 | 0 | z[i] = value[2]; |
182 | 0 | w[i] = value[3]; |
183 | 0 | } |
184 | |
|
185 | 0 | iter->in[0] += SIZEOF_BLOCK; |
186 | 0 | CONTINUE(x, y, z, w); |
187 | 0 | } |
188 | | |
189 | | DECL_WRITE(write_bit, const SwsCompMask mask) |
190 | 0 | { |
191 | 0 | av_assert2(mask == SWS_COMP_ELEMS(1)); |
192 | |
|
193 | 0 | SWS_LOOP |
194 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i += 8) { |
195 | 0 | out0[i >> 3] = x[i + 0] << 7 | |
196 | 0 | x[i + 1] << 6 | |
197 | 0 | x[i + 2] << 5 | |
198 | 0 | x[i + 3] << 4 | |
199 | 0 | x[i + 4] << 3 | |
200 | 0 | x[i + 5] << 2 | |
201 | 0 | x[i + 6] << 1 | |
202 | 0 | x[i + 7]; |
203 | 0 | } |
204 | |
|
205 | 0 | iter->out[0] += SIZEOF_BLOCK >> 3; |
206 | 0 | } |
207 | | |
208 | | DECL_WRITE(write_nibble, const SwsCompMask mask) |
209 | 0 | { |
210 | 0 | av_assert2(mask == SWS_COMP_ELEMS(1)); |
211 | |
|
212 | 0 | SWS_LOOP |
213 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i += 2) |
214 | 0 | out0[i >> 1] = x[i] << 4 | x[i + 1]; |
215 | |
|
216 | 0 | iter->out[0] += SIZEOF_BLOCK >> 1; |
217 | 0 | } |
218 | | |
219 | | #endif /* BIT_DEPTH == 8 */ |
220 | | |
221 | | SWS_FOR(PX, READ_PLANAR, DECL_IMPL_READ, read_planar) |
222 | | SWS_FOR(PX, READ_PACKED, DECL_IMPL_READ, read_packed) |
223 | | SWS_FOR(PX, READ_NIBBLE, DECL_IMPL_READ, read_nibble) |
224 | | SWS_FOR(PX, READ_BIT, DECL_IMPL_READ, read_bit) |
225 | | SWS_FOR(PX, READ_PALETTE, DECL_IMPL_READ, read_palette) |
226 | | SWS_FOR(PX, WRITE_PLANAR, DECL_IMPL_WRITE, write_planar) |
227 | | SWS_FOR(PX, WRITE_PACKED, DECL_IMPL_WRITE, write_packed) |
228 | | SWS_FOR(PX, WRITE_NIBBLE, DECL_IMPL_WRITE, write_nibble) |
229 | | SWS_FOR(PX, WRITE_BIT, DECL_IMPL_WRITE, write_bit) |
230 | | |
231 | | SWS_FOR_STRUCT(PX, READ_PLANAR, DECL_ENTRY) |
232 | | SWS_FOR_STRUCT(PX, READ_PACKED, DECL_ENTRY) |
233 | | SWS_FOR_STRUCT(PX, READ_NIBBLE, DECL_ENTRY) |
234 | | SWS_FOR_STRUCT(PX, READ_BIT, DECL_ENTRY) |
235 | | SWS_FOR_STRUCT(PX, READ_PALETTE, DECL_ENTRY) |
236 | | SWS_FOR_STRUCT(PX, WRITE_PLANAR, DECL_ENTRY) |
237 | | SWS_FOR_STRUCT(PX, WRITE_PACKED, DECL_ENTRY) |
238 | | SWS_FOR_STRUCT(PX, WRITE_NIBBLE, DECL_ENTRY) |
239 | | SWS_FOR_STRUCT(PX, WRITE_BIT, DECL_ENTRY) |
240 | | |
241 | | /***************************** |
242 | | * Scaling / filtering reads * |
243 | | *****************************/ |
244 | | |
245 | | DECL_SETUP(setup_filter_v, params, out) |
246 | 0 | { |
247 | 0 | if (params->uop->par.filter.type != SWS_PIXEL_F32) |
248 | 0 | return AVERROR(ENOTSUP); |
249 | | |
250 | 0 | const SwsFilterWeights *filter = params->uop->data.kernel; |
251 | 0 | static_assert(sizeof(out->priv.ptr) <= sizeof(int32_t[2]), |
252 | 0 | ">8 byte pointers not supported"); |
253 | | |
254 | | /* Pre-convert weights to float */ |
255 | 0 | float *weights = av_calloc(filter->num_weights, sizeof(float)); |
256 | 0 | if (!weights) |
257 | 0 | return AVERROR(ENOMEM); |
258 | | |
259 | 0 | for (int i = 0; i < filter->num_weights; i++) |
260 | 0 | weights[i] = (float) filter->weights[i] / SWS_FILTER_SCALE; |
261 | |
|
262 | 0 | out->priv.ptr = weights; |
263 | 0 | out->priv.i32[2] = filter->filter_size; |
264 | 0 | out->free = ff_op_priv_free; |
265 | 0 | return 0; |
266 | 0 | } Unexecuted instantiation: uops_backend.c:setup_filter_v_U8 Unexecuted instantiation: uops_backend.c:setup_filter_v_U16 Unexecuted instantiation: uops_backend.c:setup_filter_v_F32 Unexecuted instantiation: uops_backend.c:setup_filter_v_U32 |
267 | | |
268 | | /* Fully general vertical planar filter case */ |
269 | | DECL_READ(read_planar_fv, const SwsCompMask mask, const SwsPixelType type) |
270 | 0 | { |
271 | 0 | av_assert2(type == SWS_PIXEL_F32); |
272 | 0 | const SwsOpExec *exec = iter->exec; |
273 | 0 | const float *restrict weights = impl->priv.ptr; |
274 | 0 | const int filter_size = impl->priv.i32[2]; |
275 | 0 | weights += filter_size * iter->y; |
276 | |
|
277 | 0 | block_t xs, ys, zs, ws; |
278 | 0 | if (X) memset(&xs.f32, 0, sizeof(xs.f32)); |
279 | 0 | if (Y) memset(&ys.f32, 0, sizeof(ys.f32)); |
280 | 0 | if (Z) memset(&zs.f32, 0, sizeof(zs.f32)); |
281 | 0 | if (W) memset(&ws.f32, 0, sizeof(ws.f32)); |
282 | |
|
283 | 0 | for (int j = 0; j < filter_size; j++) { |
284 | 0 | const float weight = weights[j]; |
285 | |
|
286 | 0 | SWS_LOOP |
287 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
288 | 0 | if (X) xs.f32[i] += weight * in0[i]; |
289 | 0 | if (Y) ys.f32[i] += weight * in1[i]; |
290 | 0 | if (Z) zs.f32[i] += weight * in2[i]; |
291 | 0 | if (W) ws.f32[i] += weight * in3[i]; |
292 | 0 | } |
293 | |
|
294 | 0 | if (X) in0 = bump_ptr(in0, exec->in_stride[0]); |
295 | 0 | if (Y) in1 = bump_ptr(in1, exec->in_stride[1]); |
296 | 0 | if (Z) in2 = bump_ptr(in2, exec->in_stride[2]); |
297 | 0 | if (W) in3 = bump_ptr(in3, exec->in_stride[3]); |
298 | 0 | } |
299 | |
|
300 | 0 | if (X) iter->in[0] += SIZEOF_BLOCK; |
301 | 0 | if (Y) iter->in[1] += SIZEOF_BLOCK; |
302 | 0 | if (Z) iter->in[2] += SIZEOF_BLOCK; |
303 | 0 | if (W) iter->in[3] += SIZEOF_BLOCK; |
304 | |
|
305 | 0 | CONTINUE(&xs, &ys, &zs, &ws); |
306 | 0 | } Unexecuted instantiation: uops_backend.c:read_planar_fv_U8 Unexecuted instantiation: uops_backend.c:read_planar_fv_U16 Unexecuted instantiation: uops_backend.c:read_planar_fv_F32 Unexecuted instantiation: uops_backend.c:read_planar_fv_U32 |
307 | | |
308 | | DECL_SETUP(setup_filter_h, params, out) |
309 | 0 | { |
310 | 0 | if (params->uop->par.filter.type != SWS_PIXEL_F32) |
311 | 0 | return AVERROR(ENOTSUP); |
312 | | |
313 | 0 | SwsFilterWeights *filter = params->uop->data.kernel; |
314 | 0 | out->priv.i32[2] = filter->filter_size; |
315 | | |
316 | | /* The horizontal filter uop reads weights for a full SWS_BLOCK_SIZE |
317 | | * outputs per block (see read_planar_fh), so the weights array must be |
318 | | * padded up to the block-aligned output count. Pad the tail with zero |
319 | | * weights, which contribute nothing to the accumulated sums. */ |
320 | 0 | const size_t padded_w = FFALIGN(filter->dst_size, SWS_BLOCK_SIZE); |
321 | 0 | if (padded_w == filter->dst_size) { |
322 | 0 | out->priv.ptr = av_refstruct_ref(filter->weights); |
323 | 0 | out->free = ff_op_priv_unref; |
324 | 0 | return 0; |
325 | 0 | } |
326 | | |
327 | 0 | int *weights = av_calloc(padded_w * filter->filter_size, sizeof(*weights)); |
328 | 0 | if (!weights) |
329 | 0 | return AVERROR(ENOMEM); |
330 | 0 | memcpy(weights, filter->weights, filter->num_weights * sizeof(*weights)); |
331 | 0 | out->priv.ptr = weights; |
332 | 0 | out->free = ff_op_priv_free; |
333 | 0 | return 0; |
334 | 0 | } Unexecuted instantiation: uops_backend.c:setup_filter_h_U8 Unexecuted instantiation: uops_backend.c:setup_filter_h_U16 Unexecuted instantiation: uops_backend.c:setup_filter_h_F32 Unexecuted instantiation: uops_backend.c:setup_filter_h_U32 |
335 | | |
336 | | /* Fully general horizontal planar filter case */ |
337 | | DECL_READ(read_planar_fh, const SwsCompMask mask, const SwsPixelType type) |
338 | 0 | { |
339 | 0 | av_assert2(type == SWS_PIXEL_F32); |
340 | 0 | const SwsOpExec *exec = iter->exec; |
341 | 0 | const int *restrict weights = impl->priv.ptr; |
342 | 0 | const int filter_size = impl->priv.i32[2]; |
343 | 0 | const float scale = 1.0f / SWS_FILTER_SCALE; |
344 | 0 | const int xpos = iter->x; |
345 | 0 | weights += filter_size * iter->x; |
346 | |
|
347 | 0 | block_t xs, ys, zs, ws; |
348 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
349 | 0 | const int offset = exec->in_offset_x[xpos + i]; |
350 | 0 | pixel_t *start0 = bump_ptr(in0, offset); |
351 | 0 | pixel_t *start1 = bump_ptr(in1, offset); |
352 | 0 | pixel_t *start2 = bump_ptr(in2, offset); |
353 | 0 | pixel_t *start3 = bump_ptr(in3, offset); |
354 | |
|
355 | 0 | inter_t sx = 0, sy = 0, sz = 0, sw = 0; |
356 | 0 | for (int j = 0; j < filter_size; j++) { |
357 | 0 | const int weight = weights[j]; |
358 | 0 | if (X) sx += weight * start0[j]; |
359 | 0 | if (Y) sy += weight * start1[j]; |
360 | 0 | if (Z) sz += weight * start2[j]; |
361 | 0 | if (W) sw += weight * start3[j]; |
362 | 0 | } |
363 | |
|
364 | 0 | if (X) xs.f32[i] = (float) sx * scale; |
365 | 0 | if (Y) ys.f32[i] = (float) sy * scale; |
366 | 0 | if (Z) zs.f32[i] = (float) sz * scale; |
367 | 0 | if (W) ws.f32[i] = (float) sw * scale; |
368 | |
|
369 | 0 | weights += filter_size; |
370 | 0 | } |
371 | |
|
372 | 0 | CONTINUE(&xs, &ys, &zs, &ws); |
373 | 0 | } Unexecuted instantiation: uops_backend.c:read_planar_fh_U8 Unexecuted instantiation: uops_backend.c:read_planar_fh_U16 Unexecuted instantiation: uops_backend.c:read_planar_fh_F32 Unexecuted instantiation: uops_backend.c:read_planar_fh_U32 |
374 | | |
375 | | SWS_FOR(PX, READ_PLANAR_FV, DECL_IMPL_READ, read_planar_fv) |
376 | | SWS_FOR(PX, READ_PLANAR_FH, DECL_IMPL_READ, read_planar_fh) |
377 | | SWS_FOR_STRUCT(PX, READ_PLANAR_FV, DECL_ENTRY, .setup = fn(setup_filter_v) ) |
378 | | SWS_FOR_STRUCT(PX, READ_PLANAR_FH, DECL_ENTRY, .setup = fn(setup_filter_h) ) |
379 | | |
380 | | /*************************** |
381 | | * Permutation and copying * |
382 | | ***************************/ |
383 | | |
384 | | DECL_FUNC(permute, const SwsCompMask mask, int num_moves, |
385 | | int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5, |
386 | | int8_t s0, int8_t s1, int8_t s2, int8_t s3, int8_t s4, int8_t s5) |
387 | 0 | { |
388 | 0 | const int8_t dst[SWS_UOP_MOVE_MAX] = { d0, d1, d2, d3, d4, d5 }; |
389 | 0 | const int8_t src[SWS_UOP_MOVE_MAX] = { s0, s1, s2, s3, s4, s5 }; |
390 | |
|
391 | 0 | pixel_t *ptr[5] = { NULL, x, y, z, w }; |
392 | 0 | for (int n = 0; n < num_moves; n++) |
393 | 0 | ptr[dst[n] + 1] = ptr[src[n] + 1]; |
394 | | |
395 | | /* The unneeded registers may still alias the used ones, so point them |
396 | | * back at the stack to avoid collisions */ |
397 | 0 | block_t xx, yy, zz, ww; |
398 | 0 | CONTINUE(X ? ptr[1] : xx.px, |
399 | 0 | Y ? ptr[2] : yy.px, |
400 | 0 | Z ? ptr[3] : zz.px, |
401 | 0 | W ? ptr[4] : ww.px); |
402 | 0 | } Unexecuted instantiation: uops_backend.c:permute_U8 Unexecuted instantiation: uops_backend.c:permute_U16 Unexecuted instantiation: uops_backend.c:permute_U32 Unexecuted instantiation: uops_backend.c:permute_F32 |
403 | | |
404 | | DECL_FUNC(copy, const SwsCompMask mask, int num_moves, |
405 | | int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5, |
406 | | int8_t s0, int8_t s1, int8_t s2, int8_t s3, int8_t s4, int8_t s5) |
407 | 0 | { |
408 | 0 | const size_t block_size = SWS_BLOCK_SIZE * sizeof(pixel_t); |
409 | 0 | const int8_t dst[SWS_UOP_MOVE_MAX] = { d0, d1, d2, d3, d4, d5 }; |
410 | 0 | const int8_t src[SWS_UOP_MOVE_MAX] = { s0, s1, s2, s3, s4, s5 }; |
411 | |
|
412 | 0 | block_t data[5]; |
413 | 0 | memcpy(&data[1].px, x, block_size); |
414 | 0 | memcpy(&data[2].px, y, block_size); |
415 | 0 | memcpy(&data[3].px, z, block_size); |
416 | 0 | memcpy(&data[4].px, w, block_size); |
417 | |
|
418 | 0 | for (int n = 0; n < num_moves; n++) |
419 | 0 | data[dst[n] + 1] = data[src[n] + 1]; |
420 | |
|
421 | 0 | memcpy(x, &data[1].px, block_size); |
422 | 0 | memcpy(y, &data[2].px, block_size); |
423 | 0 | memcpy(z, &data[3].px, block_size); |
424 | 0 | memcpy(w, &data[4].px, block_size); |
425 | |
|
426 | 0 | CONTINUE(x, y, z, w); |
427 | 0 | } Unexecuted instantiation: uops_backend.c:copy_U8 Unexecuted instantiation: uops_backend.c:copy_U16 Unexecuted instantiation: uops_backend.c:copy_U32 Unexecuted instantiation: uops_backend.c:copy_F32 |
428 | | |
429 | | SWS_FOR(PX, PERMUTE, DECL_IMPL, permute) |
430 | | SWS_FOR(PX, COPY, DECL_IMPL, copy) |
431 | | SWS_FOR_STRUCT(PX, PERMUTE, DECL_ENTRY) |
432 | | SWS_FOR_STRUCT(PX, COPY, DECL_ENTRY) |
433 | | |
434 | | /********************* |
435 | | * Format conversion * |
436 | | *********************/ |
437 | | |
438 | | #define DECL_CAST(DST, dst) \ |
439 | | DECL_FUNC(to_##dst, const SwsCompMask mask) \ |
440 | 0 | { \ |
441 | 0 | block_t xx, yy, zz, ww; \ |
442 | 0 | \ |
443 | 0 | SWS_LOOP \ |
444 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { \ |
445 | 0 | if (X) xx.dst[i] = x[i]; \ |
446 | 0 | if (Y) yy.dst[i] = y[i]; \ |
447 | 0 | if (Z) zz.dst[i] = z[i]; \ |
448 | 0 | if (W) ww.dst[i] = w[i]; \ |
449 | 0 | } \ |
450 | 0 | \ |
451 | 0 | CONTINUE(&xx, &yy, &zz, &ww); \ |
452 | 0 | } \ Unexecuted instantiation: uops_backend.c:to_u16_U8 Unexecuted instantiation: uops_backend.c:to_u32_U8 Unexecuted instantiation: uops_backend.c:to_f32_U8 Unexecuted instantiation: uops_backend.c:to_u8_U16 Unexecuted instantiation: uops_backend.c:to_u32_U16 Unexecuted instantiation: uops_backend.c:to_f32_U16 Unexecuted instantiation: uops_backend.c:to_u16_U32 Unexecuted instantiation: uops_backend.c:to_f32_U32 Unexecuted instantiation: uops_backend.c:to_u8_F32 Unexecuted instantiation: uops_backend.c:to_u16_F32 Unexecuted instantiation: uops_backend.c:to_u32_F32 Unexecuted instantiation: uops_backend.c:to_u8_U8 Unexecuted instantiation: uops_backend.c:to_u16_U16 Unexecuted instantiation: uops_backend.c:to_u8_U32 Unexecuted instantiation: uops_backend.c:to_u32_U32 Unexecuted instantiation: uops_backend.c:to_f32_F32 |
453 | | \ |
454 | | SWS_FOR(PX, TO_##DST, DECL_IMPL, to_##dst) \ |
455 | | SWS_FOR_STRUCT(PX, TO_##DST, DECL_ENTRY) |
456 | | |
457 | | DECL_CAST(U8, u8) |
458 | | DECL_CAST(U16, u16) |
459 | | DECL_CAST(U32, u32) |
460 | | DECL_CAST(F32, f32) |
461 | | |
462 | | /******************** |
463 | | * Bit manipulation * |
464 | | ********************/ |
465 | | |
466 | | #if !IS_FLOAT |
467 | | DECL_FUNC(lshift, const SwsCompMask mask, const uint8_t amount) |
468 | 0 | { |
469 | 0 | SWS_LOOP |
470 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
471 | 0 | if (X) x[i] <<= amount; |
472 | 0 | if (Y) y[i] <<= amount; |
473 | 0 | if (Z) z[i] <<= amount; |
474 | 0 | if (W) w[i] <<= amount; |
475 | 0 | } |
476 | |
|
477 | 0 | CONTINUE(x, y, z, w); |
478 | 0 | } Unexecuted instantiation: uops_backend.c:lshift_U16 Unexecuted instantiation: uops_backend.c:lshift_U32 Unexecuted instantiation: uops_backend.c:lshift_U8 |
479 | | |
480 | | DECL_FUNC(rshift, const SwsCompMask mask, const uint8_t amount) |
481 | 0 | { |
482 | 0 | SWS_LOOP |
483 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
484 | 0 | if (X) x[i] >>= amount; |
485 | 0 | if (Y) y[i] >>= amount; |
486 | 0 | if (Z) z[i] >>= amount; |
487 | 0 | if (W) w[i] >>= amount; |
488 | 0 | } |
489 | |
|
490 | 0 | CONTINUE(x, y, z, w); |
491 | 0 | } Unexecuted instantiation: uops_backend.c:rshift_U16 Unexecuted instantiation: uops_backend.c:rshift_U8 Unexecuted instantiation: uops_backend.c:rshift_U32 |
492 | | #endif |
493 | | |
494 | | SWS_FOR(PX, LSHIFT, DECL_IMPL, lshift) |
495 | | SWS_FOR(PX, RSHIFT, DECL_IMPL, rshift) |
496 | | |
497 | | SWS_FOR_STRUCT(PX, LSHIFT, DECL_ENTRY) |
498 | | SWS_FOR_STRUCT(PX, RSHIFT, DECL_ENTRY) |
499 | | |
500 | | #ifdef PIXEL_SWAP |
501 | | DECL_FUNC(swap_bytes, const SwsCompMask mask) |
502 | 0 | { |
503 | 0 | SWS_LOOP |
504 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
505 | 0 | if (X) x[i] = PIXEL_SWAP(x[i]); |
506 | 0 | if (Y) y[i] = PIXEL_SWAP(y[i]); |
507 | 0 | if (Z) z[i] = PIXEL_SWAP(z[i]); |
508 | 0 | if (W) w[i] = PIXEL_SWAP(w[i]); |
509 | 0 | } |
510 | |
|
511 | 0 | CONTINUE(x, y, z, w); |
512 | 0 | } Unexecuted instantiation: uops_backend.c:swap_bytes_U16 Unexecuted instantiation: uops_backend.c:swap_bytes_U32 |
513 | | #endif /* PIXEL_SWAP */ |
514 | | |
515 | | SWS_FOR(PX, SWAP_BYTES, DECL_IMPL, swap_bytes) |
516 | | SWS_FOR_STRUCT(PX, SWAP_BYTES, DECL_ENTRY) |
517 | | |
518 | | #ifdef PIXEL_MAX |
519 | | DECL_FUNC(expand_bit, const SwsCompMask mask) |
520 | 0 | { |
521 | 0 | SWS_LOOP |
522 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
523 | 0 | if (X) x[i] = x[i] ? PIXEL_MAX : 0; |
524 | 0 | if (Y) y[i] = y[i] ? PIXEL_MAX : 0; |
525 | 0 | if (Z) z[i] = z[i] ? PIXEL_MAX : 0; |
526 | 0 | if (W) w[i] = w[i] ? PIXEL_MAX : 0; |
527 | 0 | } |
528 | |
|
529 | 0 | CONTINUE(x, y, z, w); |
530 | 0 | } Unexecuted instantiation: uops_backend.c:expand_bit_U8 Unexecuted instantiation: uops_backend.c:expand_bit_U16 Unexecuted instantiation: uops_backend.c:expand_bit_U32 |
531 | | #endif |
532 | | |
533 | | #if BIT_DEPTH == 8 |
534 | | DECL_FUNC(expand_pair, const SwsCompMask mask) |
535 | 0 | { |
536 | 0 | block_t x16, y16, z16, w16; |
537 | |
|
538 | 0 | SWS_LOOP |
539 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
540 | 0 | if (X) x16.u16[i] = x[i] << 8 | x[i]; |
541 | 0 | if (Y) y16.u16[i] = y[i] << 8 | y[i]; |
542 | 0 | if (Z) z16.u16[i] = z[i] << 8 | z[i]; |
543 | 0 | if (W) w16.u16[i] = w[i] << 8 | w[i]; |
544 | 0 | } |
545 | |
|
546 | 0 | CONTINUE(&x16, &y16, &z16, &w16); |
547 | 0 | } |
548 | | |
549 | | DECL_FUNC(expand_quad, const SwsCompMask mask) |
550 | 0 | { |
551 | 0 | block_t x32, y32, z32, w32; |
552 | 0 |
|
553 | 0 | SWS_LOOP |
554 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
555 | 0 | if (X) x32.u32[i] = (uint32_t) x[i] << 24 | x[i] << 16 | x[i] << 8 | x[i]; |
556 | 0 | if (Y) y32.u32[i] = (uint32_t) y[i] << 24 | y[i] << 16 | y[i] << 8 | y[i]; |
557 | 0 | if (Z) z32.u32[i] = (uint32_t) z[i] << 24 | z[i] << 16 | z[i] << 8 | z[i]; |
558 | 0 | if (W) w32.u32[i] = (uint32_t) w[i] << 24 | w[i] << 16 | w[i] << 8 | w[i]; |
559 | 0 | } |
560 | 0 |
|
561 | 0 | CONTINUE(&x32, &y32, &z32, &w32); |
562 | 0 | } |
563 | | #endif /* BIT_DEPTH == 8 */ |
564 | | |
565 | | SWS_FOR(PX, EXPAND_BIT, DECL_IMPL, expand_bit) |
566 | | SWS_FOR(PX, EXPAND_PAIR, DECL_IMPL, expand_pair) |
567 | | SWS_FOR(PX, EXPAND_QUAD, DECL_IMPL, expand_quad) |
568 | | SWS_FOR_STRUCT(PX, EXPAND_BIT, DECL_ENTRY) |
569 | | SWS_FOR_STRUCT(PX, EXPAND_PAIR, DECL_ENTRY) |
570 | | SWS_FOR_STRUCT(PX, EXPAND_QUAD, DECL_ENTRY) |
571 | | |
572 | | /************************* |
573 | | * Packing and unpacking * |
574 | | ************************/ |
575 | | |
576 | | #if !IS_FLOAT |
577 | | DECL_FUNC(unpack, const SwsCompMask mask, |
578 | | const uint8_t bx, const uint8_t by, |
579 | | const uint8_t bz, const uint8_t bw) |
580 | 0 | { |
581 | 0 | const uint8_t sx = bw + bz + by; |
582 | 0 | const uint8_t sy = bw + bz; |
583 | 0 | const uint8_t sz = bw; |
584 | 0 | const uint8_t sw = 0; |
585 | |
|
586 | 0 | const pixel_t mx = (1 << bx) - 1; |
587 | 0 | const pixel_t my = (1 << by) - 1; |
588 | 0 | const pixel_t mz = (1 << bz) - 1; |
589 | 0 | const pixel_t mw = (1 << bw) - 1; |
590 | |
|
591 | 0 | SWS_LOOP |
592 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
593 | 0 | const pixel_t val = x[i]; |
594 | 0 | if (X) x[i] = (val >> sx) & mx; |
595 | 0 | if (Y) y[i] = (val >> sy) & my; |
596 | 0 | if (Z) z[i] = (val >> sz) & mz; |
597 | 0 | if (W) w[i] = (val >> sw) & mw; |
598 | 0 | } |
599 | |
|
600 | 0 | CONTINUE(x, y, z, w); |
601 | 0 | } Unexecuted instantiation: uops_backend.c:unpack_U8 Unexecuted instantiation: uops_backend.c:unpack_U16 Unexecuted instantiation: uops_backend.c:unpack_U32 |
602 | | |
603 | | DECL_FUNC(pack, const SwsCompMask mask, |
604 | | const uint8_t bx, const uint8_t by, |
605 | | const uint8_t bz, const uint8_t bw) |
606 | 0 | { |
607 | 0 | const uint8_t sx = bw + bz + by; |
608 | 0 | const uint8_t sy = bw + bz; |
609 | 0 | const uint8_t sz = bw; |
610 | 0 | const uint8_t sw = 0; |
611 | |
|
612 | 0 | SWS_LOOP |
613 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
614 | 0 | pixel_t val = 0; |
615 | 0 | if (X) val |= x[i] << sx; |
616 | 0 | if (Y) val |= y[i] << sy; |
617 | 0 | if (Z) val |= z[i] << sz; |
618 | 0 | if (W) val |= w[i] << sw; |
619 | 0 | x[i] = val; |
620 | 0 | } |
621 | |
|
622 | 0 | CONTINUE(x, y, z, w); |
623 | 0 | } Unexecuted instantiation: uops_backend.c:pack_U8 Unexecuted instantiation: uops_backend.c:pack_U16 Unexecuted instantiation: uops_backend.c:pack_U32 |
624 | | #endif /* !IS_FLOAT */ |
625 | | |
626 | | SWS_FOR(PX, UNPACK, DECL_IMPL, unpack) |
627 | | SWS_FOR(PX, PACK, DECL_IMPL, pack) |
628 | | SWS_FOR_STRUCT(PX, UNPACK, DECL_ENTRY) |
629 | | SWS_FOR_STRUCT(PX, PACK, DECL_ENTRY) |
630 | | |
631 | | /*********************** |
632 | | * Pixel data clearing * |
633 | | ***********************/ |
634 | | |
635 | | #ifdef PIXEL_MAX |
636 | | DECL_FUNC(clear, const SwsCompMask mask, const SwsCompMask one, |
637 | | const SwsCompMask zero) |
638 | 0 | { |
639 | 0 | #define ONE(N) SWS_COMP_TEST(one, N) |
640 | 0 | #define ZERO(N) SWS_COMP_TEST(zero, N) |
641 | 0 | const pixel_t cx = ONE(0) ? PIXEL_MAX : ZERO(0) ? 0 : impl->priv.px[0]; |
642 | 0 | const pixel_t cy = ONE(1) ? PIXEL_MAX : ZERO(1) ? 0 : impl->priv.px[1]; |
643 | 0 | const pixel_t cz = ONE(2) ? PIXEL_MAX : ZERO(2) ? 0 : impl->priv.px[2]; |
644 | 0 | const pixel_t cw = ONE(3) ? PIXEL_MAX : ZERO(3) ? 0 : impl->priv.px[3]; |
645 | |
|
646 | 0 | SWS_LOOP |
647 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
648 | 0 | if (X) x[i] = cx; |
649 | 0 | if (Y) y[i] = cy; |
650 | 0 | if (Z) z[i] = cz; |
651 | 0 | if (W) w[i] = cw; |
652 | 0 | } |
653 | |
|
654 | 0 | CONTINUE(x, y, z, w); |
655 | 0 | } Unexecuted instantiation: uops_backend.c:clear_U8 Unexecuted instantiation: uops_backend.c:clear_U16 Unexecuted instantiation: uops_backend.c:clear_U32 |
656 | | #endif |
657 | | |
658 | | SWS_FOR(PX, CLEAR, DECL_IMPL, clear) |
659 | | SWS_FOR_STRUCT(PX, CLEAR, DECL_ENTRY, .setup = ff_sws_setup_vec4) |
660 | | |
661 | | /************************* |
662 | | * Arithmetic operations * |
663 | | *************************/ |
664 | | |
665 | | DECL_FUNC(scale, const SwsCompMask mask) |
666 | 0 | { |
667 | 0 | const pixel_t scale = impl->priv.px[0]; |
668 | |
|
669 | 0 | SWS_LOOP |
670 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
671 | 0 | if (X) x[i] *= scale; |
672 | 0 | if (Y) y[i] *= scale; |
673 | 0 | if (Z) z[i] *= scale; |
674 | 0 | if (W) w[i] *= scale; |
675 | 0 | } |
676 | |
|
677 | 0 | CONTINUE(x, y, z, w); |
678 | 0 | } Unexecuted instantiation: uops_backend.c:scale_U8 Unexecuted instantiation: uops_backend.c:scale_U16 Unexecuted instantiation: uops_backend.c:scale_U32 Unexecuted instantiation: uops_backend.c:scale_F32 |
679 | | |
680 | | DECL_FUNC(add, const SwsCompMask mask) |
681 | 0 | { |
682 | 0 | SWS_LOOP |
683 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
684 | 0 | if (X) x[i] += impl->priv.px[0]; |
685 | 0 | if (Y) y[i] += impl->priv.px[1]; |
686 | 0 | if (Z) z[i] += impl->priv.px[2]; |
687 | 0 | if (W) w[i] += impl->priv.px[3]; |
688 | 0 | } |
689 | |
|
690 | 0 | CONTINUE(x, y, z, w); |
691 | 0 | } Unexecuted instantiation: uops_backend.c:add_F32 Unexecuted instantiation: uops_backend.c:add_U8 Unexecuted instantiation: uops_backend.c:add_U16 Unexecuted instantiation: uops_backend.c:add_U32 |
692 | | |
693 | | DECL_FUNC(min, const SwsCompMask mask) |
694 | 0 | { |
695 | 0 | SWS_LOOP |
696 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
697 | 0 | if (X) x[i] = FFMIN(x[i], impl->priv.px[0]); |
698 | 0 | if (Y) y[i] = FFMIN(y[i], impl->priv.px[1]); |
699 | 0 | if (Z) z[i] = FFMIN(z[i], impl->priv.px[2]); |
700 | 0 | if (W) w[i] = FFMIN(w[i], impl->priv.px[3]); |
701 | 0 | } |
702 | |
|
703 | 0 | CONTINUE(x, y, z, w); |
704 | 0 | } Unexecuted instantiation: uops_backend.c:min_F32 Unexecuted instantiation: uops_backend.c:min_U8 Unexecuted instantiation: uops_backend.c:min_U16 Unexecuted instantiation: uops_backend.c:min_U32 |
705 | | |
706 | | DECL_FUNC(max, const SwsCompMask mask) |
707 | 0 | { |
708 | 0 | SWS_LOOP |
709 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
710 | 0 | if (X) x[i] = FFMAX(x[i], impl->priv.px[0]); |
711 | 0 | if (Y) y[i] = FFMAX(y[i], impl->priv.px[1]); |
712 | 0 | if (Z) z[i] = FFMAX(z[i], impl->priv.px[2]); |
713 | 0 | if (W) w[i] = FFMAX(w[i], impl->priv.px[3]); |
714 | 0 | } |
715 | |
|
716 | 0 | CONTINUE(x, y, z, w); |
717 | 0 | } Unexecuted instantiation: uops_backend.c:max_F32 Unexecuted instantiation: uops_backend.c:max_U8 Unexecuted instantiation: uops_backend.c:max_U16 Unexecuted instantiation: uops_backend.c:max_U32 |
718 | | |
719 | | SWS_FOR(PX, SCALE, DECL_IMPL, scale) |
720 | | SWS_FOR(PX, ADD, DECL_IMPL, add) |
721 | | SWS_FOR(PX, MIN, DECL_IMPL, min) |
722 | | SWS_FOR(PX, MAX, DECL_IMPL, max) |
723 | | SWS_FOR_STRUCT(PX, SCALE, DECL_ENTRY, .setup = ff_sws_setup_scalar ) |
724 | | SWS_FOR_STRUCT(PX, ADD, DECL_ENTRY, .setup = ff_sws_setup_vec4 ) |
725 | | SWS_FOR_STRUCT(PX, MIN, DECL_ENTRY, .setup = ff_sws_setup_vec4 ) |
726 | | SWS_FOR_STRUCT(PX, MAX, DECL_ENTRY, .setup = ff_sws_setup_vec4 ) |
727 | | |
728 | | /************* |
729 | | * Dithering * |
730 | | *************/ |
731 | | |
732 | | DECL_SETUP(setup_dither, params, out) |
733 | 0 | { |
734 | 0 | const SwsUOp *uop = params->uop; |
735 | 0 | const SwsDitherUOp *dither = &uop->par.dither; |
736 | 0 | const int size = 1 << dither->size_log2; |
737 | 0 | if (size >= SWS_BLOCK_SIZE) { |
738 | | /* No extra padding needed */ |
739 | 0 | out->priv.ptr = av_refstruct_ref(uop->data.ptr); |
740 | 0 | out->free = ff_op_priv_unref; |
741 | 0 | return 0; |
742 | 0 | } |
743 | | |
744 | 0 | const int stride = FFMAX(size, SWS_BLOCK_SIZE); |
745 | 0 | const int height = ff_sws_dither_height(dither); |
746 | 0 | pixel_t *matrix = av_malloc(sizeof(pixel_t) * height * stride); |
747 | 0 | if (!matrix) |
748 | 0 | return AVERROR(ENOMEM); |
749 | 0 | out->priv.ptr = matrix; |
750 | 0 | out->free = ff_op_priv_free; |
751 | | |
752 | | /* Pad to multiple of block size. We don't need extra padding for the |
753 | | * height because ff_sws_dither_height() already includes any padding |
754 | | * necessary for the y_offset */ |
755 | 0 | for (int y = 0; y < height; y++) { |
756 | 0 | pixel_t *row = &matrix[y * stride]; |
757 | 0 | for (int x = 0; x < size; x++) |
758 | 0 | row[x] = uop->data.ptr[y * size + x].px; |
759 | 0 | for (int x = size; x < stride; x++) |
760 | 0 | row[x] = row[x % size]; |
761 | 0 | } |
762 | |
|
763 | 0 | return 0; |
764 | 0 | } Unexecuted instantiation: uops_backend.c:setup_dither_F32 Unexecuted instantiation: uops_backend.c:setup_dither_U8 Unexecuted instantiation: uops_backend.c:setup_dither_U16 Unexecuted instantiation: uops_backend.c:setup_dither_U32 |
765 | | |
766 | | DECL_FUNC(dither, const SwsCompMask mask, |
767 | | const uint8_t off0, const uint8_t off1, |
768 | | const uint8_t off2, const uint8_t off3, |
769 | | const uint8_t size_log2) |
770 | 0 | { |
771 | 0 | const int size = 1 << size_log2; |
772 | 0 | const int stride = FFMAX(size, SWS_BLOCK_SIZE); |
773 | |
|
774 | 0 | const pixel_t *matrix = impl->priv.ptr; |
775 | 0 | matrix += (iter->y & (size - 1)) * stride; |
776 | 0 | matrix += (iter->x & (size - 1)) & ~(SWS_BLOCK_SIZE - 1); |
777 | |
|
778 | 0 | const pixel_t *const row0 = &matrix[off0 * stride]; |
779 | 0 | const pixel_t *const row1 = &matrix[off1 * stride]; |
780 | 0 | const pixel_t *const row2 = &matrix[off2 * stride]; |
781 | 0 | const pixel_t *const row3 = &matrix[off3 * stride]; |
782 | |
|
783 | 0 | SWS_LOOP |
784 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
785 | 0 | if (X) x[i] += row0[i]; |
786 | 0 | if (Y) y[i] += row1[i]; |
787 | 0 | if (Z) z[i] += row2[i]; |
788 | 0 | if (W) w[i] += row3[i]; |
789 | 0 | } |
790 | |
|
791 | 0 | CONTINUE(x, y, z, w); |
792 | 0 | } Unexecuted instantiation: uops_backend.c:dither_F32 Unexecuted instantiation: uops_backend.c:dither_U8 Unexecuted instantiation: uops_backend.c:dither_U16 Unexecuted instantiation: uops_backend.c:dither_U32 |
793 | | |
794 | | SWS_FOR(PX, DITHER, DECL_IMPL, dither) |
795 | | SWS_FOR_STRUCT(PX, DITHER, DECL_ENTRY, .setup = fn(setup_dither) ) |
796 | | |
797 | | /********************* |
798 | | * Linear operations * |
799 | | *********************/ |
800 | | |
801 | | typedef struct { |
802 | | /* Stored in split form for convenience */ |
803 | | pixel_t m[4][4]; |
804 | | pixel_t k[4]; |
805 | | } fn(LinCoeffs); |
806 | | |
807 | | DECL_SETUP(setup_linear, params, out) |
808 | 0 | { |
809 | 0 | const SwsUOp *uop = params->uop; |
810 | 0 | fn(LinCoeffs) c; |
811 | |
|
812 | 0 | for (int i = 0; i < 4; i++) { |
813 | 0 | for (int j = 0; j < 4; j++) |
814 | 0 | c.m[i][j] = uop->data.mat4x5[i][j].px; |
815 | 0 | c.k[i] = uop->data.mat4x5[i][4].px; |
816 | 0 | } |
817 | |
|
818 | 0 | out->priv.ptr = av_memdup(&c, sizeof(c)); |
819 | 0 | out->free = ff_op_priv_free; |
820 | 0 | return out->priv.ptr ? 0 : AVERROR(ENOMEM); |
821 | 0 | } Unexecuted instantiation: uops_backend.c:setup_linear_U8 Unexecuted instantiation: uops_backend.c:setup_linear_U16 Unexecuted instantiation: uops_backend.c:setup_linear_U32 Unexecuted instantiation: uops_backend.c:setup_linear_F32 |
822 | | |
823 | | /** |
824 | | * Fully general case for a 5x5 linear affine transformation. Should never be |
825 | | * called without constant `mask`. This function will compile down to the |
826 | | * appropriately optimized version for the required subset of operations when |
827 | | * called with a constant mask. |
828 | | */ |
829 | | DECL_FUNC(linear, const SwsCompMask mask, const uint32_t one, const uint32_t zero) |
830 | 0 | { |
831 | 0 | const fn(LinCoeffs) c = *(const fn(LinCoeffs) *) impl->priv.ptr; |
832 | |
|
833 | 0 | SWS_LOOP |
834 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
835 | 0 | const pixel_t xx = x[i]; |
836 | 0 | const pixel_t yy = y[i]; |
837 | 0 | const pixel_t zz = z[i]; |
838 | 0 | const pixel_t ww = w[i]; |
839 | |
|
840 | 0 | #define LIN_VAL(I, J, val) \ |
841 | 0 | ((one & SWS_MASK(I, J)) ? (val) : (uinter_t) c.m[I][J] * (val)) |
842 | |
|
843 | 0 | #define LIN_ROW(I, var) do { \ |
844 | 0 | pixel_t tmp = (zero & SWS_MASK(I, 4)) ? 0 : c.k[I]; \ |
845 | 0 | if (!(zero & SWS_MASK(I, 0))) tmp += LIN_VAL(I, 0, xx); \ |
846 | 0 | if (!(zero & SWS_MASK(I, 1))) tmp += LIN_VAL(I, 1, yy); \ |
847 | 0 | if (!(zero & SWS_MASK(I, 2))) tmp += LIN_VAL(I, 2, zz); \ |
848 | 0 | if (!(zero & SWS_MASK(I, 3))) tmp += LIN_VAL(I, 3, ww); \ |
849 | 0 | var[i] = tmp; \ |
850 | 0 | } while (0) |
851 | |
|
852 | 0 | if (X) LIN_ROW(0, x); |
853 | 0 | if (Y) LIN_ROW(1, y); |
854 | 0 | if (Z) LIN_ROW(2, z); |
855 | 0 | if (W) LIN_ROW(3, w); |
856 | 0 | } |
857 | |
|
858 | 0 | CONTINUE(x, y, z, w); |
859 | 0 | } Unexecuted instantiation: uops_backend.c:linear_U8 Unexecuted instantiation: uops_backend.c:linear_U16 Unexecuted instantiation: uops_backend.c:linear_U32 Unexecuted instantiation: uops_backend.c:linear_F32 |
860 | | |
861 | | SWS_FOR(PX, LINEAR, DECL_IMPL, linear) |
862 | | SWS_FOR_STRUCT(PX, LINEAR, DECL_ENTRY, .setup = fn(setup_linear) ) |
863 | | |
864 | | /****************** |
865 | | * Look-up tables * |
866 | | ******************/ |
867 | | |
868 | | DECL_SETUP(setup_lut3d, params, out) |
869 | 0 | { |
870 | 0 | const SwsLut3D *lut = params->uop->data.lut3d; |
871 | 0 | out->priv.ptr = (void *) av_refstruct_ref_c(lut); |
872 | 0 | out->free = ff_op_priv_unref; |
873 | 0 | return 0; |
874 | 0 | } Unexecuted instantiation: uops_backend.c:setup_lut3d_F32 Unexecuted instantiation: uops_backend.c:setup_lut3d_U8 Unexecuted instantiation: uops_backend.c:setup_lut3d_U16 Unexecuted instantiation: uops_backend.c:setup_lut3d_U32 |
875 | | |
876 | | #if IS_FLOAT |
877 | | av_always_inline static vec3_t fn(vec3)(v3u16_t v) |
878 | 0 | { |
879 | 0 | return (vec3_t) { v.x, v.y, v.z }; |
880 | 0 | } |
881 | | |
882 | 0 | #define lerp(a, b, w) ((a) + (w) * ((pixel_t) (b) - (a))) |
883 | | |
884 | | av_always_inline static |
885 | | vec3_t fn(lerp3)(vec3_t a, vec3_t b, pixel_t w) |
886 | 0 | { |
887 | 0 | return (vec3_t) { |
888 | 0 | lerp(a.x, b.x, w), |
889 | 0 | lerp(a.y, b.y, w), |
890 | 0 | lerp(a.z, b.z, w), |
891 | 0 | }; |
892 | 0 | } |
893 | | |
894 | | av_always_inline static |
895 | | vec3_t fn(lut3d_static)(const SwsLut3D *restrict lut3d, vec3_t rgb) |
896 | 0 | { |
897 | 0 | const int r_base = (int) rgb.x; |
898 | 0 | const int g_base = (int) rgb.y; |
899 | 0 | const int b_base = (int) rgb.z; |
900 | |
|
901 | 0 | int off0 = (r_base < INPUT_LUT_SIZE - 1); |
902 | 0 | int off1 = (g_base < INPUT_LUT_SIZE - 1) * INPUT_LUT_SIZE; |
903 | 0 | int off2 = (b_base < INPUT_LUT_SIZE - 1) * INPUT_LUT_SIZE * INPUT_LUT_SIZE; |
904 | 0 | pixel_t f0 = rgb.x - r_base; |
905 | 0 | pixel_t f1 = rgb.y - g_base; |
906 | 0 | pixel_t f2 = rgb.z - b_base; |
907 | | |
908 | | /* Sort offsets descending by relative weight */ |
909 | 0 | if (f0 < f1) { |
910 | 0 | FFSWAP(pixel_t, f0, f1); |
911 | 0 | FFSWAP(int, off0, off1); |
912 | 0 | } |
913 | 0 | if (f0 < f2) { |
914 | 0 | FFSWAP(pixel_t, f0, f2); |
915 | 0 | FFSWAP(int, off0, off2); |
916 | 0 | } |
917 | 0 | if (f1 < f2) { |
918 | 0 | FFSWAP(pixel_t, f1, f2); |
919 | 0 | FFSWAP(int, off1, off2); |
920 | 0 | } |
921 | | |
922 | | /* Tetrahedral interpolation */ |
923 | 0 | const pixel_t w0 = 1 - f0; |
924 | 0 | const pixel_t w1 = f0 - f1; |
925 | 0 | const pixel_t w2 = f1 - f2; |
926 | 0 | const pixel_t w3 = f2; |
927 | |
|
928 | 0 | const v3u16_t *restrict base = &lut3d->input[b_base][g_base][r_base]; |
929 | 0 | const vec3_t v0 = fn(vec3)(base[0]); |
930 | 0 | const vec3_t v1 = fn(vec3)(base[off0]); |
931 | 0 | const vec3_t v2 = fn(vec3)(base[off0 + off1]); |
932 | 0 | const vec3_t v3 = fn(vec3)(base[off0 + off1 + off2]); |
933 | |
|
934 | 0 | return (vec3_t) { |
935 | 0 | w0 * v0.x + w1 * v1.x + w2 * v2.x + w3 * v3.x, |
936 | 0 | w0 * v0.y + w1 * v1.y + w2 * v2.y + w3 * v3.y, |
937 | 0 | w0 * v0.z + w1 * v1.z + w2 * v2.z + w3 * v3.z, |
938 | 0 | }; |
939 | 0 | } |
940 | | |
941 | | av_always_inline static |
942 | | vec3_t fn(lut3d_dynamic)(const SwsLut3D *restrict lut3d, vec3_t rgb) |
943 | 0 | { |
944 | 0 | rgb.x *= (TONE_LUT_SIZE - 1) / (pixel_t) UINT16_MAX; |
945 | | |
946 | | /* Linear interpolation */ |
947 | 0 | const int Ix = (int) rgb.x; |
948 | 0 | const pixel_t If = rgb.x - Ix; |
949 | |
|
950 | 0 | const v2u16_t a = lut3d->tone_map[Ix]; |
951 | 0 | const v2u16_t b = lut3d->tone_map[Ix + 1]; |
952 | |
|
953 | 0 | const pixel_t k = lerp(a.y, b.y, If); |
954 | 0 | const pixel_t bias = (1 << 15) - k; |
955 | 0 | const pixel_t scale = k / (pixel_t) (1 << 15); |
956 | |
|
957 | 0 | rgb.x = lerp(a.x, b.x, If); |
958 | 0 | rgb.y = bias + scale * rgb.y; |
959 | 0 | rgb.z = bias + scale * rgb.z; |
960 | | |
961 | | /* Re-scale to output LUT size */ |
962 | 0 | rgb.x *= (OUTPUT_LUT_SIZE_I - 1) / (pixel_t) UINT16_MAX; |
963 | 0 | rgb.y *= (OUTPUT_LUT_SIZE_PT - 1) / (pixel_t) UINT16_MAX; |
964 | 0 | rgb.z *= (OUTPUT_LUT_SIZE_PT - 1) / (pixel_t) UINT16_MAX; |
965 | | |
966 | | /* Trilinear interpolation */ |
967 | 0 | const int lo0 = (int) rgb.x; |
968 | 0 | const int lo1 = (int) rgb.y; |
969 | 0 | const int lo2 = (int) rgb.z; |
970 | |
|
971 | 0 | const int hi0 = FFMIN(lo0 + 1, OUTPUT_LUT_SIZE_I - 1); |
972 | 0 | const int hi1 = FFMIN(lo1 + 1, OUTPUT_LUT_SIZE_PT - 1); |
973 | 0 | const int hi2 = FFMIN(lo2 + 1, OUTPUT_LUT_SIZE_PT - 1); |
974 | |
|
975 | 0 | const pixel_t w0 = rgb.x - lo0; |
976 | 0 | const vec3_t c000 = fn(vec3)(lut3d->output[lo2][lo1][lo0]); |
977 | 0 | const vec3_t c001 = fn(vec3)(lut3d->output[lo2][lo1][hi0]); |
978 | 0 | const vec3_t c00 = fn(lerp3)(c000, c001, w0); |
979 | 0 | const vec3_t c010 = fn(vec3)(lut3d->output[lo2][hi1][lo0]); |
980 | 0 | const vec3_t c011 = fn(vec3)(lut3d->output[lo2][hi1][hi0]); |
981 | 0 | const vec3_t c01 = fn(lerp3)(c010, c011, w0); |
982 | 0 | const vec3_t c100 = fn(vec3)(lut3d->output[hi2][lo1][lo0]); |
983 | 0 | const vec3_t c101 = fn(vec3)(lut3d->output[hi2][lo1][hi0]); |
984 | 0 | const vec3_t c10 = fn(lerp3)(c100, c101, w0); |
985 | 0 | const vec3_t c110 = fn(vec3)(lut3d->output[hi2][hi1][lo0]); |
986 | 0 | const vec3_t c111 = fn(vec3)(lut3d->output[hi2][hi1][hi0]); |
987 | 0 | const vec3_t c11 = fn(lerp3)(c110, c111, w0); |
988 | |
|
989 | 0 | const pixel_t w1 = rgb.y - lo1; |
990 | 0 | const vec3_t c0 = fn(lerp3)(c00, c01, w1); |
991 | 0 | const vec3_t c1 = fn(lerp3)(c10, c11, w1); |
992 | |
|
993 | 0 | const pixel_t w2 = rgb.z - lo2; |
994 | 0 | return fn(lerp3)(c0, c1, w2); |
995 | 0 | } |
996 | | |
997 | | DECL_FUNC(lut3d, const SwsCompMask mask, const int dynamic) |
998 | 0 | { |
999 | 0 | const SwsLut3D *restrict lut3d = impl->priv.ptr; |
1000 | |
|
1001 | 0 | SWS_LOOP |
1002 | 0 | for (int i = 0; i < SWS_BLOCK_SIZE; i++) { |
1003 | 0 | vec3_t c = { x[i], y[i], z[i] }; |
1004 | 0 | c = fn(lut3d_static)(lut3d, c); |
1005 | 0 | if (dynamic) |
1006 | 0 | c = fn(lut3d_dynamic)(lut3d, c); |
1007 | |
|
1008 | 0 | x[i] = c.x; |
1009 | 0 | y[i] = c.y; |
1010 | 0 | z[i] = c.z; |
1011 | 0 | } |
1012 | |
|
1013 | 0 | CONTINUE(x, y, z, w); |
1014 | 0 | } |
1015 | | #endif /* IS_FLOAT */ |
1016 | | |
1017 | | SWS_FOR(PX, LUT_3D, DECL_IMPL, lut3d) |
1018 | | SWS_FOR_STRUCT(PX, LUT_3D, DECL_ENTRY, .setup = fn(setup_lut3d) ) |
1019 | | |
1020 | | #undef PIXEL_MAX |
1021 | | #undef PIXEL_SWAP |
1022 | | #undef pixel_t |
1023 | | #undef inter_t |
1024 | | #undef uinter_t |
1025 | | #undef vec3_t |
1026 | | #undef PX |
1027 | | #undef px |