Pixi.js: als gl-Matrix betrachtet?

Erstellt am 30. Juni 2017  ·  39Kommentare  ·  Quelle: pixijs/pixi.js

Das mag Ketzerei sein, aber ich werfe hier eine Idee raus und lasse die Leute verdammten Mord schreien ... haben wir jemals die Möglichkeit in Betracht gezogen, auf Matrizen zu standardisieren, Punkte, die auf Arrays statt auf Objekten basieren? WebGL erwartet Arrays in den meisten seiner Vertex/Texture/etc APIs. Es gibt auch viele bestehende Ökosystemmodule, die auf einfache alte oder native Arrays standardisieren (z. B. https://github.com/toji/gl-matrix). gl-matrix wäre schön, da viele Browser Hardware-SIMD-Unterstützung hinter Flags haben , und werden in Kürze verfügbar sein (tatsächlich unterstützt gl-matrix dies jetzt intern.)

Mir ist klar, dass dies ein massiver Paradigmenwechsel für pixi wäre und die Abwärtskompatibilität völlig brechen würde ... trotzdem wollte ich das rauswerfen und sehen, was die Leute denken und wie sehr / wenig sie die Idee hassen;)

Hilfreichster Kommentar

@GoodBoyDigital Ich denke, vielleicht hast du Recht. Rückgriff auf meine Freundin Mrs. google, ich bin darüber gestolpert:

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

die am besten bewertete Antwort (derzeit 44 Stimmen) erscheint vernünftig und relevant.

Alle 39 Kommentare

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

2) Einfache 6 Felder "a,b,c,d,tx,ty" funktionieren viel besser als die Float32Array(9)-Matrix. Kann keine Links zu den Tests geben, aber sowohl ich als auch

3) JS bietet doppelte Präzision, was für Apps wichtig ist, die mit großen Koordinaten arbeiten. "projection x transform" für Grafiken und Sprites ist besser auf JS-Seite.

Ich verwende ein Float32Array(9) in v5, das in meinen jsperf-Tests ähnlich, wenn nicht sogar die gleiche Leistung war und uns daran hindert, toArray- und Transponierungsoperationen durchzuführen.

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

gl-matrix ist von Vorteil, weil es SIMD hatte (was, wie Ivan erwähnte, eine tote Spezifikation ist), aber auch Nachteile bei der Implementierung hat. Wir möchten, dass eine 3x3-Matrix ( Float32Array(9) ) die GPU trifft, aber Operationen wie eine 2D-Matrix ausführen, um Rechenzeit zu sparen. gl-matrix hat dafür keinen guten Mechanismus.

Die v5-Version verwendet Speicher, den wir direkt auf die GPU hochladen können, und arbeitet nur mit den 2D-Teilen, die uns wichtig sind. Es ermöglicht uns auch, SharedArrayBuffers und andere Optimierungen zu verwenden, die uns mehr Arbeit an Webworkern ermöglichen könnten. Wir werden sehen, wie weit wir damit kommen.

@englercj Ich fürchte, wir müssen Math.fround an vielen Stellen verwenden, um konsistent zu sein. Versuchen Sie es mit Float64Array.

Ich könnte versuchen, es zu Float64Array zu machen, aber dann müssen wir es für den Upload immer noch auf einfache Genauigkeit verkleinern. Denken Sie auch daran, dass wir derzeit ein float32 verwenden, wenn wir auf die GPU hochladen . Also machen wir die Mathematik doppelt und kürzen dann auf einfach. Dies ist möglicherweise genauer, als alles einzeln zu tun, aber ich möchte versuchen, mit dem von uns hochgeladenen Datentyp konsistent zu sein. Leider bedeutet das Single-Precision bis GL 4.0 und WebGL 2 ist nur GL ES 3.0 :(

Matrix-Upload war nie unser Engpass, wir verwenden an diesen Stellen "uniform3fv", es ist keine einfache Operation, und es folgt ein DrawCall und in den meisten Fällen ein Big Buffer-Upload. Die Heavy-Pixi-App macht nur etwa 400 Drawcalls pro Frame,

Nachdem ich auf Benutzerprobleme mit großen Koordinaten gestoßen bin, ziehe ich es vor, alles mit doppelter Genauigkeit zu speichern, bis wir es hochladen.

Außerdem ist die Notation "a,b,c,d,tx,ty" einfacher zu schreiben und zu lesen als "0,1,3,4,6,7". Sie werden auch in der Wirbelsäule verwendet und haben darüber hinaus sehr ausgeklügelte Transformationen. Wenn wir zu Matrizen wechseln, wird es nicht so einfach sein, unseren Code später zu überprüfen. Für manche Leute ist es schwierig, sich Matrixoperationen vorzustellen, aber ich lese sie leicht.

UPD. Ich denke auch, dass dieser uns mehr helfen wird, als Matrizen zu konvertieren: https://github.com/gameofbombs/gobi/blob/master/src/core/math/FlatTransform2d.ts , das ist "Flat" Transformation, enthält alle benötigten Felder zur Berechnung der Matrix.

UPD2. Aber für 3D-Transformationen ist Float32Array(16) besser und ich werde nicht dagegen sprechen.

Meine Stimme geht an diejenige, die die beste Leistung liefert. Zuletzt habe ich überprüft, ob es schneller war, Objekte über Arrays zu verwenden. Obwohl ich mir nicht 100% sicher bin, ob das noch stimmt, kann sich das durchaus geändert haben!

Für 3D bevorzuge ich den gl-Matrix-Stil, vor allem, weil viele Dinge auf die GPU hochgeladen werden! Bei Pixi ist dies im Allgemeinen nicht der Fall. Die meisten Manipulationen finden im js-Land statt (zB Sprite-Batcher).

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

Hier ist der Test, den ich gemacht habe. Object ist langsamer als Float32Array, beides ist viel langsamer als normales Array. Dann bekommen wir doppelte Präzision und die schnellste CPU-Geschwindigkeit und es kann direkt hochgeladen werden.

Bearbeiten: Sieht so aus, als ob das Ergebnis von Array ein Zufall war, ich kann es nicht reproduzieren?

Meine Stimme geht an diejenige, die die beste Leistung liefert.
Zuletzt habe ich überprüft, ob es schneller war, Objekte über Arrays zu verwenden.

Das ist sehr interessant. Es scheint nicht intuitiv zu sein, dass Objekte schneller wären als ein rein numerisches Array, da die zugrunde liegende VM in der Lage sein sollte, eine Reihe von Optimierungen durchzuführen, da sie weiß, dass die Objektsemantik weitgehend entfernt werden könnte. Ich bin gespannt, ob Sie irgendwelche Ideen haben, _warum_ Objekte schneller sein könnten?

Relevante Ergebnisse meiner Comp (i7, Windows 10):

Chrom 59:

image

Firefox 54.0.1 (32-Bit):

image

Microsoft Edge 40.15063.0.0:

image

Scheint, als wäre mein Chrome-Ergebnis, dass Array schneller war, ein Zufall, ich bin mir nicht sicher, was das war, aber ich kann es jetzt nicht reproduzieren. Es sind ungefähr 50 Mio. ops/s, aber bei einem Lauf, den ich zuvor gemacht habe, waren es 500 Mio. ops/s. Seltsam...

In jedem Fall ist das Float32Array-Member in allen Browsern durchweg dieselbe Geschwindigkeit oder schneller als das Objekt. Deshalb habe ich es umgestellt, es ist die gleiche Geschwindigkeit wie zuvor (oder schneller), aber wir vermeiden es jetzt, ein Array für Uploads zu transponieren und zu füllen.

Kannst du das bitte auch mit Float64 machen? :)

Ich interessiere mich mehr für die Codequalität als für eine weitere Matrixoperation pro Drawcall.

Außerdem verwenden wir nicht viel invertieren. updateTransform() ist unser Problem.

Ich interessiere mich mehr für die Codequalität als für eine weitere Matrixoperation pro Drawcall.

Wie ist die höhere Codequalität von Float64Array? Ich verstehe, dass wir mehr Präzision bekommen, aber ich bin mir nicht sicher, warum das so wichtig ist, da wir sowieso auf einfache Präzision reduzieren.

Außerdem verwenden wir nicht viel invertieren. updateTransform() ist unser Problem.

Dies ist ein Benchmarking des Lesens/Schreibens des Datenspeichers, die Operation, die an den Werten dazwischen durchgeführt wird, ist irrelevant.

Ich interessiere mich mehr für die Codequalität als für eine weitere Matrixoperation pro Drawcall.

Dem stimme ich auch zu. Bedenken Sie, dass die "Standardisierung" auf Array-basierten Matrizen, Punkten und Vektoren eher eine Verbesserung der Codequalität als eine Leistungsverbesserung darstellen könnte ... zu einem großen Gewinn an Codequalität.

Dies ist ein Benchmarking des Lesens/Schreibens des Datenspeichers,
die an den Werten dazwischen durchgeführte Operation ist irrelevant.

Ich glaube ihr habt beide recht. Dies ist ein allgemeines Benchmarking für das Lesen/Schreiben von Datenspeichern. Aber Ivan hat einen wirklich guten Punkt; Wenn updateTransform() die überwältigende Operation ist, wäre es verlockend, dies zu sehen.

Ich mache mir generell Sorgen um Mikrobenchmarks; Bei diesen statischen Datensätzen frage ich mich, ob wir in diesen Tests versehentlich Compileroptimierungen in Javascript-VMs ausnutzen. Das Ausführen von Tests in der realen Welt wäre viel aufschlussreicher (auf Kosten des Aufwands für die Einrichtung).

Dem stimme ich auch zu. Bedenken Sie, dass die "Standardisierung" auf Array-basierten Matrizen, Punkten und Vektoren eher eine Verbesserung der Codequalität als eine Leistungsverbesserung darstellen könnte ... zu einem großen Gewinn an Codequalität.

Ich bin für "(a,b),(c,d),(tx,ty)" Matrix mit doppelter Genauigkeit, mit Konvertierung in float32array zum Hochladen und unterstützt von "posX,posY,pivotX, pivotY,scaleX,scaleY, scherX,scherY,rotZ". Ich werde es trotzdem in meinem Fork verwenden, aber ich bevorzuge es, mich auch nicht mit Matrix-Arrays in Masterpixi zu beschäftigen. Das ist mein Standart.

Ich bezweifle auch, dass es möglich ist, Leute dazu zu bringen, ein oder zwei Standards für Vec Math in js zu verwenden.

Wie ist die höhere Codequalität von Float64Array? Ich verstehe, dass wir mehr Präzision bekommen, aber ich bin mir nicht sicher, warum das so wichtig ist, da wir sowieso auf einfache Präzision reduzieren.

Wir multiplizieren die Kameratransformation mit der Spritetransformation (zum Scrollen) in updateTransform. Das Ergebnis passt nur auf den Bildschirm, wenn es klein ist, also sind die Zahlen am Ende klein, aber sowohl die Sprite-Position als auch die Kameraposition können groß sein. Benutzerseitige Lösungen:

1) berechne alles auf seiner Seite. PIXI behandelt nur relativ kleine Koordinaten.
2) Teilen Sie die Welt in große Koordinaten auf, Sprites haben relativ kleine Koordinaten, dies funktioniert jedoch nicht für Subpixel-Kameras => Kamera benötigt auch große und kleine Koordinaten.

Bei großen Projekten ist es in Ordnung, den Benutzer dazu zu zwingen, dies auf seiner Seite zu tun, aber für kleine ist es nur ein weiterer Kopfschmerz.

Ich bezweifle auch, dass es möglich ist, Leute dazu zu bringen, ein oder zwei Standards für Vec Math in js zu verwenden.

Ich verstehe nicht was du meinst, kannst du das näher erläutern?

Ich verstehe nicht was du meinst, kannst du das näher erläutern?

Ich kann nicht, es ist zu viel für mich.

Wir haben Leute mit unterschiedlichen Erfahrungen sowohl in Low-Level-Optimierungen. und Sprachkonstrukte, DSL-s. Wir brauchen einen Standart, der uns alle in gewisser Weise zufrieden stellt.

In den letzten zwei Jahren habe ich zwei Forks von pixi (für v3 und v4) mit unterschiedlichen Transforms gemacht, ich beschäftige mich mit "pixi-spine", das seine eigene erweiterte Transformation hat und ich mache einen dritten Fork. Aus der Sicht von "past ivan" ist Array das beste, weil es die einfachste Form hat und es "gl-matrix" gibt.

Ich stimme @ivanpopelyshev zu, dass die Beibehaltung von 64-Bit wichtig ist. Ich versuche herauszufinden, wie wir das effizient machen, ohne für jeden Frame Puffer zu erstellen und zu kopieren.

Vielleicht speichern wir es als Float64Array und kopieren es beim Hochladen in ein Float32Array. Das lässt uns zumindest ein typisiertes Array als Speicherunterlage verwenden, das einfacher zu/von einem Webworker zu kopieren sein sollte.

Float64Array ist es dann, ich muss nur daran denken, (0,1), (3,4), (6,7) als X,Y,translate zu verwenden

Alles interessante Dinge, Leute, ich würde gerne unsere vorgeschlagene Lösung in einem echten Pixi-Szenario vergleichen - so etwas wie Bunnymark.

Meine Erfahrung in diesem Bereich ist, dass wir, als ich und @ivanpopelyshev das letzte Mal für Bunny Mark auf gl-Matrix

Das ist aber schon eine Weile her und ich würde es wirklich vorziehen, wenn ich hier falsch liege!
Wenn der Geschwindigkeitsunterschied jetzt vernachlässigbar ist, denke ich, dass die oben vorgeschlagene Route ein Ass sein wird.

Pixi ist GESCHWINDIGKEIT: P Stellen wir sicher, dass wir testen, bevor wir uns vollständig auf eine Lösung festlegen.

Wir brauchen noch Benchmark von Float64Array. Diese Implementierung ist für mich akzeptabel, aber ich persönlich werde alte Matrix in meinem Fork verwenden. Vergessen Sie auch nicht, Eigenschaften nur aus Kompatibilitätsgründen hinzuzufügen.

Noch eine Sache: @mreinstein , einer der

Gibt es etwas, bei dem ich helfen kann: dieses aktualisierte Bunnymark? Ich freue mich, dafür etwas Zeit zu spenden.

Ich wäre sehr daran interessiert, die Perf-Zeug, die hier passiert, mitzuverfolgen. Unabhängig von den Ergebnissen. Wenn das Array-basierte Zeug immer noch viel langsamer ist, bin ich wirklich neugierig auf das _warum_ dahinter.

Etwas zu beachten in Bezug auf: die Perf-Tests ... Chrome's v8 hat kürzlich (in v59) einige ziemlich dramatische Änderungen an v8 namens Turbofan veröffentlicht. Angeblich hat es einige signifikante Leistungsverbesserungen.

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

Es könnte interessant sein, das aktualisierte Bunnymark auf einer Version auszuführen, bevor Turbofan im Vergleich zu jetzt vorhanden war, nur zum Teufel.

@GoodBoyDigital Ich habe die Bank aktualisiert, um Float64Array aufzunehmen, und das Lesen/Schreiben in das Array ist durchweg schneller als das Objekt. Wenn es in pixi langsamer wird, hat sich etwas anderes geändert, da das Lesen/Schreiben in einen Float64Array-Backing-Speicher schneller ist als ein Objekt.

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

Nur bei Edge stimmt die Objektgeschwindigkeit überein oder übertrifft Float64Array, und es ist wirklich nahe.

Ich habe dies in meiner Umgebung getestet und erhalte ähnliche Ergebnisse ... was zur Hölle?! Warum sollte das Lesen/Schreiben von Float64-Arrays wesentlich schneller sein als vergleichbare Float32-Array-Operationen? Das einzige, was mir in den Sinn kommt, ist, dass sich vielleicht 64-Bit-Floats an Wortgrenzen ausrichten? Ich bin ratlos.

Danke für das Angebot @mreinstein ! Wenn Sie uns mit einigen Perf-Tests helfen könnten, würde das sicherlich die ganze Debatte mit kalten harten Fakten zunichte machen!

Am besten fork pixi und dann die Transformationen durch gl-Matrix oder @englercj- Matrix-Klasse ersetzen. In diesem Fall müssen wir nur den Sprite-Batch auch wirklich zum Laufen bringen - nicht die ganze Engine!

Sobald wir eine optimierte Version haben, können wir Perf hier testen: https://pixijs.github.io/bunny-mark/
Wir können mit den verschiedenen Array-Typen herumspielen.

@englercj das ist toller Typ! Es ist ermutigend, diese Ergebnisse mit Sicherheit zu sehen. Ist die v5-Version in der Nähe eines Zustands, in dem wir Bunny Mark eine Runde drehen können?

@mreinstein nur eine Ahnung, ich denke, es könnte mit der Konvertierung von 64bit -> 32bit zu tun haben
als Zahl in js ist 64bit richtig?

@GoodBoyDigital Ich denke, vielleicht hast du Recht. Rückgriff auf meine Freundin Mrs. google, ich bin darüber gestolpert:

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

die am besten bewertete Antwort (derzeit 44 Stimmen) erscheint vernünftig und relevant.

Wenn Sie uns mit einigen Leistungstests helfen könnten

Alles klar, ich helfe gerne dabei. :)

Am besten fork pixi

@GoodBoyDigital @englercj was ist der beste Zweig, um zu diesem Zeitpunkt

Ersetzen Sie dann die Transformationen durch gl-matrix oder @englercj -
In diesem Fall müssen wir nur den Sprite-Batch auch wirklich zum Laufen bringen - nicht die ganze Engine!

Können Sie das noch etwas genauer ausführen? Ich möchte nicht die ganze Engine in gl-Matrix konvertieren, nur um die Perf-Bank auszuführen ... Ich sehe keine Sprite-Batch-Sachen in https://github.com/pixijs/bunny-mark Es scheint ein PIXI.Container als Wurzelelement, zu dem die Hasen hinzugefügt werden. Wollen Sie damit sagen, dass ich mit pixi.container, pixi.sprite beginnen und von dort rückwärts im Abhängigkeitsbaum nach oben arbeiten sollte, um alle Stellen zu finden, an denen das Transformationsmaterial ersetzt werden muss? Ich sage nicht, dass ich anderer Meinung bin, ich möchte nur sicherstellen, dass ich die richtige Strategie habe, um unnötige Arbeit zu minimieren.

updateTransform enthält zwei Matrixoperationen:

  1. Komposition aus Position,Pivot,Skala,Rotation - kann nicht verbessert werden.
  2. Multiplikation mit der Elternmatrix - kann verbessert werden.

Ich schlage vor, eine Matrixklasse mit alten "a,b,c,d,tx,ty"-Requisiten zu erstellen, die von Float64Array unterstützt werden, und updateTransform neu zu schreiben. Außerdem hat @mreinstein genug Dinge gemacht, um im Kern zu sein, ich schlage vor, wir fügen ihn hinzu, damit er Zugriff auf Zweige hat und eine Farm baut.

So hat er Zugriff auf Zweige und baut eine Farm.

Jeder hat Zugriff darauf, fork + PR macht das alles.

Ich bin gespannt, welche Ergebnisse ihr mit Bunny Mark bekommt. Durchführen einer Perf-Analyse des Codes, der über 8,75 s läuft:

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

Fast die ganze Zeit wird mit Javascript-Aufrufen verbracht.

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

Von dieser in Javascript verbrachten Zeit wird der Löwenanteil tatsächlich in Sprite.calculateVertices() . 4x mehr als in TransformStatic.updateTransform() ausgegeben wird

In Firefox bekomme ich ungefähr die doppelte Framerate, aber die Aufteilung der aufgewendeten Zeit ist ähnlich; calculateVertices() nimmt in beiden Browsern die meiste Zeit in Anspruch. Ist dies zu erwarten? Erzielst du ähnliche Ergebnisse bei deinen Bunnymark-Läufen?

Dies wird für Hasen erwartet. Und Matrixoperationen, über die wir sprechen, werden an zwei Stellen ausgeführt: upateTransform() für die Multiplikation und flush() EINMAL PRO AUFRUF. Im großen Maßstab ist das egal.

Ich bin verwirrt. :) oben stellt das Rendern einen winzigen Bruchteil der Gesamtbildzeit dar. Vertex- und Transformationsaktualisierungen überfordern die Gesamtbildzeit.

Wenn das falsch ist und fps nicht das Maß dafür ist, wie leistungsfähig mein Pixi-Build ist, nach welchen Kriterien messe ich einen bestimmten Build?

Es kann entweder auf der CPU oder auf der GPU-Seite gedrosselt werden (nicht gezeigt),

Wenn Sie viel weniger als 60 FPS haben, aber "Idle" groß ist - seine GPU.

Wenn der Leerlauf klein ist, dann seine CPU.

BerechnenVertices hat eine Matrixoperation im Inneren - einfach vier Ecken mit einer Matrix multiplizieren.

Nur eine kleine Idee für TS Fork: Fügen Sie eine Transformation hinzu, die Eigenschaften für Matrixtypen einfügt. Schade, dass es diese Art von Transformationen für TS noch nicht gibt :(

Ich denke, es kann auch für Babel getan werden, wenn wir einen Weg finden, Matrixvariablen mit Anmerkungen zu versehen.

Ich kann nicht mehr verstehen, was los ist.

Alt text

Etwas zu bedenken: Das Ziel dieses Benchmarks war in erster Linie zu sehen, ob die Verwendung von Objekten im Vergleich zu gl-Matrix ein großer Performance-Hit sein würde, wie er angenommen wurde. Unabhängig von den Unterschieden in unseren Benchmark-Ergebnissen scheinen wir durchweg zu zeigen, dass die Objektperf nicht schlechter ist als die der meisten Array-Fälle.

Ich möchte hier auch keine Rückschlüsse auf die Leistung von Pixis im Allgemeinen ziehen, da ich die Hasenmarke profiliert habe. In Chrome werden > 50% der Gesamtzeit des Programms in Sprite.calculateVertices() (40% ish) verbracht, gefolgt von TransformStatic.updateTransform() (11% ish) Firefox scheint doppelt so schnell zu laufen, aber das Verhältnis der in diesen beiden Funktionen verbrachten Zeit ist immer noch konsistent.

Ich möchte vermeiden, zu weit vom Thema abzuweichen, aber ich sage, dass ich bei diesem Bunnymark-Profiling langsam denke, dass unsere Verwendung von es5-Gettern/Settern etwas mit dem Perf-Drop in Chrome zu tun haben könnte: https: //jsperf.com/es5-getter-setters-versus-getter-setter-methods/10

Hängt einer von euch hier mit Slack rum? Ich denke, es wäre einfacher, in Semi-Echtzeit zu chatten, als hier Nachrichten weiterzugeben.

Welche E-Mail @mreinstein ? Werde dich einladen, nachzulassen 👍

Basierend auf dem, was @englercj sagt, tun wir dies anscheinend nicht. Schließen.

Nur kleines Update: Ich habe 3x3-Matrix anstelle von 3x2 in https://github.com/pixijs/pixi-projection/blob/master/src/Matrix2d.ts , basierend auf Float64Array.

Dieser Thread wurde automatisch gesperrt, da nach dem Schließen in letzter Zeit keine Aktivität stattgefunden hat. Bitte öffnen Sie eine neue Ausgabe für verwandte Fehler.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

Makio64 picture Makio64  ·  3Kommentare

madroneropaulo picture madroneropaulo  ·  3Kommentare

finscn picture finscn  ·  3Kommentare

lunabunn picture lunabunn  ·  3Kommentare

sntiagomoreno picture sntiagomoreno  ·  3Kommentare