Zeichne und aktualisiere die Reihenfolge in 3D-Grafiken

7

In allen Codebeispielen, die ich mir angesehen habe, sieht die Spieleschleife ungefähr so ​​aus:

while(true)
{
   InputAndUpdate();
   Draw();

   SwapBuffers();
}

Zerstört dies jedoch nicht die Parallelität zwischen CPU und GPU? Nach dem Aufruf der Swap-Puffer sitzt die GPU untätig da, während die CPU die Eingabe und Aktualisierung übernimmt. Wenn die CPU die Ausgabe der Zeichenbefehle beendet hat, wartet sie, bis das Rendern der GPU abgeschlossen ist. Warum wird es nicht so gemacht? ::

while(true)
{
   Draw(); //First issue the draw commands
   InputAndUpdate(); //Update while the GPU is busy rendering

   SwapBuffers(); //Now block and wait for the GPU to finish
}
Hannesh
quelle
Daran habe ich noch nie gedacht. +1 interessante Frage.
Die kommunistische Ente
Der erste. Wenn Sie die Sekunde ausführen, erhöhen Sie die Eingangsverzögerung um ein Vollbild, möglicherweise mehr, je nachdem, wie Sie die Eingabe und die V-Synchronisierung erhalten. Achten Sie immer darauf, die Eingangsverzögerung nicht zu erhöhen
Peter Ølsted

Antworten:

5

Dies wäre der Fall, wenn Sie keinen zusätzlichen Rückpuffer zum Rendern haben (Doppelpufferung). Auf diese Weise kann die CPU weitermachen und Dinge erledigen, ohne auf den eigentlichen Pufferaustausch warten zu müssen (was normalerweise der Fall ist, da Sie den hinteren Puffer erst ändern können, wenn er ohne Risiko in den vorderen Puffer kopiert wurde korrumpieren, was Sie gerade gerendert haben). Wenn ein Draw-Aufruf oder ein Swap ausgeführt wird, wird die Anforderung in einen Puffer mit Befehlen gestellt, die die GPU verarbeiten kann, sodass die CPU andere Aufgaben ausführen kann, während die GPU im Rückstand ist. So erhält moderne Hardware Parallelität. Ich glaube, D3D hat eine Begrenzung für die Anzahl der Frames, die Sie vor dem Blockieren eines "Swaps" rendern können (Sie ').

Das Konzept einer Spielschleife wie in beiden obigen Beispielen ist ziemlich veraltet. Mit der Einführung mehrerer Verarbeitungseinheiten auf der CPU können Sie möglicherweise auf einem Thread rendern, während Sie einige Aktualisierungsarbeiten an einem oder mehreren anderen Threads ausführen. Möglicherweise möchten Sie sich mit dem Konzept der Jobwarteschlangen befassen, um die gesamte verfügbare CPU-Verarbeitungsleistung zu maximieren.

Roger Perkins
quelle
-1

Die Lösung, die Sie gewählt haben, führt nicht dazu, dass CPU und GPU parrarel funktionieren. Sie ändert lediglich die Reihenfolge, in der sie aufeinander warten Um das volle Potenzial von CPU und GPU auszuschöpfen, müssen Sie Zeichnen und Aktualisieren in zwei verschiedenen Threads aufrufen und einen weiteren zweiten Puffer für die CPU-Aktivitäten verwenden (damit CPu Aktualisierungsergebnisse in Puffer 2 generiert) GPU aus Puffer 1 lesen und wenn die CPU mit Puffer 1 arbeitet GPU verwenden Sie Puffer 2 genau wie Swap-Puffer, die die GPU verwendet, um Änderungen im bereits gezeichneten Frame zu verhindern.

Ali1S232
quelle
@Gajet schlagen Sie vor, alle Spieldaten auch auf der CPU-Seite doppelt zu puffern?
Maik Semder
so etwas, aber nicht alle Daten, nur das, was sich bewegen kann. Damit sowohl die GPU als auch die CPU aus dem CPU-Puffer [0] lesen und jeweils ihre Berechnungen durchführen und ihre Ergebnisse im Speicherpuffer / CPU-Puffer [1] speichern. Wenn beide Arbeiten abgeschlossen sind, beginnen sie mit dem Lesen aus dem CPU-Puffer [1]
Ali1S232
Dies ist übertrieben, unpraktisch und endet in einer chaotischen Codebasis, da die Spieleinheit haben wird normale und doppelt gepufferte Eigenschaften aufweist, die für das Rendern relevant sind. Es gibt viel einfachere Lösungen für die Kommunikation vom Game-Thread zum Render-Thread, wie z. B. Befehlswarteschlangen. -1 für diesen Vorschlag
Maik Semder
Ich bin damit einverstanden, aber ich denke, es ist die einzige Möglichkeit, die Leistung von CPU und GPU gleichzeitig vollständig zu nutzen. Befehlswarteschlangen funktionieren beispielsweise nicht, da die CPU jedes Mal, wenn sie generierende Rahmendaten fertigstellt, alle ihre Daten an die GPU weitergeben sollte, und das bedeutet, dass Sie Sie müssen warten, bis die CPU fertig ist, und dann den gesamten Puffer zu diesem Zeitpunkt kopieren. Beachten Sie, dass sich nichts auf der Welt ändern sollte, während die GPU die Welt zeichnet. Wenn Sie also Befehlswarteschlangen verwenden, ändert sich die CPU und die GPU nicht aufeinander warten.
Ali1S232
Die Tatsache, dass einer auf den Abschluss des anderen wartet, bedeutet nicht, dass er nicht parallel ausgeführt wird, sondern der erste, der beendet wird, muss warten, da Rendering und Spielaktualisierung synchronisiert werden müssen. Aber sie laufen voll parallel. Der Doppelpuffer-Vorschlag löst also ein Problem, das nicht vorhanden ist.
Maik Semder