PDA

Ver la versión completa : Solución definitiva para que el TV-Out funcione en tus programas



kounch
21/02/2006, 14:17
Hola
mi candidatura al concurso GP2X 2006 consiste en un corrector automático de la salida de TV para los programas que estén corriendo. No se puede hacer público nada del sofware que se ha entregado hasta que ellos lo hagan, pero lo que si puedo hacer es contaros todo lo que he deducido de la investigación para hacerlo. Ahí va:

El tamaño de la salida a pantalla (LCD o TV) está controlado por tres registros de la memoria:

C000 2906 - Escala horizontal de la pantalla
C000 2908 - Escala vertical de la pantalla
C000 290C - Anchura de la pantalla

El area visualizable de la pantalla está controlado por los registros de ventanas RGB:

C000 0x28E2+window*8 Coordenada X1 de la ventana número (window+1)
C000 0x28E4+window*8 Coordenada X2 de la ventana número (window+1)
C000 0x28E6+window*8 Coordenada Y1 de la ventana número (window+1)
C000 0x28E8+window*8 Coordenada Y2 de la ventana número (window+1)

Donde window puede variar de 0 a 3.

Los valores que se deben aplicar a estos registros dependen de que la pantalla esté en LCD, en TV-Out PAL o en TV-Out NTSC. El método para calcularlo es el siguiente:
Comprobamos si el TV-Out está activado, para ello se debe cumplir que el valor de C000 2800 tenga el bit 17 con valor 1.
Miramos el tamaño real de la pantalla. Para ello comprobar el valor del registros C000 2818 (altura real de la pantalla). Si el valor es 239, estamos en LCD. Si el valor es 287, estamos en TV PAL. Si el valor es 231, estamos en TV NTSC.
Tomamos la dimension X de nuestra imagen a representar, y aplicamos este calculo: dimensionX/320*MaxX donde MaxX es 1024 si estamos en LCD o 489 Si estamos en TV. El resultado lo ponemos en C000 2906
Tomamos la dimension Y de nuestra imagen a representar, y aplicamos este calculo: dimensionY/240*MaxY*BitsPP donde BistPP es 1 para 8 bits y 2 para 16 bits de color. MaxY es 320 si estamos en LCD, 274 Si estamos en TV PAL o 331 si estamos en TV NTSC. El resultado lo aplicamos en C000 2908.
Nos aseguramos de que el valor en C000 290C es 320*BitsPP
Finalmente, escalamos las ventanas RGB teniendo en cuenta que sus coordenadas deben tener un ancho maximo de 329 para LCD o de 669 para TV, así como un alto máximo de 239 para LCD, de 279 para TV PAL o de 231 para TV NTSC

Todo esto se traduce, por ejemplo, en cambiar estas dos funciones en la minimal lib:

void gp2x_video_RGB_setscaling(int W, int H)
{
float escalaw,escalah;
int bpp=(gp2x_memregs[0x28DA>>1]>>9)&0x3;

if(gp2x_memregs[0x2800>>1]&0x100) //Vemos si el TV-Out esta activado
{
escalaw=489.0; //Factor de escala RGB Horizontal para TV (comun a PAL y NTSC)
if (gp2x_memregs[0x2818>>1] == 287) //Comprobacion si la altura de la pantalla es para PAL
escalah=274.0; //Factor de escala RGB Vertical para TV PAL
else if (gp2x_memregs[0x2818>>1] == 239) //Comprobacion si la altura de la pantalla es para NTSC
escalah=331.0; //Factor de escala RGB Vertical para TV NTSC
}
else //Suponemos que esta en modo LCD (TV-Out desactivado)
{
escalaw=1024.0; //Escala RGB Horizontal para LCD
escalah=320.0; //Escala RGB Vertical para LCD
}

// scale horizontal
gp2x_memregs[0x2906>>1]=(unsigned short)((float)escalaw *(W/320.0));
// scale vertical
gp2x_memregl[0x2908>>2]=(unsigned long)((float)escalah *bpp *(H/240.0));
}
void gp2x_video_RGB_setwindows(int window0, int window1, int window2, int window3, int x, int y)
{
int window,mode,mode2,x1,y1,x2,y2;
int xmax,ymax;

if(gp2x_memregs[0x2800>>1]&0x100) //Vemos si el TV-Out esta activado
{
xmax=669; //Maximo ancho en modo TV-Out (comun a PAL y NTSC)
if (gp2x_memregs[0x2818>>1] == 287) //Comprobacion si la altura de la pantalla es para PAL
ymax=279; //Maximo alto en modo TV-Out PAL
else if (gp2x_memregs[0x2818>>1] == 239) //Comprobacion si la altura de la pantalla es para NTSC
ymax=231; //Maximo alto en modo TV-Out NTSC
}
else //Suponemos que esta en modo LCD (TV-Out desactivado)
{
xmax=319; //Maximo ancho en modo LCD
ymax=239; //Maximo alto en modo LCD
}

//Escalamos las coordenadas segun las dimensiones de la pantalla
x=(x * xmax) / 319;
y=(y * ymax) / 239;

//enable all RGB windows
gp2x_memregs[0x2880>>1]|=(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2);

for(window=0;window<4;window++) //windows 0..3
{
if(window==0) x1=0, y1=0, x2=x, y2=y, mode=window0;
if(window==1) x1=x, y1=0, x2=xmax, y2=y, mode=window1;
if(window==2) x1=0, y1=y, x2=x, y2=ymax, mode=window2;
if(window==3) x1=x, y1=y, x2=xmax, y2=ymax, mode=window3;

if(mode<0) { gp2x_memregs[0x28da>>1]&=~(1<<(window<<1)); }
else {
mode2=(mode>0x0F?0xF:mode);

//set alpha 0..0xE / colorkey,solid 0xF value
if(window<3)
{
gp2x_memregs[0x28de>>1]&=~(mode2<<(window<<2));
gp2x_memregs[0x28de>>1]|= (mode2<<(window<<2));
}
else
{
gp2x_memregs[0x28e0>>1]&=~(mode2<<((window-3)<<2));
gp2x_memregs[0x28e0>>1]|= (mode2<<((window-3)<<2));
}

//set window as blended (2), transparent/colorkey (1), solid (0)
gp2x_memregs[0x28dc>>1]&=~(3 <<(window<<1));
gp2x_memregs[0x28dc>>1]|= ((mode==0x11 ? 0 : (mode==0x10 ? 1 : 2))<<(window<<1));

//window coordinates
gp2x_memregs[(0x28e2+window*8)>>1]=x1;
gp2x_memregs[(0x28e4+window*8)>>1]=x2;
gp2x_memregs[(0x28e6+window*8)>>1]=y1;
gp2x_memregs[(0x28e8+window*8)>>1]=y2;

//enable window
gp2x_memregs[0x28da>>1]|=(3<<(window<<1));
}
}Simplemente aplicando estos dos cambios he recompilado el GP2XEngine así como el GP2XSpectrum y el Selector, y funcionan perfectamente con la televisión.

Perdón por el rollo, y espero que esto sea útil para todos.

kounch

EDIT: El ejemplo que he puesto es válido para la minimal lib 0.B siempre y cuando no se altere el valor del registro MLC_STL_HW (C000 290C) con funciones propias.

chipan
21/02/2006, 15:09
De rollo nada, ¡te mereces un kiosko en la gran via!

kounch
21/02/2006, 15:41
Gracias, pero tampoco es para tanto. Acabo de subir la teoría al wiki, aquí (http://wiki.gp32spain.com/index.php/FAQ_de_programaci%C3%B3n#C.C3.B3mo_hacer_una_aplic aci.C3.B3n_compatible_con_la_salida_de_TV).

K-teto
21/02/2006, 15:57
En el wiki ingles tambien hay informacion sobre el tema, de hecho el gnuboy2x que he mandado a la compo es compatible con el tvout usando la minilib :D
Que por cierto ha sido un grano en el culo esto del tvout hasta que descubri la pagina del wiki, y aun despues de tener la info, no encontraba el por que solo veia media pantalla, y era por la ventana rgb XDDD

ursaiz
21/02/2006, 16:00
Hola,

No has dejado unos videos flash de ejemplos , me suena de otro post pero no recuerdo el nombre la pagina.

kounch
21/02/2006, 16:35
En el wiki ingles tambien hay informacion sobre el tema, de hecho el gnuboy2x que he mandado a la compo es compatible con el tvout usando la minilib :D
Que por cierto ha sido un grano en el culo esto del tvout hasta que descubri la pagina del wiki, y aun despues de tener la info, no encontraba el por que solo veia media pantalla, y era por la ventana rgb XDDDSí, yo también estuve mirando los datos del Wiki inglés, pero indica mal la información sobre el factor de escala horizontal (ya que toman en cuenta la escala sólo para LCD), y vertical (que tiene datos erróneos para NTSC). Además, en efecto, no mencionan para nada el tamaño de las ventanas RGB. Cuando tenga un rato, también cambiaré la página del wiki inglés.

kounch
21/02/2006, 16:37
Hola,
No has dejado unos videos flash de ejemplos , me suena de otro post pero no recuerdo el nombre la pagina.Supongo que te refieres a este: http://www.youtube.com/watch?v=K6yJY3JOtf8 y este: http://www.youtube.com/watch?v=6t7DvF_LWDI

ursaiz
21/02/2006, 16:38
Eso es gracias :)

kounch
21/02/2006, 17:23
Sí, yo también estuve mirando los datos del Wiki inglés, pero indica mal la información sobre el factor de escala horizontal (ya que toman en cuenta la escala sólo para LCD), y vertical (que tiene datos erróneos para NTSC). Además, en efecto, no mencionan para nada el tamaño de las ventanas RGB. Cuando tenga un rato, también cambiaré la página del wiki inglés.Ya está cambiado el Wiki inglés: http://wiki.gp2x.org/wiki/TV-out_support

WinterN
21/02/2006, 19:09
Una preguntilla. Por lo visto el TV-Out que hay implementado actualmente en el firmware de la consola saca la resolución de la pantalla (320x240), aunque la aplicación o video en cuestión soportase más resolución.

¿Aquí ocurre igual?

kounch
21/02/2006, 19:28
Una preguntilla. Por lo visto el TV-Out que hay implementado actualmente en el firmware de la consola saca la resolución de la pantalla (320x240), aunque la aplicación o video en cuestión soportase más resolución.

¿Aquí ocurre igual?Lo que sucede es que, tanto el menú de la consola, como la configuración por defecto que tienes al iniciar la minimal lib o las SDL, toman una resolución de 320x240. Sin embargo, al aplicar escalado por hardware, se redimensiona la resolución que tu indiques para "caber" dentro de la pantalla actual (320x240 en LCD, 669x271 en PAL y 669x231 en NTSC si no me equivoco).

Por lo tanto, supongo que si alguien programara algo usando una resolución superior y utilizara lo que indico más arriba, obtendría una resolución escalada a 320x240 en LCD y a la que corresponda en TV-Out.

Las especificaciones del hardware de la consola indican que puedes utilizar resoluciones de hasta 1024x1024 sólo limitadas por el ancho de banda interno de los componentes.

Franxis
22/02/2006, 02:28
Gracias Kounch por publicar aquí el código fuente, pero la solución no es "definitiva". No sirve si se tiene un ancho de video distinto de 320:
gp2x_memregs[0x290C>>1]=width*bpp; /* Set Video Width */

¿Alguna forma de que funcione también en esta situación?

Sin TV-Out asi funciona:
gp2x_memregl[0x2908>>2]=(unsigned long)((float)W *bpp *(H/240.0));
Pero con TV-Out no...

Salu2

kounch
22/02/2006, 04:08
Gracias Kounch por publicar aquí el código fuente, pero la solución no es "definitiva". No sirve si se tiene un ancho de video distinto de 320:
gp2x_memregs[0x290C>>1]=width*bpp; /* Set Video Width */

¿Alguna forma de que funcione también en esta situación?

Sin TV-Out asi funciona:
gp2x_memregl[0x2908>>2]=(unsigned long)((float)W *bpp *(H/240.0));
Pero con TV-Out no...

Salu2¿Qué quieres decir con "mal"? ¿Mitad de altura, mitad de anchura, imagen reducida, imagen ampliada...?

La cuenta que hago yo, para convertir de algo que funciona en 320x240 (LCD) y que luego funcione en TV-Out es la siguiente.


//Obtengo la escala que valía en LCD (esto seria lo que a ti te funciona bien)
horizontal=gp2x_memregs[0x2906>>1];
vertical=gp2x_memregs[0x2908>>1];
//De ahi "deduzco" el valor original que se habría aplicado a la llamada a gp2x_video_RGB_setscaling(int W, int H)
width=(horizontal/1024.0)*320.0;
height=(vertical/(320.0*bpp))*240.0;

//Con los valores deducidos, reescalo la pantalla
// Ajuste de escala horizontal
gp2x_memregs[0x2906>>1]=(unsigned short)((float)escalaw *(width/320.0));
// Ajuste de escala vertical
gp2x_memregl[0x2908>>2]=(unsigned long)((float)escalah *bpp *(height/240.0));
Con esto, en el caso del MAME ;) se me corrige siempre el tamaño con un buen resultado (en algunos casos se corta un poco por debajo la imagen).

Igual mirando este código ves por dónde se te está yendo.

kounch
22/02/2006, 04:29
gp2x_memregs[0x290C>>1]=width*bpp; /* Set Video Width */
...
Sin TV-Out asi funciona:
gp2x_memregl[0x2908>>2]=(unsigned long)((float)W *bpp *(H/240.0));
Pero con TV-Out no...Salu2Mirando un poco más este código... ¿la W es el ancho que vas a aplicar y al que llamas width más arriba?
Si es así, ese cálculo no vale. Tienes que aplicar el factor de escala de altura (escalah) apropiado para cada caso:
escalah=320.0 para LCD
escalah=274.0 para TV PAL
escalah=331.0 para TV NTSC

Así, sería algo como
gp2x_memregl[0x2908>>2]=(unsigned long)((float)escalah *bpp *(H/240.0));

Franxis
22/02/2006, 05:11
No me has entendido, creo pero da igual... Aquí paso la función de escalado que funciona ok con cualquier ancho de video:



void SetVideoScaling(int pixels,int width,int height)
{
float x, y;
float escalaw,escalah;

int bpp=(gp2x_memregs[0x28DA>>1]>>9)&0x3; /* bytes per pixel */

if(gp2x_memregs[0x2800>>1]&0x100) /* TV-Out ON? */
{
escalaw=489.0; /* X-Scale with TV-Out (PAL or NTSC) */
if (gp2x_memregs[0x2818>>1] == 287) /* PAL? */
escalah=(pixels*274.0)/320.0; /* Y-Scale with PAL */
else if (gp2x_memregs[0x2818>>1] == 239) /* NTSC? */
escalah=(pixels*331.0)/320.0; /* Y-Scale with NTSC */
}
else /* TV-Out OFF? */
{
escalaw=1024.0; /* X-Scale for LCD */
escalah=pixels; /* Y-Scale for LCD */
}

x=(escalaw*width)/320.0;
y=(escalah*bpp*height)/240.0;
gp2x_memregs[0x2906>>1]=(unsigned short)x; /* scale horizontal */
gp2x_memregl[0x2908>>2]=(unsigned long)y; /* scale vertical */
gp2x_memregs[0x290C>>1]=pixels*bpp; /* Set Video Width */
}


Funciona ok ya en el MAME, lo único parece que se pierde algo de pantalla por los bordes y la imagen aparece quizás con demasiado brillo, pero va ok... Gracias Kounch por todo...

fosfy45
22/02/2006, 05:18
Interesante programa; ¿ funciona con cualquier firmware ? Lo pregunto por los que aun no nos hemos decidido a actualizar y por lo tanto no podemos usar el cable de video.

Saludos y suerte en el concurso.

kounch
22/02/2006, 05:21
No me has entendido, creo pero da igual... Aquí paso la función de escalado que funciona ok con cualquier ancho de video:

Funciona ok ya en el MAME, lo único parece que se pierde algo de pantalla por los bordes y la imagen aparece quizás con demasiado brillo, pero va ok... Gracias Kounch por todo...Justo iba a responderte que he estado mirando tu código, que acabo de compilar el mame y que creía que esta
void SetVideoScaling(int pixels,int width,int height)
{
float x, y;
float escalaw, escalah;
int bpp;

/*Comprobando TV*/
if(gp2x_memregs[0x2800>>1]&0x100)
{
escalaw=489.0; /*Factor de escala RGB Horizontal para TV (comun a PAL y NTSC)*/
if (gp2x_memregs[0x2818>>1] == 287) /*Comprobacion si la altura de la pantalla es para PAL*/
escalah=274.0; /*Factor de escala RGB Vertical para TV PAL*/
else if (gp2x_memregs[0x2818>>1] == 239) /*Comprobacion si la altura de la pantalla es para NTSC*/
escalah=331.0; /*Factor de escala RGB Vertical para TV NTSC*/
}
else /*Suponemos que esta en modo LCD (TV-Out desactivado)*/
{
escalaw=1024.0; /*Escala RGB Horizontal para LCD*/
escalah=320.0; /*Escala RGB Vertical para LCD*/
}

bpp=(gp2x_memregs[0x28DA>>1]>>9)&0x3; /* bytes per pixel */

/* Ajuste de escala vertical */
x=(unsigned short)((float)escalaw *(width/320.0));
/* Ajuste de escala vertical */
y=(unsigned long)((float)escalah *bpp *(height/240.0));


gp2x_memregs[0x2906>>1]=(unsigned short)x; /* scale horizontal */
gp2x_memregl[0x2908>>2]=(unsigned long)y; /* scale vertical */
gp2x_memregs[0x290C>>1]=width*bpp; /* Set Video Width */
}era la función que tenías que usar :D . Creo que se me olvidó mencionar al principio, que el código que he puesto vale para la minimal lib 0.B, pero que no sabía si valía para la 0.A. Voy a editarlo.

kounch
22/02/2006, 05:23
Interesante programa; ¿ funciona con cualquier firmware ? Lo pregunto por los que aun no nos hemos decidido a actualizar y por lo tanto no podemos usar el cable de video.

Saludos y suerte en el concurso.El código que propongo funcionará con cualquier firmware que permita activar el TV-Out, así que necesitarás un firmware 1.2.0 o superior.

Franxis
22/02/2006, 05:30
Kounch, voy a ver si me explico:

Lo que he postado es una función de 0.a pero es igual. Lo que quería decirte es que el código que has puesto solo funciona ok si el ancho de video es 320, si no no se vé bien. El codigo modificado que he puesto soluciona el problema.

El problema se debe es que pones 'escalah' a piñon a 320.0, 274.0o 331.0... Pero esto solo sirve si el ancho de video es 320 pixels... En cuanto esto no ocurre no se vé bien... Es el caso de los modos escalados del MAME que cada juego tiene una resolución distinta y yo cambio el ancho de video en consecuencia... Si quieres verlo prueba el MAME pulsando L+R un par de veces para ver los modos escalados... Comprobarás que no funcionan bien...

Para que funcionen bien he modificado ligeramente el codigo y adaptado a la 0.a, que es el código que he pegado antes...

saludos

fosfy45
22/02/2006, 05:38
El código que propongo funcionará con cualquier firmware que permita activar el TV-Out, así que necesitarás un firmware 1.2.0 o superior.

O.k. gracias, entonces habré de esperar a que aparezca un firmware en condiciones :(

Saludos.

kounch
22/02/2006, 05:43
Kounch, voy a ver si me explico:

Lo que he postado es una función de 0.a pero es igual. Lo que quería decirte es que el código que has puesto solo funciona ok si el ancho de video es 320, si no no se vé bien. El codigo modificado que he puesto soluciona el problema.

El problema se debe es que pones 'escalah' a piñon a 320.0, 274.0o 331.0... Pero esto solo sirve si el ancho de video es 320 pixels... En cuanto esto no ocurre no se vé bien... Es el caso de los modos escalados del MAME que cada juego tiene una resolución distinta y yo cambio el ancho de video en consecuencia... Si quieres verlo prueba el MAME pulsando L+R un par de veces para ver los modos escalados... Comprobarás que no funcionan bien...

Para que funcionen bien he modificado ligeramente el codigo y adaptado a la 0.a, que es el código que he pegado antes...

saludos
¿? A mí se me parecen bastante tu solución y la que he puesto yo. En fin...

EDIT: Acabo de verlo :( Perdon, por los post. A estas horas ya estamos algo espesos.

kounch
22/02/2006, 06:15
Último post al respecto tras revisar el código con calma; para quien use minimal lib 0.B sin modificar, el código que puse al principio, es perfectamente válido, ya que, en esta versión, se configura por defecto con un ancho RGB (registro C000 290C, MLC_STL_HW en la documentación) tomando 320 como número de pixels.

Si se utilizan funciones propias que alteren dicho registro, el código no funcionará, y deberá hacerse una adaptación como la que indica Franxis, teniendo en cuenta el nuevo ancho que se defina.