;
; yuv420_rgb_neon.s
;

 GET hdr.ka_drawer

; yuv-rgb matrix conversion and display output functions for 32 bit
; colour depth displays.
;
; The colour space conversion equations are,
;
;   Ur  = KUr(u - 128)
;   Vb  = KVb(v - 128)
;   UVg = KUg(u - 128) + KVg(v - 128)
;   Yc  = KYc(y - 16)
;    r  = Yc + Ur
;    g  = Yc - UVg
;    b  = Yc + Vc
;
; Register and stack usage for both functions,
;
; on input to loops,
; v4 = dst1          even line screen address
; v5 = bytesperrow   vertical display step
; v6 = y1            even line luminance input address
; ip = y2            odd line luminance input address
; a3 = u             Cr chroma input address
; a4 = v             Cb chroma input address
; [sp+ 0] = dst_skip
; [sp+ 4] = yc_skip
; [sp+ 8] = uv_skip
; [sp+12] = width
; [sp+16] = height
; d0                 CUr, CVb, CUg, CVg
; d1                 reserved for u[4-7], v[4-7] as u8
; q1 (d2, d3)        CY0 as 4 x s32
; d4                 CYc as 4 x s16
; d5                 128 as 8 x u8
; q4-q5              reserved for Yc[0-7] as s32
; q6-q9              work registers
; q10-q15            reserved for UVg[0-7], Ur[0-7], Vb[0-7] as s32
;
; Notes:
; The input arrays are byte arrays and the screen memory is a word array.
; The routines assumes width is at least 16 bytes, and even (cf. uv planes).
;
dst_skip            EQU  0 ; + sp        (paint + 32)
yc_skip             EQU  4 ; + sp        (paint + 36)
uv_skip             EQU  8 ; + sp        (paint + 40)
yc_width            EQU 12 ; + sp        (paint + 28)
yc_height           EQU 16 ; + sp        (paint + 24)

  MACRO
  LoadConsts
  ldr       sl, [a2, #8]
  vld1.32   q0, [sl]!       ; CUr, CVb, CUg, CVg
  vmovn.i32 d0, q0
  ldmia     sl!, {a1, a2}
  vdup.32   q1, a1          ; CY0 (may be > 16 bit)
  vdup.16   d4, a2          ; CYc
  vmov.i8   d5, #128        ; 128
  MEND

  MACRO
  LoadUV1
  ; Note: load 8 (u, v) values, save the 4 last in d1 for later
  ; Double the 4 first in d16 (u) and d16(v)
  vld1.8    {d16}, [a3]!    ; u[0-7]
  vld1.8    {d1 }, [a4]!    ; v[0-7]
  vzip.u32  d16, d1         ; {u[0-3], v[0-3]}, {u[4-7], v[4-7]}
  vmov.u8   d18, d16        ; doubling
  vzip.u8   d16, d18        ; (u, v)[0-3] -> [0-7]
  MEND

  MACRO
  LoadUV2
  ; Note: get the 4 last (u, v) values saved in d1
  ; Double the 4 first in d16 (u) and d16(v)
  vmov.u8   d16, d1         ; {u[4-7], v[4-7]}
  vmov.u8   d18, d1         ; doubling
  vzip.u8   d16, d18        ; (u, v)[4-7] -> [0-7]
  MEND

  MACRO
  CalculateUV
  vsubl.u8  q8, d16, d5     ; u - 128
  vsubl.u8  q9, d18, d5     ; v - 128
  vmull.s16 q10, d16, d0[2] ; UVg[0-7] = CUg * (u - 128)
  vmull.s16 q11, d17, d0[2] ;
  vmlal.s16 q10, d18, d0[3] ;          + CVg * (v - 128)
  vmlal.s16 q11, d19, d0[3] ;
  vmull.s16 q12, d16, d0[0] ; Ur[0-7] = CUr * (u - 128)
  vmull.s16 q13, d17, d0[0] ;
  vmull.s16 q14, d18, d0[1] ; Vb[0-7] = CVb * (v - 128)
  vmull.s16 q15, d19, d0[1] ;
  MEND

  MACRO
  CalculateYC
  vmovl.u8  q4, d8
  vmull.s16 q5, d9, d4[0]   ; Yc[0-7] = CYc * y
  vmull.s16 q4, d8, d4[0]   ;
  vadd.s32  q5, q5, q1      ;         + CY0
  vadd.s32  q4, q4, q1      ;
  MEND

  MACRO
  CalculateRGB32 $dr, $dg, $db
  vadd.s32    q6, q4, q14   ; b[0-7] = Yc + Vb
  vadd.s32    q7, q5, q15   ;
  vqrshrn.s32 d12, q6, #10  ; b[0-7] -> s16
  vqrshrn.s32 d13, q7, #10  ;
  vqmovun.s16 $db, q6       ; b[0-7] -> [0, 255]

  vsub.s32    q6, q4, q10   ; g[0-7] = Yc - UVg
  vsub.s32    q7, q5, q11   ;
  vqrshrn.s32 d12, q6, #10  ; g[0-7] -> s16
  vqrshrn.s32 d13, q7, #10  ;
  vqmovun.s16 $dg, q6       ; g[0-7] -> [0, 255]

  vadd.s32    q6, q4, q12   ; r[0-7] = Yc + Ur
  vadd.s32    q7, q5, q13   ;
  vqrshrn.s32 d12, q6, #10  ; r[0-7] -> s16
  vqrshrn.s32 d13, q7, #10  ;
  vqmovun.s16 $dr, q6       ; r[0-7] -> [0, 255]
  MEND

  MACRO
  CalculateRGB16
  vadd.s32    q6, q4, q14   ; b[0-7] = Yc + Vb
  vadd.s32    q7, q5, q15   ;
  vqrshrun.s32 d18, q6, #2  ; b[0-7] -> u16 ( >> 10 - 8)
  vqrshrun.s32 d19, q7, #2  ;

  vsub.s32    q6, q4, q10   ; g[0-7] = Yc - UVg
  vsub.s32    q7, q5, q11   ;
  vqrshrun.s32 d16, q6, #2  ; g[0-7] -> u16 ( >> 10 - 8)
  vqrshrun.s32 d17, q7, #2  ;

  vadd.s32    q4, q4, q12   ; r[0-7] = Yc + Ur
  vadd.s32    q5, q5, q13   ;
  vqrshrun.s32 d14, q4, #2  ; r[0-7] -> u16 ( >> 10 - 8)
  vqrshrun.s32 d15, q5, #2  ;
  MEND

  AREA |A$$code|, CODE, READONLY

; ka_drawyuv420_z1_tbgr32_neon : 16m cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_tbgr32_neon
  ALIGN 32
ka_drawyuv420_z1_tbgr32_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

tbgr32_height_loop
  str   lr, [sp, #yc_height]
tbgr32_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB32 d16, d17, d18
  vmov.i8   d19, #0         ; t[0-7] = 0
  vst4.8    {d16, d17, d18, d19}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB32 d16, d17, d18
  vmov.i8   d19, #0         ; t[0-7] = 0
  vst4.8    {d16, d17, d18, d19}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB32 d16, d17, d18
  vmov.i8   d19, #0         ; t[0-7] = 0
  vst4.8    {d16, d17, d18, d19}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB32 d16, d17, d18
  vmov.i8   d19, #0         ; t[0-7] = 0
  vst4.8    {d16, d17, d18, d19}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   tbgr32_width_loop

  cmp   v3, #0
  ble   tbgr32_width0

tbgr32_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #2
  mov   v3, #16
  b     tbgr32_width_loop

tbgr32_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   tbgr32_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_abgr32_neon : 16m cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_abgr32_neon
  ALIGN 32
ka_drawyuv420_z1_abgr32_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

abgr32_height_loop
  str   lr, [sp, #yc_height]
abgr32_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB32 d16, d17, d18
  vmov.i8   d19, #255       ; t[0-7] = 255
  vst4.8    {d16, d17, d18, d19}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB32 d16, d17, d18
  vmov.i8   d19, #255       ; t[0-7] = 255
  vst4.8    {d16, d17, d18, d19}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB32 d16, d17, d18
  vmov.i8   d19, #255       ; t[0-7] = 255
  vst4.8    {d16, d17, d18, d19}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB32 d16, d17, d18
  vmov.i8   d19, #255       ; t[0-7] = 255
  vst4.8    {d16, d17, d18, d19}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   abgr32_width_loop

  cmp   v3, #0
  ble   abgr32_width0

abgr32_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #2
  mov   v3, #16
  b     abgr32_width_loop

abgr32_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   abgr32_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_trgb32_neon : 16m cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_trgb32_neon
  ALIGN 32
ka_drawyuv420_z1_trgb32_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

trgb32_height_loop
  str   lr, [sp, #yc_height]
trgb32_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB32 d18, d17, d16
  vmov.i8   d19, #0         ; t[0-7] = 0
  vst4.8    {d16, d17, d18, d19}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB32 d18, d17, d16
  vmov.i8   d19, #0         ; t[0-7] = 0
  vst4.8    {d16, d17, d18, d19}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB32 d18, d17, d16
  vmov.i8   d19, #0         ; t[0-7] = 0
  vst4.8    {d16, d17, d18, d19}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB32 d18, d17, d16
  vmov.i8   d19, #0         ; t[0-7] = 0
  vst4.8    {d16, d17, d18, d19}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   trgb32_width_loop

  cmp   v3, #0
  ble   trgb32_width0

trgb32_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #2
  mov   v3, #16
  b     trgb32_width_loop

trgb32_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   trgb32_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_argb32_neon : 16m cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_argb32_neon
  ALIGN 32
ka_drawyuv420_z1_argb32_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

argb32_height_loop
  str   lr, [sp, #yc_height]
argb32_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB32 d18, d17, d16
  vmov.i8   d19, #255       ; t[0-7] = 255
  vst4.8    {d16, d17, d18, d19}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB32 d18, d17, d16
  vmov.i8   d19, #255       ; t[0-7] = 255
  vst4.8    {d16, d17, d18, d19}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB32 d18, d17, d16
  vmov.i8   d19, #255       ; t[0-7] = 255
  vst4.8    {d16, d17, d18, d19}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB32 d18, d17, d16
  vmov.i8   d19, #255       ; t[0-7] = 255
  vst4.8    {d16, d17, d18, d19}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   argb32_width_loop

  cmp   v3, #0
  ble   argb32_width0

argb32_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #2
  mov   v3, #16
  b     argb32_width_loop

argb32_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   argb32_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_bgr16_neon : 64k cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_bgr16_neon
  ALIGN 32
ka_drawyuv420_z1_bgr16_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

bgr16_height_loop
  str   lr, [sp, #yc_height]
bgr16_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vsri.16   q9, q8, #5
  vsri.16   q9, q7, #11
  vst1.16   {q9}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vsri.16   q9, q8, #5
  vsri.16   q9, q7, #11
  vst1.16   {q9}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vsri.16   q9, q8, #5
  vsri.16   q9, q7, #11
  vst1.16   {q9}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vsri.16   q9, q8, #5
  vsri.16   q9, q7, #11
  vst1.16   {q9}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   bgr16_width_loop

  cmp   v3, #0
  ble   bgr16_width0

bgr16_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #1
  mov   v3, #16
  b     bgr16_width_loop

bgr16_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   bgr16_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_rgb16_neon : 64k cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_rgb16_neon
  ALIGN 32
ka_drawyuv420_z1_rgb16_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

rgb16_height_loop
  str   lr, [sp, #yc_height]
rgb16_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vsri.16   q7, q8, #5
  vsri.16   q7, q9, #11
  vst1.16   {q7}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vsri.16   q7, q8, #5
  vsri.16   q7, q9, #11
  vst1.16   {q7}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vsri.16   q7, q8, #5
  vsri.16   q7, q9, #11
  vst1.16   {q7}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vsri.16   q7, q8, #5
  vsri.16   q7, q9, #11
  vst1.16   {q7}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   rgb16_width_loop

  cmp   v3, #0
  ble   rgb16_width0

rgb16_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #1
  mov   v3, #16
  b     rgb16_width_loop

rgb16_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   rgb16_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_tbgr15_neon : 32k cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_tbgr15_neon
  ALIGN 32
ka_drawyuv420_z1_tbgr15_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

tbgr15_height_loop
  str   lr, [sp, #yc_height]
tbgr15_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q9, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q7, #11
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q9, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q7, #11
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q9, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q7, #11
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q9, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q7, #11
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   tbgr15_width_loop

  cmp   v3, #0
  ble   tbgr15_width0

tbgr15_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #1
  mov   v3, #16
  b     tbgr15_width_loop

tbgr15_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   tbgr15_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_abgr15_neon : 32k cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_abgr15_neon
  ALIGN 32
ka_drawyuv420_z1_abgr15_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

abgr15_height_loop
  str   lr, [sp, #yc_height]
abgr15_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q9, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q7, #11
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q9, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q7, #11
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q9, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q7, #11
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q9, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q7, #11
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   abgr15_width_loop

  cmp   v3, #0
  ble   abgr15_width0

abgr15_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #1
  mov   v3, #16
  b     abgr15_width_loop

abgr15_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   abgr15_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_trgb15_neon : 32k cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_trgb15_neon
  ALIGN 32
ka_drawyuv420_z1_trgb15_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

trgb15_height_loop
  str   lr, [sp, #yc_height]
trgb15_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q7, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q9, #11
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q7, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q9, #11
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q7, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q9, #11
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q7, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q9, #11
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   trgb15_width_loop

  cmp   v3, #0
  ble   trgb15_width0

trgb15_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #1
  mov   v3, #16
  b     trgb15_width_loop

trgb15_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   trgb15_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_argb15_neon : 32k cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_argb15_neon
  ALIGN 32
ka_drawyuv420_z1_argb15_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

argb15_height_loop
  str   lr, [sp, #yc_height]
argb15_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q7, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q9, #11
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q7, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q9, #11
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q7, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q9, #11
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q7, #1
  vsri.16   q6, q8, #6
  vsri.16   q6, q9, #11
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   argb15_width_loop

  cmp   v3, #0
  ble   argb15_width0

argb15_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #1
  mov   v3, #16
  b     argb15_width_loop

argb15_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   argb15_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_tbgr12_neon : 4k cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_tbgr12_neon
  ALIGN 32
ka_drawyuv420_z1_tbgr12_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

tbgr12_height_loop
  str   lr, [sp, #yc_height]
tbgr12_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q9, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q7, #12
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q9, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q7, #12
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q9, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q7, #12
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q9, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q7, #12
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   tbgr12_width_loop

  cmp   v3, #0
  ble   tbgr12_width0

tbgr12_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #1
  mov   v3, #16
  b     tbgr12_width_loop

tbgr12_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   tbgr12_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_abgr12_neon : 4k cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_abgr12_neon
  ALIGN 32
ka_drawyuv420_z1_abgr12_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

abgr12_height_loop
  str   lr, [sp, #yc_height]
abgr12_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q9, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q7, #12
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q9, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q7, #12
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q9, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q7, #12
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q9, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q7, #12
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   abgr12_width_loop

  cmp   v3, #0
  ble   abgr12_width0

abgr12_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #1
  mov   v3, #16
  b     abgr12_width_loop

abgr12_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   abgr12_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_trgb12_neon : 4k cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_trgb12_neon
  ALIGN 32
ka_drawyuv420_z1_trgb12_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

trgb12_height_loop
  str   lr, [sp, #yc_height]
trgb12_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q7, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q9, #12
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q7, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q9, #12
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q7, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q9, #12
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #0          ; t[0-7] = 0
  vsri.16   q6, q7, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q9, #12
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   trgb12_width_loop

  cmp   v3, #0
  ble   trgb12_width0

trgb12_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #1
  mov   v3, #16
  b     trgb12_width_loop

trgb12_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   trgb12_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

; ka_drawyuv420_z1_argb12_neon : 4k cols 100% zoom
; ----------------------
  EXPORT ka_drawyuv420_z1_argb12_neon
  ALIGN 32
ka_drawyuv420_z1_argb12_neon
  stmfd sp!, {v1-v6, sl, fp, ip, lr}
  sub   sp, sp, #20

  add   a2, a1, #drawer_yc_bpr
  ldmia a2!, {v3, v4, v5, lr} ; yc_bpr, dst1, dst_bpr, yc_height
  ldr   v6, [a1, #0]        ; y1 = frame->base[0]
  add   ip, v6, v3          ; y2 = y1 + yc_bpr
  ldmia a2!, {a3-v2}        ; yc_width, dst_skip, yc_skip, uv_skip
  add   v1, v1, v3          ; we handle two lines in one go
  add   a4, a4, v5          ; dst_skip += dst_bpr
  mov   v3, a3
  stmia sp, {a4-v3, lr}

  ldr   a3, [a1, #8]        ; u = frame->base[2]
  ldr   a4, [a1, #4]        ; v = frame->base[1]

  LoadConsts

argb12_height_loop
  str   lr, [sp, #yc_height]
argb12_width_loop
  LoadUV1

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q7, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q9, #12
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q7, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q9, #12
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  LoadUV2

  CalculateUV

  vld1.8    {d8}, [v6]!     ; y1[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q7, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q9, #12
  vst1.16   {q6}, [v4], v5

  vld1.8    {d8}, [ip]!     ; y2[0-7]
  CalculateYC

  CalculateRGB16
  vmov.i8   q6, #255        ; t[0-7] = 255
  vsri.16   q6, q7, #4
  vsri.16   q6, q8, #8
  vsri.16   q6, q9, #12
  vst1.16   {q6}, [v4]!
  sub   v4, v4, v5

  sub   v3, v3, #16         ; width - 16
  cmp   v3, #16
  bge   argb12_width_loop

  cmp   v3, #0
  ble   argb12_width0

argb12_width15
  ; move back a little so as to still load 16 values
  rsb   a1, v3, #16
  sub   a3, a3, a1, lsr #1
  sub   a4, a4, a1, lsr #1
  sub   v6, v6, a1
  sub   ip, ip, a1
  sub   v4, v4, a1, lsl #1
  mov   v3, #16
  b     argb12_width_loop

argb12_width0
  ldmia sp,{a2, v1, v2, v3, lr}
  add   a3, a3, v2          ; u += uv_skip
  add   a4, a4, v2          ; v += uv_skip
  add   v6, v6, v1          ; y1 += yc_skip
  add   ip, ip, v1          ; y2 += yc_skip
  add   v4, v4, a2          ; dst += dst_skip

  subs  lr, lr, #2          ; height--
  bgt   argb12_height_loop

  add   sp, sp, #20
  ldmfd sp!, {v1-v6, sl, fp, ip, pc}

  ALIGN 32
  END
