304 lines
21 KiB
C
304 lines
21 KiB
C
/*
|
|
* quarterpel DSP functions
|
|
* Copyright (c) 2000, 2001 Fabrice Bellard
|
|
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
|
|
*
|
|
* This file is part of FFmpeg.
|
|
*
|
|
* FFmpeg is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* FFmpeg is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with FFmpeg; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include "config.h"
|
|
#include "libavutil/attributes.h"
|
|
#include "libavutil/attributes_internal.h"
|
|
#include "libavutil/cpu.h"
|
|
#include "libavutil/mem_internal.h"
|
|
#include "libavutil/x86/cpu.h"
|
|
#include "libavcodec/qpeldsp.h"
|
|
#include "fpel.h"
|
|
#include "qpel.h"
|
|
|
|
FF_VISIBILITY_PUSH_HIDDEN
|
|
void ff_put_no_rnd_pixels8x8_l2_mmxext(uint8_t *dst,
|
|
const uint8_t *src1, const uint8_t *src2,
|
|
ptrdiff_t dstStride, ptrdiff_t src1Stride);
|
|
void ff_put_no_rnd_pixels16x16_l2_sse2(uint8_t *dst,
|
|
const uint8_t *src1, const uint8_t *src2,
|
|
ptrdiff_t dstStride, ptrdiff_t src1Stride);
|
|
|
|
#define QPEL_H(OPNAME, RND, SIZE, UNUSED1, XMM, UNUSED2, UNUSED3, L2) \
|
|
void ff_mpeg4_ ## OPNAME ## _qpel ## SIZE ## _h_lowpass_ ## XMM (uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t dstStride, \
|
|
ptrdiff_t srcStride, \
|
|
int h); \
|
|
void ff_mpeg4_ ## OPNAME ## _qpel ## SIZE ## _h_lowpass_l2_ ## XMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t dstStride, \
|
|
ptrdiff_t srcStride, \
|
|
int h, \
|
|
ptrdiff_t l2_offset);\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc10_ ## XMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
ff_mpeg4_ ## OPNAME ## _qpel ## SIZE ## _h_lowpass_l2_ ## XMM(dst, src, stride, \
|
|
stride, SIZE, 0); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc20_ ## XMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
ff_mpeg4_ ## OPNAME ## _qpel ## SIZE ## _h_lowpass_ ## XMM(dst, src, stride, \
|
|
stride, SIZE); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc30_ ## XMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
ff_mpeg4_ ## OPNAME ## _qpel ## SIZE ## _h_lowpass_l2_ ## XMM(dst, src, stride, \
|
|
stride, SIZE, 1); \
|
|
}
|
|
|
|
#define QPEL_V(OPNAME, RND, SIZE, UNUSED1, UNUSED2, XMM, UNUSED3, L2) \
|
|
void ff_mpeg4_ ## OPNAME ## _qpel ## SIZE ## _v_lowpass_ ## XMM (uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t dstStride, \
|
|
ptrdiff_t srcStride); \
|
|
static void OPNAME ## _qpel ## SIZE ## _mc01_ ## XMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
DECLARE_ALIGNED(SIZE, uint8_t, half)[SIZE*SIZE]; \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _v_lowpass_ ## XMM(half, src, \
|
|
SIZE, stride); \
|
|
ff_ ## OPNAME ## _pixels ## SIZE ## x ## SIZE ## _l2_ ## L2(dst, src, half, \
|
|
stride, stride); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc02_ ## XMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
ff_mpeg4_ ## OPNAME ## _qpel ## SIZE ## _v_lowpass_ ## XMM(dst, src, \
|
|
stride, stride); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc03_ ## XMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
DECLARE_ALIGNED(SIZE, uint8_t, half)[SIZE*SIZE]; \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _v_lowpass_ ## XMM(half, src, \
|
|
SIZE, stride); \
|
|
ff_ ## OPNAME ## _pixels ## SIZE ## x ## SIZE ## _l2_ ## L2(dst, src + stride, \
|
|
half, stride, stride); \
|
|
}
|
|
|
|
#define QPEL_HV(OPNAME, RND, SIZE, SIZEP1, HXMM, VXMM, HVXMM, L2) \
|
|
static void OPNAME ## _qpel ## SIZE ## _mc11_ ## HVXMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
DECLARE_ALIGNED(SIZE, uint8_t, half)[(SIZE + SIZEP1)*SIZE]; \
|
|
uint8_t *const halfH = half + SIZE*SIZE; \
|
|
uint8_t *const halfHV = half; \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _h_lowpass_l2_ ## HXMM(halfH, src, SIZE, \
|
|
stride, SIZEP1, 0); \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _v_lowpass_ ## VXMM(halfHV, halfH, \
|
|
SIZE, SIZE); \
|
|
ff_ ## OPNAME ## _pixels ## SIZE ## x ## SIZE ## _l2_ ## L2(dst, halfH, halfHV, \
|
|
stride, SIZE); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc31_ ## HVXMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
DECLARE_ALIGNED(SIZE, uint8_t, half)[(SIZE + SIZEP1)*SIZE]; \
|
|
uint8_t *const halfH = half + SIZE*SIZE; \
|
|
uint8_t *const halfHV = half; \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _h_lowpass_l2_ ## HXMM(halfH, src, SIZE, \
|
|
stride, SIZEP1, 1); \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _v_lowpass_ ## VXMM(halfHV, halfH, \
|
|
SIZE, SIZE); \
|
|
ff_ ## OPNAME ## _pixels ## SIZE ## x ## SIZE ## _l2_ ## L2(dst, halfH, halfHV, \
|
|
stride, SIZE); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc13_ ## HVXMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
DECLARE_ALIGNED(SIZE, uint8_t, half)[(SIZE + SIZEP1)*SIZE]; \
|
|
uint8_t *const halfH = half + SIZE*SIZE; \
|
|
uint8_t *const halfHV = half; \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _h_lowpass_l2_ ## HXMM(halfH, src, SIZE, \
|
|
stride, SIZEP1, 0); \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _v_lowpass_ ## VXMM(halfHV, halfH, \
|
|
SIZE, SIZE); \
|
|
ff_ ## OPNAME ## _pixels ## SIZE ## x ## SIZE ## _l2_ ## L2(dst, halfH + SIZE, \
|
|
halfHV, stride, SIZE); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc33_ ## HVXMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
DECLARE_ALIGNED(SIZE, uint8_t, half)[(SIZE + SIZEP1)*SIZE]; \
|
|
uint8_t *const halfH = half + SIZE*SIZE; \
|
|
uint8_t *const halfHV = half; \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _h_lowpass_l2_ ## HXMM(halfH, src, SIZE, \
|
|
stride, SIZEP1, 1); \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _v_lowpass_ ## VXMM(halfHV, halfH, \
|
|
SIZE, SIZE); \
|
|
ff_ ## OPNAME ## _pixels ## SIZE ## x ## SIZE ## _l2_ ## L2(dst, halfH + SIZE, \
|
|
halfHV, stride, SIZE); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc21_ ## HVXMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
DECLARE_ALIGNED(SIZE, uint8_t, half)[(SIZE + SIZEP1)*SIZE]; \
|
|
uint8_t *const halfH = half + SIZE*SIZE; \
|
|
uint8_t *const halfHV = half; \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _h_lowpass_ ## HXMM(halfH, src, SIZE, \
|
|
stride, SIZEP1); \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _v_lowpass_ ## VXMM(halfHV, halfH, \
|
|
SIZE, SIZE); \
|
|
ff_ ## OPNAME ## _pixels ## SIZE ## x ## SIZE ## _l2_ ## L2(dst, halfH, halfHV, \
|
|
stride, SIZE); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc23_ ## HVXMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
DECLARE_ALIGNED(SIZE, uint8_t, half)[(SIZE + SIZEP1)*SIZE]; \
|
|
uint8_t *const halfH = half + SIZE*SIZE; \
|
|
uint8_t *const halfHV = half; \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _h_lowpass_ ## HXMM(halfH, src, SIZE, \
|
|
stride, SIZEP1); \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _v_lowpass_ ## VXMM(halfHV, halfH, \
|
|
SIZE, SIZE); \
|
|
ff_ ## OPNAME ## _pixels ## SIZE ## x ## SIZE ## _l2_ ## L2(dst, halfH + SIZE, \
|
|
halfHV, stride, SIZE); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc12_ ## HVXMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
DECLARE_ALIGNED(SIZE, uint8_t, halfH)[SIZEP1*SIZE]; \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _h_lowpass_l2_ ## HXMM(halfH, src, SIZE, \
|
|
stride, SIZEP1, 0); \
|
|
ff_mpeg4_ ## OPNAME ## _qpel ## SIZE ## _v_lowpass_ ## VXMM(dst, halfH, \
|
|
stride, SIZE); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc32_ ## HVXMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
DECLARE_ALIGNED(SIZE, uint8_t, halfH)[SIZEP1*SIZE]; \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _h_lowpass_l2_ ## HXMM(halfH, src, SIZE, \
|
|
stride, SIZEP1, 1); \
|
|
ff_mpeg4_ ## OPNAME ## _qpel ## SIZE ## _v_lowpass_ ## VXMM(dst, halfH, \
|
|
stride, SIZE); \
|
|
} \
|
|
\
|
|
static void OPNAME ## _qpel ## SIZE ## _mc22_ ## HVXMM(uint8_t *dst, \
|
|
const uint8_t *src, \
|
|
ptrdiff_t stride) \
|
|
{ \
|
|
DECLARE_ALIGNED(SIZE, uint8_t, halfH)[SIZEP1*SIZE]; \
|
|
ff_mpeg4_put_ ## RND ## qpel ## SIZE ## _h_lowpass_ ## HXMM(halfH, src, SIZE, \
|
|
stride, SIZEP1); \
|
|
ff_mpeg4_ ## OPNAME ## _qpel ## SIZE ## _v_lowpass_ ## VXMM(dst, halfH, \
|
|
stride, SIZE); \
|
|
}
|
|
|
|
#define QPEL3(MACRO, SIZE, SIZEP1, HXMM, VXMM, HVXMM, L2) \
|
|
MACRO(put,, SIZE, SIZEP1, HXMM, VXMM, HVXMM, L2) \
|
|
MACRO(avg,, SIZE, SIZEP1, HXMM, VXMM, HVXMM, L2) \
|
|
MACRO(put_no_rnd, no_rnd_, SIZE, SIZEP1, HXMM, VXMM, HVXMM, L2)
|
|
|
|
QPEL3(QPEL_H, 8, 9, ssse3, sse2, ssse3, mmxext)
|
|
QPEL3(QPEL_H, 16, 17, ssse3, sse2, ssse3, sse2)
|
|
QPEL3(QPEL_V, 8, 9, ssse3, sse2, ssse3, mmxext)
|
|
QPEL3(QPEL_HV, 8, 9, ssse3, sse2, ssse3, mmxext)
|
|
QPEL3(QPEL_V, 16, 17, ssse3, sse2, ssse3, sse2)
|
|
QPEL3(QPEL_HV, 16, 17, ssse3, sse2, ssse3, sse2)
|
|
|
|
#define SET_QPEL_FUNC(OP, X, Y, SIZE, CPU, PREFIX) \
|
|
c->OP ## _qpel_pixels_tab[SIZE == 8][X+4*Y] = PREFIX ## OP ## _qpel ## SIZE ## _mc ## X ## Y ## _ ## CPU
|
|
|
|
#define SET_QPEL_FUNCS3(X, Y, SIZE, CPU, PREFIX) \
|
|
SET_QPEL_FUNC(avg, X, Y, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNC(put, X, Y, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNC(put_no_rnd, X, Y, SIZE, CPU, PREFIX)
|
|
|
|
#define SET_H_QPEL_FUNCS(SIZE, CPU, PREFIX) \
|
|
SET_QPEL_FUNCS3(1, 0, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(2, 0, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(3, 0, SIZE, CPU, PREFIX)
|
|
|
|
#define SET_V_QPEL_FUNCS(SIZE, CPU, PREFIX) \
|
|
SET_QPEL_FUNCS3(0, 1, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(0, 2, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(0, 3, SIZE, CPU, PREFIX)
|
|
|
|
#define SET_HV_QPEL_FUNCS(SIZE, CPU, PREFIX) \
|
|
SET_QPEL_FUNCS3(1, 1, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(1, 2, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(1, 3, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(2, 1, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(2, 2, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(2, 3, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(3, 1, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(3, 2, SIZE, CPU, PREFIX); \
|
|
SET_QPEL_FUNCS3(3, 3, SIZE, CPU, PREFIX)
|
|
|
|
av_cold void ff_qpeldsp_init_x86(QpelDSPContext *c)
|
|
{
|
|
int cpu_flags = av_get_cpu_flags();
|
|
|
|
#if HAVE_SSE2_EXTERNAL
|
|
if (EXTERNAL_SSE2(cpu_flags)) {
|
|
c->put_no_rnd_qpel_pixels_tab[0][0] =
|
|
c->put_qpel_pixels_tab[0][0] = ff_put_pixels16x16_sse2;
|
|
c->put_no_rnd_qpel_pixels_tab[1][0] =
|
|
c->put_qpel_pixels_tab[1][0] = ff_put_pixels8x8_sse2;
|
|
c->avg_qpel_pixels_tab[0][0] = ff_avg_pixels16x16_sse2;
|
|
c->avg_qpel_pixels_tab[1][0] = ff_avg_pixels8x8_sse2;
|
|
|
|
SET_V_QPEL_FUNCS (16, sse2,);
|
|
SET_V_QPEL_FUNCS (8, sse2,);
|
|
}
|
|
#endif
|
|
if (EXTERNAL_SSSE3(cpu_flags)) {
|
|
SET_H_QPEL_FUNCS(8, ssse3,);
|
|
SET_HV_QPEL_FUNCS(8, ssse3,);
|
|
SET_H_QPEL_FUNCS(16, ssse3,);
|
|
SET_HV_QPEL_FUNCS(16, ssse3,);
|
|
}
|
|
}
|
|
FF_VISIBILITY_POP_HIDDEN
|