Karoshi MSX Community

Desarrollo MSX => Desarrollo (Español/Spanish) => Mensaje iniciado por: Iggy Rock en 21 de Enero de 2012, 12:34:52 pm



Título: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Iggy Rock en 21 de Enero de 2012, 12:34:52 pm
Esto viene de la idea que surgió en este hilo (http://karoshi.auic.es/index.php?topic=2226.msg27184#msg27184)

La cuestión es que es mas rápido escribir una serie de datos iguales usando OUT(n),A en vez de series de OUTI's sin tener en cuenta limitaciones de escritura en VRAM. Esto es un hecho, ahora bien,  el manejo de los datos comprimidos o codificados es lo que hará que este sea una método viable o al menos si hay un límite aceptable desde el cual es preferible usar datos RLE.

EL programa que adjunto incluye un bitmap en sc3 que se comprime internamente de esta manera tan poco óptima:

En cada par de bytes:

Byte1: Dato literal
Byte2: nº de repeticiones hasta 128

De esta manera el gráfico se comprime un 55% aproximadamente. Queda en un 45% del tamaño original.

y lo vuelco a la VRAM de esta manera tan poco elegante y por supuesto tampoco optimizada:

Código:
RLEDATA_OUT: LD HL,IMAGE_RLE

LD A,[HL]
INC HL
PUSH HL
LD L,[HL]
LD H,$43
JP [HL]
.ORG $4300

REPT 128
OUT [$98],A
ENDR

POP HL
INC HL
LD A,[HL]
AND A
RET Z
INC HL
PUSH HL
LD L,[HL]
LD H,$43
JP [HL]


frente a:

Código:
RAWDATA:

CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
El resultado se puede ver pulsando la barra espaciadora o dejándola pulsada.  Gana RAWDATA!

¿que os parece optimizar el código de manera que sea "rentable" su uso?



 






Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Iggy Rock en 21 de Enero de 2012, 12:42:39 pm
Por cierto, sin tocar nada del código RLEDATA_OUT e incluyendo dos NOP's por cada OUTI, la ventaja es para el primero. Ademas hay que tener en cuenta el menor espacio ocupado. Son dos ventajas! ;D

El dato $00 indica fin del archivo.


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Iggy Rock en 21 de Enero de 2012, 01:46:46 pm
Bueno, algo mejor cambiando el orden de los datos por cada par de bytes. (nº rep, dato literal):

Código:
RLEDATA_OUT: LD DE,IMAGE_RLE

LD A,[DE]
LD L,A
INC DE
LD A,[DE]
INC DE
LD H,$43
JP [HL]
.ORG $4300

REPT 128
OUT [$98],A
ENDR

LD A,[DE]
CP 129
RET Z
LD L,A
INC DE
LD A,[DE]
INC DE
JP [HL]


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: aorante en 21 de Enero de 2012, 01:51:16 pm
La segunda ROM parece que no funciona bien... Muestra gráficos extraños en vez del avatar de un conocido coder :D

por otro lado,
¿que hace "JP [HL]"?
he visto que también esta con los registros de indice.

y "REPT 128", ¿que es?  ???

No acabo de entender lo que hace RLEDATA_OUT. Puedes poner algún comentario?
Justamente estoy interesado en una rutina descompresora RLE a VRAM y sobre todo aprender  :D

Estoy haciendo una app(win) para tratar gráficos de SC2/4 (creo que puse un comentario en estos foros) y quiero añadirle la opción de comprimir en RLE.

saludos!



Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Iggy Rock en 21 de Enero de 2012, 02:00:15 pm
Ese @aorante!: No tengas en cuenta la Segunda ROM.

- JP (HL) salta a la dirección indicada por el registro HL. Es un poco confuso al ir entre paréntesis.
- REPT X/ ENDR ... Eduardo te vacastigar: " REPITELO CIEN VECES"  ;D. Repite X veces lo que hay entre las dos sentencias.
- Las rutinas de compresión y descompresión son muy rudimentarias, solo para pruebas. Pero si te interesa te la pasaré una vez esté optimizada.



Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: aorante en 21 de Enero de 2012, 02:22:02 pm
Ese @aorante!: No tengas en cuenta la Segunda ROM.
Ok. Ya he visto la tercera!  :)

Citar
- JP (HL) salta a la dirección indicada por el registro HL. Es un poco confuso al ir entre paréntesis.

entiendo, pero al "leer" el codigo es un lio!   :o
Se me han suicidado 128 neuronas!!!  ;D

Citar
- REPT X/ ENDR ... Eduardo te vacastigar: " REPITELO CIEN VECES"  ;D. Repite X veces lo que hay entre las dos sentencias.

es que pico rutinas en el SDCC (combino C y ASM), y no tiene tantas facilities como el asMSX...   :P

Citar
- Las rutinas de compresión y descompresión son muy rudimentarias, solo para pruebas. Pero si te interesa te la pasaré una vez esté optimizada.

Muchas gracias...  :D


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Iggy Rock en 21 de Enero de 2012, 05:16:17 pm
Un poquito mas rápido usando la pila:

Código:
RLEDATA_OUT: LD [STACK],SP
LD SP,IMAGE_RLE
POP BC

LD A,C
LD L,B
LD H,$43
JP [HL]
.ORG $4300

REPT 128
OUT [$98],A
ENDR

POP BC
LD A,C
LD L,B
AND A
JP Z,RLEDATA_END
JP [HL]
RLEDATA_END: LD SP,[STACK]
RET


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Mortimer en 21 de Enero de 2012, 07:15:50 pm
Muy interesante, veo que mi intuición iba por buen camino  :D

Y ya para rizar el rizo, si queremos también la máxima compresión y hay espacio en la ram, quizás se pueda aplicar antes alguna compresión basada en Lempel-Ziv, porque los datos RLE a su vez suelen ser bastantes comprimibles con ese sistema.



Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Iggy Rock en 21 de Enero de 2012, 07:45:33 pm
Muy interesante, veo que mi intuición iba por buen camino  :D

Y ya para rizar el rizo, si queremos también la máxima compresión y hay espacio en la ram, quizás se pueda aplicar antes alguna compresión basada en Lempel-Ziv, porque los datos RLE a su vez suelen ser bastantes comprimibles con ese sistema.



Si que es muy interesante! :D. Con la última optimización usando la pila, por lo que he visto una compresión del 50% aprox. compensa en espacio y en velocidad. Depende de como estén ordenados los datos puede ser incluso mas rápido que OUTI a secas y por supuesto mas rápido si es OUTI+NOP.

La compresión es muy sencilla para permitir la velocidad en la descompresión a VRAM pero si hay grandes areas continuas puede ser bastante efectivo.

Os dejo el código por si quieres trastear o aorante quiere mirarlo para su uso:

* Hay que añadir un bitmap en screen 3 (&H0600 bytes)

Código:
.page 1
.ROM
.start BOOT
.DB "RLE2VDP"


VRAMFRM EQU $0000
DATA_PORT EQU $0098 ;PUEDE VARIARSE
REG_PORT EQU $0099 ;PUEDE VARIARSE
IMAGE_RLE EQU $8800
STACK EQU $87F0
INTVECTAB EQU $FC00 ;TABLA -$101
HOOK EQU $FDFD

.INCLUDE "ASM/SYSVAR.ASM"
.INCLUDE "ASM/KEYBOARD.ASM"



BOOT: EI

CALL $0075

DI


;COMPRESION RLE 127

LD HL,IMAGE1
LD DE,IMAGE_RLE
COMPRLEBC1: LD BC,$0000
LD A,[HL]
AND A
JR Z,COMPRLEND
COMPRLEBC0: INC HL ;CPI PARA OPTIMIZAR
LD C,[HL]
BIT 7,B
JR Z,COMPRLEJP3
LD B,0
DEC HL
JR COMPRLEJP2

COMPRLEJP3: INC B

CP C
JR Z,COMPRLEBC0
COMPRLEJP2: LD [DE],A ;GUARDA DATO
INC DE
LD A,B
RLCA ;DUPLICA
NEG ;NEGATIVO

LD [DE],A ;GUARDA Nº REPETICIONES EN NEGATIVO
INC DE
JR COMPRLEBC1
COMPRLEND: LD [DE],A

LD HL,RAWDATA


;CONFIGURA GANCHO INTERRUPCIONES IM2

LD HL,RLEDATA
LD [HOOK+1],HL
CALL INSTALLISR
I_LOOP: JR I_LOOP

INSTALLISR: DI
LD HL,INTVECTAB
LD E,L
LD D,H
INC DE
LD [HL],HOOK>>8
LD BC,256
LDIR
LD A,$C3
LD [HOOK],A

LD A,INTVECTAB>>8
LD I,A
IM 2
EI
RET   

;________________________________________________

RLEDATA: IN A,[REG_PORT]
LD A,44
LD B,7
CALL W_REGVDP
LD HL,VRAMFRM
CALL INIVPOKE
CALL RLEDATA_OUT
LD A,11
LD B,7
CALL W_REGVDP

;BARRA ESPACIADORA
;OUT: FLAG C

LD C,8
CALL K_GET_LINE
RRA
JR NC,NO_SPACE1

LD HL,RAWDATA
LD      [HOOK+1],HL
                LD      A,$C3
        LD      [HOOK],A

NO_SPACE1: EI
RETI


RLEDATA_OUT: LD [STACK],SP
LD SP,IMAGE_RLE
POP BC

LD A,C
LD L,B
LD H,$44
JP [HL]
.ORG $4400

REPT 128
OUT [DATA_PORT],A
ENDR

POP BC
LD L,B
LD A,C
AND A
JP Z,RLEDATA_END
JP [HL]

RLEDATA_END: LD SP,[STACK]
RET


RAWDATA: IN A,[REG_PORT]

LD A,44
LD B,7
CALL W_REGVDP

LD HL,VRAMFRM
CALL INIVPOKE

LD HL,IMAGE1
LD C,DATA_PORT

CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S

LD A,11
LD B,7
CALL W_REGVDP

;BARRA ESPACIADORA
;OUT: FLAG C

LD C,8
CALL K_GET_LINE
RRA
JR NC,NO_SPACE2

LD HL,RLEDATA
LD      [HOOK+1],HL
                LD      A,$C3
        LD      [HOOK],A

NO_SPACE2: EI
RETI
REPOUTI256:

REPT 256
OUTI
ENDR
RET

W_REGVDP:       OUT     (REG_PORT),A
                LD      A,B
                OR      10000000B
                OUT     (REG_PORT),A
                RET

INIVPOKE:       LD      A,L
                OUT     [REG_PORT],A
                LD      A,H
                OR      01000000B
                OUT     [REG_PORT],A
                RET

IMAGE1: .INCBIN "IMAGE1.SC3"
IMAGE1_OEF: DB 0


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Dioniso en 21 de Enero de 2012, 08:49:11 pm
Yo me quedo con el vuelco "raw".

Si se volcaran 128 veces el valor 1 y 128 veces el valor 0 pues sería un buen método el que planteáis, pero si cada vez que no se repite el valor hay que hacer esto:

Código:
POP HL
INC HL
LD A,[HL]
AND A
RET Z
INC HL
PUSH HL
LD L,[HL]
LD H,$43
JP [HL]

pues olvidaos ... Tendría que ser una imagen de lo más simple para que medio funcionara.

La diferencia entre OUT y OUTI es de 5 t-states, nada más.

POP   HL      ; 10 t-states
INC   HL      ;  6 t-states
LD   A,[HL]      ;  7 t-states
AND   A      ;  4 t-states
RET   Z      ; 11 t-states
INC   HL      ;  6 t-states
PUSH   HL      ; 11 t-states
LD   L,[HL]      ;  7 t-states
LD   H,$43      ;  7 t-states
JP   [HL]      ;  4 t-states

-Esto hace un total de 73 t-states.
-Le añadimos un OUT, es decir, 11 t-states.
-Son 11 instrucciones por lo que se le habría que añadir 11 t-states más en modo IM1.
-Total, 95 s-tates para un valor cada vez que no se repite.

RLE = 95 t-states, RAW = 17 (mediante OUTI). Supongo que la imagen debería tener una compresión de casi el 80% para que el método RLE a VRAM fuera mejor que el volcado RAW.


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Dioniso en 21 de Enero de 2012, 08:56:23 pm
He visto que también lo haríais en modo IM2. Bueno, en ese caso se recortan la rutinas:

RLE = 84 frente a RAW = 16


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Dioniso en 21 de Enero de 2012, 09:06:36 pm
Por qué no me habré leído el post entero ...

Acabo de ver que habéis optimizado la rutina. Ahora sería:

POP   BC      ; 10 t-states
LD   L,B      ;  4 t-states         
LD   A,C      ;  4 t-states         
AND   A      ;  4 t-states         
JP   Z,RLEDATA_END   ; 10 t-states      
JP   [HL]      ;  4 t-states
más el OUT

Lo que en modo IM2 resulta en lo siguiente:

RLE = 47, RAW = 16  cuando no se repite el valor
RLE = 11, RAW = 16 cuando se repite el valor

edito: corregida la gamba del modo IM2 más abajo


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Mortimer en 21 de Enero de 2012, 09:11:16 pm
He visto que también lo haríais en modo IM2. Bueno, en ese caso se recortan la rutinas:

RLE = 84 frente a RAW = 16

Creo que estás mezclando el modo de interrupción (IM0, IM1 ó IM2) con la velocidad de ejecución debido al ciclo adicional del estado M1 del Z80. Independientemente del modo de interrupción, los retardos introducidos son (Según http://map.grauw.nl/resources/z80instr.php (http://map.grauw.nl/resources/z80instr.php))

Citar
Every instruction has 1 additional M1 wait state
Instructions starting with a CB, DD, ED, FD, DDCB or DDFD opcode have two additional M1 wait states

Por lo que la direrencia entre OUT (n),A y OUTI son 6 ciclos.

En cuanto al problema de la sobrecarga si hay pocos datos repetidos, y si queremos complicarnos mucho la vida, podríamos utilizar un bit del byte que indica las repeticiones, para indicar si lo siguiente que viene es un bloque que no merece la pena ser comprimido y volcar con OUTI, o es RLE. En desensamblado añadiría algo de sobrecarga, pero la rutina de compresión ya tendría que ser algo más inteligente para que valorara cuando indicar que lo siguiente es una cadena literal


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Dioniso en 21 de Enero de 2012, 09:23:03 pm
Creo que estás mezclando el modo de interrupción (IM0, IM1 ó IM2) con la velocidad de ejecución debido al ciclo adicional del estado M1 del Z80.

Ha sido una paja mental mía. Sí ... La edad.  :angel:

RLE = 54, RAW = 18  cuando no se repite el valor
RLE = 12, RAW = 18 cuando se repite el valor


Vaya gamba con el IM2 ...


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Iggy Rock en 21 de Enero de 2012, 09:27:27 pm
@Dioniso , gracias por echarle un tiento al código. :D

Si, la última optimización mejora bastante los tiempos y permite un mayor rango de archivos candidatos a RLE.


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: aorante en 21 de Enero de 2012, 10:13:19 pm
Si, la última optimización mejora bastante los tiempos y permite un mayor rango de archivos candidatos a RLE.

supongo que no digo nada nuevo para los que ya lleváis tiempo peleando en estas cosas, pero quizás pueda servir los que no conocen mucho el tema.
En el caso de una pantalla de screen2/4, si se usa para volcar un tileset (patrones+colores), o un gráfico, si te curras el orden de los tiles por colores y que estos estén arreglados (el fondo y la tinta seguidos), una compresión RLE solo en los datos de los colores se puede ganar mucho, mientras que utilizarlo en los patrones puede que incluso ocupe más. Los conversores no suelen darte los datos ordenados, y hay que pasar unas horas arreglandolo con la tecnica "handmade"  ;D

ahí queda eso!  :D


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Dioniso en 21 de Enero de 2012, 11:05:36 pm
Sí, efectivamente. O cosas como tener el cero y el uno como color negro, sin necesitar transparencias de ningún tipo. Algo como:

$06,$06,$16,$06,$06,$16,$06,$06,$16,$06,$06,$16,$06,$06,$16,$06,$06,$16,$06,$06,$16

serían 28 bytes en RLE y 21 en RAW. Mientras que las TILES se podrían optimizar a:

$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16

y serían 2 bytes en RLE  :laugh:

Pero quizá no merezca la pena meterse en tanta "optimización" si hablamos de cargar los tres bancos de patrones. La diferencia de velocidad sería despreciable.


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: aorante en 24 de Enero de 2012, 08:56:38 pm
una duda...

como funciona el RLE?

es correcto lo siguiente?

1er byte - número repeticiones (de 1 a 255). Si es 0 es fin.
2do byte - valor



Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Mortimer en 24 de Enero de 2012, 10:12:36 pm
Sí, sería correcto, no hay forma 'oficial' de hacerlo, así que verás varias implementaciones con la misma idea básica, y quizás algunos posibles refinamientos como por ejemplo para intentar optimizar el tamaño de los casos sin repetición.


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: j4mk3 en 24 de Enero de 2012, 11:44:14 pm
...se puede ganar mucho, mientras que utilizarlo en los patrones puede que incluso ocupe más. Los conversores no suelen darte los datos ordenados, y hay que pasar unas horas arreglandolo con la tecnica "handmade"  ;D

Y lo que costó en el Hans...la de dios y horas con el nMSXTiles. verdad Aorante? :) ...moviendo, girando..cambiando colores. La experiencia fue muy util para que Pentacour refinara la aplicación y pusiera nuevas opciones destinadas a este tipo de faenitas.
En Hans Adventure, el volcado a VRAM es directo desde RLE, pero creo q no optimizado. En el gráfico de portada tube que poner 3 parones para entrar en la interrupción y que no parara la música. Así que a groso modo...tardo 3 frames en hacerlo entero. Pero ya digo que no está nada optimizado ni con buffer en Ram ni nada.

Interesante Hilo y aquí mi experiencia. ;)


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: theNestruo en 25 de Enero de 2012, 12:25:19 am
es correcto lo siguiente?
1er byte - número repeticiones (de 1 a 255). Si es 0 es fin.
2do byte - valor
Una variante típica es que algún bit del primer byte te permita alternar entre "vienen n repeticiones" o "vienen n bytes sin repetición" para los fragmentos en los que viene una buena mezcolaina de bytes.
Ejemplo chorra (considero el primer bit 0 y 1 significando repeticiones y fragmento exacto):
Código:
84 10   04 14 6F 3D 41   82 9F   00
se traduciría a:
Código:
10 10 10 10  14 6F 3D 41  9F 9F

Luego tienes variantes de todo tipo, según las necesidades específicas que tengas...
Por ejemplo, puedes hacer repeticiones de bloques ("repetir 7 veces la siguiente secuencia de 4 bytes").
Otro ejemplo: en mi época de GP32, para pintar sprites por software, lo que hice fue un pseudo-RLE en el que si el primer bit era 0 indicaba hueco a saltar y 1 indicaba número de bytes a copiar (es decir, comprimía las repeticiones de bytes transparentes). Ahorraba ir haciendo un if por cada byte y los fragmentos a copiar se volcaban con un memcpy().

Implementar RLE es como cocinar una tortilla: lo básico es el huevo batido; luego cada uno le añade lo que más le guste ;D


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: aorante en 25 de Enero de 2012, 10:13:55 am
Gracias theNestruo!

estoy incluyendo en la tool que estoy programando la compresión de los datos con RLE y la opción primera me parece interesante. Estoy pensando en poner las dos formas: la sencilla que preguntaba (qe va muy bien para los colores) y la que tu dices.

Saludos!


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: aorante en 25 de Enero de 2012, 08:51:48 pm
he programado esta rutina para descomprimir RLE a VRAM (1ºB:1-255=repeticion,0=fin ; 2ºB:valor)
Funciona, pero tengo la duda con lo de la escritura a VRAM en los TMS99xx. He puesto 2 "nops", pero no se si sobran o faltan.
¿podéis echarme una mano en este tema?
y
¿se puede optimizar?


Código:
; descompresor RLE a VRAM
unRLE2VR:
  ; direccion de VRAM (DE)
  in A,($99)
  di
  ld A,E   
  out ($99),A
  ld A,D       
  add A,$40
  out ($99),A
  ei
 
getCMD: ;mira byte de codigo, 1-255 repeticion   
  ld A,[HL]
  cp 0  ;si es 0 es fin
  ret Z ;sale de la funcion
 
  inc HL 
  ld B,A ;numero de repeticiones
   
  ld A,[HL] ;recoge el valor
 
RLE_bucle:
  out ($98),A
  nop
  nop
  djnz RLE_bucle
 
  inc HL
  jr getCMD


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: Mortimer en 25 de Enero de 2012, 09:18:58 pm
Pues si consideramos que 28 son los mínimos ciclos seguros, te sobraría un NOP en el bucle, porque ya quedaría

Código:
RLE_bucle:
  out ($98),A    ; 12 ciclos
  nop         ; 5
  djnz RLE_bucle ; 14 si se repite

Total 31

Y apurando un pelín más
Código:
RLE_bucle:
  OUT ($98),A    ; 12 ciclos
  DEC B        ; 5
  JP NZ,RLE_bucle  ; 11

Total 28!

Y en cuanto al resto, cambia CP 0 por AND A y ahorrarás 3 ciclos, y también el JR final, puedes cambiarlo por un JP y ahorras 2 ciclos más por iteración.


Título: Re: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?
Publicado por: aorante en 27 de Enero de 2012, 12:55:27 pm
gracias por la ayuda Mortimer!