FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/x86/vc1dsp_mmx.c
Date: 2026-07-18 19:31:15
Exec Total Coverage
Lines: 39 39 100.0%
Functions: 48 48 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 /*
2 * VC-1 and WMV3 - DSP functions MMX-optimized
3 * Copyright (c) 2007 Christophe GISQUET <christophe.gisquet@free.fr>
4 *
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following
12 * conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 #include "libavutil/attributes.h"
28 #include "libavutil/mem_internal.h"
29 #include "libavutil/x86/asm.h"
30 #include "libavutil/x86/cpu.h"
31 #include "libavcodec/vc1dsp.h"
32 #include "constants.h"
33 #include "fpel.h"
34 #include "vc1dsp.h"
35
36 #if HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL
37
38 void ff_vc1_put_ver_16b_shift2_mmx(int16_t *dst,
39 const uint8_t *src, x86_reg stride,
40 int rnd, int64_t shift);
41 void ff_vc1_put_hor_16b_shift2_mmx(uint8_t *dst, x86_reg stride,
42 const int16_t *src, int rnd);
43 void ff_vc1_avg_hor_16b_shift2_mmxext(uint8_t *dst, x86_reg stride,
44 const int16_t *src, int rnd);
45
46 #define OP_PUT(S,D)
47 #define OP_AVG(S,D) "pavgb " #S ", " #D " \n\t"
48
49 /** Add rounder from mm7 to mm3 and pack result at destination */
50 #define NORMALIZE_MMX(SHIFT) \
51 "paddw %%mm7, %%mm3 \n\t" /* +bias-r */ \
52 "paddw %%mm7, %%mm4 \n\t" /* +bias-r */ \
53 "psraw "SHIFT", %%mm3 \n\t" \
54 "psraw "SHIFT", %%mm4 \n\t"
55
56 #define TRANSFER_DO_PACK(OP) \
57 "packuswb %%mm4, %%mm3 \n\t" \
58 OP((%2), %%mm3) \
59 "movq %%mm3, (%2) \n\t"
60
61 #define TRANSFER_DONT_PACK(OP) \
62 OP(0(%2), %%mm3) \
63 OP(8(%2), %%mm4) \
64 "movq %%mm3, 0(%2) \n\t" \
65 "movq %%mm4, 8(%2) \n\t"
66
67 /** @see MSPEL_FILTER13_CORE for use as UNPACK macro */
68 #define DO_UNPACK(reg) "punpcklbw %%mm0, " reg "\n\t"
69 #define DONT_UNPACK(reg)
70
71 /** Compute the rounder 32-r or 8-r and unpacks it to mm7 */
72 #define LOAD_ROUNDER_MMX(ROUND) \
73 "movd "ROUND", %%mm7 \n\t" \
74 "punpcklwd %%mm7, %%mm7 \n\t" \
75 "punpckldq %%mm7, %%mm7 \n\t"
76
77 /**
78 * Core of the 1/4 and 3/4 shift bicubic interpolation.
79 *
80 * @param UNPACK Macro unpacking arguments from 8 to 16 bits (can be empty).
81 * @param MOVQ "movd 1" or "movq 2", if data read is already unpacked.
82 * @param A1 Address of 1st tap (beware of unpacked/packed).
83 * @param A2 Address of 2nd tap
84 * @param A3 Address of 3rd tap
85 * @param A4 Address of 4th tap
86 */
87 #define MSPEL_FILTER13_CORE(UNPACK, MOVQ, A1, A2, A3, A4) \
88 MOVQ "*0+"A1", %%mm1 \n\t" \
89 MOVQ "*4+"A1", %%mm2 \n\t" \
90 UNPACK("%%mm1") \
91 UNPACK("%%mm2") \
92 "pmullw "MANGLE(ff_pw_3)", %%mm1\n\t" \
93 "pmullw "MANGLE(ff_pw_3)", %%mm2\n\t" \
94 MOVQ "*0+"A2", %%mm3 \n\t" \
95 MOVQ "*4+"A2", %%mm4 \n\t" \
96 UNPACK("%%mm3") \
97 UNPACK("%%mm4") \
98 "pmullw %%mm6, %%mm3 \n\t" /* *18 */ \
99 "pmullw %%mm6, %%mm4 \n\t" /* *18 */ \
100 "psubw %%mm1, %%mm3 \n\t" /* 18,-3 */ \
101 "psubw %%mm2, %%mm4 \n\t" /* 18,-3 */ \
102 MOVQ "*0+"A4", %%mm1 \n\t" \
103 MOVQ "*4+"A4", %%mm2 \n\t" \
104 UNPACK("%%mm1") \
105 UNPACK("%%mm2") \
106 "psllw $2, %%mm1 \n\t" /* 4* */ \
107 "psllw $2, %%mm2 \n\t" /* 4* */ \
108 "psubw %%mm1, %%mm3 \n\t" /* -4,18,-3 */ \
109 "psubw %%mm2, %%mm4 \n\t" /* -4,18,-3 */ \
110 MOVQ "*0+"A3", %%mm1 \n\t" \
111 MOVQ "*4+"A3", %%mm2 \n\t" \
112 UNPACK("%%mm1") \
113 UNPACK("%%mm2") \
114 "pmullw %%mm5, %%mm1 \n\t" /* *53 */ \
115 "pmullw %%mm5, %%mm2 \n\t" /* *53 */ \
116 "paddw %%mm1, %%mm3 \n\t" /* 4,53,18,-3 */ \
117 "paddw %%mm2, %%mm4 \n\t" /* 4,53,18,-3 */
118
119 /**
120 * Macro to build the vertical 16 bits version of vc1_put_shift[13].
121 * Here, offset=src_stride. Parameters passed A1 to A4 must use
122 * %3 (src_stride) and %4 (3*src_stride).
123 *
124 * @param NAME Either 1 or 3
125 * @see MSPEL_FILTER13_CORE for information on A1->A4
126 */
127 #define MSPEL_FILTER13_VER_16B(NAME, A1, A2, A3, A4) \
128 static void \
129 vc1_put_ver_16b_ ## NAME ## _mmx(int16_t *dst, const uint8_t *src, \
130 x86_reg src_stride, \
131 int rnd, int64_t shift) \
132 { \
133 int h = 8; \
134 src -= src_stride; \
135 __asm__ volatile( \
136 LOAD_ROUNDER_MMX("%5") \
137 "movq "MANGLE(ff_pw_53)", %%mm5\n\t" \
138 "movq "MANGLE(ff_pw_18)", %%mm6\n\t" \
139 ".p2align 3 \n\t" \
140 "1: \n\t" \
141 MSPEL_FILTER13_CORE(DO_UNPACK, "movd 1", A1, A2, A3, A4) \
142 NORMALIZE_MMX("%6") \
143 TRANSFER_DONT_PACK(OP_PUT) \
144 /* Last 3 (in fact 4) bytes on the line */ \
145 "movd 8+"A1", %%mm1 \n\t" \
146 DO_UNPACK("%%mm1") \
147 "movq %%mm1, %%mm3 \n\t" \
148 "paddw %%mm1, %%mm1 \n\t" \
149 "paddw %%mm3, %%mm1 \n\t" /* 3* */ \
150 "movd 8+"A2", %%mm3 \n\t" \
151 DO_UNPACK("%%mm3") \
152 "pmullw %%mm6, %%mm3 \n\t" /* *18 */ \
153 "psubw %%mm1, %%mm3 \n\t" /*18,-3 */ \
154 "movd 8+"A3", %%mm1 \n\t" \
155 DO_UNPACK("%%mm1") \
156 "pmullw %%mm5, %%mm1 \n\t" /* *53 */ \
157 "paddw %%mm1, %%mm3 \n\t" /*53,18,-3 */ \
158 "movd 8+"A4", %%mm1 \n\t" \
159 DO_UNPACK("%%mm1") \
160 "psllw $2, %%mm1 \n\t" /* 4* */ \
161 "psubw %%mm1, %%mm3 \n\t" \
162 "paddw %%mm7, %%mm3 \n\t" \
163 "psraw %6, %%mm3 \n\t" \
164 "movq %%mm3, 16(%2) \n\t" \
165 "add %3, %1 \n\t" \
166 "add $24, %2 \n\t" \
167 "decl %0 \n\t" \
168 "jnz 1b \n\t" \
169 : "+r"(h), "+r" (src), "+r" (dst) \
170 : "r"(src_stride), "r"(3*src_stride), \
171 "m"(rnd), "m"(shift) \
172 NAMED_CONSTRAINTS_ADD(ff_pw_3,ff_pw_53,ff_pw_18) \
173 : "memory" \
174 ); \
175 }
176
177 /**
178 * Macro to build the horizontal 16 bits version of vc1_put_shift[13].
179 * Here, offset=16 bits, so parameters passed A1 to A4 should be simple.
180 *
181 * @param NAME Either 1 or 3
182 * @see MSPEL_FILTER13_CORE for information on A1->A4
183 */
184 #define MSPEL_FILTER13_HOR_16B(NAME, A1, A2, A3, A4, OP, OPNAME) \
185 static void \
186 OPNAME ## vc1_hor_16b_ ## NAME ## _mmx(uint8_t *dst, x86_reg stride, \
187 const int16_t *src, int rnd) \
188 { \
189 int h = 8; \
190 src -= 1; \
191 rnd -= (-4+58+13-3)*256; /* Add -256 bias */ \
192 __asm__ volatile( \
193 LOAD_ROUNDER_MMX("%4") \
194 "movq "MANGLE(ff_pw_18)", %%mm6 \n\t" \
195 "movq "MANGLE(ff_pw_53)", %%mm5 \n\t" \
196 ".p2align 3 \n\t" \
197 "1: \n\t" \
198 MSPEL_FILTER13_CORE(DONT_UNPACK, "movq 2", A1, A2, A3, A4) \
199 NORMALIZE_MMX("$7") \
200 /* Remove bias */ \
201 "paddw "MANGLE(ff_pw_128)", %%mm3 \n\t" \
202 "paddw "MANGLE(ff_pw_128)", %%mm4 \n\t" \
203 TRANSFER_DO_PACK(OP) \
204 "add $24, %1 \n\t" \
205 "add %3, %2 \n\t" \
206 "decl %0 \n\t" \
207 "jnz 1b \n\t" \
208 : "+r"(h), "+r" (src), "+r" (dst) \
209 : "r"(stride), "m"(rnd) \
210 NAMED_CONSTRAINTS_ADD(ff_pw_3,ff_pw_18,ff_pw_53,ff_pw_128) \
211 : "memory" \
212 ); \
213 }
214
215 /** 1/4 shift bicubic interpolation */
216 90 MSPEL_FILTER13_VER_16B(shift1, "0(%1,%4 )", "0(%1,%3,2)", "0(%1,%3 )", "0(%1 )")
217 45 MSPEL_FILTER13_HOR_16B(shift1, "2*3(%1)", "2*2(%1)", "2*1(%1)", "2*0(%1)", OP_PUT, put_)
218 45 MSPEL_FILTER13_HOR_16B(shift1, "2*3(%1)", "2*2(%1)", "2*1(%1)", "2*0(%1)", OP_AVG, avg_)
219
220 /** 3/4 shift bicubic interpolation */
221 90 MSPEL_FILTER13_VER_16B(shift3, "0(%1 )", "0(%1,%3 )", "0(%1,%3,2)", "0(%1,%4 )")
222 45 MSPEL_FILTER13_HOR_16B(shift3, "2*0(%1)", "2*1(%1)", "2*2(%1)", "2*3(%1)", OP_PUT, put_)
223 45 MSPEL_FILTER13_HOR_16B(shift3, "2*0(%1)", "2*1(%1)", "2*2(%1)", "2*3(%1)", OP_AVG, avg_)
224
225 typedef void (*vc1_mspel_mc_filter_ver_16bits)(int16_t *dst, const uint8_t *src, x86_reg src_stride, int rnd, int64_t shift);
226 typedef void (*vc1_mspel_mc_filter_hor_16bits)(uint8_t *dst, x86_reg dst_stride, const int16_t *src, int rnd);
227
228 /**
229 * Interpolate fractional pel values by applying proper vertical then
230 * horizontal filter.
231 *
232 * @param dst Destination buffer for interpolated pels.
233 * @param src Source buffer.
234 * @param stride Stride for both src and dst buffers.
235 * @param hmode Horizontal filter (expressed in quarter pixels shift).
236 * @param hmode Vertical filter.
237 * @param rnd Rounding bias.
238 */
239 #define VC1_MSPEL_MC(OP, INSTR)\
240 static void OP ## vc1_mspel_mc(uint8_t *dst, const uint8_t *src, ptrdiff_t stride,\
241 int hmode, int vmode, int rnd)\
242 {\
243 static const vc1_mspel_mc_filter_ver_16bits vc1_put_shift_ver_16bits[] =\
244 { NULL, vc1_put_ver_16b_shift1_mmx, ff_vc1_put_ver_16b_shift2_mmx, vc1_put_ver_16b_shift3_mmx };\
245 static const vc1_mspel_mc_filter_hor_16bits vc1_put_shift_hor_16bits[] =\
246 { NULL, OP ## vc1_hor_16b_shift1_mmx, ff_vc1_ ## OP ## hor_16b_shift2_ ## INSTR, OP ## vc1_hor_16b_shift3_mmx };\
247 \
248 __asm__ volatile(\
249 "pxor %%mm0, %%mm0 \n\t"\
250 ::: "memory"\
251 );\
252 \
253 static const int shift_value[] = { 0, 5, 1, 5 };\
254 int shift = (shift_value[hmode]+shift_value[vmode])>>1;\
255 int r;\
256 LOCAL_ALIGNED(16, int16_t, tmp, [12*8]);\
257 \
258 r = (1<<(shift-1)) + rnd-1;\
259 vc1_put_shift_ver_16bits[vmode](tmp, src-1, stride, r, shift);\
260 \
261 vc1_put_shift_hor_16bits[hmode](dst, stride, tmp+1, 64-rnd);\
262 } \
263 static void OP ## vc1_mspel_mc_16(uint8_t *dst, const uint8_t *src, \
264 int stride, int hmode, int vmode, int rnd)\
265 { \
266 OP ## vc1_mspel_mc(dst + 0, src + 0, stride, hmode, vmode, rnd); \
267 OP ## vc1_mspel_mc(dst + 8, src + 8, stride, hmode, vmode, rnd); \
268 dst += 8*stride; src += 8*stride; \
269 OP ## vc1_mspel_mc(dst + 0, src + 0, stride, hmode, vmode, rnd); \
270 OP ## vc1_mspel_mc(dst + 8, src + 8, stride, hmode, vmode, rnd); \
271 }
272
273 324 VC1_MSPEL_MC(put_, mmx)
274 324 VC1_MSPEL_MC(avg_, mmxext)
275
276 /** Macro to ease bicubic filter interpolation functions declarations */
277 #define DECLARE_FUNCTION(a, b) \
278 static void put_vc1_mspel_mc ## a ## b ## _mmx(uint8_t *dst, \
279 const uint8_t *src, \
280 ptrdiff_t stride, \
281 int rnd) \
282 { \
283 put_vc1_mspel_mc(dst, src, stride, a, b, rnd); \
284 }\
285 static void avg_vc1_mspel_mc ## a ## b ## _mmxext(uint8_t *dst, \
286 const uint8_t *src, \
287 ptrdiff_t stride, \
288 int rnd) \
289 { \
290 avg_vc1_mspel_mc(dst, src, stride, a, b, rnd); \
291 }\
292 static void put_vc1_mspel_mc ## a ## b ## _16_mmx(uint8_t *dst, \
293 const uint8_t *src, \
294 ptrdiff_t stride, \
295 int rnd) \
296 { \
297 put_vc1_mspel_mc_16(dst, src, stride, a, b, rnd); \
298 }\
299 static void avg_vc1_mspel_mc ## a ## b ## _16_mmxext(uint8_t *dst, \
300 const uint8_t *src,\
301 ptrdiff_t stride, \
302 int rnd) \
303 { \
304 avg_vc1_mspel_mc_16(dst, src, stride, a, b, rnd); \
305 }
306
307 24 DECLARE_FUNCTION(1, 1)
308 24 DECLARE_FUNCTION(1, 2)
309 24 DECLARE_FUNCTION(1, 3)
310
311 24 DECLARE_FUNCTION(2, 1)
312 24 DECLARE_FUNCTION(2, 2)
313 24 DECLARE_FUNCTION(2, 3)
314
315 24 DECLARE_FUNCTION(3, 1)
316 24 DECLARE_FUNCTION(3, 2)
317 24 DECLARE_FUNCTION(3, 3)
318
319 #define FN_ASSIGN(OP, X, Y, INSN) \
320 dsp->OP##vc1_mspel_pixels_tab[1][X+4*Y] = OP##vc1_mspel_mc##X##Y##INSN; \
321 dsp->OP##vc1_mspel_pixels_tab[0][X+4*Y] = OP##vc1_mspel_mc##X##Y##_16##INSN
322
323 65 av_cold void ff_vc1dsp_init_mmx(VC1DSPContext *dsp)
324 {
325 65 FN_ASSIGN(put_, 1, 1, _mmx);
326 65 FN_ASSIGN(put_, 1, 2, _mmx);
327 65 FN_ASSIGN(put_, 1, 3, _mmx);
328
329 65 FN_ASSIGN(put_, 2, 1, _mmx);
330 65 FN_ASSIGN(put_, 2, 2, _mmx);
331 65 FN_ASSIGN(put_, 2, 3, _mmx);
332
333 65 FN_ASSIGN(put_, 3, 1, _mmx);
334 65 FN_ASSIGN(put_, 3, 2, _mmx);
335 65 FN_ASSIGN(put_, 3, 3, _mmx);
336 65 }
337
338 60 av_cold void ff_vc1dsp_init_mmxext(VC1DSPContext *dsp)
339 {
340 60 FN_ASSIGN(avg_, 1, 1, _mmxext);
341 60 FN_ASSIGN(avg_, 1, 2, _mmxext);
342 60 FN_ASSIGN(avg_, 1, 3, _mmxext);
343
344 60 FN_ASSIGN(avg_, 2, 1, _mmxext);
345 60 FN_ASSIGN(avg_, 2, 2, _mmxext);
346 60 FN_ASSIGN(avg_, 2, 3, _mmxext);
347
348 60 FN_ASSIGN(avg_, 3, 1, _mmxext);
349 60 FN_ASSIGN(avg_, 3, 2, _mmxext);
350 60 FN_ASSIGN(avg_, 3, 3, _mmxext);
351 60 }
352 #endif /* HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL */
353