;
; Copyright 2012 The LibYuv Project Authors. All rights reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;

%ifdef __YASM_VERSION_ID__
%if __YASM_VERSION_ID__ < 01020000h
%error AVX2 is supported only by yasm 1.2.0 or later.
%endif
%endif
%include "x86inc.asm"

SECTION .text

; cglobal numeric constants are parameters, gpr regs, mm regs

; void YUY2ToYRow_SSE2(const uint8* src_yuy2, uint8* dst_y, int pix)

%macro YUY2TOYROW 2-3
cglobal %1ToYRow%3, 3, 3, 3, src_yuy2, dst_y, pix
%ifidn %1,YUY2
    pcmpeqb    m2, m2, m2        ; generate mask 0x00ff00ff
    psrlw      m2, m2, 8
%endif

    ALIGN      4
.convertloop:
    mov%2      m0, [src_yuy2q]
    mov%2      m1, [src_yuy2q + mmsize]
    lea        src_yuy2q, [src_yuy2q + mmsize * 2]
%ifidn %1,YUY2
    pand       m0, m0, m2   ; YUY2 even bytes are Y
    pand       m1, m1, m2
%else
    psrlw      m0, m0, 8    ; UYVY odd bytes are Y
    psrlw      m1, m1, 8
%endif
    packuswb   m0, m0, m1
%if cpuflag(AVX2)
    vpermq     m0, m0, 0xd8
%endif
    sub        pixd, mmsize
    mov%2      [dst_yq], m0
    lea        dst_yq, [dst_yq + mmsize]
    jg         .convertloop
    REP_RET
%endmacro

; TODO(fbarchard): Remove MMX.  Add SSSE3 pshufb version.
INIT_MMX MMX
YUY2TOYROW YUY2,a,
YUY2TOYROW YUY2,u,_Unaligned
YUY2TOYROW UYVY,a,
YUY2TOYROW UYVY,u,_Unaligned
INIT_XMM SSE2
YUY2TOYROW YUY2,a,
YUY2TOYROW YUY2,u,_Unaligned
YUY2TOYROW UYVY,a,
YUY2TOYROW UYVY,u,_Unaligned
INIT_YMM AVX2
YUY2TOYROW YUY2,a,
YUY2TOYROW UYVY,a,

; void SplitUVRow_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix)

%macro SplitUVRow 1-2
cglobal SplitUVRow%2, 4, 4, 5, src_uv, dst_u, dst_v, pix
    pcmpeqb    m4, m4, m4        ; generate mask 0x00ff00ff
    psrlw      m4, m4, 8
    sub        dst_vq, dst_uq

    ALIGN      4
.convertloop:
    mov%1      m0, [src_uvq]
    mov%1      m1, [src_uvq + mmsize]
    lea        src_uvq, [src_uvq + mmsize * 2]
    psrlw      m2, m0, 8         ; odd bytes
    psrlw      m3, m1, 8
    pand       m0, m0, m4        ; even bytes
    pand       m1, m1, m4
    packuswb   m0, m0, m1
    packuswb   m2, m2, m3
%if cpuflag(AVX2)
    vpermq     m0, m0, 0xd8
    vpermq     m2, m2, 0xd8
%endif
    mov%1      [dst_uq], m0
    mov%1      [dst_uq + dst_vq], m2
    lea        dst_uq, [dst_uq + mmsize]
    sub        pixd, mmsize
    jg         .convertloop
    REP_RET
%endmacro

INIT_MMX MMX
SplitUVRow a,
SplitUVRow u,_Unaligned
INIT_XMM SSE2
SplitUVRow a,
SplitUVRow u,_Unaligned
INIT_YMM AVX2
SplitUVRow a,

; void MergeUVRow_SSE2(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
;                      int width);

%macro MergeUVRow_ 1-2
cglobal MergeUVRow_%2, 4, 4, 3, src_u, src_v, dst_uv, pix
    sub        src_vq, src_uq

    ALIGN      4
.convertloop:
    mov%1      m0, [src_uq]
    mov%1      m1, [src_vq]
    lea        src_uq, [src_uq + mmsize]
    punpcklbw  m2, m0, m1       // first 8 UV pairs
    punpckhbw  m0, m0, m1       // next 8 UV pairs
%if cpuflag(AVX2)
    vperm2i128 m1, m2, m0, 0x20  // low 128 of ymm2 and low 128 of ymm0
    vperm2i128 m2, m2, m0, 0x31  // high 128 of ymm2 and high 128 of ymm0
    mov%1      [dst_uvq], m1
    mov%1      [dst_uvq + mmsize], m2
%else
    mov%1      [dst_uvq], m2
    mov%1      [dst_uvq + mmsize], m0
%endif
    lea        dst_uvq, [dst_uvq + mmsize * 2]
    sub        pixd, mmsize
    jg         .convertloop
    REP_RET
%endmacro

INIT_MMX MMX
MergeUVRow_ a,
MergeUVRow_ u,_Unaligned
INIT_XMM SSE2
MergeUVRow_ a,
MergeUVRow_ u,_Unaligned
INIT_YMM AVX2
MergeUVRow_ a,