; Copyright © 2019-2021, VideoLAN and dav1d authors ; Copyright © 2019, Two Orioles, LLC ; All rights reserved. ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions are met: ; ; 1. Redistributions of source code must retain the above copyright notice, this ; list of conditions and the following disclaimer. ; ; 2. Redistributions in binary form must reproduce the above copyright notice, ; this list of conditions and the following disclaimer in the documentation ; and/or other materials provided with the distribution. ; ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. %include "config.asm" %include "ext/x86/x86inc.asm" %include "x86/filmgrain_common.asm" SECTION_RODATA pw_1024: times 8 dw 1024 pb_27_17_17_27: db 27, 17, 17, 27 times 6 db 0, 32 pb_23_22_h: db 23, 22 times 7 db 0, 32 pb_27_17: times 8 db 27, 17 pb_17_27: times 8 db 17, 27 pb_23_22: times 8 db 23, 22 pb_mask: db 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0 rnd_next_upperbit_mask: dw 0x100B, 0x2016, 0x402C, 0x8058 byte_blend: db 0, 0, 0, 0xff, 0, 0, 0, 0 pw_seed_xor: times 2 dw 0xb524 times 2 dw 0x49d8 pb_1: times 4 db 1 hmul_bits: dw 32768, 16384, 8192, 4096 round: dw 2048, 1024, 512 mul_bits: dw 256, 128, 64, 32, 16 round_vals: dw 32, 64, 128, 256, 512 max: dw 255, 240, 235 min: dw 0, 16 pw_1: dw 1 %macro JMP_TABLE 2-* %xdefine %1_8bpc_%2_table %%table %xdefine %%base %1_8bpc_%2_table %xdefine %%prefix mangle(private_prefix %+ _%1_8bpc_%2) %%table: %rep %0 - 2 dd %%prefix %+ .ar%3 - %%base %rotate 1 %endrep %endmacro JMP_TABLE generate_grain_y, ssse3, 0, 1, 2, 3 JMP_TABLE generate_grain_uv_420, ssse3, 0, 1, 2, 3 JMP_TABLE generate_grain_uv_422, ssse3, 0, 1, 2, 3 JMP_TABLE generate_grain_uv_444, ssse3, 0, 1, 2, 3 SECTION .text %if ARCH_X86_32 %define PIC_ptr(a) base+a %else %define PIC_ptr(a) a %endif %macro SCRATCH 3 %if ARCH_X86_32 mova [rsp+%3*mmsize], m%1 %define m%2 [rsp+%3*mmsize] %else SWAP %1, %2 %endif %endmacro INIT_XMM ssse3 cglobal generate_grain_y_8bpc, 2, 7 + 2 * ARCH_X86_64, 16, buf, fg_data LEA r4, $$ %define base r4-$$ movq m1, [base+rnd_next_upperbit_mask] movq m4, [base+mul_bits] movq m7, [base+hmul_bits] mov r2d, [fg_dataq+FGData.grain_scale_shift] movd m2, [base+round+r2*2] movd m0, [fg_dataq+FGData.seed] mova m5, [base+pb_mask] pshuflw m2, m2, q0000 pshuflw m0, m0, q0000 mov r2, -73*82 sub bufq, r2 lea r3, [base+gaussian_sequence] .loop: pand m6, m0, m1 psrlw m3, m6, 10 por m6, m3 ; bits 0xf, 0x1e, 0x3c and 0x78 are set pmullw m6, m4 ; bits 0x0f00 are set pshufb m3, m5, m6 ; set 15th bit for next 4 seeds psllq m6, m3, 30 por m3, m6 psllq m6, m3, 15 por m3, m6 ; aggregate each bit into next seed's high bit pmulhuw m6, m0, m7 por m3, m6 ; 4 next output seeds pshuflw m0, m3, q3333 psrlw m3, 5 %if ARCH_X86_64 movq r6, m3 mov r8, r6 movzx r5d, r6w shr r6d, 16 shr r8, 32 movzx r7, r8w shr r8, 16 movd m6, [r3+r5*2] pinsrw m6, [r3+r6*2], 1 pinsrw m6, [r3+r7*2], 2 pinsrw m6, [r3+r8*2], 3 %else movd r6, m3 pshuflw m3, m3, q3232 movzx r5, r6w shr r6, 16 movd m6, [r3+r5*2] pinsrw m6, [r3+r6*2], 1 movd r6, m3 movzx r5, r6w shr r6, 16 pinsrw m6, [r3+r5*2], 2 pinsrw m6, [r3+r6*2], 3 %endif pmulhrsw m6, m2 packsswb m6, m6 movd [bufq+r2], m6 add r2, 4 jl .loop ; auto-regression code movsxd r2, [fg_dataq+FGData.ar_coeff_lag] movsxd r2, [base+generate_grain_y_8bpc_ssse3_table+r2*4] lea r2, [r2+base+generate_grain_y_8bpc_ssse3_table] jmp r2 .ar1: %if ARCH_X86_32 DEFINE_ARGS buf, fg_data, cf3, unused, val3, min, max %elif WIN64 DEFINE_ARGS shift, fg_data, cf3, buf, val3, min, max, x, val0 mov bufq, r0 %else DEFINE_ARGS buf, fg_data, cf3, shift, val3, min, max, x, val0 %endif movsx cf3d, byte [fg_dataq+FGData.ar_coeffs_y+3] movd m4, [fg_dataq+FGData.ar_coeffs_y] mov ecx, [fg_dataq+FGData.ar_coeff_shift] %if ARCH_X86_32 mov r1m, cf3d DEFINE_ARGS buf, shift, val3, min, max, x, val0 %define hd r0mp %define cf3d r1mp %elif WIN64 DEFINE_ARGS shift, h, cf3, buf, val3, min, max, x, val0 %else DEFINE_ARGS buf, h, cf3, shift, val3, min, max, x, val0 %endif pxor m6, m6 pcmpgtb m7, m6, m4 punpcklbw m4, m7 pinsrw m4, [base+pw_1], 3 pshufd m5, m4, q1111 pshufd m4, m4, q0000 movd m3, [base+round_vals+shiftq*2-12] ; rnd pshuflw m3, m3, q0000 sub bufq, 82*73-(82*3+79) mov hd, 70 mov mind, -128 mov maxd, 127 .y_loop_ar1: mov xq, -76 movsx val3d, byte [bufq+xq-1] .x_loop_ar1: movq m0, [bufq+xq-82-1] ; top/left pcmpgtb m7, m6, m0 punpcklbw m0, m7 psrldq m2, m0, 2 ; top psrldq m1, m0, 4 ; top/right punpcklwd m0, m2 punpcklwd m1, m3 pmaddwd m0, m4 pmaddwd m1, m5 paddd m0, m1 .x_loop_ar1_inner: movd val0d, m0 psrldq m0, 4 imul val3d, cf3d add val3d, val0d sar val3d, shiftb movsx val0d, byte [bufq+xq] add val3d, val0d cmp val3d, maxd cmovns val3d, maxd cmp val3d, mind cmovs val3d, mind mov byte [bufq+xq], val3b ; keep val3d in-place as left for next x iteration inc xq jz .x_loop_ar1_end test xq, 3 jnz .x_loop_ar1_inner jmp .x_loop_ar1 .x_loop_ar1_end: add bufq, 82 dec hd jg .y_loop_ar1 .ar0: RET .ar2: %if ARCH_X86_32 ALLOC_STACK -16*8 %endif DEFINE_ARGS buf, fg_data, shift mov shiftd, [fg_dataq+FGData.ar_coeff_shift] movd m6, [base+round_vals-12+shiftq*2] movd m7, [base+byte_blend+1] SCRATCH 7, 15, 7 movq m0, [fg_dataq+FGData.ar_coeffs_y+0] ; cf0-7 movd m1, [fg_dataq+FGData.ar_coeffs_y+8] ; cf8-11 pxor m7, m7 pshuflw m6, m6, q0000 punpcklwd m6, m7 pcmpgtb m4, m7, m0 pcmpgtb m5, m7, m1 punpcklbw m0, m4 punpcklbw m1, m5 DEFINE_ARGS buf, fg_data, h, x pshufd m4, m1, q0000 pshufd m5, m1, q1111 pshufd m3, m0, q3333 pshufd m2, m0, q2222 pshufd m1, m0, q1111 pshufd m0, m0, q0000 SCRATCH 0, 8, 0 SCRATCH 1, 9, 1 SCRATCH 2, 10, 2 SCRATCH 3, 11, 3 SCRATCH 4, 12, 4 SCRATCH 5, 13, 5 SCRATCH 6, 14, 6 sub bufq, 82*73-(82*3+79) mov hd, 70 .y_loop_ar2: mov xq, -76 .x_loop_ar2: movq m0, [bufq+xq-82*2-2] ; y=-2,x=[-2,+5] movhps m0, [bufq+xq-82*1-2] ; y=-1,x=[-2,+5] pcmpgtb m2, m7, m0 punpckhbw m1, m0, m2 punpcklbw m0, m2 psrldq m5, m0, 2 ; y=-2,x=[-1,+5] psrldq m3, m1, 2 ; y=-1,x=[-1,+5] psrldq m4, m1, 4 ; y=-1,x=[+0,+5] punpcklwd m2, m0, m5 punpcklwd m3, m4 pmaddwd m2, m8 pmaddwd m3, m11 paddd m2, m3 psrldq m4, m0, 4 ; y=-2,x=[+0,+5] psrldq m5, m0, 6 ; y=-2,x=[+1,+5] psrldq m6, m0, 8 ; y=-2,x=[+2,+5] punpcklwd m4, m5 punpcklwd m6, m1 psrldq m5, m1, 6 ; y=-1,x=[+1,+5] psrldq m1, m1, 8 ; y=-1,x=[+2,+5] punpcklwd m5, m1 pmaddwd m4, m9 pmaddwd m6, m10 pmaddwd m5, m12 paddd m4, m6 paddd m2, m5 paddd m2, m4 paddd m2, m14 movq m0, [bufq+xq-2] ; y=0,x=[-2,+5] .x_loop_ar2_inner: pcmpgtb m4, m7, m0 punpcklbw m1, m0, m4 pmaddwd m3, m1, m13 paddd m3, m2 psrldq m1, 4 ; y=0,x=0 psrldq m2, 4 ; shift top to next pixel psrad m3, [fg_dataq+FGData.ar_coeff_shift] ; don't packssdw since we only care about one value paddw m3, m1 packsswb m3, m3 pslldq m3, 2 pand m3, m15 pandn m1, m15, m0 por m0, m1, m3 psrldq m0, 1 ; overwrite 2 pixels, but that's ok movd [bufq+xq-1], m0 inc xq jz .x_loop_ar2_end test xq, 3 jnz .x_loop_ar2_inner jmp .x_loop_ar2 .x_loop_ar2_end: add bufq, 82 dec hd jg .y_loop_ar2 RET .ar3: DEFINE_ARGS buf, fg_data, shift %if ARCH_X86_32 ALLOC_STACK -16*14 %elif WIN64 SUB rsp, 16*6 %assign stack_size_padded (stack_size_padded+16*6) %assign stack_size (stack_size+16*6) %else ALLOC_STACK -16*6 %endif mov shiftd, [fg_dataq+FGData.ar_coeff_shift] movd m6, [base+round_vals-12+shiftq*2] movd m7, [base+byte_blend] movu m0, [fg_dataq+FGData.ar_coeffs_y+ 0] ; cf0-15 movq m2, [fg_dataq+FGData.ar_coeffs_y+16] ; cf16-23 pxor m3, m3 pcmpgtb m4, m3, m0 pcmpgtb m3, m2 pshuflw m6, m6, q0000 SCRATCH 6, 14, 12 SCRATCH 7, 15, 13 punpckhbw m1, m0, m4 punpcklbw m0, m4 punpcklbw m2, m3 pshufd m3, m0, q1111 pshufd m4, m0, q2222 pshufd m5, m0, q3333 pshufd m0, m0, q0000 mova [rsp+ 0*16], m0 mova [rsp+ 1*16], m3 mova [rsp+ 2*16], m4 mova [rsp+ 3*16], m5 pshufd m6, m1, q1111 pshufd m7, m1, q2222 pshufd m5, m1, q3333 pshufd m1, m1, q0000 pshufd m3, m2, q1111 psrldq m0, m2, 10 pinsrw m2, [base+pw_1], 5 pshufd m4, m2, q2222 pshufd m2, m2, q0000 pinsrw m0, [base+round_vals+shiftq*2-10], 3 mova [rsp+ 4*16], m1 mova [rsp+ 5*16], m6 SCRATCH 7, 8, 6 SCRATCH 5, 9, 7 SCRATCH 2, 10, 8 SCRATCH 3, 11, 9 SCRATCH 4, 12, 10 SCRATCH 0, 13, 11 DEFINE_ARGS buf, fg_data, h, x sub bufq, 82*73-(82*3+79) mov hd, 70 .y_loop_ar3: mov xq, -76 .x_loop_ar3: movu m0, [bufq+xq-82*3-3] ; y=-3,x=[-3,+12] pxor m3, m3 pcmpgtb m3, m0 punpckhbw m2, m0, m3 punpcklbw m0, m3 psrldq m5, m0, 2 psrldq m6, m0, 4 psrldq m7, m0, 6 punpcklwd m4, m0, m5 punpcklwd m6, m7 pmaddwd m4, [rsp+ 0*16] pmaddwd m6, [rsp+ 1*16] paddd m4, m6 movu m1, [bufq+xq-82*2-3] ; y=-2,x=[-3,+12] pxor m5, m5 pcmpgtb m5, m1 punpckhbw m3, m1, m5 punpcklbw m1, m5 palignr m6, m2, m0, 10 palignr m7, m2, m0, 12 psrldq m0, 8 punpcklwd m0, m6 punpcklwd m7, m1 pmaddwd m0, [rsp+ 2*16] pmaddwd m7, [rsp+ 3*16] paddd m0, m7 paddd m0, m4 psrldq m4, m1, 2 psrldq m5, m1, 4 psrldq m6, m1, 6 psrldq m7, m1, 8 punpcklwd m4, m5 punpcklwd m6, m7 pmaddwd m4, [rsp+ 4*16] pmaddwd m6, [rsp+ 5*16] paddd m4, m6 paddd m0, m4 movu m2, [bufq+xq-82*1-3] ; y=-1,x=[-3,+12] pxor m7, m7 pcmpgtb m7, m2 punpckhbw m5, m2, m7 punpcklbw m2, m7 palignr m7, m3, m1, 10 palignr m3, m1, 12 psrldq m1, m2, 2 punpcklwd m7, m3 punpcklwd m3, m2, m1 pmaddwd m7, m8 pmaddwd m3, m9 paddd m7, m3 paddd m0, m7 psrldq m6, m2, 4 psrldq m1, m2, 6 psrldq m3, m2, 8 palignr m4, m5, m2, 10 palignr m5, m5, m2, 12 punpcklwd m6, m1 punpcklwd m3, m4 punpcklwd m5, m14 pmaddwd m6, m10 pmaddwd m3, m11 pmaddwd m5, m12 paddd m0, m6 paddd m3, m5 paddd m0, m3 movq m1, [bufq+xq-3] ; y=0,x=[-3,+4] .x_loop_ar3_inner: pxor m5, m5 pcmpgtb m5, m1 punpcklbw m2, m1, m5 pmaddwd m2, m13 pshufd m3, m2, q1111 paddd m2, m3 ; left+cur paddd m2, m0 ; add top psrldq m0, 4 psrad m2, [fg_dataq+FGData.ar_coeff_shift] ; don't packssdw since we only care about one value packsswb m2, m2 pslldq m2, 3 pand m2, m15 pandn m3, m15, m1 por m1, m2, m3 movd [bufq+xq-3], m1 psrldq m1, 1 inc xq jz .x_loop_ar3_end test xq, 3 jnz .x_loop_ar3_inner jmp .x_loop_ar3 .x_loop_ar3_end: add bufq, 82 dec hd jg .y_loop_ar3 RET %macro generate_grain_uv_fn 3 ; ss_name, ss_x, ss_y INIT_XMM ssse3 cglobal generate_grain_uv_%1_8bpc, 1, 7 + 3 * ARCH_X86_64, 16, buf, bufy, fg_data, uv movifnidn r2, r2mp movifnidn r3, r3mp LEA r4, $$ %define base r4-$$ movq m1, [base+rnd_next_upperbit_mask] movq m4, [base+mul_bits] movq m7, [base+hmul_bits] mov r5d, [fg_dataq+FGData.grain_scale_shift] movd m6, [base+round+r5*2] mova m5, [base+pb_mask] movd m0, [fg_dataq+FGData.seed] movd m2, [base+pw_seed_xor+uvq*4] pxor m0, m2 pshuflw m6, m6, q0000 pshuflw m0, m0, q0000 lea r6, [base+gaussian_sequence] %if %2 %if ARCH_X86_64 mov r7d, 73-35*%3 %else mov r3mp, 73-35*%3 %endif add bufq, 44 .loop_y: mov r5, -44 .loop_x: %else mov r5, -82*73 sub bufq, r5 .loop: %endif pand m2, m0, m1 psrlw m3, m2, 10 por m2, m3 ; bits 0xf, 0x1e, 0x3c and 0x78 are set pmullw m2, m4 ; bits 0x0f00 are set pshufb m3, m5, m2 ; set 15th bit for next 4 seeds psllq m2, m3, 30 por m3, m2 psllq m2, m3, 15 por m3, m2 ; aggregate each bit into next seed's high bit pmulhuw m2, m0, m7 por m2, m3 ; 4 next output seeds pshuflw m0, m2, q3333 psrlw m2, 5 %if ARCH_X86_64 movd r9d, m2 pshuflw m2, m2, q3232 movzx r8, r9w shr r9, 16 movd m3, [r6+r8*2] pinsrw m3, [r6+r9*2], 1 movd r9d, m2 movzx r8, r9w shr r9, 16 pinsrw m3, [r6+r8*2], 2 pinsrw m3, [r6+r9*2], 3 %else movd r2, m2 pshuflw m2, m2, q3232 movzx r1, r2w shr r2, 16 movd m3, [r6+r1*2] pinsrw m3, [r6+r2*2], 1 movd r2, m2 movzx r1, r2w shr r2, 16 pinsrw m3, [r6+r1*2], 2 pinsrw m3, [r6+r2*2], 3 %endif pmulhrsw m3, m6 packsswb m3, m3 movd [bufq+r5], m3 add r5, 4 %if %2 jl .loop_x add bufq, 82 %if ARCH_X86_64 dec r7d %else dec r3mp %endif jg .loop_y %else jl .loop %endif %if ARCH_X86_32 mov r2, r2mp %endif ; auto-regression code movsxd r5, [fg_dataq+FGData.ar_coeff_lag] movsxd r5, [base+generate_grain_uv_%1_8bpc_ssse3_table+r5*4] lea r5, [r5+base+generate_grain_uv_%1_8bpc_ssse3_table] jmp r5 .ar0: DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift movifnidn bufyq, bufymp %if ARCH_X86_32 ALLOC_STACK -2*16 %endif imul uvd, 28 mov shiftd, [fg_dataq+FGData.ar_coeff_shift] movd m5, [fg_dataq+FGData.ar_coeffs_uv+uvq] movd m4, [base+hmul_bits+shiftq*2] DEFINE_ARGS buf, bufy, h, x pxor m0, m0 pcmpgtb m0, m5 punpcklbw m5, m0 movd m7, [base+pb_1] %if %2 movd m6, [base+hmul_bits+2+%3*2] %endif pshuflw m5, m5, q0000 pshuflw m4, m4, q0000 pshufd m7, m7, q0000 %if %2 pshuflw m6, m6, q0000 %endif punpcklqdq m5, m5 punpcklqdq m4, m4 %if %2 punpcklqdq m6, m6 %endif pcmpeqw m1, m1 pslldq m1, 12>>%2 SCRATCH 1, 8, 0 SCRATCH 4, 9, 1 %if %2 sub bufq, 82*(73-35*%3)+82-(82*3+41) %else sub bufq, 82*70-3 %endif add bufyq, 3+82*3 mov hd, 70-35*%3 .y_loop_ar0: xor xd, xd .x_loop_ar0: ; first 32 pixels %if %2 movu m1, [bufyq+xq*2] %if %3 movu m2, [bufyq+xq*2+82] %endif movu m3, [bufyq+xq*2+16] %if %3 movu m4, [bufyq+xq*2+82+16] %endif pmaddubsw m0, m7, m1 %if %3 pmaddubsw m1, m7, m2 %endif pmaddubsw m2, m7, m3 %if %3 pmaddubsw m3, m7, m4 paddw m0, m1 paddw m2, m3 %endif pmulhrsw m0, m6 pmulhrsw m2, m6 %else movu m0, [bufyq+xq] pxor m6, m6 pcmpgtb m6, m0 punpckhbw m2, m0, m6 punpcklbw m0, m6 %endif pmullw m0, m5 pmullw m2, m5 pmulhrsw m0, m9 pmulhrsw m2, m9 movu m1, [bufq+xq] pxor m4, m4 pcmpgtb m4, m1 punpckhbw m3, m1, m4 %if %2 punpcklbw m1, m4 paddw m2, m3 paddw m0, m1 %else punpcklbw m6, m1, m4 paddw m2, m3 paddw m0, m6 %endif packsswb m0, m2 %if %2 movu [bufq+xq], m0 add xd, 16 cmp xd, 32 jl .x_loop_ar0 ; last 6/12 pixels movu m1, [bufyq+xq*(1+%2)] %if %3 movu m2, [bufyq+xq*2+82] %endif pmaddubsw m0, m7, m1 %if %3 pmaddubsw m1, m7, m2 paddw m0, m1 %endif pmulhrsw m0, m6 pmullw m0, m5 pmulhrsw m0, m9 movq m1, [bufq+xq] pxor m4, m4 pcmpgtb m4, m1 punpcklbw m2, m1, m4 paddw m0, m2 packsswb m0, m0 pandn m2, m8, m0 pand m1, m8 por m2, m1 movq [bufq+xq], m2 %else add xd, 16 cmp xd, 80 je .y_loop_final_ar0 movu [bufq+xq-16], m0 jmp .x_loop_ar0 .y_loop_final_ar0: pandn m2, m8, m0 pand m1, m8 por m2, m1 movu [bufq+xq-16], m2 %endif add bufq, 82 add bufyq, 82<<%3 dec hd jg .y_loop_ar0 RET .ar1: %if ARCH_X86_32 RESET_STACK_STATE %endif DEFINE_ARGS buf, bufy, fg_data, uv, val3, cf3, min, max, x imul uvd, 28 movsx cf3d, byte [fg_dataq+FGData.ar_coeffs_uv+uvq+3] movd m4, [fg_dataq+FGData.ar_coeffs_uv+uvq-1] pinsrw m4, [fg_dataq+FGData.ar_coeffs_uv+uvq+4], 2 %if ARCH_X86_32 mov r3mp, cf3d DEFINE_ARGS buf, shift, fg_data, val3, min, max, x %elif WIN64 DEFINE_ARGS shift, bufy, fg_data, buf, val3, cf3, min, max, x mov bufq, r0 %else DEFINE_ARGS buf, bufy, fg_data, shift, val3, cf3, min, max, x %endif mov shiftd, [fg_dataq+FGData.ar_coeff_shift] movd m3, [base+round_vals+shiftq*2-12] ; rnd %if %2 movd m7, [base+pb_1] movd m6, [base+hmul_bits+2+%3*2] %endif psrldq m4, 1 %if ARCH_X86_32 DEFINE_ARGS buf, shift, val0, val3, min, max, x %elif WIN64 DEFINE_ARGS shift, bufy, h, buf, val3, cf3, min, max, x, val0 %else DEFINE_ARGS buf, bufy, h, shift, val3, cf3, min, max, x, val0 %endif pxor m5, m5 punpcklwd m3, m5 %if %2 punpcklwd m6, m6 %endif pcmpgtb m5, m4 punpcklbw m4, m5 pshufd m5, m4, q1111 pshufd m4, m4, q0000 pshufd m3, m3, q0000 %if %2 pshufd m7, m7, q0000 pshufd m6, m6, q0000 sub bufq, 82*(73-35*%3)+44-(82*3+41) %else sub bufq, 82*69+3 %endif %if ARCH_X86_32 add r1mp, 79+82*3 mov r0mp, 70-35*%3 %else add bufyq, 79+82*3 mov hd, 70-35*%3 %endif mov mind, -128 mov maxd, 127 .y_loop_ar1: mov xq, -(76>>%2) movsx val3d, byte [bufq+xq-1] .x_loop_ar1: %if %2 %if ARCH_X86_32 mov r2, r1mp movq m0, [r2+xq*2] %if %3 movq m1, [r2+xq*2+82] %endif %else movq m0, [bufyq+xq*2] %if %3 movq m1, [bufyq+xq*2+82] %endif %endif pmaddubsw m2, m7, m0 %if %3 pmaddubsw m0, m7, m1 paddw m2, m0 %endif pmulhrsw m2, m6 %else %if ARCH_X86_32 mov r2, r1mp movd m2, [r2+xq] %else movd m2, [bufyq+xq] %endif pxor m0, m0 pcmpgtb m0, m2 punpcklbw m2, m0 %endif movq m0, [bufq+xq-82-1] ; top/left pxor m1, m1 pcmpgtb m1, m0 punpcklbw m0, m1 psrldq m1, m0, 4 ; top/right punpcklwd m1, m2 psrldq m2, m0, 2 ; top punpcklwd m0, m2 pmaddwd m0, m4 pmaddwd m1, m5 paddd m0, m1 paddd m0, m3 .x_loop_ar1_inner: movd val0d, m0 psrldq m0, 4 %if ARCH_X86_32 imul val3d, r3mp %else imul val3d, cf3d %endif add val3d, val0d sar val3d, shiftb movsx val0d, byte [bufq+xq] add val3d, val0d cmp val3d, maxd cmovns val3d, maxd cmp val3d, mind cmovs val3d, mind mov byte [bufq+xq], val3b ; keep val3d in-place as left for next x iteration inc xq jz .x_loop_ar1_end test xq, 3 jnz .x_loop_ar1_inner jmp .x_loop_ar1 .x_loop_ar1_end: add bufq, 82 %if ARCH_X86_32 add r1mp, 82<<%3 dec r0mp %else add bufyq, 82<<%3 dec hd %endif jg .y_loop_ar1 RET .ar2: %if ARCH_X86_32 ALLOC_STACK -8*16 %endif DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift movifnidn bufyq, bufymp mov shiftd, [fg_dataq+FGData.ar_coeff_shift] imul uvd, 28 movd m7, [base+round_vals-12+shiftq*2] movu m0, [fg_dataq+FGData.ar_coeffs_uv+uvq+0] ; cf0-12 pxor m2, m2 pcmpgtb m2, m0 punpckhbw m1, m0, m2 punpcklbw m0, m2 pinsrw m1, [base+pw_1], 5 punpcklwd m7, m7 pshufd m7, m7, q0000 DEFINE_ARGS buf, bufy, fg_data, h, unused, x pshufd m4, m1, q0000 pshufd m5, m1, q1111 pshufd m6, m1, q2222 pshufd m3, m0, q3333 pshufd m2, m0, q2222 pshufd m1, m0, q1111 pshufd m0, m0, q0000 SCRATCH 0, 8, 0 SCRATCH 1, 9, 1 SCRATCH 2, 10, 2 SCRATCH 3, 11, 3 SCRATCH 4, 12, 4 SCRATCH 5, 13, 5 SCRATCH 6, 14, 6 SCRATCH 7, 15, 7 %if %2 movd m7, [base+hmul_bits+2+%3*2] movd m6, [base+pb_1] punpcklwd m7, m7 pshufd m6, m6, q0000 pshufd m7, m7, q0000 sub bufq, 82*(73-35*%3)+44-(82*3+41) %else sub bufq, 82*69+3 %endif add bufyq, 79+82*3 mov hd, 70-35*%3 .y_loop_ar2: mov xq, -(76>>%2) .x_loop_ar2: pxor m2, m2 movq m0, [bufq+xq-82*2-2] ; y=-2,x=[-2,+5] movhps m0, [bufq+xq-82*1-2] ; y=-1,x=[-2,+5] pcmpgtb m2, m0 punpckhbw m1, m0, m2 punpcklbw m0, m2 psrldq m5, m0, 2 ; y=-2,x=[-1,+5] psrldq m3, m1, 2 ; y=-1,x=[-1,+5] psrldq m4, m1, 4 ; y=-1,x=[+0,+5] punpcklwd m2, m0, m5 punpcklwd m3, m4 pmaddwd m2, m8 pmaddwd m3, m11 paddd m2, m3 psrldq m4, m0, 4 ; y=-2,x=[+0,+5] psrldq m5, m0, 6 ; y=-2,x=[+1,+5] psrldq m0, 8 ; y=-2,x=[+2,+5] punpcklwd m4, m5 punpcklwd m0, m1 psrldq m3, m1, 6 ; y=-1,x=[+1,+5] psrldq m1, m1, 8 ; y=-1,x=[+2,+5] punpcklwd m3, m1 pmaddwd m4, m9 pmaddwd m0, m10 pmaddwd m3, m12 paddd m4, m0 paddd m2, m3 paddd m2, m4 %if %2 movq m1, [bufyq+xq*2] %if %3 movq m3, [bufyq+xq*2+82] %endif pmaddubsw m0, m6, m1 %if %3 pmaddubsw m1, m6, m3 paddw m0, m1 %endif pmulhrsw m0, m7 %else movd m0, [bufyq+xq] pxor m1, m1 pcmpgtb m1, m0 punpcklbw m0, m1 %endif punpcklwd m0, m15 pmaddwd m0, m14 paddd m2, m0 movq m0, [bufq+xq-2] ; y=0,x=[-2,+5] pxor m4, m4 movd m5, [base+byte_blend+1] punpcklbw m5, m5 .x_loop_ar2_inner: pcmpgtb m1, m4, m0 punpcklbw m0, m1 pmaddwd m3, m0, m13 paddd m3, m2 psrldq m2, 4 ; shift top to next pixel psrad m3, [fg_dataq+FGData.ar_coeff_shift] pslldq m3, 4 pand m3, m5 paddw m0, m3 packsswb m0, m0 movd [bufq+xq-2], m0 psrldq m0, 1 inc xq jz .x_loop_ar2_end test xq, 3 jnz .x_loop_ar2_inner jmp .x_loop_ar2 .x_loop_ar2_end: add bufq, 82 add bufyq, 82<<%3 dec hd jg .y_loop_ar2 RET .ar3: %if ARCH_X86_32 RESET_STACK_STATE %endif DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift movifnidn bufyq, bufymp %if ARCH_X86_32 ALLOC_STACK -15*16 %else SUB rsp, 16*7 %assign stack_size_padded (stack_size_padded+16*7) %assign stack_size (stack_size+16*7) %endif mov shiftd, [fg_dataq+FGData.ar_coeff_shift] imul uvd, 28 movu m0, [fg_dataq+FGData.ar_coeffs_uv+uvq+ 0] ; cf0-15 pxor m3, m3 pcmpgtb m3, m0 punpckhbw m1, m0, m3 punpcklbw m0, m3 pshufd m2, m0, q1111 pshufd m3, m0, q2222 pshufd m4, m0, q3333 pshufd m0, m0, q0000 pshufd m5, m1, q1111 pshufd m6, m1, q2222 pshufd m7, m1, q3333 pshufd m1, m1, q0000 mova [rsp+ 0*16], m0 mova [rsp+ 1*16], m2 mova [rsp+ 2*16], m3 mova [rsp+ 3*16], m4 mova [rsp+ 4*16], m1 mova [rsp+ 5*16], m5 mova [rsp+ 6*16], m6 SCRATCH 7, 8, 7 movu m2, [fg_dataq+FGData.ar_coeffs_uv+uvq+16] ; cf16-24 [24=luma] pxor m4, m4 pcmpgtb m4, m2 punpckhbw m5, m2, m4 punpcklbw m2, m4 pshufd m4, m2, q3232 punpcklwd m3, m4, m5 pshuflw m5, m4, q3321 pshufd m4, m3, q0000 pshufd m3, m2, q1111 pshufd m2, m2, q0000 pinsrw m5, [base+round_vals+shiftq*2-10], 3 SCRATCH 2, 9, 8 SCRATCH 3, 10, 9 SCRATCH 4, 11, 10 SCRATCH 5, 12, 11 movd m2, [base+round_vals-12+shiftq*2] %if %2 movd m1, [base+pb_1] movd m3, [base+hmul_bits+2+%3*2] %endif pxor m0, m0 punpcklwd m2, m0 %if %2 punpcklwd m3, m3 %endif pshufd m2, m2, q0000 %if %2 pshufd m1, m1, q0000 pshufd m3, m3, q0000 SCRATCH 1, 13, 12 %endif SCRATCH 2, 14, 13 %if %2 SCRATCH 3, 15, 14 %endif DEFINE_ARGS buf, bufy, fg_data, h, unused, x %if %2 sub bufq, 82*(73-35*%3)+44-(82*3+41) %else sub bufq, 82*69+3 %endif add bufyq, 79+82*3 mov hd, 70-35*%3 .y_loop_ar3: mov xq, -(76>>%2) .x_loop_ar3: movu m0, [bufq+xq-82*3-3] ; y=-3,x=[-3,+12] pxor m4, m4 pcmpgtb m4, m0 punpckhbw m3, m0, m4 punpcklbw m0, m4 psrldq m5, m0, 2 psrldq m6, m0, 4 psrldq m7, m0, 6 punpcklwd m4, m0, m5 punpcklwd m6, m7 pmaddwd m4, [rsp+ 0*16] pmaddwd m6, [rsp+ 1*16] paddd m4, m6 palignr m2, m3, m0, 10 palignr m3, m0, 12 psrldq m0, 8 movu m1, [bufq+xq-82*2-3] ; y=-2,x=[-3,+12] pxor m6, m6 pcmpgtb m6, m1 punpckhbw m5, m1, m6 punpcklbw m1, m6 punpcklwd m0, m2 punpcklwd m3, m1 pmaddwd m0, [rsp+ 2*16] pmaddwd m3, [rsp+ 3*16] paddd m0, m3 paddd m0, m4 movu m2, [bufq+xq-82*1-3] ; y=-1,x=[-3,+12] pxor m7, m7 pcmpgtb m7, m2 punpckhbw m6, m2, m7 punpcklbw m2, m7 palignr m3, m5, m1, 10 palignr m5, m1, 12 psrldq m4, m2, 2 punpcklwd m3, m5 punpcklwd m5, m2, m4 pmaddwd m3, [rsp+ 6*16] pmaddwd m5, m8 paddd m3, m5 paddd m0, m3 psrldq m3, m1, 2 psrldq m4, m1, 4 psrldq m5, m1, 6 psrldq m1, 8 punpcklwd m3, m4 punpcklwd m5, m1 pmaddwd m3, [rsp+ 4*16] pmaddwd m5, [rsp+ 5*16] paddd m3, m5 paddd m0, m3 %if %2 movq m1, [bufyq+xq*2] %if %3 movq m3, [bufyq+xq*2+82] %endif pmaddubsw m7, m13, m1 %if %3 pmaddubsw m5, m13, m3 paddw m7, m5 %endif pmulhrsw m7, m15 %else movd m7, [bufyq+xq] pxor m1, m1 pcmpgtb m1, m7 punpcklbw m7, m1 %endif psrldq m1, m2, 4 psrldq m3, m2, 6 palignr m4, m6, m2, 10 palignr m6, m2, 12 psrldq m2, 8 punpcklwd m1, m3 punpcklwd m2, m4 punpcklwd m6, m7 pmaddwd m1, m9 pmaddwd m2, m10 pmaddwd m6, m11 paddd m1, m2 paddd m0, m6 paddd m0, m1 paddd m0, m14 movq m1, [bufq+xq-3] ; y=0,x=[-3,+4] pxor m4, m4 movd m5, [base+byte_blend] .x_loop_ar3_inner: pcmpgtb m2, m4, m1 punpcklbw m3, m1, m2 pmaddwd m2, m3, m12 pshufd m3, m2, q1111 paddd m2, m3 ; left+cur paddd m2, m0 ; add top psrldq m0, 4 psrad m2, [fg_dataq+FGData.ar_coeff_shift] ; don't packssdw, we only care about one value packsswb m2, m2 pandn m3, m5, m1 pslld m2, 24 pand m2, m5 por m1, m2, m3 movd [bufq+xq-3], m1 psrldq m1, 1 inc xq jz .x_loop_ar3_end test xq, 3 jnz .x_loop_ar3_inner jmp .x_loop_ar3 .x_loop_ar3_end: add bufq, 82 add bufyq, 82<<%3 dec hd jg .y_loop_ar3 RET %endmacro generate_grain_uv_fn 420, 1, 1 generate_grain_uv_fn 422, 1, 0 generate_grain_uv_fn 444, 0, 0 %macro vpgatherdw 5-6 ; dst, src, base, tmp_gpr[x2], tmp_xmm_reg %assign %%idx 0 %define %%tmp %2 %if %0 == 6 %define %%tmp %6 %endif %rep 4 %if %%idx == 0 movd %5 %+ d, %2 pshuflw %%tmp, %2, q3232 %else movd %5 %+ d, %%tmp %if %%idx == 2 punpckhqdq %%tmp, %%tmp %elif %%idx == 4 psrlq %%tmp, 32 %endif %endif movzx %4 %+ d, %5 %+ w shr %5 %+ d, 16 %if %%idx == 0 movd %1, [%3+%4] %else pinsrw %1, [%3+%4], %%idx + 0 %endif pinsrw %1, [%3+%5], %%idx + 1 %assign %%idx %%idx+2 %endrep %endmacro INIT_XMM ssse3 ; fgy_32x32xn(dst, src, stride, fg_data, w, scaling, grain_lut, h, sby) %if ARCH_X86_32 %if STACK_ALIGNMENT < mmsize cglobal fgy_32x32xn_8bpc, 0, 7, 16, 0 - (5 * mmsize + 16 * gprsize), \ dst, src, scaling, unused1, fg_data, picptr, unused2 ; copy stack arguments to new position post-alignment, so that we ; don't have to keep the old stack location in a separate register mov r0, r0m mov r1, r2m mov r2, r4m mov r3, r6m mov r4, r7m mov r5, r8m mov [rsp+5*mmsize+ 4*gprsize], r0 mov [rsp+5*mmsize+ 6*gprsize], r1 mov [rsp+5*mmsize+ 8*gprsize], r2 mov [rsp+5*mmsize+10*gprsize], r3 mov [rsp+5*mmsize+11*gprsize], r4 mov [rsp+5*mmsize+12*gprsize], r5 %else cglobal fgy_32x32xn_8bpc, 0, 7, 16, 5 * mmsize + 4 * gprsize, \ dst, src, scaling, unused1, fg_data, picptr, unused2 %endif mov srcq, srcm mov fg_dataq, r3m mov scalingq, r5m %if STACK_ALIGNMENT < mmsize %define r0m [rsp+5*mmsize+ 4*gprsize] %define r1m [rsp+5*mmsize+ 5*gprsize] %define r2m [rsp+5*mmsize+ 6*gprsize] %define r3m [rsp+5*mmsize+ 7*gprsize] %define r4m [rsp+5*mmsize+ 8*gprsize] %define r5m [rsp+5*mmsize+ 9*gprsize] %define r6m [rsp+5*mmsize+10*gprsize] %define r7m [rsp+5*mmsize+11*gprsize] %define r8m [rsp+5*mmsize+12*gprsize] %endif LEA r5, pb_mask %define base r5-pb_mask mov r5m, picptrq %else cglobal fgy_32x32xn_8bpc, 6, 15, 16, dst, src, stride, fg_data, w, scaling, grain_lut lea r7, [pb_mask] %define base r7-pb_mask %endif mov r6d, [fg_dataq+FGData.scaling_shift] movd m3, [base+mul_bits+r6*2-14] mov r6d, [fg_dataq+FGData.clip_to_restricted_range] movd m4, [base+max+r6*4] movd m5, [base+min+r6*2] punpcklwd m3, m3 punpcklwd m4, m4 punpcklwd m5, m5 pshufd m3, m3, q0000 pshufd m4, m4, q0000 pshufd m5, m5, q0000 SCRATCH 3, 11, 0 SCRATCH 4, 12, 1 SCRATCH 5, 13, 2 %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, overlap %else DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, unused, sby, see, overlap %endif mov sbyd, r8m mov overlapd, [fg_dataq+FGData.overlap_flag] ; left_overlap: overlap & 1 test overlapd, overlapd jz .no_vertical_overlap mova m6, [base+pw_1024] mova m7, [base+pb_27_17_17_27] SCRATCH 6, 14, 3 SCRATCH 7, 15, 4 test sbyd, sbyd jnz .vertical_overlap ; fall-through .no_vertical_overlap: mov r8m, overlapd %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, see, fg_data, picptr, unused imul seed, (173 << 24) | 37 %else imul seed, sbyd, (173 << 24) | 37 %endif add seed, (105 << 24) | 178 rol seed, 8 movzx seed, seew xor seed, [fg_dataq+FGData.seed] %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, see, w, picptr, src_bak mov r3m, seed mov wq, r4m %else DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \ unused1, unused2, see, unused3 %endif lea src_bakq, [srcq+wq] neg wq sub dstmp, srcq %if ARCH_X86_32 mov r1m, src_bakq mov r4m, wq DEFINE_ARGS dst, src, scaling, see, unused1, unused2, unused3 %endif .loop_x: %if ARCH_X86_32 mov seed, r3m %endif mov r6d, seed or seed, 0xEFF4 shr r6d, 1 test seeb, seeh lea seed, [r6+0x8000] cmovp seed, r6d ; updated seed %if ARCH_X86_32 mov r3m, seed DEFINE_ARGS dst, src, scaling, offy, unused1, unused2, offx mov offxd, offyd %else DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \ offx, offy, see, unused mov offyd, seed mov offxd, seed %endif ror offyd, 8 shr offxd, 12 and offyd, 0xf imul offyd, 164 lea offyq, [offyq+offxq*2+747] ; offy*stride+offx %if ARCH_X86_32 ; r0m=dst, r1m=src_bak, r2m=stride, r3m=see, r4m=w, r5m=picptr, ; r6m=grain_lut, r7m=h, r8m=overlap_v|h DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut %else DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \ h, offxy, see, unused %endif .loop_x_odd: mov hd, r7m mov grain_lutq, grain_lutmp .loop_y: ; src mova m0, [srcq] pxor m2, m2 punpckhbw m1, m0, m2 punpcklbw m0, m2 ; m0-1: src as word ; scaling[src] %if ARCH_X86_32 vpgatherdw m4, m0, scalingq-1, r0, r5, m3 vpgatherdw m5, m1, scalingq-1, r0, r5, m3 %else vpgatherdw m4, m0, scalingq-1, r12, r13, m3 vpgatherdw m5, m1, scalingq-1, r12, r13, m3 %endif REPX {psrlw x, 8}, m4, m5 ; grain = grain_lut[offy+y][offx+x] movu m3, [grain_lutq+offxyq] pcmpgtb m7, m2, m3 punpcklbw m2, m3, m7 punpckhbw m3, m7 ; noise = round2(scaling[src] * grain, scaling_shift) pmullw m2, m4 pmullw m3, m5 pmulhrsw m2, m11 pmulhrsw m3, m11 ; dst = clip_pixel(src, noise) paddw m0, m2 paddw m1, m3 pmaxsw m0, m13 pmaxsw m1, m13 pminsw m0, m12 pminsw m1, m12 packuswb m0, m1 movifnidn dstq, dstmp mova [dstq+srcq], m0 add srcq, r2mp add grain_lutq, 82 dec hd jg .loop_y %if ARCH_X86_32 add r4mp, 16 %else add wq, 16 %endif jge .end %if ARCH_X86_32 mov srcq, r1mp add srcq, r4mp %else lea srcq, [src_bakq+wq] %endif btc dword r8m, 2 jc .next_blk add offxyd, 16 test dword r8m, 2 ; r8m & 2 = have_top_overlap jz .loop_x_odd %if ARCH_X86_32 add dword [rsp+5*mmsize+1*gprsize], 16 %else add r11d, 16 ; top_offxyd %endif jnz .loop_x_odd_v_overlap .next_blk: test dword r8m, 1 jz .loop_x test dword r8m, 2 jnz .loop_x_hv_overlap ; horizontal overlap (without vertical overlap) .loop_x_h_overlap: %if ARCH_X86_32 ; r0m=dst, r1m=src_bak, r2m=stride, r3m=see, r4m=w, r5m=picptr, ; r6m=grain_lut, r7m=h, r8m=overlap_v|h DEFINE_ARGS dst, src, scaling, offxy, unused1, unused2, unused3 add offxyd, 16 ; left_offxyd mov [rsp+5*mmsize+0*gprsize], offxyd DEFINE_ARGS dst, src, scaling, see, unused1, unused2, unused3 mov seed, r3m %else DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \ offx, offy, see, left_offxy lea left_offxyd, [offyd+16] ; previous column's offy*stride+offx %endif mov r6d, seed or seed, 0xEFF4 shr r6d, 1 test seeb, seeh lea seed, [r6+0x8000] cmovp seed, r6d ; updated seed %if ARCH_X86_32 mov r3m, seed DEFINE_ARGS dst, src, scaling, offy, unused1, unused2, offx mov offxd, offyd %else mov offyd, seed mov offxd, seed %endif ror offyd, 8 shr offxd, 12 and offyd, 0xf imul offyd, 164 lea offyq, [offyq+offxq*2+747] ; offy*stride+offx %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut %else DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \ h, offxy, see, left_offxy %endif mov hd, r7m mov grain_lutq, grain_lutmp .loop_y_h_overlap: ; src mova m0, [srcq] pxor m2, m2 punpckhbw m1, m0, m2 punpcklbw m0, m2 ; m0-1: src as word ; scaling[src] %if ARCH_X86_32 vpgatherdw m4, m0, scalingq-1, r0, r5, m3 vpgatherdw m5, m1, scalingq-1, r0, r5, m3 %else vpgatherdw m4, m0, scalingq-1, r12, r13, m3 vpgatherdw m5, m1, scalingq-1, r12, r13, m3 %endif REPX {psrlw x, 8}, m4, m5 ; grain = grain_lut[offy+y][offx+x] movu m3, [grain_lutq+offxyq] %if ARCH_X86_32 mov r5, [rsp+5*mmsize+0*gprsize] movd m7, [grain_lutq+r5] %else movd m7, [grain_lutq+left_offxyq] %endif punpcklbw m7, m3 pmaddubsw m6, m15, m7 pmulhrsw m6, m14 packsswb m6, m6 shufps m6, m3, q3210 pcmpgtb m2, m6 punpcklbw m7, m6, m2 punpckhbw m6, m2 ; noise = round2(scaling[src] * grain, scaling_shift) pmullw m7, m4 pmullw m6, m5 pmulhrsw m7, m11 pmulhrsw m6, m11 ; dst = clip_pixel(src, noise) paddw m0, m7 paddw m1, m6 pmaxsw m0, m13 pmaxsw m1, m13 pminsw m0, m12 pminsw m1, m12 packuswb m0, m1 movifnidn dstq, dstmp mova [dstq+srcq], m0 add srcq, r2mp add grain_lutq, 82 dec hd jg .loop_y_h_overlap %if ARCH_X86_32 add r4mp, 16 %else add wq, 16 %endif jge .end %if ARCH_X86_32 mov srcq, r1m add srcq, r4m %else lea srcq, [src_bakq+wq] %endif xor dword r8m, 4 add offxyd, 16 ; since this half-block had left-overlap, the next does not test dword r8m, 2 ; have_top_overlap jz .loop_x_odd %if ARCH_X86_32 add dword [rsp+5*mmsize+1*gprsize], 16 %else add r11d, 16 ; top_offxyd %endif jmp .loop_x_odd_v_overlap .end: RET .vertical_overlap: %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, overlap %else DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, tmp, sby, see, overlap %endif or overlapd, 2 ; top_overlap: overlap & 2 mov r8m, overlapd movzx sbyd, sbyb %if ARCH_X86_32 imul r4, [fg_dataq+FGData.seed], 0x00010001 DEFINE_ARGS tmp, src, scaling, sby, see, picptr, unused %else imul seed, [fg_dataq+FGData.seed], 0x00010001 %endif imul tmpd, sbyd, 173 * 0x00010001 imul sbyd, 37 * 0x01000100 add tmpd, (105 << 16) | 188 add sbyd, (178 << 24) | (141 << 8) and tmpd, 0x00ff00ff and sbyd, 0xff00ff00 xor seed, tmpd %if ARCH_X86_32 xor sbyd, seed ; (cur_seed << 16) | top_seed DEFINE_ARGS dst, src, scaling, see, w, picptr, src_bak mov r3m, seed mov wq, r4m %else xor seed, sbyd ; (cur_seed << 16) | top_seed DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \ tmp, unused2, see, unused3 %endif lea src_bakq, [srcq+wq] neg wq sub dstmp, srcq %if ARCH_X86_32 mov r1m, src_bakq mov r4m, wq DEFINE_ARGS tmp, src, scaling, see, unused1, picptr, unused2 %endif .loop_x_v_overlap: %if ARCH_X86_32 mov seed, r3m %endif ; we assume from the block above that bits 8-15 of tmpd are zero'ed, ; because of the 'and tmpd, 0x00ff00ff' above mov r6d, seed or seed, 0xeff4eff4 test seeb, seeh setp tmpb ; parity of top_seed shr seed, 16 shl tmpd, 16 test seeb, seeh setp tmpb ; parity of cur_seed or r6d, 0x00010001 xor tmpd, r6d mov seed, tmpd ror seed, 1 ; updated (cur_seed << 16) | top_seed %if ARCH_X86_32 mov r3m, seed DEFINE_ARGS dst, src, scaling, offy, unused1, unused2, offx mov offxd, offyd %else DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \ offx, offy, see, unused, top_offxy mov offyd, seed mov offxd, seed %endif ror offyd, 8 ror offxd, 12 and offyd, 0xf000f and offxd, 0xf000f imul offyd, 164 ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy lea offyq, [offyq+offxq*2+0x10001*747+32*82] %if ARCH_X86_32 DEFINE_ARGS top_offxy, src, scaling, offxy, h, picptr, grain_lut %else DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \ h, offxy, see, unused, top_offxy %endif movzx top_offxyd, offxyw %if ARCH_X86_32 mov [rsp+5*mmsize+1*gprsize], top_offxyd DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut %endif shr offxyd, 16 .loop_x_odd_v_overlap: %if ARCH_X86_32 mov r5, r5m lea r5, [base+pb_27_17] mov [rsp+5*mmsize+12], r5 %else mova m8, [pb_27_17] %endif mov hd, r7m mov grain_lutq, grain_lutmp .loop_y_v_overlap: ; src mova m0, [srcq] pxor m2, m2 punpckhbw m1, m0, m2 punpcklbw m0, m2 ; m0-1: src as word ; scaling[src] %if ARCH_X86_32 vpgatherdw m4, m0, scalingq-1, r0, r5, m3 vpgatherdw m5, m1, scalingq-1, r0, r5, m3 %else vpgatherdw m4, m0, scalingq-1, r12, r13, m3 vpgatherdw m5, m1, scalingq-1, r12, r13, m3 %endif REPX {psrlw x, 8}, m4, m5 ; grain = grain_lut[offy+y][offx+x] movu m3, [grain_lutq+offxyq] %if ARCH_X86_32 mov r5, [rsp+5*mmsize+1*gprsize] movu m7, [grain_lutq+r5] %else movu m7, [grain_lutq+top_offxyq] %endif punpckhbw m6, m7, m3 punpcklbw m7, m3 %if ARCH_X86_32 mov r5, [rsp+5*mmsize+12] pmaddubsw m3, [r5], m6 pmaddubsw m6, [r5], m7 %else pmaddubsw m3, m8, m6 pmaddubsw m6, m8, m7 %endif pmulhrsw m3, m14 pmulhrsw m6, m14 packsswb m6, m3 pcmpgtb m7, m2, m6 punpcklbw m2, m6, m7 punpckhbw m6, m7 ; noise = round2(scaling[src] * grain, scaling_shift) pmullw m2, m4 pmullw m6, m5 pmulhrsw m2, m11 pmulhrsw m6, m11 ; dst = clip_pixel(src, noise) paddw m0, m2 paddw m1, m6 pmaxsw m0, m13 pmaxsw m1, m13 pminsw m0, m12 pminsw m1, m12 packuswb m0, m1 movifnidn dstq, dstmp mova [dstq+srcq], m0 %if ARCH_X86_32 add dword [rsp+5*mmsize+12], mmsize %else mova m8, [pb_17_27] %endif add srcq, r2mp add grain_lutq, 82 dec hw jz .end_y_v_overlap ; 2 lines get vertical overlap, then fall back to non-overlap code for ; remaining (up to) 30 lines btc hd, 16 jnc .loop_y_v_overlap jmp .loop_y .end_y_v_overlap: %if ARCH_X86_32 add r4mp, 16 %else add wq, 16 %endif jge .end_hv %if ARCH_X86_32 mov srcq, r1mp add srcq, r4mp %else lea srcq, [src_bakq+wq] %endif btc dword r8m, 2 jc .loop_x_hv_overlap add offxyd, 16 %if ARCH_X86_32 add dword [rsp+5*mmsize+1*gprsize], 16 %else add top_offxyd, 16 %endif jmp .loop_x_odd_v_overlap .loop_x_hv_overlap: %if ARCH_X86_32 mov r5, r5m lea r5, [base+pb_27_17] mov [rsp+5*mmsize+12], r5 DEFINE_ARGS tmp, src, scaling, offxy, w, picptr, src_bak mov r5, [rsp+5*mmsize+1*gprsize] mov r4, offxyd add r5, 16 add r4, 16 mov [rsp+5*mmsize+2*gprsize], r5 ; topleft_offxy mov [rsp+5*mmsize+0*gprsize], r4 ; left_offxy DEFINE_ARGS tmp, src, scaling, see, w, picptr, src_bak xor tmpd, tmpd mov seed, r3m %else mova m8, [pb_27_17] DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \ tmp, unused2, see, unused3 ; we assume from the block above that bits 8-15 of tmpd are zero'ed %endif mov r6d, seed or seed, 0xeff4eff4 test seeb, seeh setp tmpb ; parity of top_seed shr seed, 16 shl tmpd, 16 test seeb, seeh setp tmpb ; parity of cur_seed or r6d, 0x00010001 xor tmpd, r6d mov seed, tmpd ror seed, 1 ; updated (cur_seed << 16) | top_seed %if ARCH_X86_32 mov r3m, seed DEFINE_ARGS dst, src, scaling, offy, unused1, unused2, offx mov offxd, offyd %else DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \ offx, offy, see, left_offxy, top_offxy, topleft_offxy lea topleft_offxyq, [top_offxyq+16] lea left_offxyq, [offyq+16] mov offyd, seed mov offxd, seed %endif ror offyd, 8 ror offxd, 12 and offyd, 0xf000f and offxd, 0xf000f imul offyd, 164 ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy lea offyq, [offyq+offxq*2+0x10001*747+32*82] %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut movzx r5, offxyw ; top_offxy mov [rsp+5*mmsize+1*gprsize], r5 %else DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \ h, offxy, see, left_offxy, top_offxy, topleft_offxy movzx top_offxyd, offxyw %endif shr offxyd, 16 mov hd, r7m mov grain_lutq, grain_lutmp .loop_y_hv_overlap: ; grain = grain_lut[offy+y][offx+x] movu m3, [grain_lutq+offxyq] %if ARCH_X86_32 mov r5, [rsp+5*mmsize+1*gprsize] ; top_offxy mov r0, [rsp+5*mmsize+0*gprsize] ; left_offxy movu m6, [grain_lutq+r5] mov r5, [rsp+5*mmsize+2*gprsize] ; topleft_offxy movd m4, [grain_lutq+r0] movd m7, [grain_lutq+r5] %else movu m6, [grain_lutq+top_offxyq] movd m4, [grain_lutq+left_offxyq] movd m7, [grain_lutq+topleft_offxyq] %endif ; do h interpolation first (so top | top/left -> top, left | cur -> cur) punpcklbw m4, m3 punpcklbw m7, m6 pmaddubsw m2, m15, m4 pmaddubsw m4, m15, m7 pmulhrsw m2, m14 pmulhrsw m4, m14 packsswb m2, m2 packsswb m4, m4 shufps m2, m3, q3210 shufps m4, m6, q3210 ; followed by v interpolation (top | cur -> cur) punpcklbw m3, m4, m2 punpckhbw m4, m2 %if ARCH_X86_32 mov r5, [rsp+5*mmsize+12] pmaddubsw m7, [r5], m4 pmaddubsw m4, [r5], m3 %else pmaddubsw m7, m8, m4 pmaddubsw m4, m8, m3 %endif pmulhrsw m7, m14 pmulhrsw m4, m14 packsswb m4, m7 pxor m2, m2 pcmpgtb m7, m2, m4 punpcklbw m3, m4, m7 punpckhbw m4, m7 ; src mova m0, [srcq] punpckhbw m1, m0, m2 punpcklbw m0, m2 ; m0-1: src as word ; scaling[src] %if ARCH_X86_32 vpgatherdw m5, m0, scalingq-1, r0, r5, m7 vpgatherdw m6, m1, scalingq-1, r0, r5, m7 %else vpgatherdw m5, m0, scalingq-1, r13, r14, m7 vpgatherdw m6, m1, scalingq-1, r13, r14, m7 %endif REPX {psrlw x, 8}, m5, m6 ; noise = round2(scaling[src] * grain, scaling_shift) pmullw m3, m5 pmullw m4, m6 pmulhrsw m3, m11 pmulhrsw m4, m11 ; dst = clip_pixel(src, noise) paddw m0, m3 paddw m1, m4 pmaxsw m0, m13 pmaxsw m1, m13 pminsw m0, m12 pminsw m1, m12 packuswb m0, m1 movifnidn dstq, dstmp mova [dstq+srcq], m0 %if ARCH_X86_32 add dword [rsp+5*mmsize+12], mmsize %else mova m8, [pb_17_27] %endif add srcq, r2mp add grain_lutq, 82 dec hw jz .end_y_hv_overlap ; 2 lines get vertical overlap, then fall back to non-overlap code for ; remaining (up to) 30 lines btc hd, 16 jnc .loop_y_hv_overlap jmp .loop_y_h_overlap .end_y_hv_overlap: %if ARCH_X86_32 add r4mp, 16 %else add wq, 16 %endif jge .end_hv %if ARCH_X86_32 mov srcq, r1m add srcq, r4m %else lea srcq, [src_bakq+wq] %endif xor dword r8m, 4 add offxyd, 16 %if ARCH_X86_32 add dword [rsp+5*mmsize+1*gprsize], 16 %else add top_offxyd, 16 %endif jmp .loop_x_odd_v_overlap .end_hv: RET %macro FGUV_FN 3 ; name, ss_hor, ss_ver INIT_XMM ssse3 %if ARCH_X86_32 ; fguv_32x32xn_i420_ssse3(dst, src, stride, fg_data, w, scaling, grain_lut, h, ; sby, luma, lstride, uv_pl, is_id) %if STACK_ALIGNMENT < mmsize DECLARE_ARG 0, 1, 2, 3, 4, 5, 6, 7, 8 cglobal fguv_32x32xn_i%1_8bpc, 0, 7, 8, 0 - (7 * mmsize + (13 + 3) * gprsize), \ tmp, src, scaling, h, fg_data, picptr, unused mov r0, r0m mov r1, r2m mov r2, r4m mov r3, r6m mov r4, r7m mov [rsp+7*mmsize+3*gprsize], r0 mov [rsp+7*mmsize+5*gprsize], r1 mov [rsp+7*mmsize+7*gprsize], r2 mov [rsp+7*mmsize+9*gprsize], r3 mov [rsp+7*mmsize+10*gprsize], r4 mov r0, r8m mov r1, r9m mov r2, r10m mov r4, r11m mov r3, r12m mov [rsp+7*mmsize+11*gprsize], r0 mov [rsp+7*mmsize+12*gprsize], r1 mov [rsp+7*mmsize+13*gprsize], r2 mov [rsp+7*mmsize+14*gprsize], r4 %else cglobal fguv_32x32xn_i%1_8bpc, 0, 7, 8, 7 * mmsize + (4) * gprsize, \ tmp, src, scaling, h, fg_data, picptr, unused %endif mov srcq, srcm mov fg_dataq, r3m mov scalingq, r5m %if STACK_ALIGNMENT < mmsize %define r0m [rsp+7*mmsize+ 3*gprsize] %define r1m [rsp+7*mmsize+ 4*gprsize] %define r2m [rsp+7*mmsize+ 5*gprsize] %define r3m [rsp+7*mmsize+ 6*gprsize] %define r4m [rsp+7*mmsize+ 7*gprsize] %define r5m [rsp+7*mmsize+ 8*gprsize] %define r6m [rsp+7*mmsize+ 9*gprsize] %define r7m [rsp+7*mmsize+10*gprsize] %define r8m [rsp+7*mmsize+11*gprsize] %define r9m [rsp+7*mmsize+12*gprsize] %define r10m [rsp+7*mmsize+13*gprsize] %define r11m [rsp+7*mmsize+14*gprsize] %define r12m [rsp+7*mmsize+15*gprsize] %endif LEA r5, pb_mask %define base r5-pb_mask mov r5m, r5 %else cglobal fguv_32x32xn_i%1_8bpc, 6, 15, 16, dst, src, stride, fg_data, w, scaling, \ grain_lut, tmp, sby, luma, lstride, uv_pl, is_id lea r8, [pb_mask] %define base r8-pb_mask %endif mov r6d, [fg_dataq+FGData.scaling_shift] movd m3, [base+mul_bits+r6*2-14] mov r6d, [fg_dataq+FGData.clip_to_restricted_range] lea tmpd, [r6d*2] %if ARCH_X86_32 && STACK_ALIGNMENT < mmsize test r3, r3 %else cmp dword r12m, 0 ; is_idm %endif movd m5, [base+min+r6*2] cmovne r6d, tmpd movd m4, [base+max+r6*2] punpcklwd m3, m3 punpcklwd m5, m5 punpcklwd m4, m4 pshufd m3, m3, q0000 pshufd m5, m5, q0000 pshufd m4, m4, q0000 SCRATCH 3, 11, 0 SCRATCH 4, 12, 1 SCRATCH 5, 13, 2 cmp byte [fg_dataq+FGData.chroma_scaling_from_luma], 0 jne .csfl %macro %%FGUV_32x32xN_LOOP 3 ; not-csfl, ss_hor, ss_ver %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, overlap %else DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, unused, sby, see, overlap %endif %if %1 mov r6d, dword r11m movd m0, [fg_dataq+FGData.uv_mult+r6*4] movd m1, [fg_dataq+FGData.uv_luma_mult+r6*4] punpcklbw m6, m1, m0 movd m7, [fg_dataq+FGData.uv_offset+r6*4] punpcklwd m6, m6 punpcklwd m7, m7 pshufd m6, m6, q0000 pshufd m7, m7, q0000 SCRATCH 6, 14, 3 SCRATCH 7, 15, 4 %endif mov sbyd, r8m mov overlapd, [fg_dataq+FGData.overlap_flag] ; left_overlap: overlap & 1 test overlapd, overlapd jz %%no_vertical_overlap %if ARCH_X86_32 %if %2 mova m1, [base+pb_23_22_h] %else mova m1, [base+pb_27_17_17_27] %endif mova m0, [base+pw_1024] %else %if %2 mova m1, [pb_23_22_h] %else mova m1, [pb_27_17_17_27] %endif mova m0, [pw_1024] %endif SCRATCH 0, 8, 5 SCRATCH 1, 9, 6 test sbyd, sbyd jnz %%vertical_overlap ; fall-through %%no_vertical_overlap: mov r8m, overlapd %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, see, fg_data, picptr, overlap imul seed, (173 << 24) | 37 %else imul seed, sbyd, (173 << 24) | 37 %endif add seed, (105 << 24) | 178 rol seed, 8 movzx seed, seew xor seed, [fg_dataq+FGData.seed] %if ARCH_X86_32 mov r3m, seed DEFINE_ARGS luma, src, scaling, see, w, picptr, src_bak %define luma_bakq lumaq mov wq, r4m %if %3 shl r10mp, 1 %endif %else DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ unused2, unused3, see, overlap, unused4, src_bak, lstride, luma_bak mov lstrideq, r10mp %endif mov lumaq, r9mp lea src_bakq, [srcq+wq] lea luma_bakq, [lumaq+wq*(1+%2)] neg wq sub r0mp, srcq %if ARCH_X86_32 mov r1m, src_bakq mov r11m, luma_bakq mov r4m, wq DEFINE_ARGS tmp, src, scaling, see, unused1, picptr, unused2 %else mov r11mp, src_bakq mov r12mp, strideq %endif %%loop_x: %if ARCH_X86_32 mov seed, r3m %endif mov r6d, seed or seed, 0xEFF4 shr r6d, 1 test seeb, seeh lea seed, [r6+0x8000] cmovp seed, r6d ; updated seed %if ARCH_X86_32 mov r3m, seed DEFINE_ARGS dst, src, scaling, offy, w, picptr, offx mov offxd, offyd %else DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ offx, offy, see, overlap, unused1, unused2, lstride mov offyd, seed mov offxd, seed %endif ror offyd, 8 shr offxd, 12 and offyd, 0xf imul offyd, 164>>%3 lea offyq, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+(3+(6>>%2))] ; offy*stride+offx %if ARCH_X86_32 DEFINE_ARGS luma, src, scaling, offxy, h, picptr, grain_lut %else DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ h, offxy, see, overlap, unused1, unused2, lstride, luma_bak %endif %%loop_x_odd: mov hd, r7m mov grain_lutq, grain_lutmp %%loop_y: ; src %if ARCH_X86_32 mov lumaq, r9mp %endif %if %2 mova m4, [lumaq+ 0] mova m6, [lumaq+16] mova m0, [srcq] %if ARCH_X86_32 add lumaq, r10mp mov r9mp, lumaq mov r5, r5m movd m7, [base+pb_1] %else movd m7, [pb_1] %endif pshufd m7, m7, q0000 pxor m2, m2 pmaddubsw m4, m7 pmaddubsw m6, m7 pavgw m4, m2 pavgw m6, m2 %else mova m4, [lumaq] mova m0, [srcq] %if ARCH_X86_32 add lumaq, r10mp mov r9mp, lumaq %endif pxor m2, m2 %endif %if %1 %if %2 packuswb m4, m6 ; luma %endif punpckhbw m6, m4, m0 punpcklbw m4, m0 ; { luma, chroma } pmaddubsw m6, m14 pmaddubsw m4, m14 psraw m6, 6 psraw m4, 6 paddw m6, m15 paddw m4, m15 packuswb m4, m6 ; pack+unpack = clip punpckhbw m6, m4, m2 punpcklbw m4, m2 %elif %2 == 0 punpckhbw m6, m4, m2 punpcklbw m4, m2 %endif ; scaling[luma_src] %if ARCH_X86_32 vpgatherdw m7, m4, scalingq-1, r0, r5 vpgatherdw m5, m6, scalingq-1, r0, r5 %else vpgatherdw m7, m4, scalingq-1, r12, r2 vpgatherdw m5, m6, scalingq-1, r12, r2 %endif REPX {psrlw x, 8}, m7, m5 ; unpack chroma_source punpckhbw m1, m0, m2 punpcklbw m0, m2 ; m0-1: src as word ; grain = grain_lut[offy+y][offx+x] movu m3, [grain_lutq+offxyq+ 0] pcmpgtb m6, m2, m3 punpcklbw m2, m3, m6 punpckhbw m3, m6 ; noise = round2(scaling[luma_src] * grain, scaling_shift) pmullw m2, m7 pmullw m3, m5 pmulhrsw m2, m11 pmulhrsw m3, m11 %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut %endif ; dst = clip_pixel(src, noise) paddw m0, m2 paddw m1, m3 pmaxsw m0, m13 pmaxsw m1, m13 pminsw m0, m12 pminsw m1, m12 packuswb m0, m1 movifnidn dstq, dstmp mova [dstq+srcq], m0 %if ARCH_X86_32 add srcq, r2mp ; we already incremented lumaq above %else add srcq, r12mp %if %3 lea lumaq, [lumaq+lstrideq*2] %else add lumaq, lstrideq %endif %endif add grain_lutq, 82 dec hw jg %%loop_y %if ARCH_X86_32 DEFINE_ARGS luma, src, scaling, offxy, w, picptr, grain_lut mov wq, r4m %endif add wq, 16 jge %%end %if ARCH_X86_32 mov srcq, r1mp mov lumaq, r11mp %else mov srcq, r11mp %endif lea lumaq, [luma_bakq+wq*(1+%2)] add srcq, wq %if ARCH_X86_32 mov r4m, wq mov r9m, lumaq %endif %if %2 == 0 ; adjust top_offxy %if ARCH_X86_32 add dword [rsp+7*mmsize+1*gprsize], 16 %else add r11d, 16 %endif add offxyd, 16 btc dword r8m, 2 jc %%loop_x_even test dword r8m, 2 jz %%loop_x_odd jmp %%loop_x_odd_v_overlap %%loop_x_even: %endif test dword r8m, 1 jz %%loop_x ; r8m = sbym test dword r8m, 2 jne %%loop_x_hv_overlap ; horizontal overlap (without vertical overlap) %%loop_x_h_overlap: %if ARCH_X86_32 %if %2 lea r6, [offxyd+16] mov [rsp+7*mmsize+0*gprsize], r6 %else mov [rsp+7*mmsize+0*gprsize], offxyd %endif DEFINE_ARGS luma, src, scaling, see, w, picptr, grain_lut mov seed, r3m %else DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ offx, offy, see, left_offxy, unused1, unused2, lstride %if %2 lea left_offxyd, [offyd+16] ; previous column's offy*stride+offx %else mov left_offxyd, offyd %endif %endif mov r6d, seed or seed, 0xEFF4 shr r6d, 1 test seeb, seeh lea seed, [r6+0x8000] cmovp seed, r6d ; updated seed %if ARCH_X86_32 mov r3m, seed DEFINE_ARGS luma, src, scaling, offy, w, picptr, offx mov offxd, offyd %else DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ offx, offy, see, left_offxy, unused1, unused2, lstride mov offyd, seed mov offxd, seed %endif ror offyd, 8 shr offxd, 12 and offyd, 0xf imul offyd, 164>>%3 lea offyq, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+3+(6>>%2)] ; offy*stride+offx %if ARCH_X86_32 DEFINE_ARGS luma, src, scaling, offxy, h, picptr, grain_lut %else DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ h, offxy, see, left_offxy, unused1, unused2, lstride, luma_bak %endif mov hd, r7m mov grain_lutq, grain_lutmp %%loop_y_h_overlap: ; src %if ARCH_X86_32 mov lumaq, r9mp %endif %if %2 mova m4, [lumaq+ 0] mova m6, [lumaq+16] mova m0, [srcq] %if ARCH_X86_32 add lumaq, r10mp mov r9mp, lumaq mov r5, r5m movd m7, [base+pb_1] %else movd m7, [pb_1] %endif pshufd m7, m7, q0000 pxor m2, m2 pmaddubsw m4, m7 pmaddubsw m6, m7 pavgw m4, m2 pavgw m6, m2 %else mova m4, [lumaq] mova m0, [srcq] %if ARCH_X86_32 add lumaq, r10mp mov r9mp, lumaq %endif pxor m2, m2 %endif %if %1 %if %2 packuswb m4, m6 ; luma %endif punpckhbw m6, m4, m0 punpcklbw m4, m0 ; { luma, chroma } pmaddubsw m6, m14 pmaddubsw m4, m14 psraw m6, 6 psraw m4, 6 paddw m6, m15 paddw m4, m15 packuswb m4, m6 ; pack+unpack = clip punpckhbw m6, m4, m2 punpcklbw m4, m2 %elif %2 == 0 punpckhbw m6, m4, m2 punpcklbw m4, m2 %endif ; scaling[luma_src] %if ARCH_X86_32 vpgatherdw m7, m4, scalingq-1, r0, r5 vpgatherdw m5, m6, scalingq-1, r0, r5 %else vpgatherdw m7, m4, scalingq-1, r12, r2 vpgatherdw m5, m6, scalingq-1, r12, r2 %endif REPX {psrlw x, 8}, m7, m5 ; unpack chroma_source punpckhbw m1, m0, m2 punpcklbw m0, m2 ; m0-1: src as word ; grain = grain_lut[offy+y][offx+x] movu m4, [grain_lutq+offxyq+ 0] %if ARCH_X86_32 mov r0, [rsp+7*mmsize+0*gprsize] movd m2, [grain_lutq+r0+ 0] %else movd m2, [grain_lutq+left_offxyq+ 0] %endif punpcklbw m2, m4 pmaddubsw m3, m9, m2 pmulhrsw m3, m8 packsswb m3, m3 shufps m3, m4, q3210 pxor m4, m4 pcmpgtb m4, m3 punpcklbw m2, m3, m4 punpckhbw m3, m4 ; noise = round2(scaling[luma_src] * grain, scaling_shift) pmullw m2, m7 pmullw m3, m5 pmulhrsw m2, m11 pmulhrsw m3, m11 %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut %endif ; dst = clip_pixel(src, noise) paddw m0, m2 paddw m1, m3 pmaxsw m0, m13 pmaxsw m1, m13 pminsw m0, m12 pminsw m1, m12 packuswb m0, m1 movifnidn dstq, dstmp mova [dstq+srcq], m0 %if ARCH_X86_32 add srcq, r2mp ; lumaq has already been incremented above %else add srcq, r12mp %if %3 lea lumaq, [lumaq+lstrideq*2] %else add lumaq, lstrideq %endif %endif add grain_lutq, 82 dec hw jg %%loop_y_h_overlap %if ARCH_X86_32 DEFINE_ARGS luma, src, scaling, offxy, w, picptr, grain_lut mov wq, r4m %endif add wq, 16 jge %%end %if ARCH_X86_32 mov srcq, r1mp mov lumaq, r11mp %else mov srcq, r11mp %endif lea lumaq, [luma_bakq+wq*(1+%2)] add srcq, wq %if ARCH_X86_32 mov r4m, wq mov r9m, lumaq %endif %if %2 == 0 xor dword r8m, 4 ; adjust top_offxyd %if ARCH_X86_32 add dword [rsp+7*mmsize+1*gprsize], 16 %else add r11d, 16 %endif add offxyd, 16 %endif ; r8m = sbym test dword r8m, 2 %if %2 jne %%loop_x_hv_overlap jmp %%loop_x_h_overlap %else jne %%loop_x_odd_v_overlap jmp %%loop_x_odd %endif %%end: RET %%vertical_overlap: %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, overlap %else DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, tmp, sby, see, overlap %endif or overlapd, 2 ; top_overlap: overlap & 2 mov r8m, overlapd movzx sbyd, sbyb %if ARCH_X86_32 imul r4, [fg_dataq+FGData.seed], 0x00010001 DEFINE_ARGS tmp, src, scaling, sby, see, picptr, unused %else imul seed, [fg_dataq+FGData.seed], 0x00010001 %endif imul tmpd, sbyd, 173 * 0x00010001 imul sbyd, 37 * 0x01000100 add tmpd, (105 << 16) | 188 add sbyd, (178 << 24) | (141 << 8) and tmpd, 0x00ff00ff and sbyd, 0xff00ff00 xor seed, tmpd %if ARCH_X86_32 xor sbyd, seed ; (cur_seed << 16) | top_seed DEFINE_ARGS luma, src, scaling, see, w, picptr, src_bak mov r3m, seed mov wq, r4m %if %3 shl r10mp, 1 %endif %else xor seed, sbyd ; (cur_seed << 16) | top_seed DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ tmp, unused2, see, overlap, unused3, src_bak, lstride, luma_bak mov lstrideq, r10mp %endif mov lumaq, r9mp lea src_bakq, [srcq+wq] lea luma_bakq, [lumaq+wq*(1+%2)] neg wq sub r0mp, srcq %if ARCH_X86_32 mov r1m, src_bakq mov r11m, luma_bakq mov r4m, wq DEFINE_ARGS tmp, src, scaling, see, unused1, picptr, unused2 %else mov r11mp, src_bakq mov r12mp, strideq %endif %%loop_x_v_overlap: %if ARCH_X86_32 mov seed, r3m xor tmpd, tmpd %endif ; we assume from the block above that bits 8-15 of tmpd are zero'ed mov r6d, seed or seed, 0xeff4eff4 test seeb, seeh setp tmpb ; parity of top_seed shr seed, 16 shl tmpd, 16 test seeb, seeh setp tmpb ; parity of cur_seed or r6d, 0x00010001 xor tmpd, r6d mov seed, tmpd ror seed, 1 ; updated (cur_seed << 16) | top_seed %if ARCH_X86_32 mov r3m, seed DEFINE_ARGS dst, src, scaling, offy, h, picptr, offx mov offxd, offyd %else DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ offx, offy, see, overlap, top_offxy, unused, lstride mov offxd, seed mov offyd, seed %endif ror offyd, 8 ror offxd, 12 and offyd, 0xf000f and offxd, 0xf000f imul offyd, 164>>%3 ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy lea offyq, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82] %if ARCH_X86_32 DEFINE_ARGS tmp, src, scaling, offxy, h, picptr, top_offxy %else DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ h, offxy, see, overlap, top_offxy, unused, lstride, luma_bak %endif movzx top_offxyd, offxyw shr offxyd, 16 %if ARCH_X86_32 mov [rsp+7*mmsize+1*gprsize], top_offxyd DEFINE_ARGS luma, src, scaling, offxy, h, picptr, grain_lut %endif %%loop_x_odd_v_overlap: mov hd, r7m mov grain_lutq, grain_lutmp %if ARCH_X86_32 mov r5, r5m %endif %if %3 mova m1, [PIC_ptr(pb_23_22)] %else mova m1, [PIC_ptr(pb_27_17)] %endif %%loop_y_v_overlap: %if ARCH_X86_32 mov lumaq, r9mp %endif %if %2 mova m4, [lumaq+ 0] mova m6, [lumaq+16] mova m0, [srcq] %if ARCH_X86_32 add lumaq, r10mp mov r9mp, lumaq mov r5, r5m movd m7, [base+pb_1] %else movd m7, [pb_1] %endif pshufd m7, m7, q0000 pxor m2, m2 pmaddubsw m4, m7 pmaddubsw m6, m7 pavgw m4, m2 pavgw m6, m2 %else mova m4, [lumaq] mova m0, [srcq] %if ARCH_X86_32 add lumaq, r10mp mov r9mp, lumaq %endif pxor m2, m2 %endif %if %1 %if %2 packuswb m4, m6 ; luma %endif punpckhbw m6, m4, m0 punpcklbw m4, m0 ; { luma, chroma } pmaddubsw m6, m14 pmaddubsw m4, m14 psraw m6, 6 psraw m4, 6 paddw m6, m15 paddw m4, m15 packuswb m4, m6 ; pack+unpack = clip punpckhbw m6, m4, m2 punpcklbw m4, m2 %elif %2 == 0 punpckhbw m6, m4, m2 punpcklbw m4, m2 %endif ; scaling[luma_src] %if ARCH_X86_32 vpgatherdw m7, m4, scalingq-1, r0, r5 vpgatherdw m5, m6, scalingq-1, r0, r5 %else vpgatherdw m7, m4, scalingq-1, r12, r2 vpgatherdw m5, m6, scalingq-1, r12, r2 %endif REPX {psrlw x, 8}, m7, m5 ; grain = grain_lut[offy+y][offx+x] movu m3, [grain_lutq+offxyq] %if ARCH_X86_32 mov r0, [rsp+7*mmsize+1*gprsize] movu m4, [grain_lutq+r0] %else movu m4, [grain_lutq+top_offxyq] %endif punpckhbw m6, m4, m3 punpcklbw m4, m3 pmaddubsw m2, m1, m6 pmaddubsw m3, m1, m4 pmulhrsw m2, m8 pmulhrsw m3, m8 packsswb m3, m2 pxor m6, m6 pcmpgtb m6, m3 punpcklbw m2, m3, m6 punpckhbw m3, m6 ; noise = round2(scaling[luma_src] * grain, scaling_shift) pmullw m2, m7 pmullw m3, m5 pmulhrsw m2, m11 pmulhrsw m3, m11 ; unpack chroma_source pxor m4, m4 punpckhbw m6, m0, m4 punpcklbw m0, m4 ; m0-1: src as word %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut %endif ; dst = clip_pixel(src, noise) paddw m0, m2 paddw m6, m3 pmaxsw m0, m13 pmaxsw m6, m13 pminsw m0, m12 pminsw m6, m12 packuswb m0, m6 movifnidn dstq, dstmp mova [dstq+srcq], m0 dec hw je %%end_y_v_overlap %if ARCH_X86_32 add srcq, r2mp ; lumaq has already been incremented above %else add srcq, r12mp %if %3 lea lumaq, [lumaq+lstrideq*2] %else add lumaq, lstrideq %endif %endif add grain_lutq, 82 %if %3 == 0 btc hd, 16 %if ARCH_X86_32 mov r5, r5m %endif mova m1, [PIC_ptr(pb_17_27)] jnc %%loop_y_v_overlap %endif jmp %%loop_y %%end_y_v_overlap: %if ARCH_X86_32 DEFINE_ARGS luma, src, scaling, offxy, w, picptr, grain_lut mov wq, r4m %endif add wq, 16 jge %%end_hv %if ARCH_X86_32 mov srcq, r1mp mov lumaq, r11mp %else mov srcq, r11mp %endif lea lumaq, [luma_bakq+wq*(1+%2)] add srcq, wq %if ARCH_X86_32 mov r4m, wq mov r9m, lumaq %endif %if %2 ; since fg_dataq.overlap is guaranteed to be set, we never jump ; back to .loop_x_v_overlap, and instead always fall-through to ; h+v overlap %else %if ARCH_X86_32 add dword [rsp+7*mmsize+1*gprsize], 16 %else add top_offxyd, 16 %endif add offxyd, 16 btc dword r8m, 2 jnc %%loop_x_odd_v_overlap %endif %%loop_x_hv_overlap: %if ARCH_X86_32 DEFINE_ARGS tmp, src, scaling, offxy, w, picptr, unused mov r6, [rsp+7*mmsize+1*gprsize] %if %2 lea r0, [r3d+16] add r6, 16 mov [rsp+7*mmsize+0*gprsize], r0 ; left_offxy %else mov [rsp+7*mmsize+0*gprsize], r3 ; left_offxy %endif mov [rsp+7*mmsize+2*gprsize], r6 ; topleft_offxy DEFINE_ARGS tmp, src, scaling, see, w, picptr, unused mov seed, r3m xor tmpd, tmpd %else DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ tmp, offxy, see, left_offxy, top_offxy, topleft_offxy, lstride %if %2 lea topleft_offxyq, [top_offxyq+16] lea left_offxyq, [offxyq+16] %else mov topleft_offxyq, top_offxyq mov left_offxyq, offxyq %endif ; we assume from the block above that bits 8-15 of tmpd are zero'ed %endif mov r6d, seed or seed, 0xeff4eff4 test seeb, seeh setp tmpb ; parity of top_seed shr seed, 16 shl tmpd, 16 test seeb, seeh setp tmpb ; parity of cur_seed or r6d, 0x00010001 xor tmpd, r6d mov seed, tmpd ror seed, 1 ; updated (cur_seed << 16) | top_seed %if ARCH_X86_32 mov r3m, seed DEFINE_ARGS tmp, src, scaling, offy, w, picptr, offx mov offxd, offyd %else DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ offx, offy, see, left_offxy, top_offxy, topleft_offxy, lstride mov offxd, seed mov offyd, seed %endif ror offyd, 8 ror offxd, 12 and offyd, 0xf000f and offxd, 0xf000f imul offyd, 164>>%3 ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy lea offyq, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82] %if ARCH_X86_32 DEFINE_ARGS top_offxy, src, scaling, offxy, h, picptr, grain_lut %else DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \ h, offxy, see, left_offxy, top_offxy, topleft_offxy, lstride, luma_bak %endif movzx top_offxyd, offxyw shr offxyd, 16 %if ARCH_X86_32 mov [rsp+7*mmsize+1*gprsize], top_offxyd %endif mov hd, r7m mov grain_lutq, grain_lutmp %if ARCH_X86_32 mov r5, r5m %endif %if %3 mova m3, [PIC_ptr(pb_23_22)] %else mova m3, [PIC_ptr(pb_27_17)] %endif %%loop_y_hv_overlap: ; grain = grain_lut[offy+y][offx+x] %if ARCH_X86_32 mov r0, [rsp+7*mmsize+2*gprsize] ; topleft_offxy mov r5, [rsp+7*mmsize+1*gprsize] ; top_offxy movd m1, [grain_lutq+r0] mov r0, [rsp+7*mmsize+0*gprsize] ; left_offxy %else movd m1, [grain_lutq+topleft_offxyq] %endif movu m2, [grain_lutq+offxyq] %if ARCH_X86_32 movu m6, [grain_lutq+r5] movd m4, [grain_lutq+r0] %else movu m6, [grain_lutq+top_offxyq] movd m4, [grain_lutq+left_offxyq] %endif ; do h interpolation first (so top | top/left -> top, left | cur -> cur) punpcklbw m1, m6 punpcklbw m4, m2 pmaddubsw m0, m9, m1 pmaddubsw m1, m9, m4 REPX {pmulhrsw x, m8}, m0, m1 packsswb m0, m1 shufps m4, m0, m2, q3232 shufps m0, m6, q3210 ; followed by v interpolation (top | cur -> cur) punpcklbw m2, m0, m4 punpckhbw m0, m4 pmaddubsw m4, m3, m0 pmaddubsw m1, m3, m2 pmulhrsw m4, m8 pmulhrsw m1, m8 packsswb m1, m4 ; src %if ARCH_X86_32 DEFINE_ARGS luma, src, scaling, offxy, w, picptr, grain_lut mov lumaq, r9mp %endif %if %2 mova m4, [lumaq+ 0] mova m6, [lumaq+16] mova m0, [srcq] %if ARCH_X86_32 add lumaq, r10mp mov r9mp, lumaq mov r5, r5m movd m7, [base+pb_1] %else movd m7, [pb_1] %endif pshufd m7, m7, q0000 pxor m2, m2 pmaddubsw m4, m7 pmaddubsw m6, m7 pavgw m4, m2 pavgw m6, m2 %else mova m4, [lumaq] mova m0, [srcq] %if ARCH_X86_32 add lumaq, r10mp mov r9mp, lumaq %endif pxor m2, m2 %endif %if %1 %if %2 packuswb m4, m6 ; luma %endif punpckhbw m6, m4, m0 punpcklbw m4, m0 ; { luma, chroma } pmaddubsw m6, m14 pmaddubsw m4, m14 psraw m6, 6 psraw m4, 6 paddw m6, m15 paddw m4, m15 packuswb m4, m6 ; pack+unpack = clip punpckhbw m6, m4, m2 punpcklbw m4, m2 %elif %2 == 0 punpckhbw m6, m4, m2 punpcklbw m4, m2 %endif ; scaling[src] %if ARCH_X86_32 vpgatherdw m7, m4, scalingq-1, r0, r5 vpgatherdw m5, m6, scalingq-1, r0, r5 %else %if %3 vpgatherdw m7, m4, scalingq-1, r2, r12 vpgatherdw m5, m6, scalingq-1, r2, r12 %else vpgatherdw m7, m4, scalingq-1, r2, r13 vpgatherdw m5, m6, scalingq-1, r2, r13 %endif %endif REPX {psrlw x, 8}, m7, m5 ; unpack grain pxor m4, m4 pcmpgtb m4, m1 punpcklbw m2, m1, m4 punpckhbw m1, m4 ; noise = round2(scaling[src] * grain, scaling_shift) pmullw m2, m7 pmullw m1, m5 pmulhrsw m2, m11 pmulhrsw m1, m11 %if ARCH_X86_32 DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut %endif ; unpack chroma source pxor m4, m4 punpckhbw m5, m0, m4 punpcklbw m0, m4 ; m0-1: src as word ; dst = clip_pixel(src, noise) paddw m0, m2 paddw m5, m1 pmaxsw m0, m13 pmaxsw m5, m13 pminsw m0, m12 pminsw m5, m12 packuswb m0, m5 movifnidn dstq, dstmp mova [dstq+srcq], m0 %if ARCH_X86_32 add srcq, r2mp ; lumaq has been adjusted above already %else add srcq, r12mp %if %3 lea lumaq, [lumaq+lstrideq*(1+%2)] %else add lumaq, r10mp %endif %endif add grain_lutq, 82 dec hw %if %3 jg %%loop_y_h_overlap %else jle %%end_y_hv_overlap %if ARCH_X86_32 mov r5, r5m %endif mova m3, [PIC_ptr(pb_17_27)] btc hd, 16 jnc %%loop_y_hv_overlap %if ARCH_X86_64 mov lstrideq, r10mp %endif jmp %%loop_y_h_overlap %%end_y_hv_overlap: %if ARCH_X86_64 mov lstrideq, r10mp %endif %endif %if ARCH_X86_32 DEFINE_ARGS luma, src, scaling, offxy, w, picptr, grain_lut mov wq, r4m %endif add wq, 16 jge %%end_hv %if ARCH_X86_32 mov srcq, r1mp mov lumaq, r11mp %else mov srcq, r11mp %endif lea lumaq, [luma_bakq+wq*(1+%2)] add srcq, wq %if ARCH_X86_32 mov r4m, wq mov r9m, lumaq %endif %if %2 jmp %%loop_x_hv_overlap %else %if ARCH_X86_32 add dword [rsp+7*mmsize+1*gprsize], 16 %else add top_offxyd, 16 %endif add offxyd, 16 xor dword r8m, 4 jmp %%loop_x_odd_v_overlap %endif %%end_hv: RET %endmacro %%FGUV_32x32xN_LOOP 1, %2, %3 .csfl: %%FGUV_32x32xN_LOOP 0, %2, %3 %endmacro FGUV_FN 420, 1, 1 %if STACK_ALIGNMENT < mmsize DECLARE_ARG 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 %endif FGUV_FN 422, 1, 0 %if STACK_ALIGNMENT < mmsize DECLARE_ARG 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 %endif FGUV_FN 444, 0, 0