複製和存取資源資料 (Direct3D 10)

不再需要將資源視為在視訊記憶體或系統記憶體中建立。 或者,執行時間是否應該管理記憶體。 由於新的 WDDM 架構 (Windows 顯示驅動程式模型) ,應用程式現在會建立具有不同 使用 旗標的 Direct3D 10 資源,以指出應用程式如何使用資源資料。 新的驅動程式模型會將資源所使用的記憶體虛擬化;然後,它會成為作業系統/驅動程式/記憶體管理員的責任,以在預期的使用量下,將資源放在最高效能的記憶體區域中。

在預設案例下,資源可供 GPU 使用。 當然,話雖如此,有時候資源資料必須可供 CPU 使用。 若要將資源予以複製,使適當的處理器可在不影響效能的情況下進行存取,您需要具備 API 方法運作方式的基本知識。

複製資源資料

Direct3D 執行建立呼叫時,會在記憶體中建立資源。 他們可以在視訊記憶體、系統記憶體,或任何其他類型的記憶體之中建立。 由於 WDDM 驅動程式模型會把此記憶體虛擬化,應用程式不再需要追蹤資源究竟是建立於哪一種記憶體之中。

理想中,所有資源最好都位於視訊記憶體之中,以供 GPU 立即存取。 然而,有時候資源資料必須供 CPU 進行讀取,或是讓 CPU 已寫入的資源資料供 GPU 進行存取。 Direct3D 10 會藉由要求應用程式指定使用量來處理這些不同的案例,然後在必要時提供數種方法來複製資源資料。

根據建立資源的方式,並不一定都可以直接存取基礎資料。 這表示資源資料必須從來源資源中複製到另一個可供適當處理器進行存取的資源。 就 Direct3D 10 而言,預設資源可以直接由 GPU 存取,動態和預備資源可以直接由 CPU 存取。

建立資源之後,就無法變更其 使用量 。 但您可以將一個資源的內容複製到另一個被指定為不同使用方式的資源之中。 Direct3D 10 提供此功能與三種不同的方法。 前兩種方法 ( ID3D10Device::CopyResourceID3D10Device::CopySubresourceRegion) 的設計目的是將資源資料從一個資源複製到另一個資源。 第三種方法 (ID3D10Device::UpdateSubresource) 的設計目的是將資料從記憶體複製到資源。

資源可分為兩種︰可對應與不可對應。 以動態或暫存使用方式建立的資源為可對應資源,而以預設或不可變動使用方式建立的資源為不可對應資源。

在不可對應資源之間複製資料非常迅速,因為這是最常見的案例,其執行也已最佳化。 由於這些資源無法由 CPU 直接存取,因此其已進行最佳化,使 GPU 可以快速地對其進行操作。

在可對應資源之間複製資料則可能較容易發生問題,因為其效能將會取決於資源建立時指定的使用方式。 例如:GPU 可以快速地讀取動態資源,但卻無法對其進行寫入,並且 GPU 無法直接地讀取或寫入暫存資源。

想要將資料從預設使用量的資源複製到具有預備使用量的資源 (的應用程式,以允許 CPU 讀取資料,也就是 GPU 回寫問題) 必須小心。 如需此最後一個案例的詳細資訊,請參閱 存取資源資料

存取資源資料

存取資源需必須先對應該資源。基本上,「對應」即表示應用程式正在嘗試讓 CPU 對記憶體進行存取。 為使 CPU 能存取基本記憶體而對資源進行對應的程序,可能會導致某些效能瓶頸。基於這個原因,應注意如何及何時執行這項工作。

若應用程式嘗試在錯誤的時間點進行對應資源,其執行效能可能會降低到停止的程度。 若應用程式嘗試在作業完成之前對其結果進行存取,將可能導致管線停頓。

若在錯誤的時間點進行對應作業,可能會因為強制 GPU 與 CPU 互相同步而導致效能嚴重下降 。 此同步動作會在應用程式嘗試在 GPU 完成將資源複製到另一個 CPU 可以對應的資源前對其進行存取時發生。

CPU 只能從使用 D3D10_USAGE_STAGING 旗標建立的資源讀取。 由於使用此旗標建立的資源無法設定為管線的輸出,如果 CPU 想要讀取 GPU 所產生的資源中的資料,則必須將資料複製到使用預備旗標建立的資源。 應用程式可以使用 ID3D10Device::CopyResourceID3D10Device::CopySubresourceRegion 方法來將某個資源的內容複寫到另一個資源。 然後,應用程式可以藉由呼叫適當的 Map 方法來存取此資源。 不再需要存取資源時,應用程式應該接著呼叫對應的 Unmap 方法。 例如, ID3D10Texture2D::MapID3D10Texture2D::Unmap。 不同的 Map 方法會根據輸入旗標傳回一些特定值。 如需詳細資訊 ,請參閱地圖備註一節

注意

當應用程式呼叫 Map 方法時,它會接收要存取之資源資料的指標。 執行時間會根據 功能層級,確保指標具有特定的對齊方式。 對於 D3D_FEATURE_LEVEL_10_0 和更新版本,指標會對齊 16 個位元組。 針對低於 D3D_FEATURE_LEVEL_10_0,指標會對齊 4 個位元組。 16 位元組對齊可讓應用程式在原生資料上執行 SSE優化作業,而不需重新對齊或複製。

 

效能考量

建議您將您的電腦視為一台以兩種不同類型處理器構成的平行結構運作的機器︰一個或多個 CPU,以及一個或多個 GPU。 如同任何平行結構一樣,當每個處理器都排程了足夠的工作,以避免其進入閒置狀態或等待別的處理器完成工作時,運作才可達到最佳效能。

GPU/CPU 平行處理原則中最糟的情況,就是強制一個處理器等候另一個處理器工作完成的結果。 Direct3D 10 嘗試讓 ID3D10Device::CopyResourceID3D10Device::CopySubresourceRegion 方法非同步移除此成本;複製在方法傳回時不一定執行。 其優點在於應用程式不需要在 CPU 存取資料時才付出效能降低的成本,即呼叫 Map 方法時。 若 Map 方法在資料確實複製後才被呼叫,便不會造成任何效能上的損失。 另一方面,若 Map 方法在資料複製之前就被呼叫,便會發生管線停頓。

Direct3D 10 中的非同步呼叫 (是大部分的方法,特別是轉譯呼叫) 會儲存在稱為命令緩衝區的內容中。 這個緩衝區位於圖形驅動程式的內部,並用來對基礎硬體進行批次呼叫,使 Microsoft Windows 從使用者模式切換至核心模式這種極為耗費成本狀況的發生能夠盡量減少。

命令緩衝區在下列四種情況下會被排清,並造成使用者/核心模式的切換。

  1. 呼叫 Present
  2. 呼叫 ID3D10Device::Flush
  3. 命令緩衝區已滿。其大小為動態且由作業系統及圖形驅動程式控制。
  4. CPU 需要存取命令緩衝區中一個尚待執行命令的結果。

在以上四種情況中,第四種情況會對效能造成最嚴重的影響。 如果應用程式發出 ID3D10Device::CopyResourceID3D10Device::CopySubresourceRegion 呼叫,此呼叫會排入命令緩衝區中。 如果應用程式接著嘗試對應在清除命令緩衝區之前,複製呼叫的目標暫存資源,就會發生管線停止,因為複製方法呼叫不需要執行,命令緩衝區中的所有其他緩衝命令也必須執行。 這將會導致 GPU 與 CPU 進行同步,因為 CPU 將會等待 GPU 清空命令緩衝區並填滿 CPU 需要的資源後,才能存取暫存資源。 當 GPU 完成複製之後,CPU 才會開始存取暫存資源,然而此期間 GPU 就會進入閒置狀態。

若經常性地在執行階段進行此動作,將會大幅降低效能。 基於這個原因,對應以預設使用方式建立的資源時,應小心謹慎。 應用程式必須等候夠長的時間,讓命令緩衝區被清空並且完成執行佇列中所有的命令,才能嘗試對應相對應的暫存資源。 應用程式應該等候多久才行? 至少需要等待兩個影格的時間,因為這樣才能使 CPU 和 GPU 之間的平行處理原則得到最大且有效率的調控。 GPU 的運作方式,是當應用程式藉由送出呼叫到命令緩衝區中以處理第 N 個影格時,GPU 正忙碌於執行前一個影格 (N-1) 的呼叫。

因此,如果應用程式想要對應源自視訊記憶體的資源,並在應用程式提交下一個畫面格的呼叫時,呼叫 ID3D10Device::CopyResourceID3D10Device::CopySubresourceRegion ,則此呼叫實際上會在畫面 N+1 開始執行。 複製應會在應用程式正在處理第 N+2 個影格時完成。

Frame GPU/CPU 狀態
N
  • CPU 為目前的影格送出轉譯呼叫。
N+1
  • GPU 執行 CPU 在第 N 個影格時送出的呼叫。
  • CPU 為目前的影格送出轉譯呼叫。
N+2
  • GPU 完成執行 CPU 在第 N 個影格時送出的呼叫。結果準備就緒。
  • GPU 執行 CPU 在第 N+1 個影格時送出的呼叫。
  • CPU 為目前的影格送出轉譯呼叫。
N+3
  • GPU 完成執行 CPU 在第 N+1 個影格時送出的呼叫。 結果準備就緒。
  • GPU 執行 CPU 在第 N+2 個影格時送出的呼叫。
  • CPU 為目前的影格送出轉譯呼叫。
N+4 ...

 

(Direct3D 10)