Página 3 de 6

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Sab, 07 Dic 2013, 01:01
por antoniovillena
Ten cuidado con la instrucción LDI, puesto que decrementa BC y en algún caso te puede decrementar B y alterarte el bucle, se puede arreglar con esto:

$this->bbcode_second_pass_code('', '
.draw
inc bc
inc bc
ldi
ldi
dec de
dec de
inc d
djnz draw
ret
')

Pero vamos que si quieres velocidad punta olvídate del call y del contador b y haz loop unrolling (desenrollado de bucle):

$this->bbcode_second_pass_code('', '
ldi
ldi
dec de
dec de
inc d
ldi
ldi
dec de
dec de
inc d
ldi
ldi
dec de
dec de
inc d
ldi
ldi
dec de
dec de
inc d
ldi
ldi
dec de
dec de
inc d
ldi
ldi
dec de
dec de
inc d
ldi
ldi
dec de
dec de
inc d
ldi
ldi
dec de
dec de
inc d
')

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Sab, 07 Dic 2013, 01:09
por antoniovillena
Me da 1155 ciclos aplicando loop unrolling. Por cierto antes calculaba mal los ciclos por byte porque dividía entre 32, hay que dividir entre 36 puesto que también pintas los atributos. Serían 32 ciclos/byte.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Sab, 07 Dic 2013, 01:12
por radastan
Lo he resuelto con un cómodo "ld c,255" antes del primer CALL. En total se realizan 36 LDI's, así que no tengo que preocuparme.

Y si, se que duplicando código gano velocidad, pero también pierdo tamaño. Ahora mismo ya he ganado bastante, creo que lo puedo dejar por bueno, me ha quedado una rutina sencilla de usar y que ocupa poquito, que es lo que buscaba.

Es que la idea que tengo con esta librería es poder hacer juegos para Cartucho IF2 en el futuro, es decir no usar la ROM para absolutamente nada. Y al ser de 16K los cartuchos el espacio es oro.

PD: Y que divertidos son estos hilos de optimizaciones de código, aparte de didácticos.

PD2: Buenas noches y gracias Antonio.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Sab, 07 Dic 2013, 16:37
por antoniovillena
Te dejo el último código que tengo de tu rutina sólo a modo de curiosidad (ya que para el tutorial vas a emplear la versión más corta).

$this->bbcode_second_pass_code('', '
void put_sprite_x16 (unsigned char *posicion, unsigned char x, unsigned char y)
{
#asm
ld (fin+1), sp
pop bc
pop bc
pop de
pop hl
ld a, c
and 7
rrca
rrca
rrca
and $e0
or e
ld e, a
ex af, af
ld a, c
and $18
or $40
ld d, a
ldi
ldi
dec e
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
ex de, hl
ld bc, $f91e
add hl, bc
ex de, hl
ldi
ldi
dec de
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
dec e
dec e
inc d
ldi
ldi
rra
rra
rra
and 3
or $58
ld d, a
ex af, af
ld e, a
ldi
ldi
ld a, e
add a, 30
ld e, a
ldi
ldi
fin: ld sp, 0
ret
#endasm
}
')

Aparte del loop unrolling he eliminado los 2 push de / pop de y he cambiado la forma en la que se leen los parámetros. Salen 989 ciclos, unos 27 ciclos/byte. Si lo pruebas asegúrate de que estén deshabilitadas las interrupciones.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Sab, 07 Dic 2013, 22:45
por radastan
Lo que vamos a hacer es dejar tu rutina para la "librería optimizada", así la gente podrá usar la que más le convenga.

Seguiré usando la mía por una razón, voy a desarrollarla para hacer otra de 24x24 pixels y es más sencillo trabajar con el loop de la parte de impresión de pixels. Quiero una librería con varias rutinas que permitan no tener que ceñirte a los clásicos 16x16, así habrá más libertad.

Es más, necesito mayor tamaño de sprite porque uno de mis próximos juegos trabaja con sprites a color bastante grandes (no va a ser a lo Popeye, pero si igual de colorido).

EDITADO:

La he probado y no funciona, se te debe haber traspapelado alguna línea.

EDITADO 2:

Vale, he quita la primera línea y lo que hay desde la etiqueta "fin" inclusive y así si va.

¿Para qué demonios tocas el par de registros SP?

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Sab, 07 Dic 2013, 23:30
por antoniovillena
$this->bbcode_second_pass_quote('radastan', 'Â')¿Para qué demonios tocas el par de registros SP?


Es para extraer datos de la pila más rápido. Si te das cuenta hay varios POPs al principio, es un poco más rápido que con LD X,(HL), el problema es que hay que equilibrar la pila, por eso se necesita la primera y la última línea (salva y restaura el contenido de SP).

El error que te da es por un efecto colateral en tu código, deberías tener las interrupciones deshabilitadas porque no las usas (poner un DI al comienzo). Aparecen cosas raras porque se produce una interrupción mientras se leen los parámetros con POP, la interrupción corrompe los valores que hay en la pila.

Puedes currarte una rutina con un tamaño variable de sprites, así lo tengo hecho yo en el otro hilo. Procura que no haya mucho overhead de velocidad entre esta rutina y una de tamaño fijo. En los sprites grandes suele haber muchos huecos (lugares en lo que la máscara es 11111111, es decir no se pinta nada), si te buscas la forma de evitarlos ganarías bastante en velocidad.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Sab, 07 Dic 2013, 23:57
por radastan
$this->bbcode_second_pass_quote('antoniovillena', '
')Puedes currarte una rutina con un tamaño variable de sprites, así lo tengo hecho yo en el otro hilo.


Ya, pero eso es a toda luces ineficiente. Significa usar otro registro, hacer push/pop con él, etc. La rutina pierde una velocidad que en tamaños grandes de sprite es precisamente más importante, veo más lógico una rutina para cada tamaño, tampoco pretendo hace una docena (16x16, 24x24, y 48x48).

Otra cosa es el uso de megatiles, que es algo que debemos comentar aparte porque es algo que siempre he visto muy interesante y que tengo bastante desarrollado en papel.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Dom, 08 Dic 2013, 00:36
por antoniovillena
$this->bbcode_second_pass_quote('radastan', '
')Ya, pero eso es a toda luces ineficiente.


Échale un vistazo (uno rápido a modo de curiosidad) a mi engine, acabo de comentarlo (en inglés) y publicarlo en WOS.

http://www.worldofspectrum.org/forums/s ... post739114

Ineficiente no es, aunque sí es harto de complicado puesto que necesita una programa externo (GfxBu) para generar los sprites en el mismo orden en el que se pintan.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Lun, 09 Dic 2013, 23:11
por radastan
Bueno, pues ya he acabado las versiones de 24x24 y 32x32 pixels, con esto abarco prácticamente la mayoría de sprites que se pueden dar en juegos sencillos y facilito enormemente a la gente trabajar con ellos. La siguiente rutina será una genérica para poner un sprite de tamaño al gusto (x * y caracteres) destinada a logotipos y gráficos grandes para menú y presentaciones.

Os dejo el código de la de 24x24 para que veáis los cambios (pocos), la de 32x32 es prácticamente la misma evolución respecto a la de 16x16:

$this->bbcode_second_pass_code('', '
void put_sprite_x24 (unsigned char *posicion, unsigned int x, unsigned int y)
{
// -------------------------------------------
// RUTINA DE IMPRESION DE UN SPRITE 24x24 PIXELS
// CON ATRIBUTOS EN CUALQUIER POSICION DE CARACTER
// ENTRADAS:
// D será la posición del cursor vertical en caracteres
// E será la posición del cursor horizontal en caracteres
// HL es la posición de memoria donde tenemos el sprite
// SALIDAS: se escribe en el mapa de pantalla
// ADVERTENCIAS: no comprueba límites de pantalla
// -------------------------------------------
#asm
ld hl,2 ;pasamos la variable de entrada al acumulador
add hl,sp
ld d, (hl)
inc hl
inc hl
ld e, (hl)
inc hl
inc hl
ld a, (hl)
inc hl
ld h, (hl)
ld l, a
ld a, d ; recuperamos el valor vertical
and 7 ; nos quedamos con la posición en el tercio
rrca
rrca
rrca ; rotamos para dejar su valor en múltiplos de 32 (linea)
and 224 ; borramos el resto de bits por si las moscas
or e ; sumamos el valor horizontal
ld e, a ; e preparado
ld a, d
and 24 ; modificamos según el tercio de pantalla
or 64 ; nos posicionamos a partir de 16384 (16384=64+0 en dos bytes)
ld d, a ; d preparado, ya tenemos la posición en pantalla
push de ; guardamos DE (la posición de pantalla)
push de
ld b, 8
ld c,255 ; cargamos C con 255 para no afectar B con LDI
call draw2
pop de ; recuperamos DE
ld a,e ; incrementamos una línea de caracteres (+32 bytes)
add a,32
ld e,a
ld a,d
adc a,0 ; aquí finaliza la suma de 32 a DE
ld d,a
push de ; guardamos DE
ld b, 8
call draw2
pop de ; recuperamos DE
ld a,e ; incrementamos una línea de caracteres (+32 bytes)
add a,32
ld e,a
ld a,d
adc a,0 ; aquí finaliza la suma de 32 a DE
ld d,a
ld b, 8
call draw2
; Ahora imprimimos los atributos
pop de ; recuperamos el valor horizontal
ld a,d ; calculamos el valor de posición en la pantalla
rra
rra
rra ; multiplicamos por 32
and 3 ; nos quedamos con los tres bits bajos
or 88 ; apuntamos al comienzo del mapa de atributos
ld d,a ; ya tenemos d listo, e no hay que cambiarlo
push de ; guardamos la posición en pantalla
ldi ; imprimimos los colores de arriba
ldi
ldi
pop de ; recuperamos la posición de pantalla
ld a,e ; incrementamos una línea de caracteres (+32 bytes)
add a,32
ld e,a
ld a,d
adc a,0 ; aquí finaliza la suma de 32 a DE
push de ; guardamos DE
ldi ; ponemos los colores de abajo
ldi
ldi
pop de ; recuperamos la posición de pantalla
ld a,e ; incrementamos una línea de caracteres (+32 bytes)
add a,32
ld e,a
ld a,d
adc a,0 ; aquí finaliza la suma de 32 a DE
ldi ; ponemos los colores de abajo
ldi
ldi
ret

.draw2
ldi
ldi
ldi
dec de
dec de
dec de
inc d
djnz draw2 ; decrementa B y si es cero deja de saltar a draw
ret

#endasm
}')

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Lun, 09 Dic 2013, 23:24
por angel
Has pensado en sprites de 16x24 u otras combinaciones no cuadradas? :D

EDIT: esto sin ejemplos para ver no mola na :lol: