| 12345678910111213141516171819202122232425 |
- \subsection{HSL}
- \par El filtro HSL consiste en sumarle ciertos valores de Hue ("H"), Saturation ("S") y Lightness ("L") a una imagen, que se dan como par\'ametros de entrada del filtro. En el caso de este Trabajo
- Pr\'actico, ya que las im\'agenes utilizadas se encuentran en formato BMP (es decir que cada pixel est\'a representado mediante sus componentes de A, R, G y B), es necesario transformar los
- componentes a HSL, sumarles los par\'ametros y luego transformarlos de nuevo.
- \subsubsection{Implementaci\'on 1 del filtro HSL:}
- \par Inicialmente se cargan los 3 floats pasados por par\'ametro en xmm7 (con un 0 en los cuatro bits menos significativos - los que luego se sumar\'an a la transparencia -), y se reservan 16 Bytes de memoria que almacenar\'an el resultado de rgbTOhsl (como se ve en el listing \ref{hsl1_p1}). El registro xmm7 se pushea al inicio de la ejecuci\'on y luego del call a hslTOrgb en cada ciclo.
- \asmscript{hsl1_p1}{Manejo de par\'ametros y memoria din\'amica en hsl1}
- \par En cada ciclo se llama a la funci\'on rgbTOhsl, que transforma los valores ARGB del pixel fuente (cuyo puntero se encuentra en r14) a AHSL y guarda el resultado en la ubicaci\'on de destino (cuyo puntero se encuentra en rbx). Los valores son guardados en memoria de la forma indicada en la l\'inea 3 del listing \ref{hsl1_p2}; si bien la funci\'on no altera el valor de la transparencia (``A''), modifica su representaci\'on de entero de 1 Byte a punto flotante de 4 Bytes. Tras llamar a la funci\'on se hace pop del registro xmm7 que habia sido pusheado previamente; estos pasos son necesarios ya que las convenciones de llamado de C para Linux no garantizan la preservaci\'on de los registros xmm.
- \asmscript{hsl1_p2}{Transformaci\'on de RGB a HSL y guardado en memoria}
- \par El valor del pixel convertido a HSL se pasa al registro xmm8 y se le suma la m\'ascara guardada en xmm7. Para generar la m\'ascara necesaria para el truncamiento y la saturaci\'on se copia el contenido de xmm8 en xmm4, se lo invierte, filtra (mediante un pand con otra m\'ascara, para tomar s\'olo los valores correspondientes a S y L) y resta a otra m\'ascara; el resultado de estas operaciones es lo que se debe sumar a xmm8 para truncar H o saturar S y L, de ser necesario. Se copia el contenido de xmm8 a otro registro (xmm9) y se compara (mayor o igual) con una m\'ascara para determinar qu\'e componentes requieren truncamiento/saturaci\'on. Se realiza un pand entre la m\'ascara previamente creada y el resultado de la comparaci\'on y se suma a xmm8 (como se ve en el c\'odigo~\ref{hsl1_p3}).
- \asmscript{hsl1_p3}{Creaci\'on de la m\'ascara necesaria para la suma y comparaci\'on Greater/Equal}
- \par Luego se realizan nuevamente las mismas operaciones, pero comparando por menor y con las m\'ascaras correspondientes (como se ve en el c\'odigo~\ref{hsl1_p4}); entonces se obtiene en xmm8 el resultado final del filtro. Se pushea el registro xmm7.
- \asmscript{hsl1_p4}{Creaci\'on de la m\'ascara necesaria para la suma y comparaci\'on Lower Than}
- \par El resultado obtenido se copia de xmm8 a la posici\'on apuntada por rbx y luego se llama la funci\'on hslTOrgb (como se ve en el c\'odigo~\ref{hsl1_p5}), con par\'ametros fuente rbx y destino r14. Esto convierte el resultado del filtro a ARGB y lo guarda en la posici\'on de memoria a la que apunta r14, reemplazando el valor original del pixel. Luego se aumenta r14 en 4 (es decir, ahora apunta al pixel siguiente) y se reinicia el ciclo.
- \asmscript{hsl1_p5}{Actualizaci\'on del valor del pixel en la imagen (cargado a memoria del resultado de la suma).}
- \subsubsection{Implementaci\'on 2 del filtro HSL:}
- \par Al igual que en la primera implementaci\'on, se genera en xmm7 una m\'ascara a partir de los 3 par\'ametros de entrada (c\'odigo~\ref{hsl1_p1}). Sin embargo, ya que no se llamar\'a a otras funciones se podr\'a mantener el valor del registro durante toda la ejecuci\'on sin necesidad de recurrir al stack. En cada ciclo se cargan los valores de ARGB del pixel correspondiente en los 8 bits menos significativos de los registros rbx, r9, r10 y r11, respectivamente (como se ven en el c\'odigo~\ref{hsl2_p1}).
- \asmscript{hsl2_p1}{Cargado de valores ARGB en registros}
- \par Luego se busca el m\'aximo y el m\'inimo, y se computa su diferencia (que ser\'a utilizada m\'as adelante). Para obtener el Hue, se compara el m\'aximo con el m\'inimo y los componentes R, G y B; de acuerdo al resultado de la comparaci\'on se opera y se llega a un resultado intermedio. Se compara este resultado y de ser necesario se le resta 360f (siempre se debe mantener H en el intervalo [0, 360) ). Para obtener la Lightness se suman el m\'aximo y el m\'inimo y se divide este resultado por una constante. La Saturation es nula si el m\'aximo es igual al m\'inimo; de no serlo se opera con L, la diferencia entre m\'aximo y m\'inimo valor (entre R, G y B, calculada previamente) y constantes hasta llegar al valor adecuado. Para calcular el valor absoluto de (2*L-1) necesario en tales operaciones se compara (por menor) con 0 y se le resta dos veces el valor original (tras realizar un and con el resultado de la comparaci\'on), como se ve en el c\'odigo~\ref{hsl2_p2}.
- \asmscript{hsl2_p2}{C\'alculo del valor absoluto de (2*L-1)}
- \par La suma se realiza de la misma forma que en la implementaci\'on 1. El resultado de \'esta se encuentra en xmm8, y a partir de este registro (copiando y shifteando) se obtienen los valores correctos de H, S y L, que se guardan como escalares en los registros xmm6, xmm0 y xmm15, respectivamente. A partir de estos valores se calculan C, X y M; para computar X se requiere calcular el m\'odulo 2 de H/60 (valor que se encuentra en punto flotante), como se ve en el c\'odigo~\ref{hsl2_p3}. Para computar el m\'odulo en punto flotante se convierte el valor a entero con truncamiento y se compara (por menor) con 2. De ser menor se ha encontrado el resultado, de ser mayor se le resta 2.0f al valor de punto flotante y se vuelve a comparar. De esta forma se evita perder presici\'on innecesariamente (la comparaci\'on contra el entero convertido por truncamiento s\'olo ser\'a positiva si el n\'umero es efectivamente menor que 2 y el resultado final no pasa por ninguna conversi\'on).
- \asmscript{hsl2_p3}{C\'alculo del m\'odulo en punto flotante}
- \par Los valores finales de R, G y B se calculan de acuerdo al valor de H, que se convierte a entero con truncamiento y se compara (por menor) a diversas constantes. Tras computar los valores se los guarda en los 8 bits menos significativos de los registros r9, r10 y r11 respectivamente. Estos valores luego se guardan en memoria en la posici\'on apuntada por rdx (m\'as el offset correspondiente a cada componente), como se ve en el c\'odigo~\ref{hsl2_p4}, reemplazando los valores originales del pixel.
- \asmscript{hsl2_p4}{Guardado en memoria del resultado del filtro}
|