歡迎轉載【作者:張佩】【原文:http://www.yiiyee.cn/Blog/wddm1/】
Windows顯示驅動從Vista開始,使用新的WDDM編程框架,稱爲Windows Display Driver Model。也有一種最初的名稱是LDDM,L代表Longhorn,但後來微軟在所有產品線上都不再使用Longhorn代號,故而改成現在的名稱。雖然在有些地方還能看到LDDM的說法,但應理解成舊文檔的遺存,不應該做概念上的區分。
WDDM框架是一種典型的小端口(miniport)驅動框架。NT系統中的所有小端口框架,都是基於WDM框架來實現的,但小端口框架對外提供了更高級的接口,以簡化編程的難度,並提高穩定性。如下圖所示,中間的WDDM是系統提供的編程框架,我們基於這個框架,編寫裏面的小端口驅動,也就是顯示驅動。
顯示驅動類型
現在的顯卡設備,可以按照功能將它分成顯示和計算兩類。大部分的顯卡是用來連接顯示器顯示圖片和動畫用的,也有些顯卡主要確實用來做科學計算用的。顯卡處理器(GPU)對浮點運算有較強的能力,而主機處理器(CPU)處理浮點運算的能力較弱。而在科學計算領域,浮點運算是非常重要的內容,所以工業界就想到利用GPU進行科學運算。
應該說,所有的顯卡都既能夠支持顯示,又能夠支持運算。只是看它偏向哪個方面,爲哪個功能做優化罷了。對於偏重計算的顯卡,就不必配置多個顯示接口,圖像處理的模塊就不用很高級;相反,對於圖形功能偏重的顯卡,它就必須要大數據帶寬,大顯存,支持多種類型的接口,能夠實現鋸齒優化等等。
針對我們的驅動來講,如果一個顯示驅動,既支持顯卡的顯示功能,又支持運算功能,稱爲全功能驅動(Complete function);如果只支持顯示,不支持運算,就是Display Only驅動;如果只支持運算,不支持顯示功能,就是Render Only驅動。
微軟在Win8的系統上,爲所有不同類型的顯卡,編寫了Display Only和Render Only驅動。在未安裝廠商驅動或者廠商驅動被破壞、禁用的情況下,系統會默認選擇使用Display Only驅動來顯示桌面內容。但一般系統不會選擇安裝Render Only驅動,那樣就什麼都看不到了。Render Only驅動的具體應用場景,我到目前還沒有看到。可能在Render Only的數據服務器顯卡上會被運用。
我的這份顯示驅動初步教材,就是基於微軟公開的Display Only驅動項目KMDOD來寫的。不會涉及數據Render部分。其實可以很方便地把一個Display only的驅動拓展到Complete驅動,在講完所有內容後,會有一小部分內容做介紹。
KMDOD項目可以從MSDN代碼網站上下載到,地址:http://code.msdn.microsoft.com/Kernel-mode-display-only-49adea58
初始化
如果不更改編譯配置,WDDM驅動的默認啓動函數是DriverEntry。這是驅動對象初始化的地方,一般對於小端口驅動而言,它需要調用框架的初始化函數。WDDM框架的初始化函數是DxgkInitializeDisplayOnlyDriver。從內核編程好幫手WDK中,可以找到它的聲明:
NTSTATUS DxgkInitializeDisplayOnlyDriver( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath, _In_ PKMDDOD_INITIALIZATION_DATA KmdDodInitializationData );
初始化函數會完成驅動對象的初始化,所以前面兩個參數是入口函數的輸入參數。在全文最後的實驗章節中,會介紹如何查看驅動對象,就能夠比較清晰地看到WDDM框架對顯示驅動對象所進行的初始化作業了。此外,初始化函數還要完成顯示驅動相關的初始化。顯示驅動傳入一個函數結構體參數,類型是KMDDOD_INITIALIZATION_DATA,結構體裏面包含的是顯示驅動向框架提供的一系列回調函數(Callback Function)。框架會在合適的時候調用這些回調函數,完成對應功能。
結構體定義如下:
KMDOD項目沒有實現結構體中列舉的所有回調函數,所以它不能支持WDDM提供的全部和Display相關的功能。比如D3D用戶程序通過DC句柄和顯示驅動進行交互的escape回調函數,這裏就沒有實現。對於沒有實現的回調函數,在結構體中的對應函數指針應被初始化爲NULL。
第一個參數Version用來標識你所編寫的顯示驅動使用哪個版本的WDDM。WDDM一共有四個版本:1.0(Vista & Vista SP1);1.1(Win7);1.2(Win8);1.3(Win Blue)。KMDOD這個項目中使用的是Win8版本:DXGKDDI_INTERFACE_VERSION_WIN8。
爲了完成結構體初始化,我們要首先實現這些函數。在具體列舉實現代碼之前,把這些回調函數做一個簡單的分類和介紹是有必要的。
PNP和POWER函數
所有現代的物理設備都必須處理Pnp和Power事件。Pnp事件對應了設備插拔、開始、移除、停止等,以及作爲總線設備需要提供的子設備(顯示器)枚舉等;Power事件對應上電、掉電操作,以及查詢設備是否運行進行電源操作。
另外把卸載回調函數也歸入其中。卸載函數在驅動被停止,沒有任何外部模塊引用的時候,系統會嘗試將驅動卸載,這時候卸載回調被調用。
InitialData.DxgkDdiAddDevice = BddDdiAddDevice; InitialData.DxgkDdiStartDevice = BddDdiStartDevice; InitialData.DxgkDdiStopDevice = BddDdiStopDevice; InitialData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = BddDdiStopDeviceAndReleasePostDisplayOwnership; InitialData.DxgkDdiResetDevice = BddDdiResetDevice; InitialData.DxgkDdiRemoveDevice = BddDdiRemoveDevice; InitialData.DxgkDdiQueryChildRelations = BddDdiQueryChildRelations; InitialData.DxgkDdiQueryChildStatus = BddDdiQueryChildStatus; InitialData.DxgkDdiQueryDeviceDescriptor = BddDdiQueryDeviceDescriptor; InitialData.DxgkDdiSetPowerState = BddDdiSetPowerState; InitialData.DxgkDdiUnload = BddDdiUnload; InitialData.DxgkDdiQueryAdapterInfo = BddDdiQueryAdapterInfo;
顯示函數
顯卡驅動的主要功能是配置物理設備,讓它能夠輸出圖片和動畫到外部顯示設備上。和這個功能相關的函數有很多,它包括對鼠標位置的更新,顯示器Mode的枚舉和設置等函數:
InitialData.DxgkDdiSetPointerPosition = BddDdiSetPointerPosition; InitialData.DxgkDdiSetPointerShape = BddDdiSetPointerShape; InitialData.DxgkDdiIsSupportedVidPn = BddDdiIsSupportedVidPn; InitialData.DxgkDdiRecommendFunctionalVidPn = BddDdiRecommendFunctionalVidPn; InitialData.DxgkDdiEnumVidPnCofuncModality = BddDdiEnumVidPnCofuncModality; InitialData.DxgkDdiSetVidPnSourceVisibility = BddDdiSetVidPnSourceVisibility; InitialData.DxgkDdiCommitVidPn = BddDdiCommitVidPn; InitialData.DxgkDdiUpdateActiveVidPnPresentPath = BddDdiUpdateActiveVidPnPresentPath; InitialData.DxgkDdiRecommendMonitorModes = BddDdiRecommendMonitorModes;
硬件操作
最後是和物理設備交互的一些函數,首先是中斷處理函數,然後有獲取設備屬性,讀寫設備幀內存、顯示桌面內容(Present)等函數。
InitialData.DxgkDdiDpcRoutine = BddDdiDpcRoutine; InitialData.DxgkDdiInterruptRoutine = BddDdiInterruptRoutine; InitialData.DxgkDdiQueryVidPnHWCapability = BddDdiQueryVidPnHWCapability; InitialData.DxgkDdiPresentDisplayOnly = BddDdiPresentDisplayOnly; InitialData.DxgkDdiSystemDisplayEnable = BddDdiSystemDisplayEnable; InitialData.DxgkDdiSystemDisplayWrite = BddDdiSystemDisplayWrite;
功能函數
這部分是顯示驅動作爲一個驅動來講,它所實現的一般意義上的功能支持函數。這部分我只列了一個,是用戶程序和內核驅動交互用的IO控制函數。
InitialData.DxgkDdiDispatchIoRequest = BddDdiDispatchIoRequest;
完整的初始化函數:
extern "C" NTSTATUS DriverEntry( _In_ DRIVER_OBJECT* pDriverObject, _In_ UNICODE_STRING* pRegistryPath) { PAGED_CODE(); // Initialize DDI function pointers and dxgkrnl KMDDOD_INITIALIZATION_DATA InitialData = {0}; InitialData.Version = DXGKDDI_INTERFACE_VERSION_WIN8; InitialData.DxgkDdiAddDevice = BddDdiAddDevice; //…… 其它的回調函數賦值過程,上面已全部列舉,此處省略 NTSTATUS Status = DxgkInitializeDisplayOnlyDriver(pDriverObject, pRegistryPath, &InitialData); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR1("DxgkInitializeDisplayOnlyDriver failed with Status: 0x%I64x", Status); } return Status; }
可選的擴展
初始化部分到此本來可以結束,繼續講下面的回調函數實現。但其實依然可以擴展一下,不熟悉WDM的讀者可以跳過。針對所有的端口驅動框架都基於WDM來實現的這個事實,如果有的小端口驅動有必要想直接操作IRP的話,應該怎麼實現呢?
其實非常簡單。在DxgkInitializeDisplayOnlyDriver被調用過之後,驅動對象的初始化已經完成了。這時候我們可以對框架的分發函數進行Hook。
比如有一個很重要的功能,很多設備驅動都要做的。就是它希望自己能夠得到系統關機的訊息。通過一般意義上的PNP和Power事件,是沒有辦法得到系統關機訊息的。辦法是註冊自己的IRP_MJ_SHUTDOWN分發函數來接收此訊息。
下面是簡要的實現代碼:
// 下面代碼應在DxgkInitializeDisplayOnlyDriver被調用過後執行 pOldFunc = pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN]; // 保存框架有可能已實現的函數 pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = BddDdiShutdown; // 此外還需要在StartDevice函數中調用IoRegisterShutdownNotificatin函數,本文不再繼續演示 NTSTATUS BddDdiShutdown (PDEVICE_OBJECT pDev, PIRP irp) { // do something you wanted here if (pOldFunc) return pOldFunc (pDev, irp); else return STATUS_SUCCESS; }
回調函數實現
KMDOD項目定義了一個顯示驅動類,來封裝和實際功能相關的所有具體操作。這樣一來,大部分回調函數的實現都比較簡單。這個類是BASIC_DISPLAY_DRIVER,我們在第二節會具體地講它。
生命週期
WDDM框架在設計的時候,是能夠支持多個底層物理設備的。換句話說,如果系統中存在多個顯卡設備,WDDM框架都能夠很好地支持它們同時或者分別工作。作爲這個支持的一部分,在PNP操作的起始,也就是AddDevice回調函數被調用的時候,框架要求顯示驅動返回一個當前物理設備的Context,作爲識別此物理設備的標識。
那麼KMDOD也是可以支持多個顯卡設備的,所以爲每個設備創建一個BASIC_DISPLAY_DRIVER對象,作爲Context返回給框架。框架在以後調用任何一個回調函數時,都會把這個Context作爲其中的一個輸入參數來使用。
所以我們看,DriverEntry是驅動的開始,卸載函數是驅動的結束;AddDevice函數是設備工作的開始,RemoveDevice是設備結束工作的標識。我們可以用下面的框圖來描述這個概念。
設備的Context作爲一個標識物理顯卡的變量,在設備的PNP週期裏面一直運作着。當關機、設備禁用或者其他變故發生的時候,RemoveDevice回調被執行,顯示驅動將負責刪除它所創建的設備Context。
下面是AddDevice和RemoveDevice這兩個回調函數的實現。
NTSTATUS BddDdiAddDevice( _In_ DEVICE_OBJECT* pPhysicalDeviceObject, _Outptr_ PVOID* ppDeviceContext) { PAGED_CODE(); if ((pPhysicalDeviceObject == NULL) || (ppDeviceContext == NULL)) { BDD_LOG_ERROR2("One of pPhysicalDeviceObject (0x%I64x), ppDeviceContext (0x%I64x) is NULL", pPhysicalDeviceObject, ppDeviceContext); return STATUS_INVALID_PARAMETER; } *ppDeviceContext = NULL; BASIC_DISPLAY_DRIVER* pBDD = new(NonPagedPoolNx) BASIC_DISPLAY_DRIVER(pPhysicalDeviceObject); if (pBDD == NULL) { BDD_LOG_LOW_RESOURCE0("pBDD failed to be allocated"); return STATUS_NO_MEMORY; } *ppDeviceContext = pBDD; return STATUS_SUCCESS; } NTSTATUS BddDdiRemoveDevice( _In_ VOID* pDeviceContext) { PAGED_CODE(); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); if (pBDD) { delete pBDD; pBDD = NULL; } return STATUS_SUCCESS; }
其它回調函數實現
其它回調函數的實現,這裏僅僅以StartDevice爲例講解。函數原型定義如下:
NTSTATUS DxgkDdiStartDevice( _In_ const PVOID MiniportDeviceContext, _In_ PDXGK_START_INFO DxgkStartInfo, _In_ PDXGKRNL_INTERFACE DxgkInterface, _Out_ PULONG NumberOfVideoPresentSources, _Out_ PULONG NumberOfChildren )
第一個參數即設備Context,毫無疑問,它就是我們剛剛在AddDevice中創建的BASIC_DISPLAY_DRIVER對象。所以我們第一步需要獲取對象指針,並且調用到BASIC_DISPLAY_DRIVER裏面的startDevice函數中去。其實現如下:
NTSTATUS BddDdiStartDevice( _In_ VOID* pDeviceContext, _In_ DXGK_START_INFO* pDxgkStartInfo, _In_ DXGKRNL_INTERFACE* pDxgkInterface, _Out_ ULONG* pNumberOfViews, _Out_ ULONG* pNumberOfChildren) { PAGED_CODE(); BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); return pBDD->StartDevice(pDxgkStartInfo, pDxgkInterface, pNumberOfViews, pNumberOfChildren); }
其它的回調函數,實現方法和StartDevice很類似。唯一的區別是,如果StartDevice調用失敗的話,也就是設備啓動失敗的話,道理上講,很多後續的函數都不應該被調用,因爲既然設備沒有啓動,就不應該有任何針對於它的動作存在。所以這些函數被調用的時候,很多都會先確認一下,設備是否處於啓動狀態(IsDriverActive),就是判斷StartDevice是否執行成功。
下面的函數清單是所有回調函數的實現。
NTSTATUS BddDdiStopDevice( _In_ VOID* pDeviceContext) { PAGED_CODE(); BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); return pBDD->StopDevice(); } NTSTATUS BddDdiDispatchIoRequest( _In_ VOID* pDeviceContext, _In_ ULONG VidPnSourceId, _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket) { PAGED_CODE(); BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->DispatchIoRequest(VidPnSourceId, pVideoRequestPacket); } NTSTATUS BddDdiSetPowerState( _In_ VOID* pDeviceContext, _In_ ULONG HardwareUid, _In_ DEVICE_POWER_STATE DevicePowerState, _In_ POWER_ACTION ActionType) { PAGED_CODE(); BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); if (!pBDD->IsDriverActive()) { // If the driver isn't active, SetPowerState can still be called, however in BDD's case // this shouldn't do anything, as it could for instance be called on BDD Fallback after // Fallback has been stopped and BDD PnP is being started. Fallback doesn't have control // of the hardware in this case. return STATUS_SUCCESS; } return pBDD->SetPowerState(HardwareUid, DevicePowerState, ActionType); } NTSTATUS BddDdiQueryChildRelations( _In_ VOID* pDeviceContext, _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, _In_ ULONG ChildRelationsSize) { PAGED_CODE(); BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); return pBDD->QueryChildRelations(pChildRelations, ChildRelationsSize); } NTSTATUS BddDdiQueryChildStatus( _In_ VOID* pDeviceContext, _Inout_ DXGK_CHILD_STATUS* pChildStatus, _In_ BOOLEAN NonDestructiveOnly) { PAGED_CODE(); BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); return pBDD->QueryChildStatus(pChildStatus, NonDestructiveOnly); } NTSTATUS BddDdiQueryDeviceDescriptor( _In_ VOID* pDeviceContext, _In_ ULONG ChildUid, _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor) { PAGED_CODE(); BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); if (!pBDD->IsDriverActive()) { // During stress testing of PnPStop, it is possible for BDD Fallback to get called to start then stop in quick succession. // The first call queues a worker thread item indicating that it now has a child device, the second queues a worker thread // item that it no longer has any child device. This function gets called based on the first worker thread item, but after // the driver has been stopped. Therefore instead of asserting like other functions, we only warn. BDD_LOG_WARNING1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->QueryDeviceDescriptor(ChildUid, pDeviceDescriptor); } // // WDDM Display Only Driver DDIs // NTSTATUS APIENTRY BddDdiQueryAdapterInfo( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); return pBDD->QueryAdapterInfo(pQueryAdapterInfo); } NTSTATUS APIENTRY BddDdiSetPointerPosition( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->SetPointerPosition(pSetPointerPosition); } NTSTATUS APIENTRY BddDdiSetPointerShape( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->SetPointerShape(pSetPointerShape); } NTSTATUS APIENTRY BddDdiPresentDisplayOnly( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->PresentDisplayOnly(pPresentDisplayOnly); } NTSTATUS APIENTRY BddDdiStopDeviceAndReleasePostDisplayOwnership( _In_ VOID* pDeviceContext, _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo) { PAGED_CODE(); BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); return pBDD->StopDeviceAndReleasePostDisplayOwnership(TargetId, DisplayInfo); } NTSTATUS APIENTRY BddDdiIsSupportedVidPn( _In_ CONST HANDLE hAdapter, _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { // This path might hit because win32k/dxgport doesn't check that an adapter is active when taking the adapter lock. // The adapter lock is the main thing BDD Fallback relies on to not be called while it's inactive. It is still a rare // timing issue around PnpStart/Stop and isn't expected to have any effect on the stability of the system. BDD_LOG_WARNING1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->IsSupportedVidPn(pIsSupportedVidPn); } NTSTATUS APIENTRY BddDdiRecommendFunctionalVidPn( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->RecommendFunctionalVidPn(pRecommendFunctionalVidPn); } NTSTATUS APIENTRY BddDdiRecommendVidPnTopology( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->RecommendVidPnTopology(pRecommendVidPnTopology); } NTSTATUS APIENTRY BddDdiRecommendMonitorModes( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->RecommendMonitorModes(pRecommendMonitorModes); } NTSTATUS APIENTRY BddDdiEnumVidPnCofuncModality( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->EnumVidPnCofuncModality(pEnumCofuncModality); } NTSTATUS APIENTRY BddDdiSetVidPnSourceVisibility( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->SetVidPnSourceVisibility(pSetVidPnSourceVisibility); } NTSTATUS APIENTRY BddDdiCommitVidPn( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->CommitVidPn(pCommitVidPn); } NTSTATUS APIENTRY BddDdiUpdateActiveVidPnPresentPath( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->UpdateActiveVidPnPresentPath(pUpdateActiveVidPnPresentPath); } NTSTATUS APIENTRY BddDdiQueryVidPnHWCapability( _In_ CONST HANDLE hAdapter, _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps) { PAGED_CODE(); BDD_ASSERT_CHK(hAdapter != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return STATUS_UNSUCCESSFUL; } return pBDD->QueryVidPnHWCapability(pVidPnHWCaps); } //END: Paged Code #pragma code_seg(pop) #pragma code_seg(push) #pragma code_seg() // BEGIN: Non-Paged Code VOID BddDdiDpcRoutine( _In_ VOID* pDeviceContext) { BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); if (!pBDD->IsDriverActive()) { BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD); return; } pBDD->DpcRoutine(); } BOOLEAN BddDdiInterruptRoutine( _In_ VOID* pDeviceContext, _In_ ULONG MessageNumber) { BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); return pBDD->InterruptRoutine(MessageNumber); } VOID BddDdiResetDevice( _In_ VOID* pDeviceContext) { BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); pBDD->ResetDevice(); } NTSTATUS APIENTRY BddDdiSystemDisplayEnable( _In_ VOID* pDeviceContext, _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, _Out_ UINT* Width, _Out_ UINT* Height, _Out_ D3DDDIFORMAT* ColorFormat) { BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); return pBDD->SystemDisplayEnable(TargetId, Flags, Width, Height, ColorFormat); } VOID APIENTRY BddDdiSystemDisplayWrite( _In_ VOID* pDeviceContext, _In_ VOID* Source, _In_ UINT SourceWidth, _In_ UINT SourceHeight, _In_ UINT SourceStride, _In_ UINT PositionX, _In_ UINT PositionY) { BDD_ASSERT_CHK(pDeviceContext != NULL); BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext); pBDD->SystemDisplayWrite(Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY); }
版本歷史:
V1.0:2013/7/23