GPU 半虛擬化
本文說明 WDDM 中的 GPU 半虛擬化。 此功能可從 Windows 10 版本 1803 (WDDM 2.4) 開始提供。
關於 GPU 虛擬化
GPU 虛擬化是 Windows 用戶端和 Windows Server 的重要功能。 有許多案例需要有效使用虛擬機中的 GPU 資源。
伺服器案例(主機 OS 未執行使用者應用程式)包括:
- 桌面虛擬化
- 計算 (AI、ML 等)
用戶端案例(其中主機 OS 共用 VM 與使用者應用程式之間的 GPU)包括:
- 開發與測試圖形應用程式(其中測試是在 VM 中執行)
- 基於安全性考慮,在 VM 中執行應用程式
- 在具有 GPU 加速的 VM 中執行 Linux
WDDM 中的 GPU 半虛擬化
半虛擬化 (PV) 提供類似於其基礎硬體的虛擬機 (VM) 介面。 在 PV 中,您會在安裝 VM 之前明確移植客體 OS,因為非量身打造的客體 OS 無法在虛擬機監視器 (VMM) 上執行。
優勢:
- 多個 VM 共用硬體資源。
- 驅動程式碼需要做一些變更。
下圖描述 WDDM 半虛擬化設計所涉及的各種元件。
客體 VM 中的 D3D 執行時間不會變更。 具有使用者模式運行時間和 KMT 核心 Thunks 的介面會維持不變。
驅動程式元件不需要許多變更:
客體 VM 中的 UMD 必須:
- 請注意,與主機核心模式驅動程式 (KMD) 的通訊會在 VM 界限之間發生。
- 使用新增 Dxgkrnl 服務來存取登錄設定。
來賓中沒有 KMD,只有 UMD。 新的虛擬轉譯裝置(VRD)KMD 將會取代 KMD。 VRD 的目的是為了協助載入 Dxgkrnl。
來賓中沒有視頻記憶體管理員(VidMm)或排程器(VidSch)。
VM 中的 Dxgkrnl 會取得 Thunk 呼叫,並透過 VM 總線通道將它們封送至主機分割區。 客體中的 Dxgkrnl 也會為配置、行程、裝置和其他資源建立本地物件,以減少主機的流量。
虛擬轉譯裝置 (VRD)
當 VM 中沒有半虛擬化 GPU 時,VM 的 Device Manager 會顯示「Microsoft Hyper-V 視訊」適配卡。 此顯示器專用適配器預設會與 BasicRender 適配器配對,以進行渲染。
當您將半虛擬化 GPU 新增至 VM 時,VM 的 Device Manager 會顯示兩個適配卡:
- Microsoft Hyper-V 視訊配接器或 Microsoft 遠端顯示配接器
- Microsoft 虛擬轉譯驅動程式 (實際名稱是主機上 GPU 適配卡的名稱)
根據預設,VRD 會與 Hyper-V Video 配接器配對,因此所有 UI 轉譯都會與 VRD 配接器一起發生。
如果您遇到轉譯問題,您可以使用 GpuVirtualizationFlags 登錄設定來停用此配對。 在這種情況下,當應用程式特別選用時,會使用僅供轉譯的配接器(VRD)。 例如,某些 DirectX 範例可讓您變更轉譯裝置。 Direct3D 執行階段會在應用程式決定使用時,將一個邏輯顯示輸出元件新增至 VRD。
當您將多個虛擬 GPU 新增至虛擬機 (VM) 時,客戶端中可能會出現多個 VRD 轉接卡。 不過,只有其中一個可以與 Hyper-V 視訊配接器配對。 沒有辦法指定哪一個;作系統選擇。
容器和虛擬機
VM 和容器支援 GPU 虛擬化。 容器是輕量型 VM,其中主機 OS 二進位檔會對應至容器 VM。
如需容器的詳細資訊,請參閱 Windows 和容器。
保護 VM
安全 VM 有下列限制:
- 驅動程式呼叫逸出不被允許,但已知的逸出除外,這些已知的逸出會與 DriverKnownEscape 旗標搭配使用。
- 已啟用 IoMmu 隔離。 如果驅動程式不支援IoMmu隔離,VM 建立就會失敗。
開啟安全模式時:
- DxgkDdiSetVirtualMachineData 已設定 SecureVirtualMachine 旗標。
- DxgkDdiQueryAdapterInfo 已設定 SecureVirtualMachine 旗標。
有登錄設定可強制安全模式,或在開發期間停用IoMmu隔離。 如需詳細資訊,請參閱 登錄設定。
VM/容器桌面的遙控管理
您可以使用兩種方法,將虛擬機 (VM) 中的桌面內容遠端至主機:
- Hyper-V 顯示配接器
- 終端機會話遠端操作
當 RDP (遠端桌面) 用來連線到 VM 時,會使用終端機會話遠端處理。
Hyper-V 管理員會使用 VMConnect 應用程式來顯示 VM 桌面。 VMConnect 適用於兩種模式:
- 加強模式,使用遠端終端機會話。
- 使用 Hyper-V 顯示配接器的基本模式。
VM 工作進程和 VM 記憶體
當您啟動 VM 或容器時,作系統會在主機上建立下列程式:
- VM 工作處理程序 (vmwp.exe)
- VM 記憶體程序(vmmem.exe)
Vmwp 包含各種虛擬設備驅動程式,包括 vrdumed.dll,這是用於半虛擬化圖形配接器的驅動程式。
vmmem 處理虛擬位址空間可作為客體中 vGPU IO 空間的備份。 當來賓存取 IO 空間時,產生的實體位址是第二層轉譯的入口,它會使用 vmmem 程序的分頁表。
在虛擬化環境中,通常會在主機上用戶進程上下文中執行的各種 KMD DDI 呼叫,會在虛擬機運行時改為在 vmmem 進程的上下文中執行。
Dxgkrnl 會為這些進程建立單一 DXGPROCESS (以及對應的 KMD 進程物件),這稱為本文中的 VM 背景工作進程。 與 DXG VM 工作者進程相關聯的 EPROCESS 是 vmmem。
VM 程序
在客體 VM 中建立 DXGPROCESS 時,Dxgkrnl 在主機上建立對應的 DXGPROCESS 物件。 此程式稱為本文中的 VM 進程。 與 DXGPROCESS 關聯的 EPROCESS 是 vmmem。
VM 或 VM 資源配置的建立的所有繪圖操作都會在 VM 的 DXGPROCESS 範疇中完成。
為了進行偵錯,Dxgkrnl 會在 DxgkDdiCreateProcess中通知 KMD 哪個程序是 VM 工作程序或 VM 程序。 使用此資訊,驅動程式可以將 VM 程序連結至 VM 工作程序。 這項資訊有助於在多個 VM 執行時進行偵錯。
驅動程式需求
支援 GPU 半虛擬化的 KMD 必須設定 DXGK_VIDMMCAPS::ParavirtualizationSupported 功能。
使用者模式驅動程式 (UMD) 不應該在私人驅動程式數據中使用任何進程內容相關數據(指標、句柄等)。 相反地,KMD 在不同的程序環境中取得主機中的私密資料。
客戶端中的 UMD 無法與主機中的 KMD 共享記憶體。 它必須使用在中所述的函式從UMD存取登錄。
目前的半虛擬化實作會使用 VM 總線在客體與主機之間進行通訊。 訊息大小上限為 128KB。 目前,Dxgkrnl 不會將訊息分段以區塊形式發送。 因此,驅動程式必須限制在物件建立時傳遞的私有數據大小。 例如,當 Pfnd3dddiAllocatecb 用來建立許多配置時,訊息大小總計會包含標頭、全域私人數據,以及每個配置私用數據的大小乘以配置數目。 此資訊都需要容納在一則訊息中。
以全螢幕模擬模式執行應用程式
應啟用間接顯示適配器用於遠端處理(預設為啟用)。 若要停用它,請執行下列步驟。
- 開始編輯群組策略
- 流覽至 [計算機設定->系統管理範本 ->Windows 元件 ->遠端桌面服務 ->遠端桌面工作主機 ->遠端工作環境
- 開啟 [使用 WDDM 圖形顯示驅動程式進行遠端桌面連線] 專案
- 選取 [停用],然後選取 [確定]
- 重新啟動
在 VM 中,全螢幕應用程式的 DXGI 支援預設為啟用。 若要停用它,請使用 StagingTool.exe /disable 19316777
。
全螢幕應用程式必須在仿真的全螢幕模式中執行。
為所有 DXGI 應用程式啟用 eFSE,並設定交換效果轉換至 WDDM 2.0 的最低 WDDM 版本:
D3DEnableFeature.exe /enable DXGI_eFSE_Enablement_Policy
D3DEnableFeature.exe /setvariant DXGI_eFSE_Enablement_Policy 7
默認會針對 D3D9 應用程式啟用 eFSE。
VM 中的 DriverStore
主機上的驅動程式二進位檔位於驅動程式存放區 %windir%\system32\drivers\DriverStore\FileRepository<DriverDirectory>。
針對半虛擬化,VM 中的 UMD 二進位檔應該位於 %windir%\system32\drivers\HostDriverStore\FileRepository<DriverDirectory>。
主機 KMD 會報告具有驅動程式存放區完整路徑的 UMD DLL 名稱。 例如,c:\windows\system32\DriverStore\FileRepository\DriverSpecificDirectory\d3dumd.dll。
當 VM 要求 UMD 名稱時,名稱會轉譯為 <VmSystemDrive>:\windows\system32\HostDriverStore\FileRepository\DriverSpecificDirectory\d3dumd.dll。
容器中的主機驅動程式庫
針對容器,Hyper-V 會將主機中的完整主機驅動程式存放區目錄對應至容器中的 <%windir%\HostDriverStore。
完整 VM 的主機驅動程式庫
當虛擬 GPU 適配卡在 VM 中啟動時,驅動程式儲存盤案會複製到 VM。 此功能已在發行的 OS 版本中停用。
下列登錄機碼和可能的值可控制複製作業。 這個鍵預設不存在。
DWORD RTL_REGISTRY_CONTROL\GraphicsDrivers\DriverStoreCopyMode
價值 | 描述 |
---|---|
0 | 停用驅動程式存放區的複製 |
1 | 一般操作(允許複製驅動程式存放區檔案,且不會覆寫現有的檔案)。 |
2 | 啟用驅動程式存放區的複製,並覆寫現有的檔案。 |
來自 UMD 的註冊表存取
KMD 登錄機碼存在於主機上,且不會反映至 VM。 因此,UMD 無法直接讀取這類驅動程式登錄機碼。 pfnQueryAdapterInfoCb2 回呼會新增至 D3D 運行時間 D3DDDI_ADAPTERCALLBACKS 結構。 UMD 可以呼叫 pfnQueryAdapterInfoCb2,並設定 D3DDDICB_QUERYADAPTERINFO2,如下所示來讀取特定登錄機碼:
- D3DDDICB_QUERYADAPTERINFO2::QueryType 設定為 D3DDDI_QUERYADAPTERTYPE_QUERYREGISTRY。
-
pPrivateDriverData 指向一個包含用於傳回註冊表資訊的 D3DDDI_QUERYREGISTRY_INFO 結構的緩衝區。 UMD 會填入下列成員:
- D3DDDI_QUERYREGISTRY_INFO::QueryType 指定登錄存取的類型;例如,服務金鑰、配接器金鑰或驅動程式存放區路徑。
- D3DDDI_QUERYREGISTRY_FLAGS::QueryFlags 指定查詢的旗標。
- ValueName 識別要讀取的值名稱。
- ValueType 指定要讀取的值類型。
-
PrivateDriverDataSize 是
sizeof(D3DDDI_QUERYREGISTRY_INFO)
加上動態大小輸出值緩衝區大小的結果。
UMD 也可以直接呼叫 D3DKMTQueryAdapterInfo。 此呼叫對客體中的UMD很有用,因為它會封送至主機,並提供將特定名稱轉譯為來賓名稱空間的方法。
D3DKMTQueryAdapterInfo 會呼叫 D3DKMT_QUERYADAPTERINFO,如下所示來讀取特定登錄機碼:
- 類型 設定為 KMTQAITYPE_QUERYREGISTRY
- pPrivateDriverData 指向 D3DKMT_ADAPTERREGISTRYINFO 結構
-
PrivateDriverDataSize 是
sizeof(D3DKMT_ADAPTERREGISTRYINFO)
加上動態大小輸出值緩衝區大小的總和。
範例 1:從服務金鑰讀取值
WCHAR ValueName = L"EnableDebug";
D3DDDI_QUERYREGISTRY_INFO Args = {};
Args.QueryType = D3DDDI_QUERYREGISTRY_SERVICEKEY;
Args.QueryFlags.TranslatePath = FALSE or TRUE;
Args.ValueType = Supported registry value type;
wcscpy_s(Args.ValueName, ARRAYSIZE(Args.ValueName), ValueName);
D3DKMT_QUERYADAPTERINFO Args1 = {};
Args1.hAdapter = hAdapter;
Args1.Type = KMTQAITYPE_QUERYREGISTRY;
Args1.pPrivateDriverData = &Args;
Args1.PrivateDriverDataSize = sizeof(Args);
NTSTATUS Status = D3DKMTQueryAdapterInfo(&Args1);
if (NT_SUCCESS(Status) &&
Args.Status == D3DDDI_QUERYREGISTRY_STATUS_SUCCESS)
{
if (ValueType == REG_SZ || ValueType == REG_EXPAND_SZ) {
wprintf(L"Value: \"%s\"\n", Args.OutputString);
} else
if (ValueType == REG_MULTI_SZ) {
wprintf(L"Value: ");
for (UINT i = 0; i < Args.OutputValueSize; i++) {
if (Args.OutputString[i] == 0) {
wprintf(L" ");
} else {
wprintf(L"%c", Args.OutputString[i]);
}
}
wprintf(L"\n");
} else
if (ValueType == REG_DWORD) {
wprintf(L"Value: %d\n", Args.OutputDword);
} else
if (ValueType == REG_QWORD) {
wprintf(L"Value: 0x%I64x\n", Args.OutputQword);
} else
if (ValueType == REG_BINARY) {
wprintf(L"Num bytes: %d\n", Args.OutputValueSize);
for (UINT i = 0; i < Args.OutputValueSize; i++) {
wprintf(L"%d ", Args.OutputBinary[i]);
}
wprintf(L"\n");
}
}
範例 2:讀取驅動程式存放區路徑
D3DDDI_QUERYREGISTRY_INFO Args = {};
Args.QueryType = D3DDDI_QUERYREGISTRY_DRIVERSTOREPATH;
D3DKMT_QUERYADAPTERINFO Args1 = {};
Args1.hAdapter = hAdapter;
Args1.Type = KMTQAITYPE_QUERYREGISTRY;
Args1.pPrivateDriverData = &Args;
Args1.PrivateDriverDataSize = sizeof(Args);
NTSTATUS Status = D3DKMTQueryAdapterInfo(&Args1);
if (NT_SUCCESS(Status) &&
Args.Status == D3DDDI_QUERYREGISTRY_STATUS_SUCCESS)
{
Args.OutputString holds the output NULL terminated string.
Args.OutputValueSize holds the number of characters in the string
}
將檔案複製到 VM 中的 %windir%\system32 和 %windir%\syswow64
在某些情況下,驅動程式使用者模式 DLL 必須存在於 %windir%\system32 和 %windir%\syswow64 目錄中。
作業系統提供了一種方法,允許驅動程式指定應該從主機中的驅動程式存放區複製到客體中 %windir%\system32 或 %windir%\syswow64 的檔案。
在安裝 INF 中,驅動程式可以在圖形配接器登錄機碼的下列子機碼中定義多個值:
- CopyToVmOverwrite
- CopyToVmWhenNewer
- CopyToVmOverwriteWow64
- CopyToVmWhenNewerWow64
CopyToVmOverwrite 和 CopyToVmWhenNewer 子機碼可用來將檔案複製到 %windir%\system32 目錄。
CopyToVmOverwriteWow64 和 CopyToVmWhenNewerWow64 子機碼用於將檔案複製到 %windir%\syswow64 目錄。
CopyToVmOverwrite 底下的檔案 和 CopyToVmOverwriteWow64 一律會覆寫目的地中的檔案。
CopyToVmWhenNewer 下的檔案 和 CopyToVmWhenNewerWow64 只有在檔案變更日期較新時,才會覆寫目的地中的檔案。 「較新」準則會比較兩項資訊:
- 文件版本
- 最後寫入時間
當目的地檔案以 .dll 或 .exe 後綴結尾時,FileVersion 會作為最重要的比較值,其中最大的版本被視為「較新」。 當目的地檔案結尾不是以 .dll 或 .exe 後綴或兩個 FileVersion 相等時,則 LastWriteTime 會作為最不重要的比較值,其中較晚的日期/時間被視為「較新」。
子機碼下的每個值類型都必須為 REG_MULTI_SZ 或 REG_SZ。 如果實值類型是REG_MULTI_SZ,則值中應該最多有兩個字串。 這項需求表示每個值都會定義單一字串或一對字串,其中第二個字元串可能是空的。
配對中的第一個名稱是驅動程式存放區中一個檔案的路徑。 路徑相對於驅動程式存放區的根目錄,而且可以包含子目錄。
配對中的第二個名稱是檔名,因為它應該出現在 %windir%\system32
或 %windir%\syswow64
目錄中。 第二個名稱應該只是檔名,不包括路徑。
如果第二個名稱是空的,則檔名與驅動程式存放區中的檔名相同(不包括子目錄)。
此方法可讓驅動程式在主機驅動程式存放區和虛擬機中有不同的名稱。
範例 1
下列範例示範如何指示作業系統來將 <DriverStorePath>\CopyToVm\softgpu1.dll
複製到 %windir%\system32\softgpu2.dll
。
INF [DDInstall] section
HKR,"softgpukmd\CopyToVmOverwrite",SoftGpuFiles,%REG_MULTI_SZ%,"CopyToVm\softgpu1.dll”, “softgpu2.dll”
The directive creates the registry key in the software (adapter) key:
"HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\<number>\CopyToVmOverwrite”, SoftGpuFiles = REG_MULTI_SZ, “CopyToVm\softgpu1.dll”, “softgpu2.dll"
範例 2
下列範例示範如何讓 OS 將 <DriverStorePath>\softgpu1.dll
複製到 %windir%\system32\softgpu.dll
,並將 <DriverStorePath>\softgpu2.dll
複製到 %windir%\system32\softgpu2.dll
。
INF [DDInstall] section:
HKR,"CopyToVmOverwrite",SoftGpuFiles1,%REG_MULTI_SZ%,"softgpu1.dll”,”softgpu.dll"
HKR,"CopyToVmOverwrite",SoftGpuFiles2,%REG_SZ%, “softgpu2.dll"
The directive creates the registry key in the software (adapter) key:
“HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\<number>\CopyToVmOverwrite”, SoftGpuFiles1 = REG_MULTI_SZ, “softgpu1.dll”, “softgpu.dll"
“HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\<number>\CopyToVmOverwrite”, SoftGpuFiles2 = REG_SZ, “softgpu2.dll””
範例 3
下列範例示範如何讓 OS 將 <DriverStorePath>\Subdir1\Subdir2\softgpu2wow64.dll
複製到 %windir%\syswow64\softgpu.dll
,並將 <DriverStorePath>\softgpu.dll
複製到 %windir%\syswow64\softgpu2wow64.dll
。
INF [DDInstall] section:
HKR,"CopyToVmOverwriteWow64",SoftGpuFiles,%REG_MULTI_SZ%,“Subdir1\Subdir2\softgpu2wow64.dll”,”softgpu.dll”.
The directive creates the registry key in the software (adapter) key:
“HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\<number>\CopyToVmOverwriteWow64”, SoftGpuFiles = REG_MULTI_SZ, “Subdir1\Subdir2\softgpu2wow64.dll”,”softgpu.dll
DxgkDdiCreateProcess 的變更
KMD 的 DxgkDdiCreateProcess 函式必須更新,以支援 VM 工作者進程和 VM 進程。 下列欄位會新增至 DXGKARG_CREATEPROCESS 結構:
- hKmdVmWorkerProcess
- ProcessNameLength
- pProcessName
下列旗標會新增至 DXGK_CREATEPROCESSFLAGS,用於支援 VM 背景工作程序和 VM 程序:
- VirtualMachineProcess
- 虛擬機器工作處理程序
DxgkDdiSetVirtualMachineData
為 Dxgkrnl 新增了 DxgkDdiSetVirtualMachineData,以便將虛擬機器的相關資訊傳遞至 KMD。
將非同步 VM 總線訊息傳送至主機
在虛擬作業系統中,來自 Dxgkrnl 到主機的某些訊息是非同步傳送的。 此方法可改善來賓中高頻率 Dxgkrnl API 呼叫的效能。 每個同步 VM 總線訊息對主機的額外負荷可能很高。
異步訊息包括:
- D3DKMTSubmitCommand
- D3DKMTSubmitCommandToHardwareQueue
- D3DKMTSignalSynchronizationObjectFromGpu
- D3DKMTWaitForSynchronizationObjectFromGpu
GPU-PV 中的 LDA 支援
GPU-PV 支援連接顯示卡 (LDA)。 若要確保 LDA 支援的一致的實作和支援未來可能回溯移植至舊版 Windows 版本,KMD 必須呼叫 DxgkCbIsFeatureEnabled(DXGK_FEATURE_LDA_GPUPV)來檢查 GPU-PV 中的 LDA 支援。 如果函式成功並傳回 Enabled,則會啟用支援。 如果 KMD 未呼叫此回呼函式,Dxgkrnl 將假設 KMD 不支援 GPU-PV 中的 LDA。
如果 OS 支援此功能,則由驅動程式在使用者模式中啟用 LDA。 如果驅動程式在使用者模式中啟用 LDA,它應該如下所示。
執行時間 | LDA 狀態 |
---|---|
D3D12 運行時間前 | 如果支援 DXGK_FEATURE_LDA_GPUPV,且客體作系統為 Windows 11 版本 22H2(WDDM 3.1) 或更新版本,請啟用 。 |
非 DX 運行時間 (Windows) | 如果支援 DXGK_FEATURE_LDA_GPUPV,且客體作系統為 Windows 11 版本 22H2(WDDM 3.1) 或更新版本,請啟用 。 UMD 可以呼叫 D3DKMTQueryAdapterInfo(KMTQAITYPE_PHYSICALADAPTERCOUNT),而不是檢查 OS 版本,並在返回的實體適配器數量大於 1 時啟用 LDA。 |
D3D12 運行時間 (Windows) | 啟用。 請參閱 設定 D3D12 運行時間的 LDA 狀態。 |
Linux (d3d12 和非 DX 執行環境) | 如果支援 DXGK_FEATURE_LDA_GPUPV 的情況下,請啟用。 |
以小於 DXGKDDI_INTERFACE_VERSION_WDDM3_0 介面版本編譯的驅動程式不會檢查 DXGK_FEATURE_LDA_GPUPV。 這些驅動程式仍然可以為 Linux 執行環境啟用 LDA。
設定 D3D12 執行時間的 LDA 狀態
啟用或停用 D3D12 執行階段的 LDA 時,UMD 必須將正確的等級和節點映射資訊傳回執行階段。 程式代碼流程如下所示:
D3D12 會從 UMD 取得 D3D12_CROSS_NODE_SHARING_TIER 能力。
D3D12 藉由呼叫 D3DKMTQueryAdapterInfo(KMTQAITYPE_PHYSICALADAPTERCOUNT),從 Dxgkrnl 取得實體適配卡計數。
D3D12 會呼叫 pfnQueryNodeMap pfnQueryNodeMap(PhysicalAdapterCount, &map),以取得邏輯節點索引與實體節點的對應。 在此情況下,節點表示實體配接器。 UMD 必須在映射中設定實際的實體適配器索引,或使用 D3D12DDI_NODE_MAP_HIDE_NODE 來停用節點。
根據 pfnQueryNodeMap 的結果,D3D12 透過不計算隱藏節點來計算有效的實體配接器數量。
如果層的狀態和有效的實體介面卡數量不相符,D3D12 會失敗的設備創建。 發生不匹配的情況是當:
- 階層 D3D12DDI_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED,且配接器數量大於 1。
- 層未 D3D12DDI_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED,配接器計數為 1。
若要停用 LDA,UMD 必須傳回層級 D3D12DDI_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED,並在節點映射中僅啟用一個實體適配器。
D3DKMTQueryAdapterInfo(KMTQAITYPE_PHYSICALADAPTERCOUNT)
實體配接器計數的 KMTQAITYPE_PHYSICALADAPTERCOUNT 查詢會始終將正確的實體配接器數量傳回給客戶系統:
- 在 Windows 11 版本 22H2 之前的客體系統上,它會傳回 1。 此值會在來賓程式代碼中硬式編碼。 未來如果將 LDA 支援移植到舊版作業系統,可能會有所變更。
- 在 Windows 11 版本 22H2 和更新版本系統上,它會傳回:
- 啟用 DXGK_FEATURE_LDA_GPUPV 時的實際實體配接器數目。
- 否則為 1。
半虛擬化啟用
在 BIOS 中啟用虛擬化支援(VT-d 或類似版本)。 GPU-PV VMMS 虛擬機和容器的設定不同。
在 PowerShell 中(以系統管理員身分執行),在伺服器上啟用腳本執行:
set-executionpolicy unrestricted
VMMS 虛擬機設定
設定主機和 VM
VM 中的 OS 組建可能比主機中的 OS 組建還舊或更新。
在伺服器角色中啟用 Hyper-V 功能,或在用戶端上啟用 Hyper-V 功能。 在伺服器上啟用此功能時,選取選項以使用網路適配器作為外部交換器。
(選擇性)啟用測試簽署 (bcdedit -set TESTSIGNING ON)
重新啟動。
安裝支援准虛擬化的 GPU 驅動程式。
(選擇性)某些驅動程式不會設定 ParavirtualizationSupported 上限。 在此情況下,請先新增下列登錄,再安裝驅動程式,或在設定旗標之後停用/啟用裝置。
DWORD HKLM\System\CurrentControlSet\Control\GraphicsDrivers\GpuVirtualizationFlags = 1
若要檢查 OS 是否可辨識半虛擬化 GPU,請執行下列 PowerShell 命令:
Get-VMPartitionableGpu # Example output from running the command Name : \\?\PCI#VEN_10DE&DEV_1C02&SUBSYS_11C210DE&REV_A1#4&275d7527&0&0010#{064092b3-625e-43bf-9eb5-d c845897dd59}\GPUPARAV ValidPartitionCounts : {32} PartitionCount : 32 TotalVRAM : 1,000,000,000 AvailableVRAM : 1,000,000,000 MinPartitionVRAM : 0 MaxPartitionVRAM : 1,000,000,000 OptimalPartitionVRAM : 1,000,000,000 TotalEncode : 18,446,744,073,709,551,615 AvailableEncode : 18,446,744,073,709,551,615 MinPartitionEncode : 0 MaxPartitionEncode : 18,446,744,073,709,551,615 OptimalPartitionEncode : 18446744073709551615 TotalDecode : 1000000000 AvailableDecode : 1000000000 MinPartitionDecode : 0 MaxPartitionDecode : 1000000000 OptimalPartitionDecode : 1000000000 TotalCompute : 1000000000 AvailableCompute : 1000000000 MinPartitionCompute : 0 MaxPartitionCompute : 1000000000 OptimalPartitionCompute : 1000000000 CimSession : CimSession: . ComputerName : MYCOMPUTER-TEST2 IsDeleted : False
在 PowerShell 中執行下列命令,以使用 GPU 建立 VM。 建立名為 TEST 的 VM。
$vm = “TEST“ New-VM -VMName $vm -Generation 2 Set-VM -GuestControlledCacheTypes $true -VMName $vm
設定 VM 的 IO 空間。 GPU-PV 使用 IO 空間來處理 CPU 可見的配置。 至少需要 8 GB 的 IO 空間。
Set-VM -LowMemoryMappedIoSpace 1GB -VMName $vm Set-VM -HighMemoryMappedIoSpace 16GB -VMName $vm
[選擇性]根據預設,高記憶體 IO 空間的基地址會設定為 (64GB - 512MB)。 在具有36位物理記憶體尋址的 Haswell 晶片組上,IO 空間區域的結束地址必須低於 64GB,因此必須據以設定起始位址。 下列名為 SetHighMmioBase.ps1的腳本會使用下列參數執行時,將起始位址設定為 47GB:
SetHightMmioBase.ps1 “TEST” 48128 # SetHighMmioBase.ps1 param( [string]$VmName, $BaseInMB) function Get-WMIVM { [CmdletBinding()] param( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$VmName = "" ) gwmi -namespace root\virtualization\v2 -query "select * from Msvm_ComputerSystem where ElementName = '$VmName'" } function Get-WMIVmSettingData { [CmdletBinding()] param( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$VmName = "" ) $vm = Get-WMIVM $VmName return $vm.GetRelated ("Msvm_VirtualSystemSettingData","Msvm_SettingsDefineState",$null,$null, "SettingData", "ManagedElement", $false, $null) } Write-Host "Setting HighMmioGapBase to $BaseInMB for VmName $VmName" $vssd = Get-WMIVmSettingData $VmName $vmms = Get-WmiObject -Namespace "root\virtualization\v2" -Class Msvm_VirtualSystemManagementService $vssd.HighMmioGapBase = $BaseInMB $settingsText = $vssd.PSBase.GetText("CimDtd20") $ret=$vmms.ModifySystemSettings($settingsText).ReturnValue if ($ret -eq 0) { Write-Host "Successfully set" $vssd.HighMmioGapBase } else { Write-Host "Error $ret" }
將虛擬 GPU 新增至 VM 並停用檢查點。
Add-VMGpuPartitionAdapter -VMName $vm Set-VM -CheckpointType Disabled -VMName $vm
若要檢查 VM 是否有半虛擬化 GPU,請執行下列命令:
Get-VMGpuPartitionAdapter -VMName $vm in PowerShell. The output should show the adapter. # Example output from running the command MinPartitionVRAM : MaxPartitionVRAM : OptimalPartitionVRAM : MinPartitionEncode : MaxPartitionEncode : OptimalPartitionEncode : MinPartitionDecode : MaxPartitionDecode : OptimalPartitionDecode : MinPartitionCompute : MaxPartitionCompute : OptimalPartitionCompute : Name : GPU Partition Settings Id : Microsoft:9ABB95E2-D12D-43C3-B840-6F4A9CFB217B\929890BC-BB33-4687-BC1A-F72A4F1B3B3F VMId : 9abb95e2-d12d-43c3-b840-6f4a9cfb217b VMName : TEST VMSnapshotId : 00000000-0000-0000-0000-000000000000 VMSnapshotName : CimSession : CimSession: . ComputerName : MYCOMPUTER-TEST2 IsDeleted : False VMCheckpointId : 00000000-0000-0000-0000-000000000000 VMCheckpointName :
將 VM 中使用的相同用戶端組建 VHDX 複製到主機目錄。 例如,
d:\VM\os.vhdx
。開啟 Hyper-V 管理員並修改 VM 參數(選取 [VM],然後選取 [設定]):
- 安全性 - 取消核取 啟用安全開機。
- 記憶體 - 檢查 啟用動態記憶體。 將記憶體數量設定為 1,024 MB 以上。
- 處理器 - 將虛擬處理器數目 設為 2 或 4。
- 網路適配器 - 從下拉式方塊中選取要搭配 VM 使用的網路配接器。 如果已啟用網路偵錯,請務必挑選 Microsoft 偵錯NET配接器。
- SCSI 控制器 - 硬碟 - 新增 - 虛擬硬碟 - 流覽 - 選取
d:\VM\os.vhdx
OS 會在客體中初始化配接器時,將主機驅動程式存放區中的檔案複製到客體中的 HostDriverStore 目錄。
- 掛接 VM 的 VHDX。 例如,前往磁碟 f:。
- 在掛接的 VM 中,建立名為 f:\%windir%\system32\HostDriverStore\FileRepository的目錄。
- 將主機中的驅動程式檔案從 %windir%\system32\DriverStore 複寫至 VM。 VM 中應該 f:\%windir%\system32\HostDriverStore\FileRepository\YourDriverDirectory\* 。
如果驅動程式需要從
%windir%\system32
或%windir%\syswow64
存取檔案,請手動將檔案複製到 VM。如果未Microsoft簽署驅動程式,請在 VM 中啟用測試登入。 在 CMD 管理視窗中,執行下列命令:
bcdedit /store <VM drive>:\EFI\Microsoft\Boot\BCD -set {bootmgr} testsigning on
卸除 VM 的 VHDX。
啟動 VM。
使用 [Hyper-V 管理員連線] 選項連線到 VM。
在 VM 內部
檢查 VM 的設備管理員中是否有虛擬轉譯裝置。 VM 內的所有轉譯都會經過虛擬 GPU。
設定 VM 的 PowerShell 腳本
下列 PowerShell 腳本是如何從頭開始設定 VM 的範例。 修改它以符合您的需求。
Param(
[string]$VMName,
[string]$VHDPath,
[string]$SwitchName,
[switch]$CreateVm,
[switch]$InitDebug,
[switch]$CopyRegistry,
[switch]$CopyDriverStore,
[switch]$CreateSwitch,
[switch]$AddGpu,
[switch]$All
)
if($All)
{
$CreateVm = $True
$CreateInitDebug = $True
$CopyRegistry = $True
$CopyDriverStore = $True
$CreateSwitch = $True
$AddGpu = $True
$InitDebug = $True
}
$vm = $VMName
#
# Validate parameters
#
if ($CreateSwitch -or $CreateVM)
{
if ($SwitchName -eq "")
{
write "SwitchName is not set"
exit
}
}
if ($AddGpu -or $CreateVM)
{
if ($VMName -eq "")
{
write "VMName is not set"
exit
}
}
if ($InitDebug -or $CreateVM -or $CopyDriverStore -or $CopyRegistry)
{
if ($VHDPath -eq "")
{
write "VHDPath is not set"
exit
}
}
enable-windowsoptionalfeature -FeatureName Microsoft-Hyper-V-All -online
#
# Create a network switch for the VM
#
if ($CreateSwitch)
{
New-VMSwitch $SwitchName -NetAdapterName "Ethernet (Kernel Debugger)"
}
#
# Create a VM and assign VHD to it
#
if ($CreateVm)
{
New-VM -VMName $vm -Generation 2
Set-VM -GuestControlledCacheTypes $true -VMName $vm
Set-VM -LowMemoryMappedIoSpace 1Gb -VMName $vm
Set-VM -HighMemoryMappedIoSpace 32GB -VMName $vm
Set-VMProcessor -VMname $vm -count 4
Set-VMMemory -VMName $vm -DynamicMemoryEnabled $true -MinimumBytes 1024MB -MaximumBytes 4096MB -StartupBytes 1024MB -Buffer 20
Add-VMHardDiskDrive -VMName $vm -Path $VHDPath
Connect-VMNetworkAdapter -VMName $vm -Name "Network Adapter" -SwitchName $SwitchName
Set-VMFirmware -VMName $vm -EnableSecureBoot off
Set-VMFirmware -VMName $vm -FirstBootDevice (Get-VMHardDiskDrive -VMName $vm)
}
#
# Enable debugger and testsiging
#
if ($InitDebug)
```powershell
{
Mount-vhd $VHDPath
Add-PartitionAccessPath -DiskNumber (Get-DiskImage -ImagePath $VHDPath | Get-Disk).Number -PartitionNumber 1 -AssignDriveLetter
$efidrive = (Get-DiskImage -ImagePath $VHDPath | Get-Disk | Get-Partition -PartitionNumber 1).DriveLetter
bcdedit /store ${efidrive}:\EFI\Microsoft\Boot\BCD -set '{bootmgr}' testsigning on
bcdedit /store ${efidrive}:\EFI\Microsoft\Boot\BCD -set '{default}' debug on
bcdedit /store ${efidrive}:\EFI\Microsoft\Boot\BCD /dbgsettings net port:50052 key:a.b.c.d hostip:10.131.18.133
Dismount-VHD $VHDPath
}
#
# Now boot the VM without vGPU to verify that it's initialized correctly
# If everything is OK, turn off the VM
#
if ($CreateVm)
{
Write-Output "Boot the VM and turn it OFF after it's initialized"
pause
}
#
# Add virtual GPU
#
if($AddGpu)
{
Add-VMGpuPartitionAdapter -VMName $vm
Get-VMGpuPartitionAdapter -VMName $vm
}
#
# Copy the driver store to the VM
#
if ($CopyDriverStore)
{
Write "Copying driver store"
Mount-vhd $VHDPath
$drive = (Get-DiskImage -ImagePath $VHDPath | Get-Disk | Get-Partition -PartitionNumber 3).DriveLetter
xcopy /s $Env:windir\system32\driverstore\* ${drive}:\windows\system32\hostdriverstore\
Dismount-VHD $VHDPath
}
#
# Export driver registry settings
#
if ($CopyRegistry)
{
Write "Copying registry"
Mount-vhd $VHDPath
$drive = (Get-DiskImage -ImagePath $VHDPath | Get-Disk | Get-Partition -PartitionNumber 3).DriveLetter
reg load HKLM\VMSettings ${drive}:\Windows\System32\config\SYSTEM
reg copy "HKLM\System\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000" "HKLM\VmSettings\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000" /s /f
reg unload "HKLM\VmSettings"
Dismount-VHD $VHDPath
}
對 VM 進行偵錯
將 VM 調試程式設定為與一般用戶端電腦上的網路偵錯相同。
如果 VM 未啟動,或您看到黑色畫面:
關閉 VM,並使用下列命令從中移除虛擬 GPU:
$vm = “TEST“ remove-VMGpuPartitionAdapter -VMName $vm -AdapterId “<Id from Get-VMGpuPartitionAdapter>”
例如:
remove-VMGpuPartitionAdapter -VMName $vm -AdapterId “Microsoft:9ABB95E2-D12D-43C3-B840-6F4A9CFB217B\929890BC-BB33-4687-BC1A-F72A4F1B3B3F”
啟動 VM。 如果成功啟動,請確定驅動程式檔案已正確複製到 VM 中的 HostDriverStore。
使用
Add-VMGpuPartitionAdapter
命令將 vGPU 新增至 VM。再次啟動 VM。
如需詳細資訊,請參閱 疑難解答。
容器設定
容器(也稱為 主機計算系統 (HCS) 虛擬機器)與完整虛擬機器之間的差異在於作業系統的二進位檔和驅動程式存放區檔案會映射到容器。 因此,除非 windows\system32
目錄中需要驅動程式檔案,否則不需要將驅動程式檔案複製到容器。
針對安全的容器:
- 驅動程式逸出功能已禁用。
- 驅動程式必須支援在安全容器內啟用 IOMMU 隔離。
當您更新主機上的驅動程式並啟動或停止主機 GPU 時,變更會反映在容器中。
Windows 沙盒
此容器類型可用來嘗試具風險的應用程式。 桌面映像會完整地遠端顯示在主機上。 間接顯示驅動程式用於遠端處理。 因為未使用 Graphics VAIL,導致將桌面影像傳輸到主機的速度很慢。
Windows 沙箱中預設會停用虛擬 GPU。 若要啟用它,請建立 WSB 組態檔(例如,config.wsb),並設定虛擬 GPU 選項。 按兩下組態檔來啟動沙箱。
組態檔範例:
<Configuration>
<VGpu>Enable</VGpu>
</Configuration>
根據預設,容器中的 vGPU 已停用驅動程序逃逸功能。 有一個配置選項可以啟用驅動程式跳脫功能。 下列 WSB 檔案範例會在 Sandbox 中啟用 vGPU 和驅動程式逃逸:
<Configuration>
<VGpu>EnableVendorExtensions</VGpu>
</Configuration>
Windows 沙箱支援 GPU 配接器「熱插即用」。
虛擬應用程式整合在本機 (VAIL) 容器
使用此容器類型在 WCOS(Windows Core作系統)型主機內執行 Win32 應用程式。 容器中每個應用程式的映像檔會被遙控到主機。 圖形 VAIL 已啟用,以遠端管理每個應用程式的交換鏈。 允許驅動程式跳脫功能。
常見的容器需求
機器需求如下:
- Vtx 和 Vtd 都必須在 BIOS 中啟用(或其對等專案:AMD-V、AMD-IOMMU)。
- 至少 8 GB 的 RAM。
- 超過 5 GB 的系統磁碟空間。
設定 Windows 沙箱的核心調試程式
使用 CMDIAG
容器管理器服務(cmservice)控制 Hyper-V 隔離容器。 CMDIAG.EXE 是安裝 Hyper-V 和容器功能時可用的應用程式。 它可針對容器啟用內核模式偵錯、啟用測試簽署等等。
Container Manager 支援序列和 NET 偵錯。
執行 cmdiag.exe Debug
以查看選項。
CMDIAG 修改容器基底映像中的調試程序設定。 啟用內核調試程式時,應該只有一個容器實例正在執行。
變更調試程式設定之前,請先停止 HVSICS 服務。
# Example 1:
C:\Windows\system32>sc stop hvsics
SERVICE_NAME: HVSICS
TYPE : 30 WIN32
STATE : 3 STOP_PENDING
(STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x1
WAIT_HINT : 0xbb8
C:\Windows\system32>cmdiag debug -on -Serial -Force
Debugging successfully enabled. Connection string: -k com:pipe,port=\\.\pipe\debugpipe,reconnect -v
# Example 2:
C:\Windows\system32>cmdiag debug -on -net -port 51000 -key a.b.c.d -hostip 10.131.18.34
在不同的電腦上執行調試程式
當您使用序列調試程式時,您可能會想要在不同的電腦上執行它。 使用 kdsrv.exe
在不同的電腦上執行調試程式。 如需詳細資訊,請參閱 KD 連線伺服器。
若要在核心偵錯期間停用逾時,請設定下列登錄機碼:
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\Containers\UtilityVm" /v BridgeTransactionTimeout /t REG_DWORD /d 0xffffffff /f
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\Containers\UtilityVm" /v BridgeServerConnectTimeout /t REG_DWORD /d 0xffffffff /f
reg add "HKLM\SOFTWARE\Microsoft\HVSI" /f /v DisableResetContainer /t REG_DWORD /d 1
reg add "HKLM\SOFTWARE\Microsoft\HVSI" /f /v AppLaunchTimeoutInSeconds /t REG_DWORD /d 0x7fffffff
reg add "HKLM\Software\Microsoft\Terminal Server Client" /f /v ConnectionHealthMonitoringSupported /t REG_DWORD /d 0
reg add "HKLM\Software\Microsoft\Terminal Server Client" /f /v DisableUDPTransport /t REG_DWORD /d 1
reg add "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client" /f /v ConnectionHealthMonitoringSupported /t REG_DWORD /d 0
reg add "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client" /f /v DisableUDPTransport /t REG_DWORD /d 1
設定 VAIL 容器的核心調試程式
- 使用 telnet 連線到主機。 您可以從主機 OS 中的 [網络設定] 取得主機的IP位址。
- 使用
cmdiag.exe
來設定調試程式。
設定 Hypervisor 調試程式
bcdedit /hypervisorsettings NET port:50000 key:a.b.c.d hostip:1.1.1.1
bcdedit /set {hypervisorsettings} hypervisorbusparams 0.0.0 (if needed)
bcdedit /set hypervisordebug on
reboot host
故障排除
本節提供如何針對 GPU-PV 問題進行疑難解答的資訊。
Get-VMHostPartitionableGpu
呼叫 Get-VMHostPartitionableGpu 以查看是否有虛擬化 GPU。 如果輸出是空的,則會在某處發生錯誤(驅動程式未設定虛擬化上限、未啟用虛擬化等等)。
Get-VMHostPartitionableGpu
# Example output from running the command
Name : \\?\PCI#VEN_10DE&DEV_1188&SUBSYS_095B10DE&REV_A1#6&cfd27c8&0&00400008#{064092b3-625e-43bf-9eb5-dc845897dd59}\PARAV
ValidPartitionCounts : {32, 4}
PartitionCount : 32
TotalVRAM : 2,000,000
AvailableVRAM : 1,800,000
MinPartitionVRAM : 100,000
MaxPartitionVRAM : 1,000,000
OptimalPartitionVRAM : 1,000,000
TotalEncode : 20
AvailableEncode : 20
MinPartitionEncode : 1
MaxPartitionEncode : 5
OptimalPartitionEncode : 4
TotalDecode : 40
AvailableDecode : 30
MinPartitionDecode : 2
MaxPartitionDecode : 20
OptimalPartitionDecode : 15
TotalCompute : 100
AvailableCompute : 100
MinPartitionCompute : 1
MaxPartitionCompute : 50
OptimalPartitionCompute : 30
CimSession : CimSession: .
ComputerName : WIN-T3H0LVHJJ59
IsDeleted : False
使用 ETW 事件
Dxgkrnl 具有 ETW 事件的管理和操作通道。 事件會顯示在 Windows 事件查看器中:應用程式和服務記錄檔 - Microsoft - Windows - Dxgkrnl。
事件檢視器包含來自其他元件的事件,這些元件會參與建立具有 GPU-PV 的 VM(Hyper-V-Compute、Hyper-V-Worker、Hyper-V-VID 等)。
使用 Add-VMGpuPartitionAdapter
使用 Add-VMGpuPartitionAdapter時,若不需要,請勿指定功能(例如解碼)。 請勿針對這項功能使用 0。
使用 Remove-VMGpuPartitionAdapter
如果 VM 無法啟動或發生轉譯問題,請嘗試使用 remove-VMGpuPartitionAdapter 從 VM 移除虛擬 GPU。
remove-VMGpuPartitionAdapter -VMName $vm -AdapterId "Microsoft:9ABB95E2-D12D-43C3-B840-6F4A9CFB217B\929890BC-BB33-4687-BC1A-F72A4F1B3B3F"
防止 VM 在開機期間啟動
set-vm -AutomaticStartAction Nothing -VmName TEST
事件查看器事件
將事件新增至事件查看器通道,以協助識別 vGPU 啟動的問題。 您可以在「應用程式和服務記錄檔\Microsoft\Windows\Dxgkrnl」中找到事件。 事件通道為系統管理和操作。
事件會在下列情況下發出:
- vGPU 已被建立
- vGPU 已被銷毀
- 來賓開啟虛擬配接器
事件檔案位於:
- c:\Windows\System32\winevt\Logs\Microsoft-Windows-DxgKrnl-Admin.evtx
- c:\Windows\System32\winevt\Logs\Microsoft-Windows-DxgKrnl-Operational.evtx
檢查是否已建立 vGPU,以及是否有任何錯誤。
登錄設定
GpuVirtualizationFlags
GpuVirtualizationFlags 登錄機碼可用來設定半虛擬化 GPU 的行為。 密鑰位於:
DWORD HKLM\System\CurrentControlSet\Control\GraphicsDrivers\GpuVirtualizationFlags
下列位元被定義為:
位元 | 描述 |
---|---|
0x1 | 強制所有硬體適配卡的 ParavirtualizationSupported 上限。 於主機中使用這個位元。 |
0x2 | 強制 BasicRender 支援 Paravirtualization 的功能。 請在主機上使用此位。 |
0x4 | 強制安全虛擬機模式,其中所有虛擬機都會被視為安全。 在此模式中,使用者模式驅動程式有限制。 例如,驅動程式無法使用 Escape 呼叫,因此會失敗。 在主機中使用這個位元。 |
0x8 | 啟用將半虛擬化配接器與僅限顯示用的配接器配對。 在客體 VM 中使用此位元。 默認會啟用配對。 |
客戶Io空間大小(以MB為單位)
GuestIoSpaceSizeInMb 登錄機碼可用來設定虛擬 GPU 的客體 IO 空間大小,以 MB 為單位。 默認值為 1,000MB (1GB)。 機碼位於:
DWORD HKLM\System\CurrentControlSet\Control\GraphicsDrivers\Paravirtualization\GuestIoSpaceSizeInMb
訪客 IO 空間目前實現 CPU 可見的配置。 主機中的 CPU 可見配置支援存放區會固定在記憶體中,並對應至客體 IO 空間。 在客體中,配置使用者模式虛擬位址會輪替至IO空間區域。 在某些 Haswell 系統上,CPU 有 36 位實體位址。 Hyper-V 這類系統上的IO空間大小有限。
停用對於安全虛擬機的IOMMU隔離
如果驅動程式不支援IoMmu隔離,請在開發期間使用下列登錄設定來停用IoMmu隔離。
`DWORD HKLM\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\IoMmuFlags = 8`
限制虛擬函式的數目
根據預設,支援 GPU 半虛擬化的配接器所公開的虛擬函式數目為 32。 這個數位表示適配卡可以新增至 32 部虛擬機,假設每個 VM 都有一個適配卡。
您可以使用下列登錄設定來限制公開的虛擬函式數目。
DWORD HKLM\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\NumVirtualFunctions
例如,如果您將 NumVirtualFunctions
設為 1,則只能將轉接器新增至一個 GPU。 當計算機有多個支援 GPU-PV 的 GPU 適配卡,而且您想要將每個適配卡指派給 VM 時,此設定很有用。
Add-VMGpuPartitionAdapter
不允許指定要新增的配接器。 因此,如果兩個適配卡新增至 VM,兩者都可以從主機取得相同的 GPU-PV 適配卡。
WDDM 2.4 DDI 更新
下列 DDI 更新可支援 WDDM 2.4 中的 GPU 半虛擬化。
已新增DXGK_VIDMMCAPS上限
ParavirtualizationSupported 功能會新增至 DXGK_VIDMMCAPS 結構。 如果主機 KMD 實作本節中所述的所有 DIS,則會設定此上限。
透過 DDI 傳遞的驅動程式私人數據
UMD 會使用各種 DDI,與其對應的 KMD 交換私人信息。 當UMD在客體 VM 中執行時,對應的 KMD DDI 呼叫會發生在主機分割區中。 因此,UMD:
- 無法傳遞私人數據中的任何指標。
- 無法在私密數據中傳遞任何句柄。
- 不應該指示 KMD 對 GPU 狀態進行全域變更,因為這項變更可能會影響其他執行中的 VM。
已新增 DxgkDdiCreateProcess 的 VirtualMachineProcess 旗標
OS 會為每個執行中的 VM 建立 VM 工作程序。 Dxgkrnl 會建立對應的 DXGPROCESS,並在設置 VirtualMachineWorkerProcess 旗標後,呼叫 DxgkDdiCreateProcess。 在此流程上下文中,沒有進行渲染或驅動程序資源建立。 因此,驅動程式可能會略過配置特定資源。
OS 會在主機中針對使用 GPU 的客體 VM 中的每個進程建立 DXGPROCESS。 Dxgkrnl 呼叫 DxgkDdiCreateProcess,並設置 VirtualMachineProcess 旗標。 每個 VM DXG 程序都屬於與 VM 工作進程相同的 EPROCESS。
DxgkDdiQueryAdapterInfo 更新
DXGKARG_QUERYADAPTERINFO 結構會更新為包含下列欄位,以支援半虛擬化:
已新增 Flags 成員,允許 Dxgkrnl 指出下列事項:
- 它會設定 virtualMachineData ,以指出呼叫來自 VM。
- 它會設定 SecureVirtualMachine,表示 VM 以安全模式執行。
已新增 hKmdProcessHandle,這可讓驅動程式在處理源自客體 VM 的查詢時,識別和使用主機端的正確進程內容。
DxgkDdiEscape 更新
hKmdProcessHandle 成員會新增至 DXGKARG_ESCAPE 結構中,以便驅動程式在處理從客體 VM 發出的逸出操作時,能夠識別並使用主機端的正確進程上下文。
VirtualMachineData 旗標新增至 D3DDDI_ESCAPEFLAGS 結構中,以表示從虛擬機呼叫 DxgkDdiEscape。
對 GPU 配置的實體存取
目前,驅動程式不會實作配置的實際存取權。 驅動程式必須支援 GpuMmu。
WDDM 2.5 DDI 更新
針對 WDDM 2.5,為了支援副虛擬化,還需要下列 DDI 變更。
由主機 KMD 發出客體事件的訊號
當 KMD 需要向 UMD 所建立的事件發出訊號時,就會出現沒有虛擬化的情況。 若要在使用半虛擬化時處理這類案例,主機上的 KMD 必須發出客體中所建立事件的訊號。 為此目的新增了 DxgkCbSignalEvent 回調函數。 KMD 也可以使用此回呼來發出主機進程事件的訊號。
在 VM 中支援由 UMD 提供的 handle
某些驅動程式的回呼接受 UMD 所傳遞的 Dxgkrnl 配置或資源控制代碼,例如:
主機上的呼叫必須位於呼叫 DxgkDdiXxx 函式的相同線程內容中。
例如,假設沒有虛擬化,KMD 會在呼叫 D3DKMTEscape的使用者模式線程內容中呼叫 DxgkCbAcquireHandleData,這會呼叫 DxgkDdiEscape。
當UMD在虛擬機中執行時,它只知道客體配置句柄,而且無法將這類句柄傳遞至 KMD,因為 KMD 會在主機中執行。 客體中的 UMD 會呼叫 D3DKMTEscape,而主機中的 KMD 會接收對應的 DxgkDdiEscape 呼叫。 KMD 必須在該執行緒的內容中呼叫 DxgkCbAcquireHandleData。
為了能夠將客體配置/資源句柄轉譯為對應的主機句柄,會新增 D3DDDI_ESCAPEFLAGS::DriverKnownEscape 驅動程式逸出旗標。
當您呼叫 D3DKMTEscape 時,DriverKnownEscape 旗標已設置:
將 D3DKMT_ESCAPE::Type 設定為 D3DKMT_ESCAPE_DRIVERPRIVATE。
將 D3DKMT_ESCAPE::p PrivateDriverData 設定為指向下一節中定義的已知驅動程式逸出結構。 每個結構都會以 D3DDDI_DRIVERESCAPETYPE 值開頭。
不使用虛擬化時,轉譯的句柄會與輸入句柄相同。
定義下列已知的驅動程式例外。
下列代碼段示範如何使用 DriverKnownEscape 旗標。
D3DDDI_DRIVERESCAPE_TRANSLATEALLOCATIONEHANDLE Command = {};
Command.EscapeType = D3DDDI_DRIVERESCAPETYPE_TRANSLATEALLOCATIONHANDLE;
Command.hAllocation = hAlloc;
D3DKMT_ESCAPE Args = {};
Args.hAdapter = hAdapter;
Args.Flags.DriverKnownEscape = TRUE;
Args.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
Args.pPrivateDriverData = &Command;
Args.PrivateDriverDataSize = sizeof(Command);
Status = D3DKMTEscape(&Args);
WDDM 2.6 DDI 更新
從 WDDM 2.6 (Windows 10 1903 版)開始,已針對半虛擬化支持進行下列更新:
驅動程式可以在虛擬機中使用 DXGK_ALLOCATIONINFOFLAGS::ACCESSEDPHYSICALLY 旗標。 在 WDDM 2.6 之前,驅動程式無法在虛擬機中使用此旗標,且此旗標的配置建立失敗。
UMD 可以在虛擬機中使用 Pfnd3dkmtUpdateallocationproperty。 在 WDDM 2.6 之前,此呼叫會失敗。