; asmsyntax=nasm default rel global _diff_asm global diff_asm ; Alias para no volverme loco con los registros %define src rdi %define src2 rsi %define dst rdx %define cont rcx %define size r8 ; Algunos defines ultiles %define PIXEL_SIZE 4 %define SHIFT_VALUE 8 ; Potencia de 2 para hacer el calculo del promedio en enteros. %define DIV_VALUE 85 ; Multiplico por el valor sobre 3 para hacer un shift de 8bits a la derecha. (DIV * P)>>8 ; TODO: El valor SHIFT_VALUE NO PUEDE ser mayor a 8 o pierdo información en la multiplicacion ; Para ser mayor tengo que multiplicar y tener en cuenta la parte alta (pmulhw) ; Se que el valor máximo que va a haber que multiplicar es es (255*3), por eso puedo ; multiplicar hasta por 85 = (256/3), sin que supere 2^16, quedando en parte baja para pmullw. ; Mascaras y esas cosas section .data SHUFFLE_MASK: db 2,2,2,255,3,3,3,255,0,0,0,255,1,1,1,255 ; Mascara para realizar un shuffle para repetir los valores del diff DIVIDIR: dw DIV_VALUE,DIV_VALUE,DIV_VALUE,DIV_VALUE,0,0,0,0 ; Mascara para dividir con enteros usando shifts section .text ;void diff_asm ( ;unsigned char *src, unsigned char *src2, unsigned char *dst, int filas, int cols) _diff_asm: diff_asm: push rbp mov rbp, rsp ; Stack frame .calc_size: ; Calculo el tamaño de la imagen en bytes mov r9, dst ; Muevo el destino un rato para hacer el calculo del tamaño de la imagen mov rax, cont ; Cargo filas mul size ; Multiplico por las columnas xor dst, dst ; Limpio temportal mov dst, PIXEL_SIZE ; Multiplico temporal mul dst ; Multiplico por el tamaño del pixel mov size, rax ; Guardo el tamaño mov dst, r9 xor cont, cont ; Limpio el contador movdqu xmm3, [DIVIDIR] ; Cargo el valor para las divisiones para el promedio .loop: cmp cont, size ; Comparo tamaño con el contador jge .fin ; Si ya recorri la imagen voy al final pxor xmm1, xmm1 movdqu xmm0, [src] ; Cargo la imagen 1 => xmm0 = |B(P1)|G(P1)|R(P1)|A(P1)|B(P2)|G(P2)|......| movdqu xmm1, [src2] ; Cargo la imagen 2 => xmm1 = |B(P1)|G(P1)|R(P1)|A(P1)|B(P2)|G(P2)|......| .cuentas: ; Resto componente a componente de 4 pixeles de cada imagen psubb xmm1, xmm0 ; xmm1 = |B(img1_P1) - R(img2_P1)|G(Img1_P1) - Img2_P2|....| pabsb xmm0, xmm1 ; Almaceno en xmm0 el valor absoluto de la resta anterior ; TODO: Arreglar los comentarios por que estan desordenados los pixeles pxor xmm2, xmm2 movdqu xmm1, xmm0 ; Copio xmm0 a xmm1 punpckhbw xmm0, xmm2 ; Desempaqueto la parte alta => xmm0 = |B(P1)|G(P1)|R(P1)|A(P1)|B(P2)|G(P2)|R(P2)|A(P2)| punpcklbw xmm1, xmm2 ; Desempaqueto la parte baja => xmm1 = |B(P3)|G(P3)|R(P3)|A(P3)|B(P4)|G(P4)|R(P4)|A(P4)| ; Sumo horizontalmente los pixeles: phaddw xmm0, xmm1 ; xmm0 = |B(P1)+G(P1)|R(P1)+A(P1)|B(P2)+G(P2)|R(P2)+A(P2)|....| phaddw xmm0, xmm2 ; xmm0 = |B+G+R+A (P1)| B+G+R+A(P2) | B+G+R+A(P3) | B+G+R+A(P4)| 0x0 | 0x0 | 0x0 | 0x0 | .dividir: pmullw xmm0, xmm3 ; Multiplico y almaceno parte baja, no llego a usar la parte alta si SHIFT_VALUE < 8 psrlw xmm0, SHIFT_VALUE ; Divido por el valor .shuffle: packuswb xmm0, xmm2 ; xmm0 = |P1|P2|P3|P4|0x0|0x0|0x0|0x0|0x0|....| movdqu xmm2, [SHUFFLE_MASK] ; Cargo la mascara para shuffle pshufb xmm0, xmm2 ; Le hago un shuffle a xmm0 con los nuevos valores calculados .write: movdqu [dst], xmm0 ; Escribo en el destino .endLoop: ; TODO: Si el tamaño de la imagen no es multiplo de 4 acá va a sumar y hacer invalid read al llegar al final add src, PIXEL_SIZE * 4 ; Incremento 4 pixeles add src2, PIXEL_SIZE * 4 add dst, PIXEL_SIZE * 4 add cont, PIXEL_SIZE * 4 jmp .loop .fin: pop rbp ret