Merge remote-tracking branch 'qatar/master'
authorMichael Niedermayer <michaelni@gmx.at>
Fri, 26 Apr 2013 09:01:00 +0000 (11:01 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Fri, 26 Apr 2013 09:10:57 +0000 (11:10 +0200)
* commit '74685f6783e77f2545d48bd2124945ad5be39982':
  x86: Rename dsputil_rnd_template.c to rnd_template.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavcodec/x86/dsputil_mmx.c
libavcodec/x86/hpeldsp_rnd_template.c
libavcodec/x86/rnd_template.c

@@@ -3,23 -3,23 +3,23 @@@
   * Copyright (c) 2000, 2001 Fabrice Bellard
   * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
   *
 - * MMX optimization by Nick Kurshev <nickols_k@mail.ru>
 - *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * 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.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * 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 Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 + *
 + * MMX optimization by Nick Kurshev <nickols_k@mail.ru>
   */
  
  #include "libavutil/attributes.h"
  #include "libavcodec/h264dsp.h"
  #include "libavcodec/mpegvideo.h"
  #include "libavcodec/simple_idct.h"
 +#include "libavcodec/videodsp.h"
  #include "dsputil_mmx.h"
  #include "idct_xvid.h"
 +#include "diracdsp_mmx.h"
  
  //#undef NDEBUG
  //#include <assert.h>
@@@ -120,7 -118,7 +120,7 @@@ void ff_put_no_rnd_mpeg4_qpel8_v_lowpas
  #define PAVGB(a, b, c, e)               PAVGB_MMX(a, b, c, e)
  #define OP_AVG(a, b, c, e)              PAVGB_MMX(a, b, c, e)
  
- #include "dsputil_rnd_template.c"
+ #include "rnd_template.c"
  
  #undef DEF
  #undef SET_RND
@@@ -500,7 -498,7 +500,7 @@@ static void draw_edges_mmx(uint8_t *buf
              : "+r"(ptr)
              : "r"((x86_reg)wrap), "r"((x86_reg)width), "r"(ptr + wrap * height)
              );
 -    } else {
 +    } else if(w==16){
          __asm__ volatile (
              "1:                                 \n\t"
              "movd            (%0), %%mm0        \n\t"
              : "+r"(ptr)
              : "r"((x86_reg)wrap), "r"((x86_reg)width), "r"(ptr + wrap * height)
              );
 +    } else {
 +        av_assert1(w == 4);
 +        __asm__ volatile (
 +            "1:                             \n\t"
 +            "movd            (%0), %%mm0    \n\t"
 +            "punpcklbw      %%mm0, %%mm0    \n\t"
 +            "punpcklwd      %%mm0, %%mm0    \n\t"
 +            "movd           %%mm0, -4(%0)   \n\t"
 +            "movd      -4(%0, %2), %%mm1    \n\t"
 +            "punpcklbw      %%mm1, %%mm1    \n\t"
 +            "punpckhwd      %%mm1, %%mm1    \n\t"
 +            "punpckhdq      %%mm1, %%mm1    \n\t"
 +            "movd           %%mm1, (%0, %2) \n\t"
 +            "add               %1, %0       \n\t"
 +            "cmp               %3, %0       \n\t"
 +            "jb                1b           \n\t"
 +            : "+r"(ptr)
 +            : "r"((x86_reg)wrap), "r"((x86_reg)width), "r"(ptr + wrap * height)
 +            );
      }
  
      /* top and bottom (and hopefully also the corners) */
@@@ -993,15 -972,10 +993,15 @@@ void ff_avg_rv40_qpel16_mc33_mmx(uint8_
    avg_pixels16_xy2_mmx(dst, src, stride, 16);
  }
  
 -static void gmc_mmx(uint8_t *dst, uint8_t *src,
 -                    int stride, int h, int ox, int oy,
 -                    int dxx, int dxy, int dyx, int dyy,
 -                    int shift, int r, int width, int height)
 +typedef void emulated_edge_mc_func(uint8_t *dst, const uint8_t *src,
 +                                   ptrdiff_t linesize, int block_w, int block_h,
 +                                   int src_x, int src_y, int w, int h);
 +
 +static av_always_inline void gmc(uint8_t *dst, uint8_t *src,
 +                                 int stride, int h, int ox, int oy,
 +                                 int dxx, int dxy, int dyx, int dyy,
 +                                 int shift, int r, int width, int height,
 +                                 emulated_edge_mc_func *emu_edge_fn)
  {
      const int w    = 8;
      const int ix   = ox  >> (16 + shift);
      const uint16_t dxy4[4] = { dxys, dxys, dxys, dxys };
      const uint16_t dyy4[4] = { dyys, dyys, dyys, dyys };
      const uint64_t shift2 = 2 * shift;
 +#define MAX_STRIDE 4096U
 +#define MAX_H 8U
 +    uint8_t edge_buf[(MAX_H + 1) * MAX_STRIDE];
      int x, y;
  
      const int dxw = (dxx - (1 << (16 + shift))) * (w - 1);
      const int dyh = (dyy - (1 << (16 + shift))) * (h - 1);
      const int dxh = dxy * (h - 1);
      const int dyw = dyx * (w - 1);
 +    int need_emu =  (unsigned)ix >= width  - w ||
 +                    (unsigned)iy >= height - h;
 +
      if ( // non-constant fullpel offset (3% of blocks)
          ((ox ^ (ox + dxw)) | (ox ^ (ox + dxh)) | (ox ^ (ox + dxw + dxh)) |
           (oy ^ (oy + dyw)) | (oy ^ (oy + dyh)) | (oy ^ (oy + dyw + dyh))) >> (16 + shift)
          // uses more than 16 bits of subpel mv (only at huge resolution)
 -        || (dxx | dxy | dyx | dyy) & 15 ||
 -        (unsigned)ix >= width  - w ||
 -        (unsigned)iy >= height - h) {
 +        || (dxx | dxy | dyx | dyy) & 15
 +        || (need_emu && (h > MAX_H || stride > MAX_STRIDE))) {
          // FIXME could still use mmx for some of the rows
          ff_gmc_c(dst, src, stride, h, ox, oy, dxx, dxy, dyx, dyy,
                   shift, r, width, height);
      }
  
      src += ix + iy * stride;
 +    if (need_emu) {
 +        emu_edge_fn(edge_buf, src, stride, w + 1, h + 1, ix, iy, width, height);
 +        src = edge_buf;
 +    }
  
      __asm__ volatile (
          "movd         %0, %%mm6         \n\t"
      }
  }
  
 +
 +#if CONFIG_VIDEODSP
 +#if HAVE_YASM
 +#if ARCH_X86_32
 +static void gmc_mmx(uint8_t *dst, uint8_t *src,
 +                    int stride, int h, int ox, int oy,
 +                    int dxx, int dxy, int dyx, int dyy,
 +                    int shift, int r, int width, int height)
 +{
 +    gmc(dst, src, stride, h, ox, oy, dxx, dxy, dyx, dyy, shift, r,
 +        width, height, &ff_emulated_edge_mc_8);
 +}
 +#endif
 +static void gmc_sse(uint8_t *dst, uint8_t *src,
 +                    int stride, int h, int ox, int oy,
 +                    int dxx, int dxy, int dyx, int dyy,
 +                    int shift, int r, int width, int height)
 +{
 +    gmc(dst, src, stride, h, ox, oy, dxx, dxy, dyx, dyy, shift, r,
 +        width, height, &ff_emulated_edge_mc_8);
 +}
 +#else
 +static void gmc_mmx(uint8_t *dst, uint8_t *src,
 +                    int stride, int h, int ox, int oy,
 +                    int dxx, int dxy, int dyx, int dyy,
 +                    int shift, int r, int width, int height)
 +{
 +    gmc(dst, src, stride, h, ox, oy, dxx, dxy, dyx, dyy, shift, r,
 +        width, height, &ff_emulated_edge_mc_8);
 +}
 +#endif
 +#endif
 +
  /* CAVS-specific */
  void ff_put_cavs_qpel8_mc00_mmx(uint8_t *dst, uint8_t *src, ptrdiff_t stride)
  {
@@@ -1184,75 -1116,6 +1184,75 @@@ void ff_put_vc1_mspel_mc00_mmx(uint8_t 
      put_pixels8_mmx(dst, src, stride, 8);
  }
  
 +#if CONFIG_DIRAC_DECODER
 +#define DIRAC_PIXOP(OPNAME2, OPNAME, EXT)\
 +void ff_ ## OPNAME2 ## _dirac_pixels8_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
 +{\
 +    if (h&3)\
 +        ff_ ## OPNAME2 ## _dirac_pixels8_c(dst, src, stride, h);\
 +    else\
 +        OPNAME ## _pixels8_ ## EXT(dst, src[0], stride, h);\
 +}\
 +void ff_ ## OPNAME2 ## _dirac_pixels16_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
 +{\
 +    if (h&3)\
 +        ff_ ## OPNAME2 ## _dirac_pixels16_c(dst, src, stride, h);\
 +    else\
 +        OPNAME ## _pixels16_ ## EXT(dst, src[0], stride, h);\
 +}\
 +void ff_ ## OPNAME2 ## _dirac_pixels32_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
 +{\
 +    if (h&3) {\
 +        ff_ ## OPNAME2 ## _dirac_pixels32_c(dst, src, stride, h);\
 +    } else {\
 +        OPNAME ## _pixels16_ ## EXT(dst   , src[0]   , stride, h);\
 +        OPNAME ## _pixels16_ ## EXT(dst+16, src[0]+16, stride, h);\
 +    }\
 +}
 +
 +#if HAVE_MMX_INLINE
 +DIRAC_PIXOP(put, put, mmx)
 +DIRAC_PIXOP(avg, avg, mmx)
 +#endif
 +
 +#if HAVE_YASM
 +DIRAC_PIXOP(avg, ff_avg, mmxext)
 +
 +void ff_put_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
 +{
 +    if (h&3)
 +        ff_put_dirac_pixels16_c(dst, src, stride, h);
 +    else
 +    ff_put_pixels16_sse2(dst, src[0], stride, h);
 +}
 +void ff_avg_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
 +{
 +    if (h&3)
 +        ff_avg_dirac_pixels16_c(dst, src, stride, h);
 +    else
 +    ff_avg_pixels16_sse2(dst, src[0], stride, h);
 +}
 +void ff_put_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
 +{
 +    if (h&3) {
 +        ff_put_dirac_pixels32_c(dst, src, stride, h);
 +    } else {
 +    ff_put_pixels16_sse2(dst   , src[0]   , stride, h);
 +    ff_put_pixels16_sse2(dst+16, src[0]+16, stride, h);
 +    }
 +}
 +void ff_avg_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
 +{
 +    if (h&3) {
 +        ff_avg_dirac_pixels32_c(dst, src, stride, h);
 +    } else {
 +    ff_avg_pixels16_sse2(dst   , src[0]   , stride, h);
 +    ff_avg_pixels16_sse2(dst+16, src[0]+16, stride, h);
 +    }
 +}
 +#endif
 +#endif
 +
  static void vector_clipf_sse(float *dst, const float *src,
                               float min, float max, int len)
  {
@@@ -1373,11 -1236,24 +1373,11 @@@ static av_cold void dsputil_init_mmx(DS
          c->clear_block  = clear_block_mmx;
          c->clear_blocks = clear_blocks_mmx;
          c->draw_edges   = draw_edges_mmx;
 -
 -        switch (avctx->idct_algo) {
 -        case FF_IDCT_AUTO:
 -        case FF_IDCT_SIMPLEMMX:
 -            c->idct_put              = ff_simple_idct_put_mmx;
 -            c->idct_add              = ff_simple_idct_add_mmx;
 -            c->idct                  = ff_simple_idct_mmx;
 -            c->idct_permutation_type = FF_SIMPLE_IDCT_PERM;
 -            break;
 -        case FF_IDCT_XVIDMMX:
 -            c->idct_put              = ff_idct_xvid_mmx_put;
 -            c->idct_add              = ff_idct_xvid_mmx_add;
 -            c->idct                  = ff_idct_xvid_mmx;
 -            break;
 -        }
      }
  
 +#if CONFIG_VIDEODSP && (ARCH_X86_32 || !HAVE_YASM)
      c->gmc = gmc_mmx;
 +#endif
  
      c->add_bytes = add_bytes_mmx;
  #endif /* HAVE_INLINE_ASM */
  static av_cold void dsputil_init_mmxext(DSPContext *c, AVCodecContext *avctx,
                                          int mm_flags)
  {
 -#if HAVE_INLINE_ASM
 -    const int high_bit_depth = avctx->bits_per_raw_sample > 8;
 -
 -    if (!high_bit_depth && avctx->idct_algo == FF_IDCT_XVIDMMX) {
 -        c->idct_put = ff_idct_xvid_mmxext_put;
 -        c->idct_add = ff_idct_xvid_mmxext_add;
 -        c->idct     = ff_idct_xvid_mmxext;
 -    }
 -#endif /* HAVE_INLINE_ASM */
 -
  #if HAVE_MMXEXT_EXTERNAL
      SET_QPEL_FUNCS(avg_qpel,        0, 16, mmxext, );
      SET_QPEL_FUNCS(avg_qpel,        1,  8, mmxext, );
@@@ -1435,12 -1321,6 +1435,12 @@@ static av_cold void dsputil_init_sse(DS
  
      c->vector_clipf = vector_clipf_sse;
  #endif /* HAVE_INLINE_ASM */
 +
 +#if HAVE_YASM
 +#if HAVE_INLINE_ASM && CONFIG_VIDEODSP
 +    c->gmc = gmc_sse;
 +#endif
 +#endif /* HAVE_YASM */
  }
  
  static av_cold void dsputil_init_sse2(DSPContext *c, AVCodecContext *avctx,
@@@ -1509,37 -1389,8 +1509,37 @@@ av_cold void ff_dsputil_init_mmx(DSPCon
          c->add_hfyu_median_prediction = add_hfyu_median_prediction_cmov;
  #endif
  
 -    if (mm_flags & AV_CPU_FLAG_MMX)
 +    if (mm_flags & AV_CPU_FLAG_MMX) {
 +#if HAVE_INLINE_ASM
 +        const int idct_algo = avctx->idct_algo;
 +
 +        if (avctx->lowres == 0 && avctx->bits_per_raw_sample <= 8) {
 +            if (idct_algo == FF_IDCT_AUTO || idct_algo == FF_IDCT_SIMPLEMMX) {
 +                c->idct_put              = ff_simple_idct_put_mmx;
 +                c->idct_add              = ff_simple_idct_add_mmx;
 +                c->idct                  = ff_simple_idct_mmx;
 +                c->idct_permutation_type = FF_SIMPLE_IDCT_PERM;
 +            } else if (idct_algo == FF_IDCT_XVIDMMX) {
 +                if (mm_flags & AV_CPU_FLAG_SSE2) {
 +                    c->idct_put              = ff_idct_xvid_sse2_put;
 +                    c->idct_add              = ff_idct_xvid_sse2_add;
 +                    c->idct                  = ff_idct_xvid_sse2;
 +                    c->idct_permutation_type = FF_SSE2_IDCT_PERM;
 +                } else if (mm_flags & AV_CPU_FLAG_MMXEXT) {
 +                    c->idct_put              = ff_idct_xvid_mmxext_put;
 +                    c->idct_add              = ff_idct_xvid_mmxext_add;
 +                    c->idct                  = ff_idct_xvid_mmxext;
 +                } else {
 +                    c->idct_put              = ff_idct_xvid_mmx_put;
 +                    c->idct_add              = ff_idct_xvid_mmx_add;
 +                    c->idct                  = ff_idct_xvid_mmx;
 +                }
 +            }
 +        }
 +#endif /* HAVE_INLINE_ASM */
 +
          dsputil_init_mmx(c, avctx, mm_flags);
 +    }
  
      if (mm_flags & AV_CPU_FLAG_MMXEXT)
          dsputil_init_mmxext(c, avctx, mm_flags);
@@@ -7,24 -7,24 +7,24 @@@
   * mostly rewritten by Michael Niedermayer <michaelni@gmx.at>
   * and improved by Zdenek Kabelac <kabi@users.sf.net>
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * 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.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * 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 Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
- #include "dsputil_rnd_template.c"
+ #include "rnd_template.c"
  
  // put_pixels
  static void DEF(put, pixels8_x2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
index 0000000,2ff77d7..7765309
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,224 +1,224 @@@
 - * This file is part of Libav.
+ /*
+  * DSP utils mmx functions are compiled twice for rnd/no_rnd
+  * Copyright (c) 2000, 2001 Fabrice Bellard
+  * Copyright (c) 2003-2004 Michael Niedermayer <michaelni@gmx.at>
+  *
+  * MMX optimization by Nick Kurshev <nickols_k@mail.ru>
+  * mostly rewritten by Michael Niedermayer <michaelni@gmx.at>
+  * and improved by Zdenek Kabelac <kabi@users.sf.net>
+  *
 - * Libav is free software; you can redistribute it and/or
++ * This file is part of FFmpeg.
+  *
 - * Libav is distributed in the hope that it will be useful,
++ * 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.
+  *
 - * License along with Libav; if not, write to the Free Software
++ * 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
+  */
+ // put_pixels
+ static void DEF(put, pixels8_xy2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
+ {
+     MOVQ_ZERO(mm7);
+     SET_RND(mm6); // =2 for rnd  and  =1 for no_rnd version
+     __asm__ volatile(
+         "movq   (%1), %%mm0             \n\t"
+         "movq   1(%1), %%mm4            \n\t"
+         "movq   %%mm0, %%mm1            \n\t"
+         "movq   %%mm4, %%mm5            \n\t"
+         "punpcklbw %%mm7, %%mm0         \n\t"
+         "punpcklbw %%mm7, %%mm4         \n\t"
+         "punpckhbw %%mm7, %%mm1         \n\t"
+         "punpckhbw %%mm7, %%mm5         \n\t"
+         "paddusw %%mm0, %%mm4           \n\t"
+         "paddusw %%mm1, %%mm5           \n\t"
+         "xor    %%"REG_a", %%"REG_a"    \n\t"
+         "add    %3, %1                  \n\t"
+         ".p2align 3                     \n\t"
+         "1:                             \n\t"
+         "movq   (%1, %%"REG_a"), %%mm0  \n\t"
+         "movq   1(%1, %%"REG_a"), %%mm2 \n\t"
+         "movq   %%mm0, %%mm1            \n\t"
+         "movq   %%mm2, %%mm3            \n\t"
+         "punpcklbw %%mm7, %%mm0         \n\t"
+         "punpcklbw %%mm7, %%mm2         \n\t"
+         "punpckhbw %%mm7, %%mm1         \n\t"
+         "punpckhbw %%mm7, %%mm3         \n\t"
+         "paddusw %%mm2, %%mm0           \n\t"
+         "paddusw %%mm3, %%mm1           \n\t"
+         "paddusw %%mm6, %%mm4           \n\t"
+         "paddusw %%mm6, %%mm5           \n\t"
+         "paddusw %%mm0, %%mm4           \n\t"
+         "paddusw %%mm1, %%mm5           \n\t"
+         "psrlw  $2, %%mm4               \n\t"
+         "psrlw  $2, %%mm5               \n\t"
+         "packuswb  %%mm5, %%mm4         \n\t"
+         "movq   %%mm4, (%2, %%"REG_a")  \n\t"
+         "add    %3, %%"REG_a"           \n\t"
+         "movq   (%1, %%"REG_a"), %%mm2  \n\t" // 0 <-> 2   1 <-> 3
+         "movq   1(%1, %%"REG_a"), %%mm4 \n\t"
+         "movq   %%mm2, %%mm3            \n\t"
+         "movq   %%mm4, %%mm5            \n\t"
+         "punpcklbw %%mm7, %%mm2         \n\t"
+         "punpcklbw %%mm7, %%mm4         \n\t"
+         "punpckhbw %%mm7, %%mm3         \n\t"
+         "punpckhbw %%mm7, %%mm5         \n\t"
+         "paddusw %%mm2, %%mm4           \n\t"
+         "paddusw %%mm3, %%mm5           \n\t"
+         "paddusw %%mm6, %%mm0           \n\t"
+         "paddusw %%mm6, %%mm1           \n\t"
+         "paddusw %%mm4, %%mm0           \n\t"
+         "paddusw %%mm5, %%mm1           \n\t"
+         "psrlw  $2, %%mm0               \n\t"
+         "psrlw  $2, %%mm1               \n\t"
+         "packuswb  %%mm1, %%mm0         \n\t"
+         "movq   %%mm0, (%2, %%"REG_a")  \n\t"
+         "add    %3, %%"REG_a"           \n\t"
+         "subl   $2, %0                  \n\t"
+         "jnz    1b                      \n\t"
+         :"+g"(h), "+S"(pixels)
+         :"D"(block), "r"((x86_reg)line_size)
+         :REG_a, "memory");
+ }
+ // avg_pixels
+ #ifndef NO_RND
+ // in case more speed is needed - unroling would certainly help
+ static void DEF(avg, pixels8)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
+ {
+     MOVQ_BFE(mm6);
+     JUMPALIGN();
+     do {
+         __asm__ volatile(
+              "movq  %0, %%mm0           \n\t"
+              "movq  %1, %%mm1           \n\t"
+              OP_AVG(%%mm0, %%mm1, %%mm2, %%mm6)
+              "movq  %%mm2, %0           \n\t"
+              :"+m"(*block)
+              :"m"(*pixels)
+              :"memory");
+         pixels += line_size;
+         block += line_size;
+     }
+     while (--h);
+ }
+ #endif /* NO_RND */
+ static void DEF(avg, pixels16)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
+ {
+     MOVQ_BFE(mm6);
+     JUMPALIGN();
+     do {
+         __asm__ volatile(
+              "movq  %0, %%mm0           \n\t"
+              "movq  %1, %%mm1           \n\t"
+              OP_AVG(%%mm0, %%mm1, %%mm2, %%mm6)
+              "movq  %%mm2, %0           \n\t"
+              "movq  8%0, %%mm0          \n\t"
+              "movq  8%1, %%mm1          \n\t"
+              OP_AVG(%%mm0, %%mm1, %%mm2, %%mm6)
+              "movq  %%mm2, 8%0          \n\t"
+              :"+m"(*block)
+              :"m"(*pixels)
+              :"memory");
+         pixels += line_size;
+         block += line_size;
+     }
+     while (--h);
+ }
+ // this routine is 'slightly' suboptimal but mostly unused
+ static void DEF(avg, pixels8_xy2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
+ {
+     MOVQ_ZERO(mm7);
+     SET_RND(mm6); // =2 for rnd  and  =1 for no_rnd version
+     __asm__ volatile(
+         "movq   (%1), %%mm0             \n\t"
+         "movq   1(%1), %%mm4            \n\t"
+         "movq   %%mm0, %%mm1            \n\t"
+         "movq   %%mm4, %%mm5            \n\t"
+         "punpcklbw %%mm7, %%mm0         \n\t"
+         "punpcklbw %%mm7, %%mm4         \n\t"
+         "punpckhbw %%mm7, %%mm1         \n\t"
+         "punpckhbw %%mm7, %%mm5         \n\t"
+         "paddusw %%mm0, %%mm4           \n\t"
+         "paddusw %%mm1, %%mm5           \n\t"
+         "xor    %%"REG_a", %%"REG_a"    \n\t"
+         "add    %3, %1                  \n\t"
+         ".p2align 3                     \n\t"
+         "1:                             \n\t"
+         "movq   (%1, %%"REG_a"), %%mm0  \n\t"
+         "movq   1(%1, %%"REG_a"), %%mm2 \n\t"
+         "movq   %%mm0, %%mm1            \n\t"
+         "movq   %%mm2, %%mm3            \n\t"
+         "punpcklbw %%mm7, %%mm0         \n\t"
+         "punpcklbw %%mm7, %%mm2         \n\t"
+         "punpckhbw %%mm7, %%mm1         \n\t"
+         "punpckhbw %%mm7, %%mm3         \n\t"
+         "paddusw %%mm2, %%mm0           \n\t"
+         "paddusw %%mm3, %%mm1           \n\t"
+         "paddusw %%mm6, %%mm4           \n\t"
+         "paddusw %%mm6, %%mm5           \n\t"
+         "paddusw %%mm0, %%mm4           \n\t"
+         "paddusw %%mm1, %%mm5           \n\t"
+         "psrlw  $2, %%mm4               \n\t"
+         "psrlw  $2, %%mm5               \n\t"
+                 "movq   (%2, %%"REG_a"), %%mm3  \n\t"
+         "packuswb  %%mm5, %%mm4         \n\t"
+                 "pcmpeqd %%mm2, %%mm2   \n\t"
+                 "paddb %%mm2, %%mm2     \n\t"
+                 OP_AVG(%%mm3, %%mm4, %%mm5, %%mm2)
+                 "movq   %%mm5, (%2, %%"REG_a")  \n\t"
+         "add    %3, %%"REG_a"                \n\t"
+         "movq   (%1, %%"REG_a"), %%mm2  \n\t" // 0 <-> 2   1 <-> 3
+         "movq   1(%1, %%"REG_a"), %%mm4 \n\t"
+         "movq   %%mm2, %%mm3            \n\t"
+         "movq   %%mm4, %%mm5            \n\t"
+         "punpcklbw %%mm7, %%mm2         \n\t"
+         "punpcklbw %%mm7, %%mm4         \n\t"
+         "punpckhbw %%mm7, %%mm3         \n\t"
+         "punpckhbw %%mm7, %%mm5         \n\t"
+         "paddusw %%mm2, %%mm4           \n\t"
+         "paddusw %%mm3, %%mm5           \n\t"
+         "paddusw %%mm6, %%mm0           \n\t"
+         "paddusw %%mm6, %%mm1           \n\t"
+         "paddusw %%mm4, %%mm0           \n\t"
+         "paddusw %%mm5, %%mm1           \n\t"
+         "psrlw  $2, %%mm0               \n\t"
+         "psrlw  $2, %%mm1               \n\t"
+                 "movq   (%2, %%"REG_a"), %%mm3  \n\t"
+         "packuswb  %%mm1, %%mm0         \n\t"
+                 "pcmpeqd %%mm2, %%mm2   \n\t"
+                 "paddb %%mm2, %%mm2     \n\t"
+                 OP_AVG(%%mm3, %%mm0, %%mm1, %%mm2)
+                 "movq   %%mm1, (%2, %%"REG_a")  \n\t"
+         "add    %3, %%"REG_a"           \n\t"
+         "subl   $2, %0                  \n\t"
+         "jnz    1b                      \n\t"
+         :"+g"(h), "+S"(pixels)
+         :"D"(block), "r"((x86_reg)line_size)
+         :REG_a, "memory");
+ }
+ //FIXME optimize
+ static void DEF(put, pixels16_xy2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h){
+     DEF(put, pixels8_xy2)(block  , pixels  , line_size, h);
+     DEF(put, pixels8_xy2)(block+8, pixels+8, line_size, h);
+ }
+ static void DEF(avg, pixels16_xy2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h){
+     DEF(avg, pixels8_xy2)(block  , pixels  , line_size, h);
+     DEF(avg, pixels8_xy2)(block+8, pixels+8, line_size, h);
+ }