使用 Context-Local DDI 控制碼

本節僅適用于 Windows 7 和更新版本,以及 Windows Server 2008 R2 和更新版本的 Windows 作業系統。

每個物件 (例如資源、著色器等) 都有內容本機 DDI 控制碼。

假設物件與三個延後的內容搭配使用。 在此情況下,四個控制碼會參考相同的物件 (每個延後內容一個控制碼,另一個控制碼用於立即內容) 。 因為執行緒可以同時操作每個內容,所以內容本機控制碼可確保多個 CPU 執行緒不會爭用類似的記憶體, (刻意或不小心) 。 內容本機控制碼也是直覺的,因為驅動程式可能必須修改大部分在邏輯上與每個內容相關聯的資料 (例如,物件可能會受到內容系結,依此類) 。

即時內容控制碼與延後的內容控制碼仍然有區別。 特別是,即時內容控制碼保證是配置的第一個控制碼,以及最後一個終結的控制碼。 在每個延後的內容控制碼「開啟」期間會提供對應的立即內容控制碼,以將它們連結在一起。 目前沒有任何物件具有個別裝置 DDI 控制碼 (的概念,也就是在立即內容控制碼之前和終結之後建立的控制碼,而且只會依內容控制碼建立) 的順序來參考。

例如,某些控制碼與其他控制碼具有相依性關聯性 (,檢視會相依于其對應的資源) 。 立即內容的建立和解構順序保證會延伸至延後的內容控制碼,以及 (也就是說,執行時間會在執行時間建立該資源的任何內容本機檢視控制碼之前建立內容本機資源控制碼,而執行時間會在執行時間終結該資源的所有內容區域檢視控制碼) 。 當執行時間建立內容本機控制碼時,執行時間也會提供對應的內容本機相依性控制碼。

驅動程式資料組織

需要注意的驅動程式資料組織有一些疑慮。 如同 Direct3D 第 10 版,適當的資料位置可以減少 API 與驅動程式之間的快取遺漏。 資料的適當位置也可以防止快取擲回,當多個經常存取的資料片段全部解析為相同的快取索引,並耗盡快取的關聯性時,就會發生此情況。 DDI 的設計自 Direct3D 第 10 版開始,可協助避免驅動程式資訊清單這類問題,通知驅動程式滿足控制碼所需的記憶體數量,以及指派控制碼值的 API。 不過,新的執行緒相關考慮會影響 Direct3D 第 11 版時間範圍中的 DDI 設計。

自然地,內容區域控制碼會提供一種方式來關聯每個內容的物件資料,以避免執行緒之間的爭用問題。 不過,由於這類資料會針對每個延後的內容複寫,因此這類資料的大小是主要考慮。 這可提供自然合理化,以在即時內容控制碼與延後的內容控制碼之間共用唯讀資料。 在建立延後的內容控制碼期間,會提供立即內容控制碼,以建立控制碼之間的連接。 不過,位於延後內容之外的任何資料會利用 API 資料取得位置優勢,而唯讀資料的額外間接層級可防止位置優勢延伸到唯讀資料。 如果位置優點證明資料重複,某些唯讀資料可以複寫到每個內容控制碼區域。 不過,備份每個延遲內容控制碼的記憶體應該在這類進階中考慮,如果該資料相對大且不會像其他資料一樣頻繁地存取,則重新放置來自控制碼的資料可能值得。 在理想情況下,與每個延後內容控制碼相關聯的資料類型仍然會是所有高頻率的資料;因此,資料不夠大,無法考慮需要重新配置。 當然,驅動程式必須平衡這些衝突的動機。

為了讓驅動程式資料設計有效率地與 Direct3D 第 10 版相容,但尚未在實作中差異,唯讀資料應該位於連續的 (,但仍在) 立即的內容控制碼資料之後隔離。 如果驅動程式使用此設計,則驅動程式必須注意,在即時內容控制碼資料與唯讀資料之間需要快取行填補。 由於執行緒可能會經常操作每個內容控制碼資料, (如果沒有同時) ,則在未使用快取行填補時,會在立即內容控制碼資料與延後的內容控制碼資料之間發生誤判。 如果建立指標並在內容控制碼記憶體區域之間定期周遊指標,驅動程式設計必須能夠辨識出錯誤共用的懲罰。

Direct3D 執行時間會針對延遲的內容本機控制碼使用下列 Direct3D 11 DDI:

若要讓 Direct3D 執行時間擷取驅動程式所需的延後內容控制碼大小,必須使用上述 DDI 函式。 在為立即內容建立物件之後,執行時間會呼叫 CalcDeferredCoNtextHandleSize 來查詢驅動程式所需的儲存空間量,以便滿足此物件的延遲內容控制碼。 不過,Direct3D API 必須藉由判斷存取多少個唯一控制碼大小及其值,來調整其 CLS 記憶體配置器;執行時間會呼叫驅動程式的 CheckDeferredCoNtextHandleSizes 函式來取得這項資訊。 因此,在裝置具現化期間,API 會藉由雙輪詢要求延遲內容控制碼大小的陣列。 第一個輪詢是要求傳回多少大小,而第二個輪詢會傳入陣列以擷取每個大小的值。 驅動程式必須指出滿足控制碼以及哪一個控制碼類型所需的記憶體。 驅動程式可以傳回與特定控制碼類型相關聯的多個大小。 不過,未定義驅動程式從 CalcDeferredCoNtextHandleSize 傳回的值,該值在 CheckDeferredCoNtextHandleSizes 陣列中並未對應傳回。

至於建立 DDI 控制碼,則會使用延後內容上的 create 方法。 例如,檢查 CreateBlendState (D3D10_1) DestroyBlendState 函式。 HDEVICE 自然指向適當的延後內容 (與立即內容) ;假設物件沒有相依性,則其他 CONST 結構指標為 Null (假設物件沒有相依性) ;而且,D3D10DDI_HRT* 控制碼是對應之立即內容物件的D3D10DDI_H* 控制碼。

例如,對於具有相依性的物件 (,檢視在其對應的資源) 具有相依性關聯性,則提供相依性控制碼的結構指標不是 Null。 不過,結構的唯一有效成員是相依性控制碼;而 其餘的成員會填入零。 例如,在延遲的內容上呼叫驅動程式CreateShaderResourceView (D3D11) 函式時,D3D11DDIARG_CREATESHADERRESOURCEVIEW指標不會Null。 在此 CreateShaderResourceView (D3D11) 呼叫中,執行時間會將資源的適當內容本機控制碼指派給 D3D11DDIARG_CREATESHADERRESOURCEVIEW的 hDrvResource 成員。 不過,D3D11DDIARG_CREATESHADERRESOURCEVIEW的其餘成員會填入零。

下列範例程式碼示範 Direct3D 執行時間如何轉譯應用程式的建立要求,以及第一次使用延後的內容來呼叫使用者模式顯示驅動程式,以建立立即與延遲的內容。 應用程式的 ID3D11Device::CreateTexture2D 呼叫會在下列 「資源建立」區段中起始執行時間程式碼。 應用程式的 ID3D11Device::CopyResource 呼叫會在下列「延後的內容資源使用量」區段中起始執行時間程式碼。

// Device Create
 IC::pfnCheckDeferredContextHandleSizes( hIC, &u, NULL );
pArray = malloc( u * ... );
IC::pfnCheckDeferredContextHandleSizes( hIC, &u, pArray );

// Resource Create
 s = IC::pfnCalcPrivateResourceSize( hIC, &Args );
pICRHandle = malloc( s );
 IC::pfnCreateResource( hIC, &Args, pICRHandle, hRTResource );
 s2 = IC::pfnCalcDeferredContextHandleSize( hIC, D3D10DDI_HT_RESOURCE, pICRHandle );

// Deferred Context Resource Usage
pDCRHandle = malloc( s2 );
 DC::pfnCreateResource( hDC, NULL, pDCRHandle, pICRHandle );

pfnSetErrorCb 的問題

任何建立函式都不會傳回錯誤碼,這適用于 Direct3D 11 版執行緒模型。 所有 create 函式都使用 pfnSetErrorCb 從驅動程式擷取錯誤碼。 為了最大化與 Direct3D 第 10 版驅動程式模型的相容性,未導入傳回錯誤碼的新 DDI 建立函式。 相反地,驅動程式必須在建立函式期間繼續使用與 pfnSetErrorCb 搭配運作 的整合裝置/即時內容D3D10DDI_HRTCORELAYER控制碼。 當驅動程式支援命令清單時,驅動程式應該使用與對應內容相關聯的適當 pfnSetErrorCb 。 也就是說,延後的內容錯誤應該移至具有對應控制碼的特定延後內容呼叫 pfnSetErrorCb ,依此類推。

延後的內容可以透過從先前只允許DrawSetBlendState) 等D3DDDIERR_DEVICEREMOVED (的 DDI 函式呼叫 pfnSetErrorCb來傳回E_OUTOFMEMORY,因為延後的內容記憶體需求會隨著每次呼叫 DDI 函式而永久成長。 Direct3D API 會觸發本機內容移除,以協助驅動程式處理這類失敗案例,有效地將部分建置的命令清單卸載。 應用程式會繼續判斷正在錄製命令清單;不過,當應用程式最後呼叫 FinishCommandList 函式時, FinishCommandList 會傳回失敗碼E_OUTOFMEMORY。