martes, 24 de julio de 2012

Ensamblador 8086 Buffer Doble

En este último post de la serie, explicaremos la técnica de buffer doble para pintar en la memoria de gráficos y comentaremos algunas posibles mejoras al código. Como platicábamos en el post anterior, si escribimos continuamente al área de memoria, puede suceder que versiones incompletas de nuestra imagen sean desplegadas. La técnica de buffer doble consiste en reservar un área de memoria del mismo tamaño de nuestra memoria de gráficos, en nuestro caso de 64,000 bytes (320x200); y pintar nuestros pixeles en este buffer. Una vez que tengamos nuestra imagen final lista, entonces copiamos nuestro buffer al área de memoria de gráficos. Esto minimiza el tiempo en el que estamos escribiendo directamente al área de gráficos y también el parpadeo. El siguiente video muestra el resultado final.

En el siguiente proyecto de mercurial podrán encontrar los archivos para construir el ejemplo. El archivo ensambla.bat contiene la instrucción usada para crear el ejecutable.

Reservar Memoria

Usamos la interrupción 21h con el servicio 48h para reservar memoria dinámicamente para el buffer doble, el registro bx contiene la cantidad de memoria deseada en bloques de 16 bytes (función iniciar_video en libgraf.asm). Puedes encontrar más información acerca de memoria dinámica en las siguientes referencias: referencia 1 y referencia 2. La variable vram guarda la dirección inicial del buffer doble. Ahora en el código, en lugar de escribir a la dirección A000h (memoria de gráficos), escribimos al buffer doble (vram).

Es importante notar que como reservamos memoria dinámicamente al momento de ligar los archivos (link) es necesario indicar cuanta memoria extra utilizará nuestro programa en tiempo de ejecución, es por ello que usamos la opción /link /cp:4000 en el comando ml del archivo ensambla.bat. El parámetro 4000 corresponde a la cantidad que solicitamos con la interrupción 21h, servicio 48h (4000 x 16 = 64,000 = 320 x 200).

Transparencia

Pareciera que la imagen de la pelota tiene transparencia, pero si la abrimos en un editor, el exterior es de color negro. Para lograr este efecto, en la función LoadBMP de libgraf.asm ignoramos los pixeles cuyo valor sea cero, que corresponde en este caso al color negro de nuestra paleta de colores.

Posibles Mejoras

Es notorio que la pelota se mueve lentamente, esto puede deberse a que estamos haciendo mucho procesamiento innecesario. En cada ciclo del programa (1) abrimos y leemos dos archivos (uno para la imagen de fondo y otro para la imagen de la pelota), (2) escribimos dos veces a la paleta de colores, (3) escribimos las dos imágenes al buffer y (4) copiamos el buffer doble a la memoria de gráficos. Los puntos 1 y 2 sólo son necesarios al inicio del programa.

Para el punto 1, podemos modificar el método mostrar_bmp (en libgraf.asm) para que abra el archivo, reserve memoria dinámica y guarde la imagen en esta memoria. El método mostrar_bmp arrojará como resultados el ancho, el alto y el apuntador a los pixeles de la imagen. De esta forma, en nuestro ciclo principal del programa trabajaremos con información en RAM y no tendremos que abrir continuamente archivos, lo cual es un proceso que consume mucho tiempo.

Con respecto al punto 2, estamos asumiendo que todas las imágenes usadas en el programa utilizan la misma paleta de colores. En caso de que no sea así, algunas imágenes podrían lucir extrañas. Hasta el momento, las imágenes que hemos guardado con Paint parecen tener una paleta común (usamos el programa pixelformer para observar la paleta de colores de las imágenes). Habría que modificar la función mostrar_bmp para que reciba un parámetro que indique si deseamos actualizar la paleta de colores con la paleta de colores de la imagen.

Aún así, en cada ciclo del programa estamos copiando al menos 64,000 bytes del buffer doble al área de memoria de gráficos (función copiar_buffer en libgraf.asm). Creo que resultaría interesante explorar otros modos de video, como el que menciona la siguiente página, que ya tiene soporte directo para un buffer doble y en donde es posible cambiar los buffers con pocas instrucciones.

No hay comentarios:

Publicar un comentario