支援命令清單
本節僅適用於 Windows 7 和更新版本,以及 Windows Server 2008 R2 和更新版本的 Windows。
Direct3D 運行時間會針對命令列表使用下列 Direct3D 11 DDI:
CalcPrivateCommandListSize 函式會決定命令清單的使用者模式顯示驅動程式私人記憶體區域大小。
CreateCommandList 函式會建立命令清單。
RecycleCommandList 函式會回收命令清單。
RecycleCreateCommandList 函式會建立命令清單,並再次讓先前未使用的 DDI 句柄完全有效。
DestroyCommandList 函式會終結命令清單。
RecycleDestroyCommandList 函式會通知驅動程式需要輕量型解構命令清單。
CommandListExecute 函式會執行命令清單。
驅動程式 CommandListExecute、CalcPrivateCommandListSize、CreateCommandList 和 DestroyCommandList 函式的語意,大部分都是以其他類似的 DDI 函式和對應 DDI 的 API 檔為基礎,自我解釋。
在 Direct3D 運行時間成功在 pCreateCommandList 參數指向之D3D11DDIARG_CREATECOMMANDLIST結構的 hDeferredContext 成員上呼叫驅動程式的 CreateCommandList 或 RecycleCreateCommandList 函式之後,Direct3D 運行時間會在延遲的內容上執行下列解構順序:
Direct3D 執行時間會「關閉」所有開啟的延遲物件句柄。 請注意,這些句柄可能仍會顯示系結至延後的內容。
運行時間會終結延遲的內容。
在呼叫 CreateCommandList 或 RecycleCreateCommandList 期間,驅動程式對狀態重新整理 DDI 回呼函式所做的任何呼叫都會繼續透露延遲內容的目前狀態。 不過,在延遲內容的「關閉」和解構期間,任何對狀態重新整理 DDI 的呼叫都會反映沒有任何系結(也就是說,在呼叫 CreateCommandList 或 RecycleCreateCommandList 之後,所有專案都會隱含取消系結)。
延遲的內容也可以由應用程式明確放棄,或因為 API 或驅動程式的錯誤狀況而放棄。 在這種情況下,Direct3D 執行時間會執行下列順序:
Direct3D 運行時間會呼叫驅動程式的 AbandonCommandList 函式。
運行時間會從延遲的內容中解除系結句柄。
運行時間會「關閉」所有開啟的延遲物件句柄。
運行時間會回收或終結延遲的內容。
上述序列類似於立即內容的解構序列。 呼叫驅動程式的 AbandonCommandList 函式,可讓驅動程式將狀態套用至驅動程式偏好的任何專案。
在呼叫驅動程式的 CommandListExecute 函式期間,驅動程式必須轉換延遲內容的狀態,使其相當於裝置建立時的狀態。 此作業也稱為清除狀態作業。 不過,在呼叫驅動程式的 CommandListExecute 函式期間,驅動程式對 狀態重新整理 DDI 回呼函式所做的任何呼叫,仍然會反映驅動程式函式最後一次 DDI 呼叫期間所系結的內容狀態。 在下一次對驅動程式函式的 DDI 呼叫期間,驅動程式對狀態重新整理 DDI 回呼函式所做的任何呼叫都會將目前狀態顯示為完全空白,這反映了從 CommandListExecute 隱含的狀態轉換。 這個事實與狀態重新整理 DDI 回呼函式的典型語意和行為稍有不同。 如果驅動程式在呼叫其中一個驅動程式的 SetShader 函式時呼叫狀態重新整理 DDI 回呼函式,狀態重新整理 DDI 回呼函式會顯示為已系結的新著色器。 狀態重新整理 DDI 回呼行為的這種差異,可為驅動程式提供更多彈性,以反映 CommandListExecute 期間的舊狀態。
Direct3D 11 版 API 可確保命令清單已同時操作任何查詢(也就是,在命令清單中呼叫 QueryBegin 或 QueryEnd),而且只有嘗試執行命令清單的內容「開始」。 API 也可確保記錄動態資源對應之命令清單,會在目前對應的相同資源的內容上執行。 在應用程式呼叫 FinishCommandList 函式之前,Direct3D 運行時間會呼叫驅動程式的 QueryEnd 和 ResourceUnmap DDI 函式,而該查詢或動態資源仍保留開始查詢或對應的資源,因為 FinishCommandList 會隱含終止查詢範圍,並取消對應任何對應的資源。
小型命令清單的優化
小型記憶體數量命令清單的記憶體回收優化對於減少命令清單 DDI 函數調用之間的爭用,以及減少命令清單所需的呼叫處理額外負荷非常重要。 每個命令清單中固有的處理額外負荷相當重要。 此優化適用於命令清單,其中命令清單所需的處理額外負荷會主宰命令清單所需的CPU時間和記憶體空間。 小型記憶體數量命令清單例如,單一圖形命令,例如 CopyResource。 CopyResource 所需的記憶體數量是兩個指標。 不過,CopyResource 仍然需要與大型記憶體數量命令清單相同的命令清單呼叫處理量。 當小型記憶體數量命令清單以高頻率產生時,運行時間呼叫驅動程式的 CreateCommandList、DestroyCommandList、CreateDeferredContext 和 DestroyDevice(D3D10) 函式所需的處理額外負荷會變得越來越重要。 這裡所參考的記憶體是保存驅動程式數據結構的系統記憶體,其中包含 DDI 句柄的記憶體。
驅動程式的 RecycleCommandList 函式必須在驅動程式句柄用盡時通知驅動程式(但尚未刪除),以及重複使用先前未使用的驅動程式句柄時。 此通知同時適用於命令清單和延後內容句柄。 驅動程式必須回收的唯一記憶體是 DDI 句柄指向的記憶體。 雖然 RecycleCommandList 的目標是回收與句柄相關聯的記憶體,但為了提高效率,驅動程式可以完全彈性地挑選並選擇要回收的記憶體。 驅動程式無法變更立即內容命令清單處理點的記憶體區域大小。 這個大小是 CalcPrivateCommandListSize 的傳回值。 驅動程式也無法變更內容命令清單本機句柄點的記憶體區域大小。這個大小是 CalcDeferredContextHandleSize 的傳回值。
驅動程式的 RecycleCreateCommandList 和 RecycleCreateDeferredContext DDI 函式必須傳回記憶體不足的錯誤碼,E_OUTOFMEMORY HRESULT 值。 這些函式不會透過呼叫 pfnSetErrorCb 函式來提供這類錯誤碼。 此驅動程式需求可防止運行時間使用全裝置同步處理來監看這些建立類型驅動程式函式的即時內容錯誤。 監看這些錯誤會是小型記憶體數量命令清單的災難性爭用來源。
驅動程式的 RecycleDestroyCommandList、RecycleCommandList 和 RecycleCreateCommandList 函式之間的差別很重要。 其功能包括下列各項。
RecycleDestroyCommandList
運行時間會呼叫驅動程式的 RecycleDestroyCommandList 函式,以通知驅動程式需要輕量型解構。 也就是說,驅動程式尚未取消配置 DDI 命令清單句柄的記憶體。 驅動程式的 RecycleDestroyCommandList 函式是自由線程,就像驅動程式的 DestroyCommandList 函式一樣。
RecycleCommandList
驅動程式的 RecycleCommandList 函式會通知驅動程式運行時間將命令清單句柄整合回延後的內容快取。 然後,函式會提供驅動程式將與命令清單相關聯的記憶體整合到延後的內容快取中的機會。 運行時間會從延後的內容線程呼叫驅動程式的 RecycleCommandList 函式。 RecycleCommandList DDI 函式可減少驅動程序執行本身同步處理的需求。
RecycleCreateCommandList
運行時間會呼叫驅動程式的 RecycleCreateCommandList 函式,讓先前未使用的 DDI 句柄再次完全有效。
這些回收 DDI 函式提供優化機會,以協助回收小型記憶體數量命令清單的資源。 下列虛擬程式代碼會透過從 API 到 DDI 的函式呼叫流程,顯示運行時間的實作:
::FinishCommandList()
{
// Empty InterlockedSList, integrating into the cache
Loop { DC::pfnRecycleCommandList }
If (Previously Destroyed CommandList Available)
{ IC::pfnRecycleCreateCommandList }
else
{
IC::pfnCalcPrivateCommandListSize
IC::pfnCreateCommandList
IC::pfnCalcDeferredContextHandleSize(D3D11DDI_HT_COMMANDLIST)
}
Loop { DC::pfnDestroy* (context-local handle destroy) }
IC::pfnRecycleCreateDeferredContext
}
...
Sporadic: DC::pfnCreate* (context-local open during first-bind per CommandList)
CommandList::Destroy()
{
// If DC still alive, almost always recycle:
If (DC still alive)
{ IC::pfnRecycleDestroyCommandList }
Else
{ IC::pfnDestroyCommandList }
// Add to InterlockedSList
}
下列狀態圖顯示即時內容 DDI 命令清單句柄的有效性。 綠色狀態代表可與 CommandListExecute 搭配使用的句柄。