2015-06-24 130 views
2

幀開始時,我做了邏輯更新並在此之後渲染。 在我的渲染代碼中,我會做一些常用的東西。我設置了幾個狀態,緩衝區,紋理,並通過調用Draw來結束。在DirectX中渲染11

m_deviceContext->Draw(
     nbVertices, 
     0); 

在框架端我稱本顯示渲染幀。

// Present the back buffer to the screen since rendering is complete. 
if(m_vsync_enabled) 
{ 
    // Lock to screen refresh rate. 
    m_swapChain->Present(1, 0); 
} 
else 
{ 
    // Present as fast as possible. 
    m_swapChain->Present(0, 0); 
} 

通常的東西。現在,當我調用Draw時,根據MSDN

Draw將工作提交給渲染管道。

這是否意味着數據發送到GPU和主線程(稱爲繪製)繼續?還是等待渲染完成?

在我看來,只有Present函數應該讓主線程等待渲染完成。

+0

繪製提交(並繼續),實際上是屏幕更新的地方。您可以在啓用VSync的情況下查看它,因爲它會延遲。 – CodeAngry

+0

@CodeAngry 謝謝。 只是爲了確保我理解正確。我稱之爲Draw,數據發送到GPU,GPU開始計算,我稱之爲Present,當GPU完成計算後屏幕即會更新。那是對的嗎? – DannyX

回答

3

有很多可以觸發GPU開始工作的調用,Draw就是其中之一。其他的包括Dispatch,CopyResource等MSDN文檔試圖說的是像PSSetShader這樣的東西。 IASetPrimitiveTopology等在您撥打Draw之前不會做任何事情。

當您調用Present時,將其視爲'幀結束'的隱式指示符,但您的程序通常可以繼續在第一幀完成並顯示之前爲下一幀設置渲染調用。默認情況下,Windows將允許您排隊3幀,然後阻止Present調用中的CPU線程以讓GPU趕上 - 實時渲染時,您通常不希望輸入和渲染之間的延遲爲真的很高。

但事實是,GPU/CPU同步很複雜,並且Direct3D運行時也在分解請求以最小化內核調用開銷,因此在將許多Draw提交到命令隊列後,實際工作可能會發生抖動。 This old article給你如何工作的味道。在現代GPU上,您還可以進行各種內存操作,用於在內存中分頁,設置物理視頻內存區域等。

順便說一句,所有這些'魔術'在Direct3D 12中都不存在,但這意味着應用程序必須在「正確」的時間做所有事情,以確保它既高效又實用。程序員更直接地構建命令隊列,觸發各種像素和計算GPU引擎的工作,以及處理所有雜亂的東西,這些東西通過Direct3 11的運行時自動處理得更加抽象。即使如此,最終視頻驅動程序是實際與硬件對話的驅動程序,因此它們也可以進行其他類型的優化。

拇指這裏的一般規則要牢記:

  • 創建資源是昂貴的,尤其是運行時着色器編譯(由HLSL編譯器)和運行着色斑點優化(通過驅動程序)
  • 複製資源GPU(即從CPU內存中加載紋理數據)需要總線帶寬在供應方面受到限制:優先將紋理,VB和IB數據保留在您可重複使用的靜態緩衝區中。
  • 從GPU複製資源(即,將GPU內存移動到CPU內存)使用比去GPU更慢的反向通道:儘量避免需要從GPU回讀
  • 每個繪圖調用提交更大的幾何塊有助於分攤開銷(例如調用draw for具有相同狀態/着色器的10,000個三角形比調用繪製10次更快,每個1000個三角形具有不同狀態/着色器之間的變化)。