Anoche hice una buena optimización y he pasado de 940FPS (el juego está limitado a 200FPS pero para las pruebas quito el límite) a 1750FPS que es casi el doble. Para el que le interese saber como he podido optimizar tanto que siga leyendo, el que no que se pase al siguiente párrafo. Los gráficos los tengo en 2 sitios, en la memoria RAM del ordenador tengo lo que se llama SURFACE que es un bloque de memoria con las propiedades de la imagen (transparencia, ancho, alto, número de colores... y los pixels propios de la imagen) y en la memoria de la VGA tengo lo que se llama TEXTURA que todos conocéis, que ha de ser de un tamaño potencia de dos y además tiene un tamaño máximo, por lo que en muchos casos un SURFACE necesita varias TEXTURAS para poder pintarlo. El problema de las TEXTURAS es que no puedo trabajar con ellas para por ejemplo leer el color de un pixel o cambiarlo, para hacer eso tendría que bajar la textura de la RAM de la VGA a la RAM del ordenador, ahí trabajar con ella y luego volverla a subir a la RAM de la VGA y eso como podéis imaginar es muy lento. Por eso tengo un SURFACE en la RAM del ordenador, para poder operar con el, por ejemplo para detectar las colisiones o cambiar el color. Cuando hacemos una modificación de un gráfico por ejemplo cuando llueve que oscurecemos el asfalto o al derrapar los coches que dejan la marca de las gomas lo que hago es recortar del SURFACE un bloque rectangular de los pixels afectados, bloquear la TEXTURA para poder transferir ese bloque rectangular y desbloquear la TEXTURA. Esto es lento y hay que intentar hacer las mínimas transferencias posibles y además cuanto más pequeño sea el bloque más rápido aunque es preferible mandar un solo bloque de por ejemplo 100x100 pixels que no mandar 4 bloques de 50x50. ¿ En que ha consistido la mejora ? pues antes para generar el recuadro que iba a enviar a la TEXTURA lo que hacía era crear un SURFACE intermedio del tamaño del recuadro, le aplicaba las propiedades del SURFACE original (colores, transparencias, formato, aceleración RLE...) lo rellenaba con los pixels del SURFACE original, lo transfería a la TEXTURA y borraba ese SURFACE intermedio. Ahora, haciendo operaciones matemáticas con los punteros de memoria que apuntan a los pixels del SURFACE consigo transferir ese bloque a la TEXTURA sin necesidad de generar y destruir un SURFACE intermedio.
Esta noche si tengo tiempo haré una segunda optimización que reducirá mucho la memoria RAM necesaria en la VGA. ¿ Y como lo voy a conseguir ? Pues ahora mismo cada sprite tiene una TEXTURA (o varias según el tamaño del sprite) en la memoria RAM de la VGA, así por ejemplo si tenemos 2 Ferrari en pista tendremos 2 TEXTURAS en la RAM de la VGA con el mismo dibujo o por ejemplo en el caso de la lluvia, si hay 500 gotas de agua en pantalla tenemos 500 TEXTURAS igualitas en la RAM de la VGA. Lo mismo sucede con los comisarios, banderas, OSD... Como ya habréis imaginado la optimización va a consistir en tener solo una TEXTURA de cada tipo de gráfico. Dicho así parece fácil, pero eso implica que cada sprite deberá guardar el mismo todas las propiedades del gráfico (posición, color, ángulo, transparencia, alpha blending) y no como ahora que esas propiedades pertenecen a la clase TKTIGrafico. Luego a la hora de pintar en pantalla si es un gráfico usaremos sus propiedades, pero si es un sprite tendremos que sobrescribir las propiedades del gráfico antes de pintarlo. Como estar cambiando las propiedades cada vez también consume recursos lo que haré será poner un "memoria" a cada gráfico que recuerde cuales fueron las últimas propiedades con las que se pintó y si estas no van a cambiar no hace falta sobrescribirlas.
Por último he pensado una solución intermedia para los gráficos en 32bits de color como el nuevo OSD. Cada gráfico PNG o BMP que carga el juego puede tener un número de colores distinto. A la hora de pintar en pantalla esos gráficos es interesante que todos tengan el mismo formato (número de colores y como se ordenan) porque es más rápido "montar" la pantalla que vamos a mostrar. Además según el número de colores de una imagen, el obtener si un pixel concreto es transparente o no y el pintar de otro color (derrapes, lluvia) se hace de una forma distinta, por lo tanto al cargar los gráficos en el juego lo que hago es convertirlos todos al mismo formato y luego va más rápido y me olvido de tener distintas funciones para obtener o cambiar el color de un pixel. La conversión que estaba haciendo hasta ahora era de todos los gráficos a 24bits de color (8 bits para cada color R,G,B) y todo funcionaba bien (aunque realmente no se que pasará en un ordenador antiguo que la VGA no llegue a 24bits de color). El problema ha venido con el nuevo OSD 2014 que está hecho a 32bits de color (los 8 bits de cada color R,G,B más 8 bits para la transparencia de cada pixel por separado). Si sigo forzando a 24bits perdemos la información de la transparencia y si fuerzo a 32bits todos los gráficos se ven bien hasta que intento pintar sobre ellos para por ejemplo pintar los derrapes o el agua sobre el asfalto. Cuando hago esto se ve toda la zona repintada con tonos azules. He perdido 4 o 5 días intentando solucionar este problema cambiando el orden de los bytes de color, cambiando los formatos a RGBA o ARGB desplazando la dirección del puntero 8 bits a la derecha y 8 a la izquierda, sobreescribiendo solo 24bits y no 32bits.... y nada a dado resultado. Siempre tengo uno de los dos fallos, o sale todo en tonos azules o salen bien los colores pero pierdo las transparencias viéndose todos los gráficos dentro de un recuadro (normalmente rosa o verde que es como están grabados los BMP y PNG). Al final he pensado una solución que aun tengo que probar si funciona, y es hacer un modo mixto 24 y 32 bits de color. Como el problema está solo cuando modifico los pixels de las imágenes (derrapes, lluvia) lo que voy a hacer es convertir a 24 bits (formato SDL_PIXELFORMAT_RGB888
) todos los gráficos que tengan 24 bits o menos o se vayan a repintar y a 32 bits (formato SDL_PIXELFORMAT_RGBA8888) solo las imágenes que ya están a 32 bits con alpha por pixel y no se van a repintar. Este método penalizará un poco al tener que "montar" una pantalla con gráficos en 2 formatos de color, pero por lo menos podremos tener algunos gráficos a 32bits.
Bueno, eso es un poco como van las cosas en MRO. Como veis, aunque no saque versiones todos los días si que estoy trabajando para tener lo antes posible la nueva versión completamente en SDL, y una vez tengamos esa versión ponerme con la conversión a IOS (iPhone/iPad), Android y Mac. A ver si puedo sacar la versión antes del gran premio de China.
Saludos