Aula Macedonia


Curso de Programación Multimedia Bajo DOS


Artículo realizado por
José Antonio Suárez.





Capítulo 3.
Programación de tarjetas de vídeo (I).

2.- Introducción a la Tarjeta de Vídeo VGA-SVGA


Ahora llega el turno a la tarjeta de vídeo, soporte de los gráficos del ordenador. Vamos a conocer los tres modos de vídeo (modos de operación de la tarjeta) siguientes:

2.1.- VGA Estándar. 320x200x256c

Desde que hizo aparición en las placas base de los IBM PS/2 50, 60, y 80, allá por 1987, la VGA (Vídeo Graphics Array), se ha convertido en un estándar para todos los ordenadores IBM y sus clónicos compatibles.

La abreviatura VGA era para mucha gente sinónimo de resolución aceptable (hasta 640x480 píxels) y de un ramillete de colores increíble hasta entonces (256 de una paleta de 262144 posibles), al menos cuando se la comparaba con las antiguas CGA y EGA.

Desgraciadamente, para usar estos 256 colores, el BIOS de la VGA limita a los usuarios a una resolución de sólo 320x200 píxels, es decir, el conocido modo 13h estándar en el que están programados casi todos los vídeojuegos que han aparecido.

2.1.1.- Programación de la Tarjeta de Vídeo

El procedimiento para establecer el modo de vídeo es:
 
void ModoMcga(void)
{
    asm{
            // Modo 13h
            mov al,0x13
            xor ah,ah
            int 0x10
            // Limpia la memoria de vídeo
            mov ax,0xA000
            mov es,ax
            xor di,di
            xor ax,ax
            mov cx,32000
            rep stosw
    }
}

Al ser este modo de vídeo de 320 píxels horizontales por 200 verticales, da un total de 64000 píxels por pantalla.

 

2.1.2.- Ventaja del Modo 13h

Este modo tiene una ventaja y un inconveniente. La ventaja es que cada uno de los 64000 píxels que componen la imagen gráfica en el modo 13h es fácilmente direccionable en el segmento de la memoria de vídeo que comienza en 0A000h. Por ejemplo, utilizando la siguiente fórmula:

Desplazamiento= (Y * 320) + X

se puede calcular el desplazamiento del píxel dentro de la memoria de vídeo, mediante su coordenada X y su coordenada Y. Tras ello, y si se introduce un byte en la posición A000:desplazamiento, aparecerá el color inmediatamente.

Por ejemplo: si queremos poner el color 23h en el píxel (100,10), usando la fórmula anterior sería:

10 * 320 + 100 = 3300

que en hexadecimal es 0EC4h. Si hacemos el siguiente código en ensamblador, veremos aparecer un píxel en esa dirección:

mov ax,0A000h
mov ds,ax
mov (0EC4h),23h

El procedimiento que hace esto y pone un píxel en pantalla es:
 
void PonerPixelMcga(int x,int y,char color)
{
    asm{
            mov ax,0xA000
            mov es,ax
            mov bx,x
            mov dx,y
            mov di,bx
            mov bx,dx
            shl dx,8
            shl bx,6
            add dx,bx
            add di,dx
            mov al,color
            stosb
    }
}

Este procedimiento puede parecer que es mucho más complejo que el siguiente, que es el primero que se le ocurre a un programador.
 
void PonerPixelMcga(int x,int y,char color)
{
    asm{
            mov ax,0xA000
            mov es,ax
            mov bx,x
            mov dx,y
            mul dx,320
            add bx,dx
            mov di,bx
            mov al,color
            stosb
    }
}
 

2.1.3.- Velocidad de las Instrucciones

Vistos estos dos procedimientos, puede parecer que el último tendrá que ir más rápido puesto que el número de instrucciones es menor. Pero no es así. Si miramos el documento suministrado por INTEL sobre sus conjuntos de instrucciones de Ensamblador, podemos ir sumando el número de ciclos de reloj que tarda cada instrucción de cada procedimiento considerando los valores para un 486.
 

Instrucción
Ciclos
mov
1
shl
2
add
1
stosb
5
mul
18
 

Hay que especificar que estos valores son medios, ya que no es lo mismo realizar la instrucción "mov" entre dos registros que entre una posición de memoria y un valor inmediato (la primera tarda la mitad).

El primer procedimiento tarda aproximadamente 18 ciclos de reloj, mientras que el segundo tarda 30 (sólo la instrucción "mul" tarda 18 ciclos). Y si en lugar de considerar los valores para un 486, lo hacemos para un 386, la diferencia entre el primero y el segundo se disparan, dando 40 y 91 respectivamente.

Por esto, y a partir de ahora, todos los procedimientos en Ensamblador parecerán que no son los más claros, pero son los más rápidos que ha sido posible implementar con la información disponible, así, en vez de usar la instrucción "mov bl,0", pondré "xor bl,bl", porque aunque las dos tarden lo mismo en los 486, en un 386 el segundo tarda 2 ticks del reloj y el primero 4.

Tras estas aclaraciones, continuemos con el tema de la tarjeta de vídeo con la resolución MCGA (VGA 320x200x256c).

Leer un píxel sería igual de simple que escribirlo, tan sólo habría que mirar el contenido del byte correspondiente en lugar de escribir otro encima de él.

Esta facilidad es el cielo comparado con los problemas que dan los planos y los registros de máscara que se necesitan en los modos de 16 colores. Con el modo 13h, la distancia que existía entre un algoritmo gráfico en papel y una rutina gráfica, se redujo drásticamente a tan sólo una fracción. Y lo que es más importante, son incomparablemente más rápidos (sobre todo si se esfuerzan un poco los programadores e intentan aprovecharse de la información sobre las instrucciones del Ensamblador y sus distintos retardos).
 

2.1.4.- Desventaja del Modo 13h

Pasemos ahora a la desventaja que antes mencionamos. El modo 13h está limitado a una sola página, es decir, la VGA tan sólo puede mostrar una pantalla a la vez, mientras que los modos de 16 colores permiten varias, permitiendo esto mostrar al usuario cualquiera de ellas en cada momento determinado y dibujar o cambiar el contenido de las que están ocultas. Este procedimiento conocido como "page flipping" o cambio de páginas es muy importante a la hora de realizar animaciones sin parpadeo.

Por otro lado, en el modo 13h es casi imposible conseguir un scroll suave de pantalla utilizando la tarjeta tal cual. Pero como siempre hay puertas ocultas en el mundo de la informática, podemos aprovecharnos de los puertos programables de la VGA para hacer un curioso efecto visual, con el que conseguiremos que la suavidad en los scrolls grandes sea bastante aceptable, y elimine casi en todos los casos el molesto efecto de "nieve" que se suele ver en numerosas aplicaciones gráficas y vídeojuegos.

El procedimiento que consigue esto es el siguiente:
 
void EsperarBarrido(void)
{
    asm{
            mov dx,0x3da
    }
    l1:
    asm{
            in al,dx
            and al,0x08
            jnz l1
    }
    l2:
    asm{
            in al,dx
            and al,0x08
            jz l2
    }
}

Al concepto en que se basa este procedimiento se le llama Barrido Vertical. Se basa "simplemente" en uno de los muchos registros de la VGA, pero que se convierte en uno de los más útiles para la animación y los efectos de paleta.
 

2.1.5.- Teoría del Barrido Vertical

Hay un cañón de electrones en la parte posterior del monitor que mantiene los píxels "refrescados" con sus correctos valores cada 1/60 segundos o 1/70 segundos dependiendo de la frecuencia del monitor. Ese cañón dispara un haz de electrones a cada píxel, fila a fila. El retraso vertical es el tiempo que tarda el haz de electrones en retornar desde la esquina inferior derecha, en su orientación hacia la esquina superior izquierda, donde comienza de nuevo el barrido de la pantalla. Durante ese tiempo no se emiten electrones.

Este es un período extremadamente corto en el que apenas parece que dé tiempo a nada, pero no es así. Durante este tiempo se puede cambiar cualquier parte de la memoria de vídeo sin que la circuitería de vídeo se entere, por lo tanto no se actualizarán los cambios en pantalla. De esta forma, los gráficos actualizados no se verán afectados por esos efectos que todos hemos visto y que suelen ser los siguientes:





AULA MACEDONIA
a
MACEDONIA Magazine