Pixi.js: considerado gl-matrix?

Creado en 30 jun. 2017  ·  39Comentarios  ·  Fuente: pixijs/pixi.js

Esto puede ser una herejía, pero lanzaré una idea aquí y dejaré que la gente grite asesinato sangriento ... ¿alguna vez hemos considerado la posibilidad de estandarizar en matrices, puntos que se basan en matrices en lugar de en objetos? WebGL espera matrices en la mayoría de sus apis de vértice / textura / etc. También hay muchos módulos de ecosistema existentes que se estandarizan en arreglos antiguos o nativos simples (por ejemplo, https://github.com/toji/gl-matrix) gl-matrix sería bueno dado que muchos navegadores tienen soporte de hardware SIMD detrás de banderas , y estarán disponibles pronto (de hecho, gl-matrix admite esto ahora internamente).

Me doy cuenta de que esto sería un cambio de paradigma masivo para pixi, y rompería totalmente la compatibilidad con versiones anteriores ... aún así, quería lanzar esto y ver qué piensa la gente, y cuánto / poco odian la idea;)

Comentario más útil

@GoodBoyDigital Creo que quizás tengas razón. recurriendo a mi amiga mrs. google, me encontré con esto:

https://stackoverflow.com/questions/15823021/when-to-use-float32array-instead-of-array-in-javascript

la respuesta mejor calificada (actualmente con 44 votos) parece razonable y relevante.

Todos 39 comentarios

1) SIMD está muerto. https://github.com/rwaldron/tc39-notes/blob/a66df6740eec3358d5e24f81817db99d6ee41401/es8/2017-03/mar-21.md#10if -simdjs-status-update

2) Los 6 campos simples "a, b, c, d, tx, ty" funcionan mucho mejor incluso que la matriz Float32Array (9). No puedo dar enlaces a las pruebas, pero tanto yo como @GoodBoyDigital ya intentamos integrarlo.

3) JS tiene doble precisión, lo cual es fundamental para las aplicaciones que funcionan con grandes coordenadas. "Proyección x transformación" para gráficos y sprites es mejor estar en el lado de JS.

Estoy usando un Float32Array (9) en v5 que en mis pruebas jsperf era similar, si no el mismo, y evita que tengamos que hacer operaciones toArray y transponer.

https://github.com/pixijs/pixi.js/blob/455c059e8d155c1d9a05fc2ece2c02b3bdf8bf84/plugins/core/src/math/Matrix.js

gl-matrix es beneficioso porque tenía SIMD (que, como mencionó Ivan, es una especificación muerta), pero también tiene fallas en su implementación. Queremos que una matriz de 3x3 ( Float32Array(9) ) llegue a la GPU, pero realice las operaciones como si fuera una matriz 2D para ahorrar tiempo de cálculo. gl-matrix no tiene un buen mecanismo para eso.

La versión v5 usa almacenamiento que podemos cargar directamente a la GPU, además de operar solo en las partes 2D que nos interesan. También nos prepara para poder utilizar SharedArrayBuffers y otras optimizaciones que podrían permitirnos trabajar más en los webworkers. Veremos hasta dónde podemos llegar con él.

@englercj Me temo que tendremos que usar Math.fround en muchos lugares para ser coherentes. Pruebe perf Float64Array.

Podría intentar convertirlo en Float64Array, pero aún tenemos que reducirlo a precisión simple para la carga. Tenga en cuenta también que actualmente estamos usando un float32 cuando cargamos a la GPU . Entonces hacemos las matemáticas en doble, luego truncamos a simple. Esto puede ser más preciso que hacerlo todo en una sola, pero me gustaría intentar ser coherente con el tipo de datos que cargamos. Desafortunadamente, eso significa precisión simple hasta GL 4.0, y WebGL 2 es solo GL ES 3.0 :(

La carga de matrices nunca fue nuestro cuello de botella, usamos "uniform3fv" en esos lugares, no es una operación simple, y se sigue con un drawCall y, en la mayoría de los casos, con una gran carga de búfer. La aplicación Heavy Pixi solo está haciendo alrededor de 400 llamadas por cuadro,

Después de encontrar problemas del usuario con grandes coordenadas, prefiero almacenar todo con doble precisión hasta que lo carguemos.

Además, la notación "a, b, c, d, tx, ty" es más fácil de escribir y leer que "0,1,3,4,6,7". También se usa en la columna vertebral, tienen transformaciones muy sofisticadas además de eso. Si cambiamos a matrices, no será tan fácil verificar nuestro código más adelante. Para algunas personas es difícil imaginar operaciones matriciales, pero las leo fácilmente.

UPD. También creo que este nos ayudará más que convertir matrices: https://github.com/gameofbombs/gobi/blob/master/src/core/math/FlatTransform2d.ts , eso es transformación "plana", contiene todos los campos necesarios para el cálculo de la matriz.

UPD2. Pero para las transformaciones 3d, Float32Array (16) es mejor y no hablaré en contra.

Mi voto es para el que da mejor desempeño. La última vez que lo verifiqué usando objetos sobre matrices fue más rápido. Aunque no estoy 100% seguro de si eso sigue siendo cierto, ¡es posible que eso haya cambiado!

Para 3d prefiero el estilo gl-matrix, ¡principalmente porque las cosas se cargan mucho en la GPU! Con Pixi, este no suele ser el caso. La mayor parte de la manipulación ocurre en js land (por ejemplo, sprite batcher).

https://jsperf.com/obj-vs-array-view-access/1

Aquí está la prueba que hice. El objeto es más lento que Float32Array, los cuales son mucho más lentos que el Array normal. Luego obtenemos el doble de precisión y la velocidad de CPU más rápida y se puede cargar directamente.

Editar: Parece que el resultado de Array fue una casualidad, ¿no puedo reproducirlo?

Mi voto es para el que da mejor desempeño.
La última vez que lo verifiqué usando objetos sobre matrices fue más rápido.

Eso es muy interesante. Parece contradictorio que los objetos sean más rápidos que una matriz puramente numérica, porque la máquina virtual subyacente debería poder realizar una serie de optimizaciones, sabiendo que la semántica de los objetos podría eliminarse en gran medida. Tengo curiosidad por saber si tienes alguna idea de _por qué_ los objetos podrían ser más rápidos?

Resultados relevantes de mi composición (i7, Windows 10):

Chrome 59:

image

Firefox 54.0.1 (32 bits):

image

Microsoft Edge 40.15063.0.0:

image

Parece que mi resultado de Chrome de que Array sea ​​más rápido fue una casualidad, no estoy seguro de qué fue eso, pero no puedo reproducirlo ahora. Son alrededor de 50 millones de operaciones / s, pero fueron 500 millones de operaciones / s en una ejecución que hice antes. Extraño...

De cualquier manera, el miembro Float32Array es consistentemente a la misma velocidad o más rápido que el objeto en todos los navegadores. Es por eso que lo cambié, es la misma velocidad que antes (o más rápida) pero ahora evitamos transponer y llenar una matriz para cargas.

¿Puedes hacer eso con Float64 también, por favor? :)

Me preocupo por la calidad del código más de una operación matricial más por llamada.

Además, no usamos mucho invertir. updateTransform () es nuestro problema.

Me preocupo por la calidad del código más de una operación matricial más por llamada.

¿Cómo es Float64Array una mayor calidad de código? Entiendo que obtenemos más precisión, pero no estoy seguro de entender por qué es tan importante dado que de todos modos reducimos a precisión simple.

Además, no usamos mucho invertir. updateTransform () es nuestro problema.

Esto es comparar la lectura / escritura del almacenamiento de datos, la operación realizada en los valores intermedios es irrelevante.

Me preocupo por la calidad del código más de una operación matricial más por llamada.

Estoy de acuerdo con esto también. Tenga en cuenta que "estandarizar" en matrices, puntos y vectores basados ​​en matrices podría ser más una mejora de la calidad del código que de rendimiento ... Consideraría la reutilización de las bibliotecas de matriz / vector js populares y una mayor interoperabilidad con los módulos de representación populares para ser una gran victoria en la calidad del código.

Esto es una evaluación comparativa de la lectura / escritura del almacenamiento de datos,
la operación realizada en los valores intermedios es irrelevante.

Creo que ambos tienen razón. Esta es una evaluación comparativa general de lectura / escritura de almacenamiento de datos. Pero Iván tiene un buen punto; si updateTransform() es la operación abrumadora, sería convincente ver eso.

Me preocupan los micro benchmarks en general; con estos conjuntos de datos estáticos, me pregunto si inadvertidamente terminamos aprovechando las optimizaciones del compilador en javascript vms en estas pruebas. ejecutar pruebas del mundo real sería mucho más esclarecedor (a expensas de ser mucho más complicado de configurar).

Estoy de acuerdo con esto también. Tenga en cuenta que "estandarizar" en matrices, puntos y vectores basados ​​en matrices podría ser más una mejora de la calidad del código que de rendimiento ... Consideraría la reutilización de las bibliotecas de matriz / vector js populares y una mayor interoperabilidad con los módulos de representación populares para ser una gran victoria en la calidad del código.

Estoy a favor de la matriz de doble precisión "(a, b), (c, d), (tx, ty)", con conversión a float32array para cargar y respaldada por "posX, posY, pivotX, pivotY, scaleX, scaleY, shearX, shearY, rotZ ". Lo usaré en mi bifurcación de todos modos, pero prefiero no lidiar con matrices de matriz en master pixi también. Ese es mi estándar.

También dudo que sea posible hacer que la gente use uno o dos estándares para vec math en js.

¿Cómo es Float64Array una mayor calidad de código? Entiendo que obtenemos más precisión, pero no estoy seguro de entender por qué es tan importante dado que de todos modos reducimos a precisión simple.

Multiplicamos la transformación de cámara por la transformación de sprite (para desplazarse) en updateTransform. El resultado se ajusta a la pantalla solo si es pequeño, por lo que los números son pequeños al final, pero tanto la posición del sprite como la posición de la cámara pueden ser grandes. Soluciones del lado del usuario:

1) Calcule todo de su lado. PIXI solo se ocupa de coordenadas relativamente pequeñas.
2) divide el mundo en trozos con grandes coords, los sprites tienen coords relativamente pequeños, sin embargo, eso no funcionará para la cámara de subpíxeles => la cámara también necesita coords grandes y pequeños.

Está bien obligar al usuario a hacerlo de su lado en caso de un gran proyecto, pero para los pequeños es solo un dolor de cabeza más.

También dudo que sea posible hacer que la gente use uno o dos estándares para vec math en js.

No entiendo lo que quieres decir, ¿puedes dar más detalles?

No entiendo lo que quieres decir, ¿puedes dar más detalles?

No puedo, es demasiado para mí.

Contamos con personas con diferentes experiencias tanto en optimizaciones de bajo nivel. y construcciones de lenguaje, DSL-s. Necesitamos un estándar que nos satisfaga a todos en algún nivel.

En los últimos dos años, hice dos bifurcaciones de pixi (para v3 y v4) con diferentes transformaciones, estoy tratando con "pixi-spine" que tiene su propia transformación avanzada y estoy haciendo una tercera bifurcación. Desde el punto de vista del "pasado ivan", la matriz es la mejor porque es su forma más simple y hay "gl-matrix".

Estoy de acuerdo con @ivanpopelyshev en que mantener 64 bits es importante. Estoy tratando de averiguar cómo lo hacemos, de manera eficiente, sin crear y copiar búferes en cada cuadro.

Tal vez lo almacenemos como Float64Array y, al cargarlo, lo copiemos en Float32Array. Eso al menos nos permite usar una matriz con tipo como respaldo de almacenamiento que debería ser más fácil de copiar hacia / desde un webworker.

Float64Array es entonces, solo tendré que recordar usar (0,1), (3,4), (6,7) como X, Y, traducir

Todas las cosas interesantes, chicos, me gustaría que comparáramos nuestra solución propuesta en un escenario pixi real, algo así como bunnymark.

Mi experiencia en esta área es que cuando @ivanpopelyshev y yo

Sin embargo, eso fue hace un tiempo y realmente preferiría que me equivocara aquí.
Si la diferencia de velocidad ahora es insignificante, creo que la ruta propuesta anteriormente será excelente.

Pixi es SPEEED: P Asegurémonos de probar antes de comprometernos completamente con cualquier solución.

Todavía necesitamos el punto de referencia de Float64Array. Esta implementación es aceptable para mí, pero personalmente usaré una matriz antigua en mi bifurcación. Además, no olvide agregar propiedades solo por compatibilidad.

Una cosa más: @mreinstein , uno de los estándares que recuerdo es PaperScript, es un lenguaje especial para paper.js, agrega operaciones de puntos directamente en el lenguaje. Si JS tiene más azúcar de sintaxis, también usaríamos algo así.

¿Hay algo en lo que pueda ayudar con respecto a este bunnymark actualizado? Estoy feliz de poder donar algo de tiempo con esto.

Me interesaría mucho seguir las cosas de rendimiento que están sucediendo aquí. Independientemente de los resultados. Si las cosas basadas en matrices terminan siendo mucho más lentas, tengo mucha curiosidad sobre el _por qué_ detrás de ellas.

Algo a tener en cuenta con respecto a: las pruebas de rendimiento ... la v8 de Chrome recientemente (en la v59) lanzó algunos cambios bastante dramáticos en la v8 llamados turbofan. Supuestamente tiene algunas mejoras de rendimiento significativas.

https://v8project.blogspot.com/2017/05/launching-ignition-and-turbofan.html

Podría ser interesante ejecutar el bunnymark actualizado en una versión antes de que turbofan esté presente frente a ahora, solo por el gusto de hacerlo.

@GoodBoyDigital Actualicé el banco para incluir Float64Array, y es consistentemente más rápido leer / escribir en la matriz que en el objeto. Si se vuelve más lento en pixi, entonces algo más cambió, porque leer / escribir en un almacén de respaldo Float64Array es más rápido que un objeto.

https://jsperf.com/obj-vs-array-view-access/1
image

Solo en Edge la velocidad del objeto coincide / excede Float64Array, y está muy cerca.

He probado esto en mi entorno y obtengo resultados similares ... ¡¿qué diablos ?! ¿Por qué la lectura / escritura de la matriz Float64 sería significativamente más rápida que las operaciones de matriz Float32 equivalentes? Lo único que me viene a la mente es que los flotadores de 64 bits se alinean con los límites de las palabras. Estoy perplejo.

¡Gracias por la oferta @mreinstein ! ¡Si pudieras ayudarnos con algunas pruebas de rendimiento que sin duda acabarían con todo el debate con hechos duros y fríos!

Lo mejor que puede hacer es bifurcar pixi y luego reemplazar las transformaciones con la clase de matriz gl-matrix o @englercj . En este caso, solo necesitamos hacer que el lote de sprites funcione también, ¡no todo el motor!

Luego, una vez que tengamos una versión modificada, podemos probar el rendimiento aquí: https://pixijs.github.io/bunny-mark/
Podemos jugar con los diferentes tipos de matrices.

@englercj, ¡ eso es increíble, amigo! Es alentador ver estos resultados con seguridad. ¿Está la versión v5 cerca de un estado en el que podemos darle una vuelta a Bunny Mark?

@mreinstein es solo una corazonada, creo que puede tener que ver con la conversión de 64 bits -> 32 bits
como un número en js es de 64 bits, ¿verdad?

@GoodBoyDigital Creo que quizás tengas razón. recurriendo a mi amiga mrs. google, me encontré con esto:

https://stackoverflow.com/questions/15823021/when-to-use-float32array-instead-of-array-in-javascript

la respuesta mejor calificada (actualmente con 44 votos) parece razonable y relevante.

Si pudieras ayudarnos con algunas pruebas de rendimiento

Muy bien, feliz de ayudar con esto. :)

Lo mejor que puedes hacer es tenedor pixi

@GoodBoyDigital @englercj ¿cuál es la mejor rama para bifurcar en este punto?

luego reemplace las transformaciones con gl-matrix o @englercj matrix class.
En este caso, solo necesitamos hacer que el lote de sprites funcione también, ¡no todo el motor!

¿Puedes explicar esto un poco más? No quiero convertir todo el motor a gl-matrix solo para ejecutar el banco de rendimiento ... No veo ningún lote de sprites en https://github.com/pixijs/bunny-mark Parece haber un PIXI.Container como elemento raíz, al que se añaden los conejitos. ¿Estás diciendo que debería comenzar con pixi.container, pixi.sprite y trabajar hacia atrás desde allí hasta el árbol de dependencias para encontrar todos los lugares donde las cosas de transformación necesitan ser reemplazadas? No digo que no esté de acuerdo, solo quiero asegurarme de que tengo la estrategia correcta para minimizar el trabajo innecesario.

updateTransform tiene dos operaciones matriciales en su interior:

  1. composición desde posición, pivote, escala, rotación - no se puede mejorar.
  2. multiplicación por matriz matriz - se puede mejorar.

Sugiero hacer una clase de matriz con los antiguos accesorios "a, b, c, d, tx, ty" respaldados por Float64Array, y reescribir updateTransform. Además, @mreinstein hizo suficientes cosas para estar en el núcleo, sugiero que lo agreguemos, para que tenga acceso a las ramas y construya la granja.

por lo que tiene acceso a sucursales y construir finca.

Todo el mundo tiene acceso a eso, fork + PR hace todo eso.

Tengo curiosidad por saber qué tipo de resultados obtienen en bunny mark ... cuando pruebo varias ramas (dev, release, otras) de Chrome con los 100k bunnies predeterminados, obtengo 10-16 fps consistentemente. Haciendo un análisis de rendimiento en el código que se ejecuta en 8.75s:

screen shot 2017-07-02 at 11 58 03 am

Casi todo el tiempo se dedica a llamadas javascript.

screen shot 2017-07-02 at 11 57 50 am

De este tiempo dedicado a JavaScript, la mayor parte del tiempo se gasta en Sprite.calculateVertices() . 4 veces más de lo que se gasta en TransformStatic.updateTransform()

En firefox obtengo aproximadamente el doble de velocidad de fotogramas, pero el desglose del tiempo empleado es similar; calculateVertices() ocupa la mayor parte del tiempo en ambos navegadores. ¿Es esto esperado? ¿Está obteniendo resultados similares en sus carreras de bunnymark?

Esto es lo que se espera de los conejos. Y las operaciones matriciales de las que estamos hablando se realizan en dos lugares: upateTransform () para la multiplicación y flush () UNA VEZ POR LLAMADA. No importa a gran escala.

Estoy confundido. :( ¿Cómo puedo saber el rendimiento de ese punto de referencia? Tenía la impresión de que se basa principalmente en fps puros logrados. Si eso es cierto, entonces mi velocidad de fotogramas está siendo _ severamente_ estrangulada por los cálculos de vértices. Mirando el primer diagrama que pegué arriba, el renderizado es una pequeña fracción del tiempo total del marco.Las actualizaciones de vértices y transformaciones sobrepasan el tiempo total del marco.

Si eso es falso, y los fps no son la medida del rendimiento de mi compilación de pixi, ¿qué criterios utilizo para medir una compilación determinada?

Se puede estrangular en la CPU o en el lado de la GPU (no se muestra),

Si tiene FPS mucho menos de 60 pero "inactivo" es grande - su GPU.

Si inactivo es pequeño, entonces su CPU.

calcularVertices tiene una operación de matriz en el interior, solo multiplicación de cuatro esquinas por matriz.

Solo una pequeña idea para la bifurcación TS: agregue la transformación que integra las propiedades para los tipos de matriz. Es una pena que todavía no haya ese tipo de transformaciones para TS :(

Creo que también se puede hacer para babel si encontramos una manera de anotar las variables de la matriz.

Ya no puedo entender lo que está pasando.

Alt text

Algo a tener en cuenta: el objetivo de este punto de referencia en primer lugar era ver si el uso de objetos frente a gl-matrix supondría un gran impacto en el rendimiento, como se pensaba. Independientemente de las diferencias en nuestros resultados de referencia, parece que mostramos consistentemente que el rendimiento del objeto no es peor que la mayoría de los casos de matrices.

También quiero evitar sacar conclusiones de rendimiento sobre pixi en general aquí porque he perfilado la marca del conejito. En Chrome,> 50% del tiempo total del programa se gasta en Sprite.calculateVertices() (40% ish), seguido de TransformStatic.updateTransform() (11% ish) Firefox parece funcionar dos veces más rápido, pero la proporción del tiempo dedicado a esas 2 funciones sigue siendo constante.

Quiero evitar irme demasiado lejos del tema, pero diré que al hacer este perfil de bunnymark, estoy empezando a pensar que nuestro uso de es5 getters / setters podría tener algo que ver con la caída de rendimiento en Chrome: https: //jsperf.com/es5-getters-setters-versus-getter-setter-methods/10

¿Alguno de ustedes está holgazaneando aquí? Creo que sería más fácil chatear en tiempo semi-real en lugar de pasar un mensaje aquí.

¿Qué le envías a @mreinstein ? Te invitará a holgazanear 👍

Según lo que dice @englercj , aparentemente no estamos haciendo esto. Clausura.

Solo una pequeña actualización: tengo una matriz de 3x3 en lugar de 3x2 en https://github.com/pixijs/pixi-projection/blob/master/src/Matrix2d.ts , basado en Float64Array.

Este hilo se ha bloqueado automáticamente ya que no ha habido ninguna actividad reciente después de que se cerró. Abra un nuevo problema para errores relacionados.

¿Fue útil esta página
0 / 5 - 0 calificaciones