\subsection{Diferencia de Im\'agenes} \par El filtro de diferencias de imagenes consiste en leer dos im\'agenes de iguales dimensiones y computar las diferencias en lox p\'ixeles de ambas im\'agenes, analizando los componentes (B, G, R, A) de cada pixel de la primera imagen cotra los componentes del pixel equivalente de la segunda. En esta implementación de diff, luego de calcular la diferencia de cada componente se almacena en todos los canales el valor del canal con mayor diferencia.. \subsubsection{Implementaci\'on C} \label{sec:diff_imp1} Antes de iniciar el procesamiento se calcula el tama\~no total de la imagen en bytes, realizando la multiplicaci\'on "$Ancho * Alto * 4$", dicho valor se almacena en un registro de proposito general, el cual se va a usar posteriormente para controlar el recorrido de la imagen. Luego se realiza un \emph{shuffle} en el registro \emph{XMM0} para repetir el valor de diff recibido por par\'ametro en los restantes floats del registro, este registro es el que se va a utilizar para hacer la multiplicaci\'on de diff para la imagen 1. Se carga en un registro \emph{XMM} como packed single los valores \textbf{constantes} $1.0$ para realizar el c\'alculo del valor del diff para la imagen 2. A dicho registro se le resta el registro \emph{XMM0}, quedando como valor interno de cada float: \emph{1 - VALUE}. Puede observarse en el C\'odigo~\ref{diff1_1} el c\'odigo que realiza dichas operaciones. \\ \asmscript{diff1_1}{Merge1 - C\'alculo de valor del diff} Lectura imagen 1: \\ Se lee un \emph{Double Quadword} de memoria en la direcci\'on a la que apunta \emph{RDX} y se almacena temporalmente en el registro \emph{XMM0}, se realiza una copia del mismo en \emph{XMM12}. De esta forma se cargan de memoria 4 p\'ixeles a la vez. \\ Se procede a desempaquetar los 4 p\'ixeles 2 veces para poder procesar cada uno con operaciones de punto flotante. Primero de \emph{byte} a \emph{word} y luego de \emph{word} a \emph{DoubleWord} utilizando las operaciones \textbf{punpck\{l,h\}bw} y \textbf{punpck\{l,h\}wd} respectivamente. Se almacena cada p\'ixel desempaquetado en 4 registros \emph{XMM} consecutivos para mayor claridad y se utilizan los registros \emph{XMM0, XMM1 y XMM12} como almacenamiento temporal para el desempaquetado. Lectura imagen 2: \\ La lectura y desempaquetado de la imagen 2 se realiza de forma similar a la imagen 1, pero se utiliza como puntero el registro \emph{RCX} y se almacenan los p\'ixeles en otros 4 registros \emph{XMM}, se utilizan los mismos temporales que en la imagen1. \\ En el c\'odigo~\ref{diff1_2} se puede observar una lectura de memoria y parte del desempaquetado de la imagen 1. \\ \asmscript{diff1_2}{Merge1 - Lectura y desempaquetado de imagen1} Al tener los 8 p\'ixeles desempaquetados (4 de la imagen uno, 4 de la dos), se convierten dichos registros a punto flotante con la instrucci\'on \textbf{cvtdq2ps}. Terminados de convertir, se multiplican los registros correspondientes a los p\'ixeles de la imagen 1 por el registro generado anteriormente con los valores de diff. Los registros correspondientes a la imagen 2 se multiplican por el registro que contiene los valores "$1.0 - V$". Las multiplicaciones se realizan de forma empaquetada con la instrucci\'on \textbf{mulps}. \\ Luego se proceden a sumar de forma empaquetada los p\'ixeles de ambas im\'agenes, siendo el destino los de la imagen 1 para facilitar la l\'ogica. Antes de escribir los p\'ixeles nuevamente a memoria se convierten a enteros nuevamente con truncado, utilizando la instrucci\'on \textbf{cvttps2dq}. S\'olo se convierten los p\'ixeles de la imagen 1, que fueron el destino de la suma. Los registros se empaquetan dos veces con saturaci\'on sin signo, pasando de \emph{Double Word} a \emph{Word} y de \emph{Word} a \emph{Byte}. \label{sec:diff1_write} Los datos se escriben a memoria en la direcci\'on a la que apunta \emph{RDX}. En el c\'odigo~\ref{diff1_3} se observa parte de la conversi\'on a enteros, el empaquetado de los registros y la lectura a memoria. \\ \asmscript{diff1_3}{Merge1 - Conversi\'on\, empaquetado y escritura a memoria del resultado} Para finalizar se suma 16 a un registro contador y se compara el valor del mismo con el tama\~no de la imagen calculado. Si no se supera el valor, se suma 16 a los registros punteros de ambas im\'agenes y se salta nuevamente a secci\'on de lectura de la imagen 1. ~ ~ \subsubsection{Implementaci\'on 2} \label{sec:diff_imp2} Esta implementaci\'on, a diferencia de la implementaci\'on 1, realiza todas las operaciones de multiplicaci\'on y \emph{Shift} sobre p\'ixeles en enteros que, a diferencia de las instrucciones de punto flotante, \emph{deber\'ian} utilizar menos ciclos de clock y permite operar con 2 p\'ixeles por instrucci\'on. Como en la implementaci\'on~\ref{sec:diff_imp1}, antes de leer las im\'agenes, se calcula y almacena el tamaño en \textbf{bytes} de la imagen. Realizando el c\'alculo '$Ancho * Alto * 4$'. \\ Se cargan en dos registros \emph{XMM} auxiliares 2 valores \textbf{constantes} pre-cargados. Estos valores sirven para poder realizar divisiones con numeros enteros empaquetados de forma de multiplicar por dichos n\'umeros y luego realizar un \emph{shitf} a modo de dividir el valor. De esta forma, dentro de ciertos m\'argenes de error se puede simular una divisi\'on, sin tener que realizar la conversi\'on a punto flotante. Dichos valores son del tipo: $2^k$, con $k = 8$. El valor $k$ no puede ser mayor que 8, ya que de otro modo podr\'ia causar errores por \emph{overflow} con valores de p\'ixeles altos. Se recomienda que no sea menor a 7, ya que un numero menor pierde precisi\'on al realizar las multiplicaciones necesarias, cambiando la imagen de salida. Se eligen dos valores iguales, con diferencia de que uno se define como \emph{float}, repitiendose 4 veces en el registro para multiplicar el valor de diff, mientras que el otro se define de tipo \emph{Word} repitiendose 8 veces, lo que sirve para multiplicar las componentes de cada p\'ixel en una sola operaci\'on. Luego se multiplica como \emph{packed float} el valor pasado por par\'ametro en \emph{XMM0} y el cargado anteriormente, el registro se convierte a entero \emph{Dword} truncado, utilizando la operaci\'on \textbf{cvttps2dq}. Se le aplica un \emph{shuffle} que permite repetir el valor anterior como \emph{Word} en la parte baja del registro. Se copia el registro y se realiza un \emph{shift} l\'ogico \emph{Quad Word} hacia la izquierda de 8 bytes, lo que deja los 4 valores en la parte alta del registro, el mismo se suma con la copia realizada anteriormente y queda un registro que tiene en sus 8 \emph{Words} el valor $2^8 * Value$, este registro sirve para realizar las operaciones con la imagen 1. A continuaci\'on se carga el otro valor pre-cargado con \emph{Words} en un registro, y se realiza una resta empaquetada de los \emph{Word} del registro calculado para la imagen 1, lo que dejar\'ia un valor de $2^8 - (2^8 * Value)$ en cada \emph{Word}, que es el equivalente al c\'alculo $1 - Value$ cuando se divide por $2^8$. El valor final del pixel procesado, antes de dividir por $2^8$ ser\'ia: $$result = p1 * (v*2^8) + p2 * ((1-v)*2^8$$ En el C\'odigo~\ref{diff2_1} se observa las instrucciones que realizan dicho c\'alculo. \\ \asmscript{diff2_1}{Merge2 - C\'alculo de valores de diff.} La lectura de las imagenes se realiza de manera similar a la Implementaci\'on \ref{sec:diff_imp1}, pero a diferencia hay que realizar un desempaquetado menos, ya que se pueden procesar 2 p\'ixeles a la vez. Se utilizan por cada imagen 2 registros con 2 p\'ixeles cada uno en tamaño \emph{Word} cada componente los mismos. Al momento de calcular los valores de los p\'ixeles de ambas im\'agenes se realiza una multiplicaci\'on empaquetada para ambos p\'ixeles. Los p\'ixeles 1 se multiplica por el registro que contiene $2^8 * Value$, mientras que los de la imagen 2 se multiplican por el registro que contiene el valor $2^8 - (2^8 * Value)$. Luego se realiza una suma empaquetada de ambos registros. \\ Para finalizar se realiza un \emph{shift l\'ogico} a la izquierda de $8$ bytes, lo que equivale a realizar una divisi\'on por $2^8$. Todas las instrucciones utilizadas trabajan sobre \emph{Word}. En el C\'odigo~\ref{diff2_2} se puede ver las operaciones realizadas sobre los registros. \asmscript{diff2_2}{Merge2 - C\'alculo de p\'ixeles.} Para finalizar, se empaquetan nuevamente como \emph{Byte} saturados sin signo los dos registros de destino utilizados y se escriben a memoria utilizando el puntero de la imagen 1. La l\'ogica de fin de ciclo es igual a la implementaci\'on~\ref{sec:diff1_write}, se aumenta el registro contador y se revisa que no se supere el tama\~no de la imagen y mientras que no se supere, se a\~naden 16 bytes. \subsubsection{Hip\'otesis de funcionamiento para los experimentos} Con saber el funcionamiento de los algoritmos se pueden realizar algunas especulaciones respecto al funcionamiento del programa, tales como: \\ Se ve una clara mejora de performance en cuanto a la implementación secuencial de C, ya que dependiendo del compilador, puede haber hasta $4$ veces menos lecturas y escrituras a memoria. La forma de ejecuci\'on de datos empaquetados podr\'ia influir en que se consumen menos ciclos de reloj y movimientos de datos. \\ En cuanto a las dos implementaciones en \textbf{Assembler}, las mismas difieren principalmente en el c\'alculo de los valores de cada p\'ixel. \\ En la implementación~\ref{sec:diff_imp1} se realiza el c\'alculo de los valores, las multiplicaciones y las sumas trabajando enteramente con punto flotante de \textbf{\emph{precisi\'on simple}}, convirtiendose a entero solo al momento de escribir el dato a memoria. Esto implica que solo puede realizarse una instrucci\'on SSE por cada p\'ixel, ya que solo pueden procesarse $4$ valores por instrucci\'on al trabajar con punto flotante (Componentes A, R, G y B del p\'ixel). Mientras que en la implementaci\'on~\ref{sec:diff_imp2} se puede procesar 2 p\'ixeles en simultaneo con una \'unica instrucci\'on.