supports prueba pages example developer code accelerated javascript opengl opengl-es three.js webgl

javascript - prueba - webgl simulation



WebGL/OpenGL: comparando el rendimiento (3)

Para fines educativos, necesito comparar el rendimiento de WebGL con OpenGL. Tengo dos programas equivalentes escritos en WebGL y OpenGL, ahora necesito tomar la velocidad de fotogramas de ellos y compararlos.

En Javascript utilizo requestAnimationFrame para animar, y noté que causa que la velocidad de fotogramas sea siempre de 60 FPS, y se desactiva solo si cambio de pestaña o ventana. Por otro lado, si siempre llamo a la función de renderizado recursivamente, la ventana se congela por razones obvias.

Así es como estoy tomando el FPS:

var stats = new Stats(); stats.domElement.style.position = ''absolute''; stats.domElement.style.left = ''450px''; stats.domElement.style.top = ''750px''; document.body.appendChild( stats.domElement ); setInterval( function () { stats.begin(); stats.end(); }, 1000 / 60 ); var render= function() { requestAnimationFrame(render); renderer.render(scene,camera); } render();

Ahora el problema de tener siempre la escena a 60 FPS es que no puedo compararlo con la velocidad de cuadro de OpenGL, ya que OpenGL vuelve a dibujar la escena solo cuando se modifica de alguna manera (por ejemplo, si giro el objeto) y se glutPostRedisplay() llamado.

Así que supongo que si hay una forma en WebGL para volver a dibujar la escena solo cuando sea necesario, por ejemplo, cuando se gira el objeto o si se cambian algunos atributos en los sombreadores.


En realidad, no desea utilizar la velocidad de fotogramas para comparar estas cosas porque, como acaba de mencionar, tiene un límite artificial de 60 FPS debido a VSYNC.

La cantidad de fotogramas presentados estará limitada por la operación de memoria intermedia de intercambio cuando se emplea VSYNC y desea factorizar ese desorden en la medición de su rendimiento. Lo que debes hacer es iniciar un temporizador al comienzo de tu fotograma, luego al final del fotograma (justo antes de tu intercambio de búfer) glFinish (...) y finaliza el temporizador. Compare la cantidad de milisegundos que dibujará (o la resolución que mida su temporizador) en lugar de la cantidad de cuadros dibujados.


La solución correcta es usar la extensión ANGLE_timer_query cuando esté disponible.

Citando de la especificación:

Las implementaciones de OpenGL históricamente han proporcionado poca o ninguna información de tiempo útil. Las aplicaciones pueden hacerse una idea del tiempo leyendo temporizadores en la CPU, pero estos temporizadores no están sincronizados con la canalización de la representación gráfica. Leer un temporizador de CPU no garantiza la finalización de una cantidad potencialmente grande de trabajo de gráficos acumulado antes de que se lea el temporizador, y por lo tanto producirá resultados muy imprecisos. glFinish () se puede utilizar para determinar cuándo se han completado los comandos de renderización anteriores, pero inactivará la canalización de gráficos y afectará adversamente el rendimiento de la aplicación.

Esta extensión proporciona un mecanismo de consulta que se puede utilizar para determinar la cantidad de tiempo que se tarda en completar por completo un conjunto de comandos GL, y sin atascar la canalización de representación. Utiliza los mecanismos de objeto de consulta que se introdujeron por primera vez en la extensión de consulta de oclusión, que permiten que la aplicación consulte los intervalos de tiempo de forma asíncrona.

(énfasis mío)


No puede comparar las tasas de cuadros directamente en las GPU en WebGL presionando marcos. Más bien, necesita averiguar cuánto trabajo puede hacer dentro de un solo marco.

Por lo tanto, básicamente elige un framerate objetivo y luego sigue haciendo más y más trabajo hasta que rebases tu objetivo. Cuando alcanzas tu objetivo, esa es la cantidad de trabajo que puedes hacer. Puede comparar eso con alguna otra máquina o GPU usando la misma técnica.

Algunas personas sugerirán usar glFinish para verificar el tiempo. Lamentablemente, eso no funciona, ya que detiene el flujo de gráficos y ese bloqueo no es algo que normalmente sucede en una aplicación real. Sería como medir qué tan rápido puede ir un automóvil del punto A al punto B, pero en lugar de comenzar mucho antes de A y terminar mucho después de B, pise los frenos antes de llegar a B y mida el tiempo cuando llegue a B. el tiempo incluye todo el tiempo necesario para reducir la velocidad, lo cual es diferente en cada GPU y diferente entre WebGL y OpenGL, e incluso diferente para cada navegador. No tienes forma de saber cuánto tiempo pasas desacelerando y cuánto de lo gastaste haciendo lo que realmente querías medir.

Entonces, en lugar de eso, necesitas ir a toda velocidad todo el tiempo. Al igual que un automóvil, acelerarías hasta alcanzar la velocidad máxima antes de llegar al punto A y mantenerte en la velocidad máxima hasta que pases B. De la misma manera que los autos cronometran en las vueltas clasificatorias.

Normalmente no se detiene una GPU golpeando los saltos (glFinish), por lo que agregar el tiempo de parada a las mediciones de tiempo es irrelevante y no proporciona información útil. Usando glFinish, estarías cronometrando el dibujo + parada. Si una GPU dibuja en 1 segundo y se detiene en 2 y otra GPU dibuja en 2 segundos y se detiene en 1, su tiempo dirá 3 segundos para ambas GPU. Pero si los ejecutaras sin detener una GPU dibujaría 3 elementos por segundo, la otra GPU solo dibujaría 1.5 elementos por segundo. Una GPU es claramente más rápida, pero con glFinish nunca se sabe.

En cambio, corres a toda velocidad dibujando tanto como sea posible y luego mides cuánto pudiste hacer y mantienes la velocidad máxima.

Aquí hay un ejemplo: http://webglsamples.org/lots-o-objects/lots-o-objects-draw-elements.html

Básicamente dibuja cada cuadro. Si la velocidad de cuadro fue de 60 fps, dibuja 10 objetos más en el siguiente cuadro. Si la velocidad de cuadro fue inferior a 60 fps, consume menos.

Debido a que el tiempo del navegador no es perfecto, es posible que deba elegir un objetivo ligeramente inferior, como 57 fps, para determinar qué tan rápido puede llegar.

Además de eso, WebGL y OpenGL realmente solo hablan con la GPU y la GPU hace el trabajo real. El trabajo realizado por la GPU tomará la misma cantidad de tiempo independientemente de si WebGL le pide a la GPU que lo haga o OpenGL. La única diferencia está en la sobrecarga de configurar la GPU. Eso significa que realmente no quieres dibujar nada pesado. Lo ideal sería que dibujas casi nada. Haga su lienzo de 1x1 píxeles, dibuje un solo triángulo y verifique el tiempo (como en cuántos triángulos individuales puede dibujar un triángulo a la vez en WebGL frente a OpenGL a 60 fps).

Sin embargo, empeora aún más. Una aplicación real cambiará sombreadores, cambiará búferes, cambiará texturas, actualizar atributos y uniformes a menudo. Entonces, ¿qué estás cronometrando? ¿Cuántas veces puede llamar a gl.drawBuffers a 60 fps? ¿Cuántas veces puede llamar a gl.enable o gl.vertexAttribPointer o gl.uniform4fv a 60 fps? Alguna combinación? ¿Qué es una combinación razonable? 10% de llamadas a gl.verterAttribPointer + 5% de llamadas a gl.bindBuffer + 10% de llamadas a gl.uniform . La sincronización de esas llamadas es lo único diferente entre WebGL y OpenGL, ya que finalmente están hablando con la misma GPU y esa GPU funcionará a la misma velocidad independientemente.