2016-05-27 11 views
16

Es gibt mehrere Möglichkeiten, die Synchronisierung in Vulkan zu handhaben. Dies ist, wie ich es verstehe:Synchronisation zwischen Befehlspuffern in Vulkan

  • Zäune sind GPU zu CPU synchronisiert.
  • Semaphore sind GPU zu GPU-Synchronisierungen, sie werden verwendet, um die Warteschlange Übermittlungen (in der gleichen oder verschiedenen Warteschlangen) zu synchronisieren.
  • Ereignisse sind allgemeiner, zurückgesetzt und überprüft auf CPU und GPU.
  • Barrieren werden zur Synchronisation innerhalb eines Befehlspuffers verwendet.

In meinem Fall habe ich zwei Befehlspuffer. Und ich möchte, dass der zweite Befehlspuffer nach dem ersten ausgeführt wird.

submitInfo.pCommandBuffers = &firstCommandBuffer; 
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); 

// wait for first command buffer to finish 
submitInfo.pCommandBuffers = &secondCommandBuffer; 
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); 

Welche Art von Synchronisation ist dafür am besten? Wenn ich vkQueueWaitIdle(queue)), verwende, ist das die gleiche Sache wie mit einem Zaun oder sollte ich Event oder Semaphoren dafür verwenden?

Wenn ich mehrere commandbuffer in die Warteschlange zur gleichen Zeit senden:

std::vector<VkCommandBuffer> submitCmdBuffers = { 
     firstCommandBuffer, 
     secondCommandBuffer 
    }; 
    submitInfo.commandBufferCount = submitCmdBuffers.size(); 
    submitInfo.pCommandBuffers = submitCmdBuffers.data(); 

Gibt es noch eine Möglichkeit, zwischen dem ersten und dem zweiten zu synchronisieren?

+2

"* Und ich möchte, dass der zweite Befehlspuffer nach dem ersten ausgeführt wird. *" Wie viel willst du ", dass das passiert? Das heißt, was macht der zweite Befehlspuffer so, dass es so zwingend ist, dass die erste * Ausführung * abgeschlossen hat, bevor die zweite beginnt? –

+1

Der erste Befehlspuffer rendert das Objekt mit eingeschaltetem Tiefentest. Der zweite Befehlspuffer rendert Konturen von Netzen mit deaktiviertem Tiefentest. Weil es über den anderen Objekten liegen muss. – hidayat

+0

Wenn Sie eine Einreichung machen. Verwenden Sie dann vkCmdSetEvent in Ihrem ersten Befehlspuffer und vkCmdWaitEvents in Ihrem zweiten Befehl, und halten Sie die Masken für src und dst so schmal wie möglich. –

Antwort

11

Der erste Befehlspuffer rendert Objekt mit aktiviertem Tiefentest. Der zweite Befehlspuffer rendert Konturen von Netzen mit deaktiviertem Tiefentest. Weil es über den anderen Objekten liegen muss.

Für diesen Fall hängt das, was Sie benötigen, eher davon ab, was diese Befehlspuffer sind.

Wenn es sich um sekundäre Befehlspuffer handelt, die innerhalb derselben Render-Pass-Instanz ausgeführt werden, benötigen Sie keine beliebige Synchorisation. Es sei denn, Sie lesen manuell aus der Tiefenstruktur im sekundären Befehlspuffer. Warum?

Da Abschnitt 2.2.1 API Ordering schützt Sie. Das Testen der Tiefe und das Schreiben der Tiefe innerhalb einer Render-Pass-Instanz wird immer in API-Reihenfolge fortfahren. Spätere Befehle, ob im selben CB oder in einem anderen, werden in Bezug auf Tiefentests/-schreiben angeordnet.

Wenn Sie jedoch diesen Tiefenpuffer lesen müssen oder sich Ihre Befehlspuffer in verschiedenen Render-Pass-Instanzen befinden, benötigen Sie eine explizite Synchronisation über ein Ereignis.

In diesem Fall sollte die Stufenmaske für den Befehl vkCmdSetEvent die Stufe sein, die den Tiefenwert schreibt.Dies könnte EARLY_FRAGMENT_TESTS_BIT oder LATE_FRAGMENT_TESTS_BIT sein. Um sicher zu sein, benutze beide. Da Sie jedoch wahrscheinlich den gleichen Farbpuffer aktualisieren, benötigen Sie auch die Stufe COLOR_ATTACHMENT_OUTPUT_BIT. Fügen Sie diesen Befehl am Ende des ersten Befehlspuffers ein (oder nachdem die gesamte Tiefe geschrieben wurde).

Für die vkCmdWaitEvent möchten Sie auf die Pipelinestufen warten, die es benötigen. In Ihrem Fall ist dies wieder der Fragmenttest und der Farbanhang. Aber wenn eine Shader-Stufe die Tiefe lesen soll, benötigen Sie diese Stufe auch im wait-Befehl.

Da Speicher beteiligt ist, muss auch Ihre eine Speicherabhängigkeit von den Tiefen- und Farbpuffern verwenden.

Wirklich, obwohl all diese Komplexität ist, warum sollten Sie versuchen, diese Befehlspuffer wenn möglich in die gleiche Render-Pass-Instanz zu setzen. Der einzige Grund, warum Sie das nicht können, ist, wenn Sie aus dem Tiefenpuffer in einem Shader lesen müssen.

+0

Ihr Wissen ist beeindruckend :), "Wenn das sekundäre Befehlspuffer sind", warum ist es wichtig, ob sie primäre oder sekundäre Befehlspuffer sind, wenn sie im selben Render-Durchlauf sind? – hidayat

+1

@hidayat: Weil Sie nicht zwei primäre Befehlspuffer in derselben Render-Pass-Instanz haben können. 'vkCmdEndCommandBuffer' * kann nicht * aufgerufen werden, während eine Renderpass-Instanz aktiv ist. Nur mit sekundären Befehlspuffern ist es möglich, dass sie Befehle innerhalb derselben Renderpass-Instanz ausgeben. Sie tun dies, indem sie die renderpass-Instanz des primären Befehlspuffers erben, den sie ausführen. –

4

Für Ihr Szenario sollten Sie Ereignisse verwenden. Dies sollten die leichtesten Synchronisationsobjekte sein, um die Ausführung von zwei Befehlspuffern in einer bestimmten Reihenfolge zu synchronisieren, selbst wenn Sie sie gleichzeitig senden. Beachten Sie jedoch, dass Ereignisse nicht über verschiedene Warteschlangen hinweg funktionieren. Wenn Sie nur einen verwenden, verwenden Sie events und versuchen Sie, die Masken der src- und dst-Pipelinestufen so schmal wie möglich zu halten.

Semaphore sind eine weitere Möglichkeit, die Ausführung von Befehlspuffern zu synchronisieren, aber diese funktionieren nur bei der Übergabe an die Warteschlange, also sind sie schwerer als Ereignisse.

+0

Konnte eine Barriere nicht funktionieren? Ich lese hier weiter, dass Barrieren über die Grenzen des Befehlspuffers funktionieren: http://Stackoverflow.com/a/36602598/1364776 Könnte das nicht hier zutreffen? Oder sind die Ereignisse leichter als Barrieren? – mjwach