1

Tema: La sincronización del refresco vertical y el retardo del input.

Calamity escribió:
Recap escribió:

Y luego queda que hablemos sobre la sincronización. Veo que aconsejas Triple Buffer pero en MAME FX 0.136, por ejemplo, los desajustes sonoros que se producen al desactivar la sincronización del audio son imperceptibles --con lo que yo he probado-- y te permiten olvidarte de Triple Buffering y V-Sync para siempre jamás.

Éste es un tema central sobre el que me gustaría extenderme más. No lo he hecho porque, como todo esto, está en permanente revisión. Verás, en mi opinión es impensable una emulación que merezca la pena visualmente sin alguna forma de sincronización vertical. La cuestión es que la implementación normal no suele ser la mejor posible y genera problemas adicionales (input lag), especialmente la opción "triplebuffer". Por resumirlo, he sido defensor de "triplebuffer" hasta hace poco, pensando que el problema de input lag era probablemente un mito derivado de otros problemas diferentes (LCDs, USBs, etc.). Además, las opciones tradicionales para sincronización vertical, "waitvsync" y "syncrefresh" estaban rotas desde Mame v0.107 (sólo funcionaban si se activaba "throttle", lo que arruinaba el resultado). El caso es que investigando sobre el código de Mame, en GroovyMame hemos reparado dichas opciones ("waitvsync" y "syncrefresh"), de manera que "triplebuffer", con sus problemas asociados, ya no es necesario para nada, y además, ahora al combinarlas con la opción "multithreading", *creo* que hemos conseguido eliminar o reducir mucho el legendario problema de input lag asociado a la sincronización vertical. De todos modos aclaro que es una cuestión algo subjetiva, y que es más fácil detectarlo con controles tipo spinner, así que invito a quien quiera probarlo y tenga el ojo entrenado.

http://postback.geedorah.com/foros/view … 607#p12607

Es curioso que nunca haya notado hipos o problemas similares con MAME FX 0.136 sin activar T. Buffer o Wait for V-Synch. Vamos, que el Synch to Monitor ['Graphic Card'] Refresh me funciona perfectamente --tan perfectamente como con MAME FX 0.106-- con una generosa variedad de juegos. Creo recordar que Super Contra --a toda pantalla-- me daba algún fallo, pero lo tengo que confirmar.

No sabía que Groovy MAME era obra tuya también (¡!). ¿¡Dónde lo guardas (y lo discutes)!? ¿Se puede usar para la modalidad de 'tablas estáticas'? Si has conseguido devolverle a MAME la forma de sincronizar pre 0.107 (o hacer que Wait for V-Synch no introduzca retardo), sospecho que se va a hacer tremendamente popular en cuanto se corra la voz.

Respecto a las cosas que introducen retardo en la respuesta al 'input' en la emulación o los juegos bajo WIN, hay un mundo entero por abordar con rigor aún ahí. Es un hecho que Triple Buffer introduce retardo. No es el mejor de los ensayos, pero este texto vale para ver que incluso un defensor de este artefacto asume la inevitable aparición de retardo asociado:

http://www.anandtech.com/show/2794

También: http://www.anandtech.com/show/2803/7

Vamos a dejar en lo sucesivo aparte el uso de pantallas LCD dado que el retardo que todas introducen en mayor o menor medida es solo uno de sus muchos problemas y cualquiera interesado en un subforo como éste YA sabe que el CRT es la única vía contemplable. Quizás es más interesante hablar del retardo debido a la conexión USB, cuya existencia se asume de forma casi universal cuando no es cierto. Hay dispositivos USB problemáticos (y SO incapaces de gestionarlos adecuadamente), pero no es culpa del protocolo de conexión, sino de la calidad de los mismos.

Seguiremos, que esto da para mucho y... tengo que irme.

2

Re: La sincronización del refresco vertical y el retardo del input.

Gracias por abrir el nuevo hilo, Recap.

Recap escribió:

Es curioso que nunca haya notado hipos o problemas similares con MAME FX 0.136 sin activar T. Buffer o Wait for V-Synch. Vamos, que el Synch to Monitor ['Graphic Card'] Refresh me funciona perfectamente --tan perfectamente como con MAME FX 0.106-- con una generosa variedad de juegos. Creo recordar que Super Contra --a toda pantalla-- me daba algún fallo, pero lo tengo que confirmar.

Hipos, haberlos, haylos.

Por lo que puede deducirse viendo el código de Mame, 'syncrefresh' y 'waitvsync' son exactamente la misma cosa, es decir que es indiferente activar uno u otro.

El problema es que Mame sólo hace caso de estas opciones cuando, simultáneamente, activamos 'throttle' (por eso digo que estan "rotas"). Con la opción 'throttle' se activa, básicamente, un bucle de retardo, que tiene como propósito ajustar la velocidad de la emulación a la original de la placa pcb. Para ello, utiliza el reloj de nuestra cpu.

¡Pero nosotros no queremos que esto sea así! Al contrario, nuestro propósito es programar el reloj de la tarjeta gráfica de manera que sea éste el que temporice la emulación. Si 'throttle' está activo, tendremos, en la práctica, dos relojes tratando de temporizar el juego. Por muy bien que los sincronicemos, siempre habrá una pequeña diferencia entre el periodo de ambos. Podrán caminar al unísono durante bastantes frames, pero al cabo de cierto tiempo, uno no podrá alcanzar al otro, y se perderá un frame por el camino.

El problema es más o menos evidente dependiendo del juego y de si la frecuencia efectiva del modeline que hemos calculado está por encima o por debajo de la buscada. En cualquier caso, el problema existe. Y la forma de solventarlo es desactivando 'throttle'.

Por suerte, al contrario que 'syncrefresh' y 'waitvsync', 'triplebuffer' sí que funciona aunque desactivemos 'throttle'. Con esta configuración, Mame sólo hara caso del reloj de nuestra tarjeta de vídeo, y el resultado es que la velocidad de emulación se ajustará automáticamente a la de nuestra tarjeta, obteniendo scrolles perfectos.

Pero aunque visualmente conseguimos la perfección, por desgracia trasladamos el problema al audio, que sigue tratando de mantener la velocidad original. Si utilizamos modelines bien calculados, normalmente esto no se nota, ya que la diferencia es muy pequeña. Pero no siempre podremos obtener un modeline que reproduzca la velocidad original, debido a la limitación que impone nuestro monitor. El caso típico es el de los juegos verticales rotados, que tengan más de 240 líneas. En este caso el desfase entre el refresco obtenido, y la velocidad original es muy grande, y los problemas con el audio serán muy molestos.

Para solucionar este problema, SailorSat realizó el célebre parche 'soundsync', que incorpora CabMame. Con 'triplebuffer', 'soundsync' y 'nothrottle' tendríamos pues la combinación ganadora.

Pero, desgraciadamente, 'triplebuffer' parece añadir un tercer problema: input lag (retardo en la respuesta de los controles).

Hasta aquí, este es el resumen de la problemática con las versiones existentes de Mame.

Recap escribió:

No sabía que Groovy MAME era obra tuya también (¡!). ¿¡Dónde lo guardas (y lo discutes)!? ¿Se puede usar para la modalidad de 'tablas estáticas'? Si has conseguido devolverle a MAME la forma de sincronizar pre 0.107 (o hacer que Wait for V-Synch no introduzca retardo), sospecho que se va a hacer tremendamente popular en cuanto se corra la voz.

No, no es obra mía, sólo colaboro con algunos de los parches. El creador es Chris Kennedy (bitbytebit), él es el que mantiene el proyecto y programa todo el código. Todo esto ha surgido en los últimos meses alrededor del proyecto Switchres/GroovyArcade/GroovyMame. La información está muy desperdigada principalmente por estos hilos:

http://forum.arcadecontrols.com/index.p … c=107255.0
http://forum.arcadecontrols.com/index.p … c=110905.0
http://forum.arcadecontrols.com/index.p … c=106405.0
http://forum.arcadecontrols.com/index.p … c=107620.0

Luego sigo...

3

Re: La sincronización del refresco vertical y el retardo del input.

La problemática del 'throttle' me era totalmente ajena, la verdad. Y no la acabo de entender. Esa opción sirve para que MAME limite la velocidad de ejecución al 'timer' original y no use todo el rendimiento que nuestra CPU permite, ¿no es cierto? ¿Por qué el hecho de desactivarla le hace a MAME ajustarse al 'timer' de la tarjeta de vídeo? ¿Es solo gracias al 'triple buffer'? ¿Y no hay una manera de que sea sin TB?

Y Wait for V-Sych / Synch to Monitor Refresh, ¿deberían funcionar sin 'throttle'? ¿Por qué no han arreglado esto oficialmente, de ser así, después de tantas versiones?

De todos modos, tengo aún que leer los hilos que enlazas a ver qué decís. Estoy con poco tiempo estos días...

4

Re: La sincronización del refresco vertical y el retardo del input.

Recap escribió:

La problemática del 'throttle' me era totalmente ajena, la verdad. Y no la acabo de entender. Esa opción sirve para que MAME limite la velocidad de ejecución al 'timer' original y no use todo el rendimiento que nuestra CPU permite, ¿no es cierto?

Exacto.

Recap escribió:

¿Por qué el hecho de desactivarla le hace a MAME ajustarse al 'timer' de la tarjeta de vídeo? ¿Es solo gracias al 'triple buffer'?

Al desactivar 'throttle', Mame corre a todo lo que da la CPU, pero si activamos 'triplebuffer', la sincronización vertical que incorpora esta opción hace que Mame ajuste de nuevo su velocidad al refresco de la tarjeta gráfica.

Recap escribió:

¿Y no hay una manera de que sea sin TB? Y Wait for V-Sych / Synch to Monitor Refresh, ¿deberían funcionar sin 'throttle'?

Tal como está programado en la versión oficial de Mame, no: 'waitvsync y syncrefresh sólo funcionan si simultáneamente activamos 'throttle'. Permíteme Recap que pegue un fragmento del código de Mame donde se ve a las claras que este comportamiento es parte del diseño:

...de osd\windows\ddraw.c

    // sync to VBLANK
    if ((video_config.waitvsync || video_config.syncrefresh) && window->machine().video().throttled() && (!window->fullscreen || dd->back == NULL))
    {
           [--- aquí va el código para esperar el retrazado vertical---]
    }

Basta con eliminar lo que pongo en negrita para devolver el funcionamiento esperable a 'syncrefresh' y 'waitvsync', con o sin 'throttle'. Este es uno de los parches que incorpora GroovyMame.

Recap escribió:

¿Por qué no han arreglado esto oficialmente, de ser así, después de tantas versiones?

Puede que simplemente no lo consideren un problema, y prefieren que quien quiera sincronización vertical elija  la ruta de 'triplebuffer'.

En cuanto tenga tiempo iré ampliando el tema. Por cierto, gracias por el artículo, muy recomendable, y aclara ciertas cuestiones que enlazan con esto.

5

Re: La sincronización del refresco vertical y el retardo del input.

Calamity escribió:

Puede que simplemente no lo consideren un problema, y prefieren que quien quiera sincronización vertical elija  la ruta de 'triplebuffer'.

Suena raro, dado el rigor habitual de esta gente. Intentaré enterarme, a ver. ¿Es Groovy MAME para WIN?

6

Re: La sincronización del refresco vertical y el retardo del input.

Recap escribió:

Suena raro, dado el rigor habitual de esta gente. Intentaré enterarme, a ver. ¿Es Groovy MAME para WIN?

Sí, hay ejecutables para Windows y Linux:

http://mario.groovy.org/GroovyMame/

7

Re: La sincronización del refresco vertical y el retardo del input.

He intentado encontrar los 'hipos' con MAME UI FX 0.136 (Sync to monitor refresh + Throttle) y esto es lo que he obtenido tras varias horas de atención:

- Caso A -- Dodonpachi (320 x 240 x 57,550645): valor del refresco del equipo ligeramente por encima del refresco original (57,552 Hz):

'Scroll' perfectamente suave, hipos (sonoros) eventuales solo al desactivar Sync audio with video.

- Caso B -- Sengoku Ace (320 x 224 x 59,300000): valor del refresco del equipo ligeramente por debajo del refresco original (57,296 Hz):

'Scroll' perfectamente suave, hipos (sonoros) muy eventuales solo al desactivar Sync audio with video.

Saco en conclusión que Sync audio with video no necesita Triple Buffer para funcionar, pero me preocupa más por qué no obtengo las sacudidas de 'scroll' que deberían aparecer al tener Throttle activado (y por tanto, ¿hacer que MAME se rija por el reloj de la CPU en vez del de la gráfica?). Quizás es que esta cuestión (la del doble reloj, o mejor, cuál es el realmente el 'reloj de la CPU') no la acabo de entender. ¿Un poco de luz, Calamity?

8

Re: La sincronización del refresco vertical y el retardo del input.

Como dices, la opción -soundsync funciona en cualquier situación en la que exista desfase entre la velocidad original y la emulada, independientemente de la opción de sincrozación de vídeo que se utilice. Su funcionamiento es bastante rudimentario, básicamente consiste en aplicar un coeficiente a la frecuencia de muestreo del buffer de audio, calculado como velocidad-real/velocidad-emulada, que se actualiza constantemente.

Respecto a tus pruebas con MAME UI FX 0.136, parece que en los dos casos que comentas estaríamos tan cerca del refresco original (el error es de centésimas de Hz) que el problema no llega a manifestarse porque el desfase es absorbido. He revisado los parches de MAME UI FX y no actúan sobre las opciones de sincronización, por lo que descarto que en ese aspecto sea "mejor" que la versión normal. De todos modos, el dato correcto de refresco de un modo de vídeo debes obtenerlo mediante la medición que realiza Arcade_OSD el pulsar "5", en vez de usar el valor que aparece en ModeList.txt, especialmente si ya no utilizas la R9250 (en ese caso sí que son prácticamente coincidentes dado que medí uno por uno los valores reales de 'dotclock' de esa tarjeta).

A poco que te alejes de los valores originales de refresco vertical, empezarán a aparecer los problemas de hipos, pero paradójicamente, sólo si la frecuencia obtenida es mayor que la original. Esto se sabe desde hace tiempo, y de hecho, en cierto punto los modelines de la AVGA se rectificaron para que su refresco fuera ligeramente menor de 60Hz, para evitar hipos en el scroll de la mayoría de los juegos. Luego intentaré explicar por qué esto es así.

No obstante lo deseable sería que -syncrefresh ajustase la acción del juego a la frecuencia de la tarjeta de vídeo cualquiera que ésta fuera, porque no siempre podemos contar con obtener una aproximación tan buena como la de tu ejemplo, y al final hay muchos casos especiales a los que dar respuesta.

Lo que pongo a continuación es un comentario extraído del propio código de Mame, donde se explica en que consiste el mecanismo de "throttling" que implementa el emulador:

\src\emu\video.c

Throttling theory:

   This routine is called periodically with an up-to-date emulated time.
   The idea is to synchronize real time with emulated time. We do this
   by "throttling", or waiting for real time to catch up with emulated
   time.

   In an ideal world, it will take less real time to emulate and render
   each frame than the emulated time, so we need to slow things down to
   get both times in sync.

   There are many complications to this model:

       * some games run too slow, so each frame we get further and
           further behind real time; our only choice here is to not
           throttle

       * some games have very uneven frame rates; one frame will take
           a long time to emulate, and the next frame may be very fast

       * we run on top of multitasking OSes; sometimes execution time
           is taken away from us, and this means we may not get enough
           time to emulate one frame

       * we may be paused, and emulated time may not be marching
           forward

       * emulated time could jump due to resetting the machine or
           restoring from a saved state

Supongamos, para simplicar las cosas, que Mame es capaz de emular un ciclo completo en un intervalo de tiempo despreciable. Esto es: procesar el "input", emular el hardware y generar un nuevo frame, todo, en un instante. El resto del tiempo disponible tendremos que esperar, si no queremos que nuestro fps se dispare hasta el infinito.

Esta es la diferencia principal entre la emulación en general, donde normalmente tenemos que respetar el valor fps fijo, y los juegos 3D en tiempo real, donde el valor fps es arbitrario y sólo limitado por la potencia de la CPU/GPU, que es el enfoque que se explica en el artículo sobre triplebuffering que enlazaste al principio del hilo.

Para entender mejor cómo se organiza esto aquí va un esquema de la rutina que ejecuta Mame cada vez que tiene listo un frame:

video_manager::frame_update
{
.
.
.
update_throttle -> aquí se produce el primer retardo, mientras esperamos que transcurran tantos ciclos del reloj-CPU como sean necesarios para sincronizar el tiempo-real con el tiempo-emulado.
.
.
.
m_machine.osd().update -> aquí se produce el segundo retardo, mientras esperamos al inicio del 'blanking' vertical para dibujar mostrar el nuevo frame.
.
.
.
}

Lo primero que llama la atención es que el retardo (update_throttle) se ejecuta antes de que Mame muestre el frame, lo cual no parece lógico, aunque como veremos tiene poca o nula repercusión en la práctica.

El hecho de tener dos retardos no significa que ambos se lleguen a producir íntegramente. Lo que realmente ocurre es que, transcurridos unos cuantos ciclos, la suma de los dos retardos (throttle + waitvsync) tiende a ser constante, de forma que throttle se autoregula esperando sólamente el tiempo necesario para conseguir la velocidad deseada.

Consideremos primero el caso en que el refresco de la tarjeta de vídeo sea menor que el refresco original. Esto significa que el intervalo de tiempo empleado en m_machine.osd().update, esto es, esperando el blanking vertical, es mayor que el intervalo original del juego. Por tanto, tras unos pocos ciclos, update_throttle detectará que vamos más despacio que la velocidad original, por tanto cada llamada a update_throttle retornará inmediatamente sin esperar, realizándose sólo la espera propia a waitvsync dentro de m_machine.osd().update. Esto hace que la velocidad de emulación se ajuste a la velocidad de refresco impuesta por la tarjeta gráfica, resultando en un scroll perfecto.

Ahora consideremos el caso en que el refresco de la tarjeta de vídeo es mayor que el refresco original. Ahora, el tiempo empleado esperando al blaking vertical es inferior al intervalo total de retardo que necesitamos para mantener el valor de fps original. Por tanto, update_throttle detectará que vamos más deprisa, y por tanto intentará compensar este desfase con una espera adicional. Por otra parte, el blanking vertical es una breve ventana temporal que se produce en intervalos perfectamente regulares, y que hemos de aprovechar para escribir en el buffer de vídeo. El problema viene porque el pequeño retardo añadido por update_throttle, se va acumulando tras varios frames, hasta que llega un momento en que llegamos demasiado tarde para entrar en el blanking que nos tocaba, y tenemos que esperar al siguiente, lo que visualmente se traduce en un hipo de scroll imposible de ignorar.

Resulta evidente pues que la única forma de conseguir la sincronización perfecta en ambas situaciones es desactivar manualmente el mecanismo de throttling. El problema, como hemos comentado otras veces, es que al hacer esto, Mame interpreta que queremos que funcione a toda velocidad, por lo que ignora el retardo waitvsync. Esto es lo que corregimos en GroovyMame.

9

Re: La sincronización del refresco vertical y el retardo del input.

¡Epa!

Gracias mil por tomarte la molestia, Calamity. No puedo decir que he entendido todo el mecanismo, al menos en una primera lectura, pero lo iré desmenuzando. No parece fácil llegar a enterarse de cómo cocinan la cuestión el resto de emuladores de interés, y sería un tema importante.

Entiendo entonces que con un MAME con el Throttle arreglado es indiferente si el refresco de nuestro equipo es superior o inferior al del 'hardware' original, pero con un MAME estándar es mejor que sea inferior, si bien, si las discrepancias son de centésimas de Hz, en la práctica tampoco se nota. ¿?

¿Realiza Video Mode Maker la configuración de los INI atendiendo a este condicionante?

10

Re: La sincronización del refresco vertical y el retardo del input.

Recap escribió:

Entiendo entonces que con un MAME con el Throttle arreglado es indiferente si el refresco de nuestro equipo es superior o inferior al del 'hardware' original, pero con un MAME estándar es mejor que sea inferior, si bien, si las discrepancias son de centésimas de Hz, en la práctica tampoco se nota. ¿?

Eso es, exacto.

Recap escribió:

¿Realiza Video Mode Maker la configuración de los INI atendiendo a este condicionante?

No, el generador de modelines busca la mejor aproximación, quede ésta por encima o por debajo del valor buscado. En cierto momento sí me planteé el poner una opción para obtener la mejor aproximación "por debajo", pero pienso que en la práctica es mejor reparar Mame para no tener que preocuparse por esto.

La razón principal es que no es tan sencillo conocer a priori el refresco real obtenido con una precisión tal como para poder tomar decisiones sobre él, salvo en el caso de la R9250*, como comentaba, pues para esta tarjeta sí que me tome el trabajo de medir uno por uno los resultados para cada valor de dotclock introducido.

* Realmente no depende tanto de la tarjeta sino del algoritmo que utilicen los drivers para programar los PLLs de cierta familia de hardware, es decir que los valores que obtuve para la R9250 también son validos para otras tarjetas soportadas por los mismos drivers, como la X300, aunque probablemente sean diferentes de los modelos más nuevos, como las HD que tienen AtomBIOS. Ya hablaremos de este tema, que tiene miga.

De todos modos, era necesario introducir el funcionamiento del mecanismo de "throttling" que implementa Mame para tratar de explicar más adelante cuáles son las posibles causas de "input lag" que pueden producirse como resultado de la sincronización vertical.

11

Re: La sincronización del refresco vertical y el retardo del input.

Expectante quedo.

A ver si le digo algo al de MAME UI 32 FX, mientras.



(No me había percatado de que los valores que refleja Arcade OSD no son los buenos si no le obligas a reescribirlos con "5"...)