Buffers de trabajo intermedios en volcados de pantallas

Todo sobre la creación, diseño y programación de nuevo software para
nuestro Spectrum

Moderador: Sir Cilve Sinclair

sromero
Nonamed
Mensajes: 1221
Registrado: Mar Abr 17, 2007 12:35 pm
Ubicación: Valencia
Contactar:

Buffers de trabajo intermedios en volcados de pantallas

Mensaje por sromero » Jue Oct 04, 2007 12:19 pm

Enas ...

Estoy teniendo una interesantíma conversación con na_th_an vía correo electrónico tratando un tema concreto de SPLIB2, que es el cómo funciona internamente. En esta conversación, na_th_an me apunta:

na_th_an escribió:(SPlib2) se maneja sobre un buffer orientado a tiles de 8x8 y aparte están los sprites. Se tiene una rejilla. Para cada casilla se almacena el número de tile de fondo. Bien a mano, bien como resultado de mover un sprite, las casillas que se "invaliden" serán redibujadas en VRAM en la próxima llamada a sp_UpdateAll(). Lo que hace entonces es usar un buffer donde, por orden, vuelca el tile de fondo y renderiza todos los trozos de sprites que caigan en la casilla invalidada, y luego la copia este buffer a VRAM en la posición correcta.

¿Qué significa esto? Que un sprite sólo puede moverse sobre un fondo "tile" escrito en el buffer de splib2 con sp_PrintAtInv o sp_PrintAt. Cualquier cosa que pintemos nosotros por nuestra cuenta en VRAM será ignorada en el próximo sp_UpdateAll.


Esto me ha llevado a plantearme una pregunta:

- ¿Es habitual en el Spectrum el usar buffers de memoria intermedios, del mismo tamaño que la VRAM, donde trabajar y que luego se vuelquen a VRAM, o no era una práctica usada por los programadores?

Está claro que la principal desventaja es el consumo de casi 7KB de RAM para dicho buffer, además de que se "escribe" 2 veces: una sobre el buffer más luego el volcado a la VRAM.

Las ventajas también son obvias: como se escribe en un buffer intermedio, no hay parpadeos al borrar o dibujar sprites, y tan sólo tenemos que sincronizarnos con el haz de electrones para hacer un LDIR que vuelque todo el buffer rápidamente.

Teniendo en cuenta que nunca he hecho en el Spectrum un juego que requiera movimiento fluido, es decir, que jamás he tenido que enfrentarme a contar t-stados y organizar el orden en que imprimo los sprites para que no haya parpadeos, etc... preguntas que me surgen:

- ¿Es el LDIR lo bastante rápido para copiar los 7KB de memoria desde el buffer intermedio a la VRAM antes de que el haz de electrones pase por encima y tal? (Es decir, salen las cuentas de la copia para que no haya parpadeos?)

- ¿Conocéis juegos comerciales que usaran esta técnica, o para ahorrar memoria todos pintaban encima de la pantalla aprovechando lo más posible los t-stados del tiempo de dibujado del borde o cosas similares?

- ¿Qué pensáis de esa "técnica"?

saludos :)
NoP / Compiler

Avatar de Usuario
na_th_an
Nonamed
Mensajes: 1889
Registrado: Lun May 07, 2007 10:16 am
Ubicación: Andalucía

Mensaje por na_th_an » Jue Oct 04, 2007 12:52 pm

Sólo quiero puntualizar que el buffer de splib no es una copia de la VRAM completa. Tenemos estructuras de memoria en la que se almacena qué número de tile (un gráfico de 8x8) está asociada a cada casilla, y luego información sobre qué sprites caen sobre las casillas. Es a la hora de volcar a VRam cuando se crea el gráfico de 8x8 con tile de fondo+trozo de sprite y se pone en pantalla, siempre que la casilla correspondiente sea "invalidada" por mover un sprite sobre ella o por cambiar el tile de fondo.

Sobre lo que planteas, creo que el Manic Miner funciona así: con varios LDIR y un bufferazo tocho.

Te puedo, además, adelantar que:

- ¿Es el LDIR lo bastante rápido para copiar los 7KB de memoria desde el buffer intermedio a la VRAM antes de que el haz de electrones pase por encima y tal? (Es decir, salen las cuentas de la copia para que no haya parpadeos?)


No es posible. 7 Kb son muchos Kb, por eso se suelen emplear sólo dos tercios de pantalla o usar métodos alternativos por medio de pila y cosas así.

Gandulf
Nonamed
Mensajes: 1067
Registrado: Lun May 07, 2007 10:06 pm

Mensaje por Gandulf » Jue Oct 04, 2007 1:37 pm

La técnica del buffer interemedio no sólo se usaba sino que es imprescindible para juegos que tengan scroll. Si no tienes scroll no es indispensable en función del número de sprites que muevas o la rapidez de las rutinas de impresión de sprites, pero de todas formas es recomendable.

La instrucción LDIR es lenta, es mejor usar secuencias de LDI, pero de todas formas es más rápido usar la pila. En viaje al centro he quitado prácticamente todos los LDI por código para la pila, aunque no en todas las rutinas es más eficiente, depende de la rutina. Por ejemplo para el volcado a pantalla del buffer sí se nota y mucho.

El tamaño del buffer sólo tiene que ser el de toda la pantalla si no tienes marcador o bordes de pantalla, etc. Sólo tiene que tener el tamaño de la parte de pantalla que es necesario volcar en cada bucle de juego.

En cuanto a la sincronización, es imposible hacerlo en un retrazo si mueves mucha pantalla, pero hay trucos que ayudan a mininizar esto, por ejemplo esperar a que el barrido "te pase" y luego ir detrás.

Luego hay otras técnicas para el volcado de los tiles al buffer que se usan más (el suelo por ejemplo) y que consiste en usar tiles "compilados" en spectrum, con lo que tienes un aumento de velocidad enorme.

Yo los he tenido que usar (sólo unos pocos, que 48K no dan para mucho :wink: ) porque el tamaño enorme de los sprites de las tortugas (enmascarados) y la gran cantidad que se juntan en pantalla, junto a que tenemos un scroll de gran parte de la pantalla, me obligaron a exprimir a tope el Z80 para que todo vaya fluido y suave al pixel.
Un saludo,

Gandulf

sromero
Nonamed
Mensajes: 1221
Registrado: Mar Abr 17, 2007 12:35 pm
Ubicación: Valencia
Contactar:

Mensaje por sromero » Jue Oct 04, 2007 1:44 pm

Gandulf escribió:La técnica del buffer interemedio no sólo se usaba sino que es imprescindible para juegos que tengan scroll. Si no tienes scroll no es indispensable en función del número de sprites que muevas o la rapidez de las rutinas de impresión de sprites, pero de todas formas es recomendable.


Claro, cierto, también depende del juego que hagas, cierto. Si la pantalla es estática y no tienes muchos sprites, siempre te puede dar tiempo a dibujarlos todos antes de que el haz de electrones "les pille" (supongo que como mínimo habría que hacer una ordenación por la Y de los sprites para pintarlos en el orden adecuado)...

La instrucción LDIR es lenta, es mejor usar secuencias de LDI, pero de todas formas es más rápido usar la pila. En viaje al centro he quitado prácticamente todos los LDI por código para la pila, aunque no en todas las rutinas es más eficiente, depende de la rutina. Por ejemplo para el volcado a pantalla del buffer sí se nota y mucho.


¿Puedes definir el concepto "usar la pila"? Explicación teórica, ejemplos de código ASM, me interesa enormemente cualquier dato que puedas aportar.

¿Te refieres a apuntar SP a la pantalla y usar PUSHes para "dibujar"?

El tamaño del buffer sólo tiene que ser el de toda la pantalla si no tienes marcador o bordes de pantalla, etc. Sólo tiene que tener el tamaño de la parte de pantalla que es necesario volcar en cada bucle de juego.


Cierto, y siempre hay barras de estado, marcos, etc, que reducen esos 7K en mucho, claro.

En cuanto a la sincronización, es imposible hacerlo en un retrazo si mueves mucha pantalla, pero hay trucos que ayudan a mininizar esto, por ejemplo esperar a que el barrido "te pase" y luego ir detrás.


Interesante.

Esto es lo que yo espero de este foro, la verdad, comentarios de gente que YA HA HECHO cosas en el Spectrum y que ayuda a la gente que está empezando a hacerlas (como yo) a entender formas nuevas y mejores de hacer las cosas, y que no tenga que perder tiempo para acabar reinventando la rueda por mi cuenta...

:)

Luego hay otras técnicas para el volcado de los tiles al buffer que se usan más (el suelo por ejemplo) y que consiste en usar tiles "compilados" en spectrum, con lo que tienes un aumento de velocidad enorme.

Yo los he tenido que usar (sólo unos pocos, que 48K no dan para mucho :wink: ) porque el tamaño enorme de los sprites de las tortugas (enmascarados) y la gran cantidad que se juntan en pantalla, junto a que tenemos un scroll de gran parte de la pantalla, me obligaron a exprimir a tope el Z80 para que todo vaya fluido y suave al pixel.


Gracias por el comentario. :)
NoP / Compiler

Gandulf
Nonamed
Mensajes: 1067
Registrado: Lun May 07, 2007 10:06 pm

Mensaje por Gandulf » Jue Oct 04, 2007 1:50 pm

Pues siento decir que yo no publico nunca mis fuentes de los juegos. Y en el caso de Viaje al Centro de la Tierra no va a ser una excepción. Pero si quieres que comente algo sobre alguna rutina en particular o alguna técnica no tengo problema.

Con respecto a lo de usar la pila, el tema está en hacer POPs para obtener 16 bits en 10 ts y luego hacer push para meter 16 bits en 11 ts, pero esta técnica es eficiente en función del número de bytes que muevas, para mover 2 bytes no es eficiente, ya que tienes que dar dos veces valor a SP en la rutina.

Otra cosa indispensable el usar los registros "prima" como les llamo yo, porque la efectividad de la rutina depende del número de push o pops consecutivos que hagas antes de cambiar el valor de SP. Y recordar que POP incrementa SP mientras que PUSH lo decrementa, para poner los valores correctos.
Un saludo,

Gandulf

sromero
Nonamed
Mensajes: 1221
Registrado: Mar Abr 17, 2007 12:35 pm
Ubicación: Valencia
Contactar:

Mensaje por sromero » Jue Oct 04, 2007 1:55 pm

Gandulf escribió:Pues siento decir que yo no publico nunca mis fuentes de los juegos. Y en el caso de Viaje al Centro de la Tierra no va a ser una excepción.


Hombre, es algo que no comparto pero puedo llegar a entender... (con esfuerzo).

Pero si quieres que comente algo sobre alguna rutina en particular o alguna técnica no tengo problema.


No, si lo decía por si podías poner algo de ASM (a mano, al vuelo, vamos, no copiado de ningún fuente) para ilustrar lo que decías, por curiosidad.

Con respecto a lo de usar la pila, el tema está en hacer POPs para obtener 16 bits en 10 ts y luego hacer push para meter 16 bits en 11 ts, pero esta técnica es eficiente en función del número de bytes que muevas, para mover 2 bytes no es eficiente, ya que tienes que dar dos veces valor a SP en la rutina.


¿Pero lo usas solo para escribir en videomemoria o para transferir bloques?

Otra cosa indispensable el usar los registros "prima" como les llamo yo, porque la efectividad de la rutina depende del número de push o pops consecutivos que hagas antes de cambiar el valor de SP. Y recordar que POP incrementa SP mientras que PUSH lo decrementa, para poner los valores correctos.


¿Los sprites también los "pintas" con pushes?
NoP / Compiler

Gandulf
Nonamed
Mensajes: 1067
Registrado: Lun May 07, 2007 10:06 pm

Mensaje por Gandulf » Jue Oct 04, 2007 2:01 pm

Hombre, es algo que no comparto pero puedo llegar a entender... (con esfuerzo).

Siempre lo hago así. Soy de la idea de que copiar código no vale para nada, lo que vale es entender la idea y luego programarla tu. Pero bueno, cada uno tiene sus propias ideas sobre esto, y ninguna tiene porqué ser mejor que otra.

¿Pero lo usas solo para escribir en videomemoria o para transferir bloques?

Mover bloques. Al fin y al cabo volcar una pantalla es transferir un bloque. En concreto para el volcado total del buffer a pantalla y para los tiles compilados, que sólo usan PUSH y no hace falta hacer POPs.

¿Los sprites también los "pintas" con pushes?

No es eficiente. Ten en cuenta que hay que hacer rotados de datos, etc, y se liaría la rutina de forma que sería más lenta que usando LDIs.

Por cierto que los rotados no los hago sino que utilizo tablas de valores prerotados, que es mucho más eficiente, y por supuesto utiliza mucha menos memoria que utilizar sprites prerotados (inviable en un juego más o menos largo).
Un saludo,

Gandulf

Avatar de Usuario
Metalbrain
Freddy Hardest
Mensajes: 592
Registrado: Lun May 07, 2007 8:17 am
Ubicación: Sevilla
Contactar:

Mensaje por Metalbrain » Jue Oct 04, 2007 3:55 pm

sromero escribió: ¿Puedes definir el concepto "usar la pila"? Explicación teórica, ejemplos de código ASM, me interesa enormemente cualquier dato que puedas aportar.


Aquí hay código que usa la pila:
http://www.worldofspectrum.org/forums/s ... php?t=5367

sromero
Nonamed
Mensajes: 1221
Registrado: Mar Abr 17, 2007 12:35 pm
Ubicación: Valencia
Contactar:

Mensaje por sromero » Jue Oct 04, 2007 4:17 pm

Gandulf escribió:Hombre, es algo que no comparto pero puedo llegar a entender... (con esfuerzo).

Siempre lo hago así. Soy de la idea de que copiar código no vale para nada, lo que vale es entender la idea y luego programarla tu. Pero bueno, cada uno tiene sus propias ideas sobre esto, y ninguna tiene porqué ser mejor que otra.


Bueno, el concepto del OpenSource no es el de copiar código, sino el de compartir conocimientos a través del código.

¿Pero lo usas solo para escribir en videomemoria o para transferir bloques?

Mover bloques. Al fin y al cabo volcar una pantalla es transferir un bloque. En concreto para el volcado total del buffer a pantalla y para los tiles compilados, que sólo usan PUSH y no hace falta hacer POPs.


Mola :)

Gracias por la info :)
NoP / Compiler

Avatar de Usuario
na_th_an
Nonamed
Mensajes: 1889
Registrado: Lun May 07, 2007 10:16 am
Ubicación: Andalucía

Mensaje por na_th_an » Jue Oct 04, 2007 5:36 pm

sromero escribió:Bueno, el concepto del OpenSource no es el de copiar código, sino el de compartir conocimientos a través del código.


Si no fuera por esto, yo no sabría programar juegos. O lo haría mil veces peor.

No quiero desviar el tema, pero compartir el código hace más bien que daño y no cuesta nada. Otra cosa es temer que la gente despunte más y uno deje de ser "el pepinaco" para convertirse en uno más - cosa que veo un poco estúpida dado que nadie gana dinero con esto. Soy bastante talibán en mi forma de pensar con respecto a este tema, eso también es verdad, por eso prefiero intentar respetar estas posturas aunque no las comparta (de forma activa) en absoluto.

Gandulf
Nonamed
Mensajes: 1067
Registrado: Lun May 07, 2007 10:06 pm

Mensaje por Gandulf » Jue Oct 04, 2007 5:43 pm

Yo también soy bastante taliban esto. Somos talibanes de los dos extremos opuestos de forma de pensar. Pero eso no indica que tengamos que tirarnos los trastos a la cabeza.

Efectivamente es un offtopic como una casa, pero yo nunca enseño mi código, y tampoco miro el de los otros, os lo aseguro. Siempre me ha interesado más la teoría sobre cómo hacer las cosas y luego currármelas yo que el que me den todo hecho. En serio, creo que es mucho mejor.

Si alguien pregunta sobre la mejor manera de detectar en un Z80 unas 60 colisiones de sprites sin que afecte a la velocidad del juego, pues yo pondría la teoría de cómo lo hago (ticks de interrupción, en cada una una cosa distinta, y subdividir en trocitos la tarea) y no una ristra de código.

EDITADO: Además publicar los fuentes de un juego ASM, que por lo general no los comento casi nada, no difiere mucho del resultado de desensamblarlo con una utilidad. El que quiera mirar las tripas siempre puede hacerlo al fin y al cabo :wink:
Un saludo,

Gandulf

sromero
Nonamed
Mensajes: 1221
Registrado: Mar Abr 17, 2007 12:35 pm
Ubicación: Valencia
Contactar:

Mensaje por sromero » Jue Oct 04, 2007 6:01 pm

Gandulf escribió:Yo también soy bastante taliban esto. Somos talibanes de los dos extremos opuestos de forma de pensar. Pero eso no indica que tengamos que tirarnos los trastos a la cabeza.


Claro :)

Pero un detalle:

Efectivamente es un offtopic como una casa, pero yo nunca enseño mi código, y tampoco miro el de los otros, os lo aseguro. Siempre me ha interesado más la teoría sobre cómo hacer las cosas y luego currármelas yo que el que me den todo hecho. En serio, creo que es mucho mejor.


El OpenSource y el mostrar el código no trata de "ahora cojo tu rutina y hago copy & paste". No, para nada, no es eso ni de lejos.

Es, "A ver cómo ha hecho na_th_an esta rutina ... anda, mira, si hace esto así efectivamente es más rápido. Y en vez de hacer tal cálculo, tiene un tabla ... pues estaría bien usar entonces una tabla para el desplazamiento prefijado de los enemigos, y blahblahblah", etc etc.

Por ejemplo, yo no sabía cómo se hacía la paginación de los 128K en Z88DK (por temas de ubicación de las librerías, etc) hasta que miré el código fuente del Phantomasa2 de Na_th_an y ví que había que mover la pila a tal sitio y que había que tener cuidado al paginar y no usar funciones de SPLIB2 en ese caso. La compartición de código de na_th_an ha permitido que la comunidad (yo, en este caso, y cualquier otro que acuda a su código en general) se beneficie de "cómo paginar los 128K en z88dk sin que SPLIB2 se la pegue en el intento". Y nadie está hablando de "cojo el código de nathan y me lo pego en mi programa MUAHHAHAHAHAHA" ...

No es copiar, es ver y aprender por qué tu código es peor (o mejor), ver cosas que no se te habían ocurrido, y, lo más importante, no sólo conseguir todo eso para tí, sino conseguir todo eso para los demás.

Una es una visión "individual" y la otra es "comunitaria". Si no compartes código ni ves el de los demás, no crece "la comunidad", sólo tu "concimiento invididual", mientras que al compartir el código, das ideas a los que lo consultan, y otros te pueden dar sugerencias de mejora sobre él.

Si alguien pregunta sobre la mejor manera de detectar en un Z80 unas 60 colisiones de sprites sin que afecte a la velocidad del juego, pues yo pondría la teoría de cómo lo hago (ticks de interrupción, en cada una una cosa distinta, y subdividir en trocitos la tarea) y no una ristra de código.


Pues como puedes ver, se pueden hacer ambas cosas, explicar la teoría y rematarlo con un "mirad este ejemplillo":

http://www.worldofspectrum.org/forums/s ... php?t=5367

Ojo, nadie te recrimina nada, cada cual haga lo que quiera, pero está claro que un punto de vista es más beneficioso para la comunidad de programadores (y por tanto, de usuarios) que el otro. Aunque, por supuesto, respeto totalmente la decisión de cada programador de compartir o no su código.

El mío SIEMPRE será abierto, yo aprendo de otros, otros aprenden de mí, todos ganan.
NoP / Compiler

anjuel
Manic Miner
Mensajes: 297
Registrado: Mar May 08, 2007 9:14 am
Ubicación: Torreznoslandia
Contactar:

Mensaje por anjuel » Jue Oct 04, 2007 6:01 pm

Esta claro que hay distintos modos de verlo. A mi me gusta poder leer código comentado para aprender nuevas técnicas de algo concreto o cosas que desconozco como funcionan. A veces te puede inspirar para hacer algo de otra manera. Para mi es mucho mejor ;-)
(_\_) (_|_) (_/_) (_|_) ILLO KE HEHEHEHEHEHEEEHEHEHEHE!!
http://www.mojontwins.com

Avatar de Usuario
na_th_an
Nonamed
Mensajes: 1889
Registrado: Lun May 07, 2007 10:16 am
Ubicación: Andalucía

Mensaje por na_th_an » Jue Oct 04, 2007 6:05 pm

sromero escribió:[...]El mío SIEMPRE será abierto, yo aprendo de otros, otros aprenden de mí, todos ganan.


Yo aprendí a pasar variables entre ASM y C mirando el código de vuestro Columns, por ejemplo :)

Gandulf
Nonamed
Mensajes: 1067
Registrado: Lun May 07, 2007 10:06 pm

Mensaje por Gandulf » Jue Oct 04, 2007 6:11 pm

Con respecto a ese hilo de wos, pues me parece bien, yo también pongo ejemplos cortos de código a veces. Por cierto, que la rutina buena es la que pone al final, la primera versión es bastante poco óptima.

Sinceramente creo que estais equivocados con respecto a lo del código y os voy a intentar poner un ejemplo, a sabiendas de que por supuesto no vais a cambiar de idea (yo tampoco lo voy a hacer :lol: :lol: :) )

1º Si alguien sabe ensamblador y entiende un listado pegado en un foro, también sabe cargar spectaculator poner breakpoints y moverse por el código (por cierto, estupendo debugger, una maravilla). Es más incómodo, deacuerdo, pero básicamente tiene el mismo listado con solo usar un debugger. Si no entiende lo que ve en el debugger no va a entender el listado. Lo que entenderá son las explicaciones o comentarios que haya en él o en el propio foro. Para eso no hace falta poner el listado del código.

2º Para mi es mucho más divertido (yo siempre programé y sigo haciéndolo tanto el spectrum como el PC por diversión, me gusta, y mucho) mirar la documentación sobre algo y luego hacerme el programa, y luego ir mejorando mi propio código leyendo información sobre técnicas; que directamente coger un listado y ver cómo lo ha hecho alguien.

¿Qué creeis que es más útil?

- Un listado del código de impresión de sprites rotados usandos tablas de rotaciones
- Una explicación de cómo usar tablas de rotaciones, porqué y para qué, y la mejor forma de sacar partido de ellas.

Se pueden hacer las dos cosas, estoy deacuerdo, pero la segunda opción creo que es la buena.
Un saludo,

Gandulf

Responder

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 17 invitados