複製與存取資源資料 (Direct3D 10)
不再需要將資源視為在視訊記憶體或系統記憶體中建立。 或者執行期間應否管理記憶體。 由於新的 WDDM (Windows Display Driver Model) 架構,應用程式現在會建立具有不同 使用量的 Direct3D 10 資源 旗標,以指出應用程式如何使用資源數據。 新的驅動程式模型會將資源所使用的記憶體虛擬化,因而需由作業系統/驅動程式/記憶體管理員負責,根據預期的使用狀況,將資源放在最高效能的記憶體區域中。
預設情況是資源可予以 GPU 使用。 當然,話雖如此,有時候資源數據需要提供給 CPU。 複製周圍的資源數據,讓適當的處理器可以存取它,而不會影響效能,需要一些 API 方法運作方式的知識。
複製資源數據
Direct3D 執行 Create 呼叫時,會在記憶體中建立資源。 它們可以在視訊記憶體、系統記憶體或任何其他種類的記憶體中建立。 由於WDDM驅動程式模型虛擬化此記憶體,因此應用程式不再需要追蹤在 中建立的記憶體資源種類。
在理想情況下,所有資源都會位於視訊記憶體中,讓 GPU 可以立即存取它們。 不過,有時需要 CPU 讀取資源數據,或讓 GPU 存取 CPU 已寫入的資源數據。 Direct3D 10 會藉由要求應用程式指定使用量來處理這些不同的案例,然後在必要時提供數種方法來複製資源數據。
根據資源的建立方式,不一定能夠直接存取基礎數據。 這可能表示資源數據必須從來源資源複製到由適當處理器存取的另一個資源。 就 Direct3D 10 而言,預設資源可以直接由 GPU 存取,CPU 可以直接存取動態和預備資源。
建立資源之後,就無法變更其 使用量。 相反地,將某個資源的內容複製到以不同使用量建立的另一個資源。 Direct3D 10 提供這項功能與三種不同的方法。 前兩種方法(ID3D10Device::CopyResource 和 ID3D10Device::CopySubresourceRegion) 的設計目的是將資源數據從某個資源複製到另一個資源。 第三個方法(ID3D10Device::UpdateSubresource) 的設計目的是將數據從記憶體複製到資源。
資源有兩種主要類型:可對應和非可對應。 使用動態或預備使用方式建立的資源是可對應的,而以預設或不可變數建立的資源則不可對應。
在不可映射的資源之間複製資料非常快,因為這是最常見的情況,且已經過優化以提高效能。 由於 CPU 無法直接存取這些資源,因此它們經過優化,讓 GPU 可以迅速操作這些資源。
在具備對應功能的資源之間進行數據複製會更加棘手,因為效能會依賴於資源建立時的用途。 例如,GPU 可以相當快速地讀取動態資源,但無法寫入這些資源,而且 GPU 無法直接讀取或寫入暫存資源。
想要將資料從預設使用量的資源複製到具有預備使用量之資源的應用程式(以允許 CPU 讀取資料 -- 亦即 GPU 回寫問題)必須謹慎執行。 如需上一個案例的詳細資訊,請參閱 存取資源數據。
存取資源數據
存取資源需要對資源進行映射;映射基本上表示應用程式正在嘗試為CPU提供訪問記憶體的權限。 將資源對應到使CPU能夠存取基礎記憶體的過程可能會導致一些效能瓶頸,因此必須謹慎考量進行這項任務的方式與時機。
如果應用程式嘗試在錯誤的時間對應資源,效能可能會陷入停止。 如果應用程式嘗試存取作業的結果,該作業完成之前,就會發生管線停滯。
在錯誤的時間執行對應作業,可能會導致 GPU 和 CPU 彼此同步,而導致效能嚴重下降。 如果應用程式想要在 GPU 完成將資源複製到 CPU 可對應的資源之前存取資源,就會發生此同步處理。
CPU 只能從使用 D3D10_USAGE_STAGING 旗標建立的資源讀取。 由於使用此旗標建立的資源無法設定為管線的輸出,如果 CPU 想要讀取 GPU 所產生的資源中的數據,則必須將數據複製到使用預備旗標建立的資源。 應用程式可以使用 ID3D10Device::CopyResource 或 ID3D10Device::CopySubresourceRegion 方法,將某個資源的內容複製到另一個資源。 然後,應用程式可以藉由呼叫適當的 Map 方法來存取此資源。 不再需要存取資源時,應用程式應該接著呼叫對應的 Unmap 方法。 例如,ID3D10Texture2D::Map 和 ID3D10Texture2D::Unmap。 不同的 Map 方法會根據輸入旗標傳回一些特定值。 如需詳細資訊,請參閱 地圖備註部分。
注意
當應用程式呼叫 Map 方法時,它會接收要存取之資源數據的指標。 運行時間可確保指標具有特定的對齊方式,視 功能層級而定。 針對 D3D_FEATURE_LEVEL_10_0 和更新版本,指標會對齊 16 個字節。 若小於 D3D_FEATURE_LEVEL_10_0,指標會對齊 4 個字節。 16 位元組的對齊可讓應用程式在原生數據上執行 SSE優化作業,而不需要重新對齊或複製。
效能考慮
最好將計算機視為以兩種主要處理器類型的平行架構執行的計算機:一或多個CPU和一或多個 GPU。 在任何平行架構中,最佳效能是在每個處理器被分配足夠的任務以防止閒置,且各處理器之間的工作互不等待的情況下達成的。
GPU/CPU 平行處理原則最差的情況是需要強制一個處理器等待另一個處理器完成的工作結果。 Direct3D 10 會嘗試藉由讓 ID3D10Device::CopyResource 和 ID3D10Device::CopySubresourceRegion 方法來移除此成本:方法傳回時,複製不一定執行。 其優點是,應用程式不會支付實際複製數據的效能成本,直到 CPU 存取數據,也就是呼叫 Map 時。 如果在實際複製數據之後呼叫 Map 方法,則不會發生任何效能遺失。 另一方面,如果在複製數據之前呼叫 Map 方法,則會發生管線停滯。
Direct3D 10 中的異步呼叫(這是絕大多數的方法,特別是轉譯呼叫)會儲存在所謂的命令緩衝區中。 此緩衝區是圖形驅動程式的內部元件,用於批次呼叫基礎硬體,從而儘量減少在 Microsoft Windows 中從使用者模式切換到核心模式的高成本轉換。
命令緩衝區已被清空,因此在以下四種情況其中之一將造成使用者/核心模式切換。
- 被稱呼為。
- 呼叫 ID3D10Device::Flush。
- 命令緩衝區已滿;其大小是動態的,由作系統和圖形驅動程式控制。
- CPU 需要存取在命令緩衝區中等候執行的命令結果。
在上述四種情況中,第四種情況對效能是最關鍵的。 如果應用程式發出 ID3D10Device::CopyResource 或 ID3D10Device::CopySubresourceRegion 呼叫,此呼叫會排入命令緩衝區。 如果應用程式在命令緩衝區被清除之前,嘗試映射作為複製呼叫目標的暫存資源,則會發生管線停滯,因為不僅複製方法的呼叫需要執行,命令緩衝區中的所有其他緩衝命令也必須執行。 這會導致 GPU 和 CPU 同步,因為在 GPU 清空命令緩衝區並最終填入 CPU 所需的資源時,CPU 會等候存取中繼資源。 GPU 完成複本之後,CPU 就會開始存取預備資源,但在此期間,GPU 會閒置。
在運行時間經常這樣做會嚴重降低效能。 因此,對於以預設使用方式建立的資源進行對應時,應謹慎處理。 應用程式需要等待足夠長的時間,以確保命令緩衝區中的所有命令已經完成執行,並因此清空緩衝區,然後再嘗試對應相應的暫存資源。 應用程式應該等候多久? 至少需要有兩幀,這樣能夠在最大限度上利用 CPU 和 GPU 之間的平行處理。 GPU 的運作方式是,雖然應用程式會藉由將呼叫提交至命令緩衝區來處理框架 N,但 GPU 正忙於執行上一個框架 N-1 的呼叫。
因此,如果應用程式想要映射源自視訊記憶體的資源,並呼叫 ID3D10Device::CopyResource 或 ID3D10Device::CopySubresourceRegion,則當應用程式正在提交下一畫框的呼叫時,此呼叫實際上會開始在畫面 N+1 上執行。 當應用程式正在處理框架 N+2 時,應該完成複製。
框架 | GPU/CPU 狀態 |
---|---|
N |
|
N+1 |
|
N+2 |
|
N+3 |
|
N+4 | ... |
相關主題