En 13,5 FPS en un Spectrum, vimos lo que podía hacer un ordenador de 8 bits, con una imagen que se volcaba continuamente a pantalla. Un modesto Spectrum, obtuvo la marca de 13,5 FPS, que podían haber sido bastantes más, evitando la impresión de los conteos en cada cuadro, y escribiendo el código en ensamblador. Diríamos que aquel programa utilizaba tecnología de los años 80.

Ahora volvemos con lo mismo, esta vez con tecnología de los 90. Un programa muy parecido en C, que vuelca a la VGA en modo 13h (320x200x256) una imagen.

Para facilitar la programación, se ha obtado por un código compilado con Open Watcom C++ 1.7a, en modo protegido de 32 bits para DOS, usando el magnífico extensor DOS32/A. Así evitamos problemas de exceder la capacidad del segmento de datos con compiladores de 16 bits, aunque sería factible hacer caber los 63 Kb de información en él, y compilar en modo real. El código no pone énfasis en la portabilidad, pero algo de cuidado si que he tenido.

El inconveniente de optar por protected mode, es que la virtualización de Windows os impedirá ejecutar correctamente el binario, por lo que necesitaréis un DOS de verdad, o un emulador como DOSBox, VMWare o Virtual PC. Probablemente lo mismo ocurra con otros entornos que virtualizan el hardware como Linux u OS/2.

Si el Spectrum, debía volcar a la memoria de video en la dirección 4000h, un PC debe hacerlo a la 000A0000h (A000:0000 en modo real), pero sobre todo la diferencia estriba en que el procesador Z80 debía mover únicamente 6.912 bytes, mientras que el 80386 del ejemplo, lo hará con 64.000 bytes, es decir, 10 veces más.

Afortunadamente, mientras el Z80, con 3,5 Mhz de velocidad, y accesos byte a byte (8 bits), un 386 a 33 Mhz, con accesos de doble palabra en doble palabra (32 bits), es teoricamente unas 40 veces más veloz, aunque en la práctica, lo es bastante más, debido a la eficiencia de ejecución de instrucciones, que tardan menos ciclos de reloj que en su homónimo.

Entre ambos listado, hay basicamente dos diferencias, que hacen la versión de PC algo más compleja. Por un lado, los PC y compatibles, están por defecto en modo texto (80x25x16), así que deberemos pasar al modo gráfico que nos interese al principio de la ejecución, y restaurar el modo texto al terminar. Por otro lado el modo gráfico 13h (MCGA), se basa en una paleta de 262.144 colores a elegir, de los cuales pueden representarse simultaneamente en pantalla 256, por lo que deberemos asignar la paleta a utilizar antes mostrar píxeles en pantalla.

Para ser sinceros, lo más largo del programa ha sido la conversión de la imagen que se muestra (Perin). He partido del JPEG original, y lo he reescalado a 320×200, luego lo he convertido a PCX sin compresión, y con un editor hexadecimal, he eliminado los 128 primeros bytes que contienen la cabecera PCX. Por último, con el todavía útil BIN2PRO (19 Kb en formato ZIP), he convertido los datos a un array de C.

Por rendimiento y diversión, todas las operaciones (salvo las lecturas de teclado, en las que las llamadas a la biblioteca de C, se traspasan a la BIOS), se hacen accediendo directamente al hardware, incluyendo la asignación de paleta.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <conio.h>
#ifdef __WATCOMC__
#include <i86.h>
#else
#include <dos.h>
#endif

static unsigned char gacPerin[]={...};

int main (void)
{
register unsigned int iX;
clock_t clkStart, clkEnd;
union REGS udtRegs;

udtRegs.w.ax=0x13;
int386(0x10, &udtRegs, &udtRegs);

for (iX=0; iX<256; iX++)
{
outp(0x3C8, iX);
outp(0x3C9, (gacPerin[(iX*3)+64000])>>2);
outp(0x3C9, (gacPerin[(iX*3)+64001])>>2);
outp(0x3C9, (gacPerin[(iX*3)+64002])>>2);
}

iX=0;
clkStart=clock();
while (!kbhit())
{
memcpy((unsigned char *) 0x000A0000,
gacPerin, sizeof(gacPerin)-768);
iX++;
}
clkEnd=clock();
getch();

udtRegs.w.ax=0x3;
int386(0x10, &udtRegs, &udtRegs);

printf("Frames: %d; FPS: %d\n",
iX, iX*CLOCKS_PER_SEC/(clkEnd-clkStart));

return(0);
}

Ejecutando el programa bajo DOSBox, he obtenido una cifra de 518 FPS. El valor podría ser más elevado escribiendo el programa en ensamblador, y/o optimizando para una arquitectura de procesador algo más moderna, como por ejemplo Pentium.

Podéis descargar el binario, y el fuente aquí (83 Kb en formato ZIP).