Effizientes Sprite-Batching

7

Ich überlege, von XNA auf die Stage3D-APIs (Molehill) zu portieren. Als Leistungsprüfung habe ich Sprite-Batching implementiert, aber die Leistung ist nicht besonders gut, während ich mit XNA problemlos bis zu 500.000 Quads zeichnen kann, aber mit meiner Molehill-Implementierung kann ich ungefähr 1000 Quads zeichnen und während a Auf der CPU-Seite wurde ein ziemlich dramatischer Leistungsunterschied erwartet, der auf die GPU-Bindung zurückzuführen ist.

Derzeit ist die Implementierung also wie folgt.

set render states

let texture be null
let batchSize be arbitrary

for each sprite in queue
    if texture is not sprite texture
    or buffers are full

        upload vertex data to index buffer
        upload index data to vertex buffer

        bind texture
        draw triangles

        flush vertex data
        flush index data


    add sprite vertices to vertex data
    add sprite indices to index data
end

upload remaining vertex data to vertex buffer
upload remaining index data to index buffer
draw remaining triangles

flush data

Der Engpass ist das Hochladen der Puffer, aber für eine bessere Implementierung hoffe ich auf eine Diskussion hier.

Prost.

Revision:

Eine Optimierung, die in den Sinn kommt, besteht darin, den Indexpuffer beizubehalten, da die Indizes vorhersehbar sind und immer dem gleichen Format folgen. Ich werde das jetzt messen.


Das Zwischenspeichern des Indexpuffers hatte keine nennenswerten Leistungssteigerungen. Um zu verstehen, wo der Engpass liegt, habe ich ihn auf C # / XNA portiert, etwas langsamer als die Implementierung von Microsoft, aber immer noch über eine 500-mal höhere GPU-Kapazität als die Molehill-Implementierung.

Ist Molehill einfach eine extrem schlechte Abstraktionsschicht?

Casper Beyer
quelle
Es ist eine gute Idee, den Indexpuffer dauerhaft zu machen, um ein wenig Leistung zu erzielen. Das einzige andere, was mir beim Betrachten Ihres Pseudocodes einfällt, ist, dass Sie die Textur immer wieder neu binden. Sie sollten überprüfen, ob sich die Textur zwischen den Aufrufen geändert hat, und erst dann eine neue Textur binden, da Sie sonst keinen Leistungsgewinn erzielen, wenn Sie beispielsweise einen Textur-Altas verwenden.
Jonathan Connell
Eigentlich ist die Textur nur einmal gebunden, vielleicht nochmal durchgelesen.
Casper Beyer
Oh ja, es ist impliziert, dass "Textur" der Textur des Sprites beim Binden zugewiesen wird.
Casper Beyer
Sie haben 'Bind Texture' in der für jede Schleife. Ich sagte, dass es so sein sollte, damit Sie Bind Texture nicht aufrufen, wenn sich die Textur zwischen zwei Sprites nicht geändert hat. Im Moment fordern Sie die GPU auf, eine Textur in jeder Schleife neu zu binden. Dies ist eine kostspielige Operation und wird möglicherweise nicht benötigt.
Jonathan Connell
Wieder ist es nur einmal gebunden. Eine bedingte Überprüfung ist kaum eine kostspielige Operation.
Casper Beyer

Antworten:

2

Sie könnten eine Multi-Map von Sprites haben, deren Schlüssel die Textur ist. Gehen Sie dann beim Rendern durch jeden Schlüssel in der Map und rendern Sie jede Gruppe von Sprites, die dieser Textur zugeordnet sind. Wenn alle Sprites dieselbe Textur haben, können Sie jedes Sprite mit zwei Dreiecken und Texturkoordinaten darstellen. Dies bedeutet, dass Sie alle Sprites, die dieselbe Textur verwenden, in einem einzigen Durchgang mit einem einzigen Scheitelpunktpuffer und Indexpuffer zeichnen können.

Obwohl ich XNA verwende, habe ich meinen eigenen Rendering- und Batching-Prozess durchgeführt, anstatt Sprite-Batch zu verwenden, und ich rendere ungefähr 3000 Sprites gleichzeitig und erhalte derzeit ungefähr 600 fps auf einer Nvidia GTX 275 mit dem Prozess I. oben beschrieben. Als ich gerade die Sprites an die Spritebatch-Methode weitergab, gab XNA an, dass es ungefähr 25 fps waren.

In meinem Fall habe ich anstelle einer Multimap eine Klasse (SpriteData), die die Textur und eine Liste von Scheitelpunkten enthält. Immer wenn sich ein Sprite beim Renderer registriert, durchläuft der Renderer eine Liste von SpriteData, bis er einen passenden Texturtyp findet, und fügt dieses Sprite der Scheitelpunktliste hinzu.

Ich mache auch räumliche Partitionierung, um sicherzustellen, dass nur die angezeigten Sprites berücksichtigt werden.

Nic Foster
quelle