* 前情提要之本文另一篇: Windows Driver 開發學習筆記
* Graphic driver要了解一下
* Umd kmd 基本概念要懂
* 會寫程式 XD
關於 WDF 、WDK、WDM、DDK 介紹
(轉自: DDK與WDK的區別與聯繫)
最近嘗試去了解WINDOWS下的驅動開發,現在總結一下最近看到的資料。
1. 專門的開發包
首先,先從基礎的東西說起,開發WINDOWS下的驅動程序,需要一個專門的開發包
如:
- 開發 JAVA 程序,我們可能需要一個JDK
- 開發 WINDOWS 應用程式(Applications),我們需要WINDOWS的SDK
- 開發 WINDOWS 下的驅動程序(Drivers),我們需要一個DDK/WDK。
2. DDK(Driver Developer Kit)和 WDK(Windows Driver Kit)的區別:
這個要說說驅動相關的一些歷史:
- (1). 95/98/ME下,驅動模型為:Vxd, 相關資料可以看《編程高手箴言》的前幾個章節,裡面有很詳細的介紹,雖然這個東西已經過時,但大概看看還是會增長見識的。
- (2). 2000/XP/2003下,Windows採用WDM驅動模型(Windows Driver Model),開發2000/XP/2003的驅動開發包為:DDK。
- (3). Vista及以後版本,採用了WDF驅動模型(Windows Driver Foudation),對應的開發包:WDK。
其實WDK可以看做是DDK的升級版本,現在一般的WDK是包含以前DDK相關的功能,現在XP下也可以用WDK開發驅動,WDK能編譯出2000-2008的各種驅動。
3. 副檔名的區別
- Vxd驅動文件擴展名為:.vxd。
- WDM和WDF驅動文件擴展名為:.sys。
4. 相關的名詞解釋
- DDK——Driver Developer Kit,設備驅動程序開發包。
- WDK——Windows Driver Kit,Windows驅動程序開發包,就是DDK升級改名了。
- VxD——Virtual Device Driver,虛擬設備驅動程序,9X中的一種驅動程序。
- WDM——Windows Driver Model,Windows驅動程序模型,98以上版本的一種驅動程序。
- WDF——Windows Driver Frameworks, 驅動程序包括兩個類型,一個是內核級的,稱為KMDF(Kernel-Mode Driver Framework),為SYS文件;另一個是用戶級的,稱為UMDF(User-Mode Driver Framework),為DLL文件。
- 驅動程序的文件格式都是PE格式。
windows驅動開發: 比較 WDM 與 WDF
(轉載自 yinaiyun52)
如所周知,自Windows 2000開始,開發驅動程序必以WDM為基礎的,但其開發難度之大,根本不能奢望像用戶模式應用程序開發那樣容易。為改善這種局面,微軟推出了新的驅動程序開發環境 – WDF驅動模型。
WDF驅動框架對WDM進行了一次封裝
WDF框架就好像C++中的基類一樣,且這個基類中的model, IO model ,pnp和電源管理模型;且提供了一些與操作系統相關的處理函數,這些函數好像C++中的虛函數一樣,WDF驅動中能夠對這些函數進行override;特別是Pnp管理和電源管理!基本上都由WDF框架做了,而WDF的功能驅動幾乎不要對它進行特殊的處理;
要預先指出的是,WDF這不是另起爐灶改弦更張,而是以WDM為基礎進行了建模和封裝,顯著特點是降低了開發難度。
因為:
1、 將原來普通程序設計中基於對象的技術應用到了驅動開發中。 WDM中雖也有對像模型,但與真正的基於對象技術根本就不是一回事。為了實現基於對象的技術,微軟精心設計了對像模型並進行了封裝。屬性、方法、事件等等“一個都不能少”。
2、 無論內核模式的驅動程序或者用戶模式的驅動程序,都採用同一套對像模型構建,採用同一個基礎承載。這個基礎就是WDF。 WDF雖然已經是經過封裝和定義的對像模型,但對內核模式和用戶模式對象來說,WDF又是兩者的父對象。換言之兩者都是繼承了WDF才得到的,或者都是從WDF派生而來的。相對於內核模式,派生出的對象稱為“KMD框架”即KMDF;相對於用戶模式,派生出的模型稱為“UMD框架”即UMDF。無論何種模式的框架,其內部封裝的方法、執行的行為其實還是用WDM完成的。
3、 更重要的,也是微軟反复炫耀的是封裝了驅動程序中的某些共同行為:例如即插即用和電源管理就屬於這種共同行為。因為大多數驅動程序中都需要處理即插即用和電源管理問題,據說這大概要上千行的代碼,況且,沒有相當水平還不一定能處理好。為了一勞永逸,WDF乾脆將即插即用和電源管理封裝了進了對象之內,一舉成了對象的缺省(默認)行為。
4、 改變了操作系統內核與驅動程序之間的關係,WDM驅動程序中,一方面要處理硬件,另一方面要處理驅動程序與操作系統內核的交互。現在WDF則將驅動程序與操作系統內核之間進行了分離,驅動程序與操作系統交互工作交給框架內封裝的方法(函數)完成,這樣驅動開發者只需專注處理硬件的行為即可。這不僅避免了顧此失彼兩面不周的弊端,也由於雙方的分離,對操作系統內的某些改動,硬件製造商配套驅動程序的開發都有莫大的好處。
5、 兩種模式的驅動程序(KMDF、UMDF)都使用同一環境進行構建,這一環境稱為WDK。
即KMDF,UMDF的開發環境為WDK。
Windows Device Kit (WDK): 把測試套件(test suites)集成進來,DDK 就成了WDK。 WDK是針對微軟操作系統系列的驅動器集成開發系統。它組合了Windows DDK和Hardware Compatibility Test (HCT) kits(硬件兼容性測試工具),同時提供了微軟內部用來測試Windows操作系統穩定性和可靠性的測試套件。
6、 雖然經過封裝並引入基於對象的技術,所開發的驅動程序在執行效率上並不比原來遜色。
WDF和WDM的關係有點類似於MFC和Windows SDK的關係。 WDF只是在WDM上面加了一層,來簡化driver的開發,特別是PNP,power和IO cancellation 等幾個方面有很大改進。
現在學習WDF最好的資料還是DDK帶的sample code。 WHDC有一些資料:
http://www.microsoft.com/whdc/driver/wdf/default.mspx
再繼續說新舊時代
關鍵的visual studio 2012, 新時代忽然就來了, VS2012是Win8發布之後才出來的,有很多針對Win8的特性,但也能在Win7/Vista系統上運行。
舊時代
近期的win8與win10的系統出現以前, 也就是含win7之前的系統, 如果要開發kernel/driver的驅動程式, 環境的準備比較繁瑣, 首先需要手動下載WDK並安裝, 因為開發環境是在安裝好的WDK當中。WDK是Windows Driver Kit縮寫,即Windows驅動開發包。它提供的開發環境非常簡陋,不是一個便於開發的IDE環境,而僅僅是一些散裝的編譯工具包。
新時代
基本上必須要安裝三個軟體:
1. 我這裡使用 visual studio 2015版本 (或2012之後的版本)
2. WDK 10 (或Win8之後的版本)
3. Win10 SDK
請您先下載安裝 VS2015, 再安裝 Win10 的 WDK, 然後WDK的編譯環境就會自動整合進去 VS2015裡面, 所以重新開啟VS2015的時候, 在new project 新項目嚮導裡面, 就能夠找到driver(內核驅動)項目了。
開啟 Visual Studio 2015,選擇 New Project 建立新專案:
選擇 Visual C++ > Windows Driver > WDF
跳出的分別是有自動生成代碼的KMDF和沒有自動代碼的KMDF(empty),以及UMDF
我們選擇 Kernel Mode Driver (KMDF),直接按 OK 用預設值建立一個簡單的 driver 專案
測試安裝好的 Visual Studio 2015 + Windows SDK 10 + Windows Driver Kit 10
正常的話, 可以編譯通過successfully!
微軟釋出的 Driver samples for Windows 10 – 擷取video 部分
網址: https://github.com/microsoft/Windows-driver-samples/tree/master/video/KMDOD
目前我使用的為visual studio 2015 + (WinSDK)Windows Software Development kit 10.0.14393.33 + (WDK)Windows Driver kit 10.0.14393.0
資源指令碼檔案 .rc
包含目前專案中的資源所適用之指令碼的資源指令碼檔。 .aps 檔會在您每次存檔時覆寫此檔案。
原始檔控制中包含此檔案。
/*++ Copyright (c) 2011 Microsoft Corporation Module Name: SampleDisplay.rc Abstract: This modules contains the version information for the Sample Display Driver Environment: Kernel mode only --*/ #include <windows.h> #include <ntverp.h> #define VER_FILETYPE VFT_DRV #define VER_FILESUBTYPE VFT2_DRV_DISPLAY #define VER_FILEDESCRIPTION_STR "Microsoft Sample Display Driver" #define VER_INTERNALNAME_STR "SampleDisplay.sys" #define VER_ORIGINALFILENAME_STR "SampleDisplay.sys" #define VER_LANGNEUTRAL #include "common.ver"
驅動程式檔案 .inf
.INF是 Device Information File 的縮寫,是微軟為供硬體製造商散佈其設備驅動程式而發展, .INF 檔是一種具有特定格式的純文字檔,我們可說它是種安裝腳本檔(Setup Script)。為甚麼當我們在檔案總管對 .INF 檔按右鍵後,快顯功能表會出現「安裝」指令呢? 這是因為微軟已在其作業系統 Windows 中提供了 Setup API(註一),程式設計師只需用任何文書編輯軟體撰寫 .INF 檔,便可完成大部份的安裝工作。
;++ ; ; Copyright (c) 2011 Microsoft Corporation ; ; Module Name: ; ; SampleDisplay.inf ; ; Abstract: ; ; Inf file for Kernel mode display only sample driver ; ;-- [Version] Signature = "$Windows NT$" Class=Display ClassGUID={4d36e968-e325-11ce-bfc1-08002be10318} Provider=%ProviderString% DriverVer= 03/15/2011, 0.03.15.0011 CatalogFile=SampleDisplay.cat [DestinationDirs] KDODSamp.Files = 12 [SourceDisksNames] 0=%SampleDisk% [SourceDisksFiles] SampleDisplay.sys=0 [Manufacturer] %ManufacturerName%=Standard,NTx86,NTamd64,NTarm,NTarm64 ; ; Allow the driver to be loaded on VGA and XGA exposed by PCI bus and ACPI ; [Standard.NTx86] %SampleDeviceName% = KDODSamp_Inst, PCI\CC_0300 %SampleDeviceName% = KDODSamp_Inst, PCI\CC_0301 %SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0000 %SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0001 [Standard.NTamd64] %SampleDeviceName% = KDODSamp_Inst, PCI\CC_0300 %SampleDeviceName% = KDODSamp_Inst, PCI\CC_0301 %SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0000 %SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0001 [Standard.NTarm] %SampleDeviceName% = KDODSamp_Inst, PCI\CC_0300 %SampleDeviceName% = KDODSamp_Inst, PCI\CC_0301 %SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0000 %SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0001 [Standard.NTarm64] %SampleDeviceName% = KDODSamp_Inst, PCI\CC_0300 %SampleDeviceName% = KDODSamp_Inst, PCI\CC_0301 %SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0000 %SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0001 [KDODSamp_Inst] FeatureScore=F9 CopyFiles = KDODSamp.Files ; ; Install driver service ; [KDODSamp_Inst.Services] AddService = KDODSamp,0x00000002,KDODSamp_Service_Inst,KDODSamp_EventLog_Inst [KDODSamp_Service_Inst] ServiceType = %SERVICE_KERNEL_DRIVER% StartType = %SERVICE_DEMAND_START% ErrorControl = %SERVICE_ERROR_IGNORE% ServiceBinary = %12%\SampleDisplay.sys ; ; Display Adapter Specific Settings ; [KDODSamp.Files] SampleDisplay.sys [KDODSamp_EventLog_Inst] AddReg = KDODSamp_EventLog_Inst.AddReg [KDODSamp_EventLog_Inst.AddReg] HKR,,EventMessageFile,%REG_EXPAND_SZ%,"%%SystemRoot%%\System32\IoLogMsg.dll" HKR,,TypesSupported,%REG_DWORD%,7 [Strings] ; *******Localizable Strings******* ProviderString="TODO-Set-Provider" ManufacturerName="TODO-Set-Manufacturer" SampleDisk = "Sample Disk" SampleDeviceName = "Kernel mode display only sample driver" ; *******Non Localizable Strings******* SERVICE_BOOT_START = 0x0 SERVICE_SYSTEM_START = 0x1 SERVICE_AUTO_START = 0x2 SERVICE_DEMAND_START = 0x3 SERVICE_DISABLED = 0x4 SERVICE_KERNEL_DRIVER = 0x1 SERVICE_ERROR_IGNORE = 0x0 SERVICE_ERROR_NORMAL = 0x1 SERVICE_ERROR_SEVERE = 0x2 SERVICE_ERROR_CRITICAL = 0x3 REG_MULTI_SZ = 0x00010000 REG_EXPAND_SZ = 0x00020000 REG_DWORD = 0x00010001
C++程式標頭檔案 bdd.hxx
/******************************Module*Header*******************************\ * Module Name: BDD.hxx * * Basic Display Driver header file * * * Copyright (c) 2010 Microsoft Corporation \**************************************************************************/ #ifndef _BDD_HXX_ #define _BDD_HXX_ extern "C" { #define __CPLUSPLUS // Standard C-runtime headers #include <stddef.h> #include <string.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <initguid.h> // NTOS headers #include <ntddk.h> #ifndef FAR #define FAR #endif // Windows headers #include <windef.h> #include <winerror.h> // Windows GDI headers #include <wingdi.h> // Windows DDI headers #include <winddi.h> #include <ntddvdeo.h> #include <d3dkmddi.h> #include <d3dkmthk.h> #include <ntstrsafe.h> #include <ntintsafe.h> #include <dispmprt.h> }; #define EDID_V1_BLOCK_SIZE 128 #include "BDD_ErrorLog.hxx" #define MIN_WIDTH 640 #define MIN_HEIGHT 480 #define MIN_BITS_PER_PIXEL_ALLOWED 8 #define MIN_BYTES_PER_PIXEL_REPORTED 4 #define DEFAULT_WIDTH 1024 #define DEFAULT_HEIGHT 768 #define MAX_INVALID_INHERITED_WIDTH 1024 #define MAX_INVALID_INHERITED_HEIGHT 768 #define BITS_PER_BYTE 8 typedef struct _BLT_INFO { PVOID pBits; UINT Pitch; UINT BitsPerPel; POINT Offset; // To unrotated top-left of dirty rects D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation; UINT Width; // For the unrotated image UINT Height; // For the unrotated image } BLT_INFO; #define MAX_CHILDREN 1 #define MAX_VIEWS 1 typedef struct _BDD_FLAGS { UINT DriverStarted : 1; // ( 1) 1 after StartDevice and 0 after StopDevice UINT EDID_Retrieved : 1; // ( 2) EDID was successfully retrieved UINT EDID_ValidChecksum : 1; // ( 3) Retrieved EDID has a valid checksum UINT EDID_ValidHeader : 1; // ( 4) Retrieved EDID has a valid header UINT EDID_Attempted : 1; // ( 5) 1 if an attempt was made to retrieve the EDID, successful or not // IMPORTANT: All new flags must be added to just before _LastFlag (i.e. right above this comment), this allows different versions of diagnostics to still be useful. UINT _LastFlag : 1; // ( 6) Always set to 1, is used to ensure that diagnostic version matches binary version UINT Unused : 26; } BDD_FLAGS; // Represents the current mode, may not always be set (i.e. frame buffer mapped) if representing the mode passed in on single mode setups. typedef struct _CURRENT_BDD_MODE { // The source mode currently set for HW Framebuffer // For sample driver this info filled in StartDevice by the OS and never changed. DXGK_DISPLAY_INFORMATION DispInfo; // The rotation of the current mode. Rotation is performed in software during Present call D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation; D3DKMDT_VIDPN_PRESENT_PATH_SCALING Scaling; // This mode might be different from one which are supported for HW frame buffer // Scaling/displasment might be needed (if supported) UINT SrcModeWidth; UINT SrcModeHeight; // Various boolean flags the struct uses struct _CURRENT_BDD_MODE_FLAGS { UINT SourceNotVisible : 1; // 0 if source is visible UINT FullscreenPresent : 1; // 0 if should use dirty rects for present UINT FrameBufferIsActive : 1; // 0 if not currently active (i.e. target not connected to source) UINT DoNotMapOrUnmap : 1; // 1 if the FrameBuffer should not be (un)mapped during normal execution UINT IsInternal : 1; // 1 if it was determined (i.e. through ACPI) that an internal panel is being driven UINT Unused : 27; } Flags; // The start and end of physical memory known to be all zeroes. Used to optimize the BlackOutScreen function to not write // zeroes to memory already known to be zero. (Physical address is located in DispInfo) PHYSICAL_ADDRESS ZeroedOutStart; PHYSICAL_ADDRESS ZeroedOutEnd; // Linear frame buffer pointer // A union with a ULONG64 is used here to ensure this struct looks the same on 32bit and 64bit builds // since the size of a VOID* changes depending on the build. union { VOID* Ptr; ULONG64 Force8Bytes; } FrameBuffer; } CURRENT_BDD_MODE; class BASIC_DISPLAY_DRIVER; class BDD_HWBLT { public: D3DDDI_VIDEO_PRESENT_SOURCE_ID m_SourceId; BASIC_DISPLAY_DRIVER* m_DevExt; BOOLEAN m_SynchExecution; HANDLE m_hPresentWorkerThread; PVOID m_pPresentWorkerThread; // Events to contol thread execution KEVENT m_hThreadStartupEvent; KEVENT m_hThreadSuspendEvent; BDD_HWBLT(); ~BDD_HWBLT(); void Initialize(_In_ BASIC_DISPLAY_DRIVER* DevExt, _In_ UINT IdSrc) { m_DevExt = DevExt; m_SourceId = IdSrc; } void SetPresentWorkerThreadInfo(HANDLE hWorkerThread); NTSTATUS ExecutePresentDisplayOnly(_In_ BYTE* DstAddr, _In_ UINT DstBitPerPixel, _In_ BYTE* SrcAddr, _In_ UINT SrcBytesPerPixel, _In_ LONG SrcPitch, _In_ ULONG NumMoves, _In_ D3DKMT_MOVE_RECT* pMoves, _In_ ULONG NumDirtyRects, _In_ RECT* pDirtyRect, _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation); }; class BASIC_DISPLAY_DRIVER { private: DEVICE_OBJECT* m_pPhysicalDevice; DXGKRNL_INTERFACE m_DxgkInterface; // Information passed in by StartDevice DDI DXGK_START_INFO m_StartInfo; // Array of EDIDs, currently only supporting base block, hence EDID_V1_BLOCK_SIZE for size of each EDID BYTE m_EDIDs[MAX_CHILDREN][EDID_V1_BLOCK_SIZE]; CURRENT_BDD_MODE m_CurrentModes[MAX_VIEWS]; BDD_HWBLT m_HardwareBlt[MAX_VIEWS]; // Current monitorpower state (this needs to be changed if MAX_CHILDREN != 1) DEVICE_POWER_STATE m_MonitorPowerState; // Current adapter power state DEVICE_POWER_STATE m_AdapterPowerState; // Source ID to be used by SystemDisplay functions D3DDDI_VIDEO_PRESENT_SOURCE_ID m_SystemDisplaySourceId; // Various boolean flags the class uses BDD_FLAGS m_Flags; // Device information DXGK_DEVICE_INFO m_DeviceInfo; public: BASIC_DISPLAY_DRIVER(_In_ DEVICE_OBJECT* pPhysicalDeviceObject); ~BASIC_DISPLAY_DRIVER(); #pragma code_seg(push) #pragma code_seg() BOOLEAN IsDriverActive() const { return m_Flags.DriverStarted; } #pragma code_seg(pop) NTSTATUS StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo, _In_ DXGKRNL_INTERFACE* pDxgkInterface, _Out_ ULONG* pNumberOfViews, _Out_ ULONG* pNumberOfChildren); NTSTATUS StopDevice(VOID); // Must be Non-Paged VOID ResetDevice(VOID); const CURRENT_BDD_MODE* GetCurrentMode(UINT SourceId) const { return (SourceId < MAX_VIEWS)?&m_CurrentModes[SourceId]:NULL; } const DXGKRNL_INTERFACE* GetDxgkInterface() const { return &m_DxgkInterface;} // Not implemented since no IOCTLs currently handled. NTSTATUS DispatchIoRequest(_In_ ULONG VidPnSourceId, _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket); // Used to either turn off/on monitor (if possible), or mark that system is going into hibernate NTSTATUS SetPowerState(_In_ ULONG HardwareUid, _In_ DEVICE_POWER_STATE DevicePowerState, _In_ POWER_ACTION ActionType); // Report back child capabilities NTSTATUS QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, _In_ ULONG ChildRelationsSize); NTSTATUS QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus, _In_ BOOLEAN NonDestructiveOnly); // Return EDID if previously retrieved NTSTATUS QueryDeviceDescriptor(_In_ ULONG ChildUid, _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor); // Must be Non-Paged // BDD doesn't have interrupts, so just returns false BOOLEAN InterruptRoutine(_In_ ULONG MessageNumber); VOID DpcRoutine(VOID); // Return DriverCaps, doesn't support other queries though NTSTATUS QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo); NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition); NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape); NTSTATUS PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly); NTSTATUS IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn); NTSTATUS RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn); NTSTATUS RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology); NTSTATUS RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); NTSTATUS EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality); NTSTATUS SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility); NTSTATUS CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn); NTSTATUS UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath); NTSTATUS QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps); // Part of PnPStop (PnP instance only), returns current mode information (which will be passed to fallback instance by dxgkrnl) NTSTATUS StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo); // Must be Non-Paged // Call to initialize as part of bugcheck NTSTATUS SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, _Out_ UINT* pWidth, _Out_ UINT* pHeight, _Out_ D3DDDIFORMAT* pColorFormat); // Must be Non-Paged // Write out pixels as part of bugcheck VOID SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource, _In_ UINT SourceWidth, _In_ UINT SourceHeight, _In_ UINT SourceStride, _In_ INT PositionX, _In_ INT PositionY); private: VOID CleanUp(); NTSTATUS CommonStart(); NTSTATUS GetEdid(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId); // Given pixel format, give back the bits per pixel. Only supports pixel formats expected by BDD // (i.e. the ones found below in PixelFormatFromBPP or that may come in from FallbackStart) // This is because these two functions combine to allow BDD to store the bpp of a VBE mode in the // ColorFormat field of a DispInfo UINT BPPFromPixelFormat(D3DDDIFORMAT Format) const { switch (Format) { case D3DDDIFMT_UNKNOWN: return 0; case D3DDDIFMT_P8: return 8; case D3DDDIFMT_R5G6B5: return 16; case D3DDDIFMT_R8G8B8: return 24; case D3DDDIFMT_X8R8G8B8: // fall through case D3DDDIFMT_A8R8G8B8: return 32; default: BDD_LOG_ASSERTION1("Unknown D3DDDIFORMAT 0x%I64x", Format); return 0; } } // Given bits per pixel, return the pixel format at the same bpp D3DDDIFORMAT PixelFormatFromBPP(UINT BPP) const { switch (BPP) { case 8: return D3DDDIFMT_P8; case 16: return D3DDDIFMT_R5G6B5; case 24: return D3DDDIFMT_R8G8B8; case 32: return D3DDDIFMT_X8R8G8B8; default: BDD_LOG_ASSERTION1("A bit per pixel of 0x%I64x is not supported.", BPP); return D3DDDIFMT_UNKNOWN; } } // These two functions make checks on the values of some of the fields of their respective structures to ensure // that the specified fields are supported by BDD, i.e. gamma ramp must be D3DDDI_GAMMARAMP_DEFAULT NTSTATUS IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const; NTSTATUS IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const; VOID BlackOutScreen(D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId); // Returns the index into gBddBiosData.BddModes of the VBE mode that matches the given VidPnSourceMode. // If such a mode cannot be found, returns a number outside of [0, gBddBiosData.CountBddModes) UINT FindMatchingVBEMode(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const; // Must be Non-Paged // Returns the SourceId that has TargetId as a valid frame buffer or D3DDDI_ID_UNINITIALIZED if no such SourceId exists D3DDDI_VIDEO_PRESENT_SOURCE_ID FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero); // Set the given source mode on the given path NTSTATUS SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode, CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath); // Add the current mode to the given monitor source mode set NTSTATUS AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); // Add the current mode to the given VidPn source mode set NTSTATUS AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface, D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet, D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId); // Add the current mode (or the matching to pinned source mode) to the give VidPn target mode set NTSTATUS AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface, D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet, _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo, D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId); // Check that the hardware the driver is running on is hardware it is capable of driving. NTSTATUS CheckHardware(); // Helper function for RegisterHWInfo NTSTATUS WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue); // Set the information in the registry as described here: http://msdn.microsoft.com/en-us/library/windows/hardware/ff569240(v=vs.85).aspx NTSTATUS RegisterHWInfo(); }; // // Blt functions // // Must be Non-Paged VOID BltBits( BLT_INFO* pDst, CONST BLT_INFO* pSrc, UINT NumRects, _In_reads_(NumRects) CONST RECT *pRects); // // Driver Entry point // extern "C" DRIVER_INITIALIZE DriverEntry; // // PnP DDIs // VOID BddDdiUnload(VOID); // If uncommenting ENABLE_DXGK_SAL in the sources file, all the below function prototypes should be updated to use // the function typedef's from the header files. Additionally, annotations on the function definitions can be removed // as they are inherited from the prototype definition here. As an example the entire 4-line prototype for BddDdiAddDevice // is replaced by the single commented line below: // DXGKDDI_ADD_DEVICE BddDdiAddDevice; NTSTATUS BddDdiAddDevice( _In_ DEVICE_OBJECT* pPhysicalDeviceObject, _Outptr_ PVOID* ppDeviceContext); NTSTATUS BddDdiRemoveDevice( _In_ VOID* pDeviceContext); NTSTATUS BddDdiStartDevice( _In_ VOID* pDeviceContext, _In_ DXGK_START_INFO* pDxgkStartInfo, _In_ DXGKRNL_INTERFACE* pDxgkInterface, _Out_ ULONG* pNumberOfViews, _Out_ ULONG* pNumberOfChildren); NTSTATUS BddDdiStopDevice( _In_ VOID* pDeviceContext); VOID BddDdiResetDevice( _In_ VOID* pDeviceContext); NTSTATUS BddDdiDispatchIoRequest( _In_ VOID* pDeviceContext, _In_ ULONG VidPnSourceId, _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket); NTSTATUS BddDdiSetPowerState( _In_ VOID* pDeviceContext, _In_ ULONG HardwareUid, _In_ DEVICE_POWER_STATE DevicePowerState, _In_ POWER_ACTION ActionType); NTSTATUS BddDdiQueryChildRelations( _In_ VOID* pDeviceContext, _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, _In_ ULONG ChildRelationsSize); NTSTATUS BddDdiQueryChildStatus( _In_ VOID* pDeviceContext, _Inout_ DXGK_CHILD_STATUS* pChildStatus, _In_ BOOLEAN NonDestructiveOnly); NTSTATUS BddDdiQueryDeviceDescriptor( _In_ VOID* pDeviceContext, _In_ ULONG ChildUid, _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor); // Must be Non-Paged BOOLEAN BddDdiInterruptRoutine( _In_ VOID* pDeviceContext, _In_ ULONG MessageNumber); VOID BddDdiDpcRoutine( _In_ VOID* pDeviceContext); // // WDDM Display Only Driver DDIs // NTSTATUS APIENTRY BddDdiQueryAdapterInfo( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo); NTSTATUS APIENTRY BddDdiSetPointerPosition( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition); NTSTATUS APIENTRY BddDdiSetPointerShape( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape); NTSTATUS APIENTRY BddDdiPresentDisplayOnly( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly); NTSTATUS APIENTRY BddDdiIsSupportedVidPn( _In_ CONST HANDLE hAdapter, _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn); NTSTATUS APIENTRY BddDdiRecommendFunctionalVidPn( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn); NTSTATUS APIENTRY BddDdiRecommendVidPnTopology( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology); NTSTATUS APIENTRY BddDdiRecommendMonitorModes( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); NTSTATUS APIENTRY BddDdiEnumVidPnCofuncModality( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality); NTSTATUS APIENTRY BddDdiSetVidPnSourceVisibility( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility); NTSTATUS APIENTRY BddDdiCommitVidPn( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn); NTSTATUS APIENTRY BddDdiUpdateActiveVidPnPresentPath( _In_ CONST HANDLE hAdapter, _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath); NTSTATUS APIENTRY BddDdiQueryVidPnHWCapability( _In_ CONST HANDLE hAdapter, _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps); NTSTATUS APIENTRY BddDdiStopDeviceAndReleasePostDisplayOwnership( _In_ VOID* pDeviceContext, _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo); // Must be Non-Paged 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); // Must be Non-Paged VOID APIENTRY BddDdiSystemDisplayWrite( _In_ VOID* pDeviceContext, _In_ VOID* Source, _In_ UINT SourceWidth, _In_ UINT SourceHeight, _In_ UINT SourceStride, _In_ UINT PositionX, _In_ UINT PositionY); // // Frame buffer map/unmap // NTSTATUS MapFrameBuffer( _In_ PHYSICAL_ADDRESS PhysicalAddress, _In_ ULONG Length, _Outptr_result_bytebuffer_(Length) VOID** VirtualAddress); NTSTATUS UnmapFrameBuffer( _In_reads_bytes_(Length) VOID* VirtualAddress, _In_ ULONG Length); BOOLEAN IsEdidHeaderValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid); BOOLEAN IsEdidChecksumValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid); // // Memory handling // // Defaulting the value of PoolType means that any call to new Foo() // will raise a compiler error for being ambiguous. This is to help keep // any calls to allocate memory from accidentally NOT going through // these functions. _When_((PoolType & NonPagedPoolMustSucceed) != 0, __drv_reportError("Must succeed pool allocations are forbidden. " "Allocation failures cause a system crash")) void* __cdecl operator new(size_t Size, POOL_TYPE PoolType = PagedPool); _When_((PoolType & NonPagedPoolMustSucceed) != 0, __drv_reportError("Must succeed pool allocations are forbidden. " "Allocation failures cause a system crash")) void* __cdecl operator new[](size_t Size, POOL_TYPE PoolType = PagedPool); void __cdecl operator delete(void* pObject); void __cdecl operator delete(void* pObject, size_t s); void __cdecl operator delete[](void* pObject); // Pool allocation tag for the Sample Display Driver. All allocations use this tag. #define BDDTAG 'DDBS' #endif // _BDD_HXX_
C++程式檔案 bdd.cxx
/******************************Module*Header*******************************\ * Module Name: bdd.cxx * * Basic Display Driver functions implementation * * * Copyright (c) 2010 Microsoft Corporation \**************************************************************************/ #include "BDD.hxx" #pragma code_seg("PAGE") BASIC_DISPLAY_DRIVER::BASIC_DISPLAY_DRIVER(_In_ DEVICE_OBJECT* pPhysicalDeviceObject) : m_pPhysicalDevice(pPhysicalDeviceObject), m_MonitorPowerState(PowerDeviceD0), m_AdapterPowerState(PowerDeviceD0) { PAGED_CODE(); *((UINT*)&m_Flags) = 0; m_Flags._LastFlag = TRUE; RtlZeroMemory(&m_DxgkInterface, sizeof(m_DxgkInterface)); RtlZeroMemory(&m_StartInfo, sizeof(m_StartInfo)); RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes)); RtlZeroMemory(&m_DeviceInfo, sizeof(m_DeviceInfo)); for (UINT i=0;i<MAX_VIEWS;i++) { m_HardwareBlt[i].Initialize(this,i); } } BASIC_DISPLAY_DRIVER::~BASIC_DISPLAY_DRIVER() { PAGED_CODE(); CleanUp(); } NTSTATUS BASIC_DISPLAY_DRIVER::StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo, _In_ DXGKRNL_INTERFACE* pDxgkInterface, _Out_ ULONG* pNumberOfViews, _Out_ ULONG* pNumberOfChildren) { PAGED_CODE(); BDD_ASSERT(pDxgkStartInfo != NULL); BDD_ASSERT(pDxgkInterface != NULL); BDD_ASSERT(pNumberOfViews != NULL); BDD_ASSERT(pNumberOfChildren != NULL); RtlCopyMemory(&m_StartInfo, pDxgkStartInfo, sizeof(m_StartInfo)); RtlCopyMemory(&m_DxgkInterface, pDxgkInterface, sizeof(m_DxgkInterface)); RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes)); m_CurrentModes[0].DispInfo.TargetId = D3DDDI_ID_UNINITIALIZED; // Get device information from OS. NTSTATUS Status = m_DxgkInterface.DxgkCbGetDeviceInformation(m_DxgkInterface.DeviceHandle, &m_DeviceInfo); if (!NT_SUCCESS(Status)) { BDD_LOG_ASSERTION1("DxgkCbGetDeviceInformation failed with status 0x%I64x", Status); return Status; } // Ignore return value, since it's not the end of the world if we failed to write these values to the registry RegisterHWInfo(); // TODO: Uncomment the line below after updating the TODOs in the function CheckHardware // Status = CheckHardware(); if (!NT_SUCCESS(Status)) { return Status; } // This sample driver only uses the frame buffer of the POST device. DxgkCbAcquirePostDisplayOwnership // gives you the frame buffer address and ensures that no one else is drawing to it. Be sure to give it back! Status = m_DxgkInterface.DxgkCbAcquirePostDisplayOwnership(m_DxgkInterface.DeviceHandle, &(m_CurrentModes[0].DispInfo)); if (!NT_SUCCESS(Status) || m_CurrentModes[0].DispInfo.Width == 0) { // The most likely cause of failure is that the driver is simply not running on a POST device, or we are running // after a pre-WDDM 1.2 driver. Since we can't draw anything, we should fail to start. return STATUS_UNSUCCESSFUL; } m_Flags.DriverStarted = TRUE; *pNumberOfViews = MAX_VIEWS; *pNumberOfChildren = MAX_CHILDREN; return STATUS_SUCCESS; } NTSTATUS BASIC_DISPLAY_DRIVER::StopDevice(VOID) { PAGED_CODE(); CleanUp(); m_Flags.DriverStarted = FALSE; return STATUS_SUCCESS; } VOID BASIC_DISPLAY_DRIVER::CleanUp() { PAGED_CODE(); for (UINT Source = 0; Source < MAX_VIEWS; ++Source) { if (m_CurrentModes[Source].FrameBuffer.Ptr) { UnmapFrameBuffer(m_CurrentModes[Source].FrameBuffer.Ptr, m_CurrentModes[Source].DispInfo.Height * m_CurrentModes[Source].DispInfo.Pitch); m_CurrentModes[Source].FrameBuffer.Ptr = NULL; m_CurrentModes[Source].Flags.FrameBufferIsActive = FALSE; } } } NTSTATUS BASIC_DISPLAY_DRIVER::DispatchIoRequest(_In_ ULONG VidPnSourceId, _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket) { PAGED_CODE(); BDD_ASSERT(pVideoRequestPacket != NULL); BDD_ASSERT(VidPnSourceId < MAX_VIEWS); return STATUS_NOT_IMPLEMENTED; } NTSTATUS BASIC_DISPLAY_DRIVER::SetPowerState(_In_ ULONG HardwareUid, _In_ DEVICE_POWER_STATE DevicePowerState, _In_ POWER_ACTION ActionType) { PAGED_CODE(); UNREFERENCED_PARAMETER(ActionType); BDD_ASSERT((HardwareUid < MAX_CHILDREN) || (HardwareUid == DISPLAY_ADAPTER_HW_ID)); if (HardwareUid == DISPLAY_ADAPTER_HW_ID) { if (DevicePowerState == PowerDeviceD0) { // When returning from D3 the device visibility defined to be off for all targets if (m_AdapterPowerState == PowerDeviceD3) { DXGKARG_SETVIDPNSOURCEVISIBILITY Visibility; Visibility.VidPnSourceId = D3DDDI_ID_ALL; Visibility.Visible = FALSE; SetVidPnSourceVisibility(&Visibility); } } // Store new adapter power state m_AdapterPowerState = DevicePowerState; // There is nothing to do to specifically power up/down the display adapter return STATUS_SUCCESS; } else { // TODO: This is where the specified monitor should be powered up/down NOTHING; return STATUS_SUCCESS; } } NTSTATUS BASIC_DISPLAY_DRIVER::QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, _In_ ULONG ChildRelationsSize) { PAGED_CODE(); BDD_ASSERT(pChildRelations != NULL); // The last DXGK_CHILD_DESCRIPTOR in the array of pChildRelations must remain zeroed out, so we subtract this from the count ULONG ChildRelationsCount = (ChildRelationsSize / sizeof(DXGK_CHILD_DESCRIPTOR)) - 1; BDD_ASSERT(ChildRelationsCount <= MAX_CHILDREN); for (UINT ChildIndex = 0; ChildIndex < ChildRelationsCount; ++ChildIndex) { pChildRelations[ChildIndex].ChildDeviceType = TypeVideoOutput; pChildRelations[ChildIndex].ChildCapabilities.HpdAwareness = HpdAwarenessInterruptible; pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.InterfaceTechnology = m_CurrentModes[0].Flags.IsInternal ? D3DKMDT_VOT_INTERNAL : D3DKMDT_VOT_OTHER; pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.MonitorOrientationAwareness = D3DKMDT_MOA_NONE; pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.SupportsSdtvModes = FALSE; // TODO: Replace 0 with the actual ACPI ID of the child device, if available pChildRelations[ChildIndex].AcpiUid = 0; pChildRelations[ChildIndex].ChildUid = ChildIndex; } return STATUS_SUCCESS; } NTSTATUS BASIC_DISPLAY_DRIVER::QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus, _In_ BOOLEAN NonDestructiveOnly) { PAGED_CODE(); UNREFERENCED_PARAMETER(NonDestructiveOnly); BDD_ASSERT(pChildStatus != NULL); BDD_ASSERT(pChildStatus->ChildUid < MAX_CHILDREN); switch (pChildStatus->Type) { case StatusConnection: { // HpdAwarenessInterruptible was reported since HpdAwarenessNone is deprecated. // However, BDD has no knowledge of HotPlug events, so just always return connected. pChildStatus->HotPlug.Connected = IsDriverActive(); return STATUS_SUCCESS; } case StatusRotation: { // D3DKMDT_MOA_NONE was reported, so this should never be called BDD_LOG_ERROR0("Child status being queried for StatusRotation even though D3DKMDT_MOA_NONE was reported"); return STATUS_INVALID_PARAMETER; } default: { BDD_LOG_WARNING1("Unknown pChildStatus->Type (0x%I64x) requested.", pChildStatus->Type); return STATUS_NOT_SUPPORTED; } } } // EDID retrieval NTSTATUS BASIC_DISPLAY_DRIVER::QueryDeviceDescriptor(_In_ ULONG ChildUid, _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor) { PAGED_CODE(); BDD_ASSERT(pDeviceDescriptor != NULL); BDD_ASSERT(ChildUid < MAX_CHILDREN); // If we haven't successfully retrieved an EDID yet (invalid ones are ok, so long as it was retrieved) if (!m_Flags.EDID_Attempted) { GetEdid(ChildUid); } if (!m_Flags.EDID_Retrieved || !m_Flags.EDID_ValidHeader || !m_Flags.EDID_ValidChecksum) { // Report no EDID if a valid one wasn't retrieved return STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED; } else if (pDeviceDescriptor->DescriptorOffset == 0) { // Only the base block is supported RtlCopyMemory(pDeviceDescriptor->DescriptorBuffer, m_EDIDs[ChildUid], min(pDeviceDescriptor->DescriptorLength, EDID_V1_BLOCK_SIZE)); return STATUS_SUCCESS; } else { return STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA; } } NTSTATUS BASIC_DISPLAY_DRIVER::QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo) { PAGED_CODE(); BDD_ASSERT(pQueryAdapterInfo != NULL); switch (pQueryAdapterInfo->Type) { case DXGKQAITYPE_DRIVERCAPS: { if (pQueryAdapterInfo->OutputDataSize < sizeof(DXGK_DRIVERCAPS)) { BDD_LOG_ERROR2("pQueryAdapterInfo->OutputDataSize (0x%I64x) is smaller than sizeof(DXGK_DRIVERCAPS) (0x%I64x)", pQueryAdapterInfo->OutputDataSize, sizeof(DXGK_DRIVERCAPS)); return STATUS_BUFFER_TOO_SMALL; } DXGK_DRIVERCAPS* pDriverCaps = (DXGK_DRIVERCAPS*)pQueryAdapterInfo->pOutputData; // Nearly all fields must be initialized to zero, so zero out to start and then change those that are non-zero. // Fields are zero since BDD is Display-Only and therefore does not support any of the render related fields. // It also doesn't support hardware interrupts, gamma ramps, etc. RtlZeroMemory(pDriverCaps, sizeof(DXGK_DRIVERCAPS)); pDriverCaps->WDDMVersion = DXGKDDI_WDDMv1_2; pDriverCaps->HighestAcceptableAddress.QuadPart = -1; pDriverCaps->SupportNonVGA = TRUE; pDriverCaps->SupportSmoothRotation = TRUE; return STATUS_SUCCESS; } case DXGKQAITYPE_DISPLAY_DRIVERCAPS_EXTENSION: { DXGK_DISPLAY_DRIVERCAPS_EXTENSION* pDriverDisplayCaps; if (pQueryAdapterInfo->OutputDataSize < sizeof(*pDriverDisplayCaps)) { BDD_LOG_ERROR2("pQueryAdapterInfo->OutputDataSize (0x%I64x) is smaller than sizeof(DXGK_DISPLAY_DRIVERCAPS_EXTENSION) (0x%I64x)", pQueryAdapterInfo->OutputDataSize, sizeof(DXGK_DISPLAY_DRIVERCAPS_EXTENSION)); return STATUS_INVALID_PARAMETER; } pDriverDisplayCaps = (DXGK_DISPLAY_DRIVERCAPS_EXTENSION*)pQueryAdapterInfo->pOutputData; // Reset all caps values RtlZeroMemory(pDriverDisplayCaps, pQueryAdapterInfo->OutputDataSize); // We claim to support virtual display mode. pDriverDisplayCaps->VirtualModeSupport = 1; return STATUS_SUCCESS; } default: { // BDD does not need to support any other adapter information types BDD_LOG_WARNING1("Unknown QueryAdapterInfo Type (0x%I64x) requested", pQueryAdapterInfo->Type); return STATUS_NOT_SUPPORTED; } } } NTSTATUS BASIC_DISPLAY_DRIVER::CheckHardware() { PAGED_CODE(); NTSTATUS Status; ULONG VendorID; ULONG DeviceID; // TODO: If developing a driver for PCI based hardware, then use the second method to retrieve Vendor/Device IDs. // If developing for non-PCI based hardware (i.e. ACPI based hardware), use the first method to retrieve the IDs. #if 1 // ACPI-based device // Get the Vendor & Device IDs on non-PCI system ACPI_EVAL_INPUT_BUFFER_COMPLEX AcpiInputBuffer = {0}; AcpiInputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE; AcpiInputBuffer.MethodNameAsUlong = ACPI_METHOD_HARDWARE_ID; AcpiInputBuffer.Size = 0; AcpiInputBuffer.ArgumentCount = 0; BYTE OutputBuffer[sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 0x10]; RtlZeroMemory(OutputBuffer, sizeof(OutputBuffer)); ACPI_EVAL_OUTPUT_BUFFER* pAcpiOutputBuffer = reinterpret_cast<ACPI_EVAL_OUTPUT_BUFFER*>(&OutputBuffer); Status = m_DxgkInterface.DxgkCbEvalAcpiMethod(m_DxgkInterface.DeviceHandle, DISPLAY_ADAPTER_HW_ID, &AcpiInputBuffer, sizeof(AcpiInputBuffer), pAcpiOutputBuffer, sizeof(OutputBuffer)); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR1("DxgkCbReadDeviceSpace failed to get hardware IDs with status 0x%I64x", Status); return Status; } VendorID = ((ULONG*)(pAcpiOutputBuffer->Argument[0].Data))[0]; DeviceID = ((ULONG*)(pAcpiOutputBuffer->Argument[0].Data))[1]; #else // PCI-based device // Get the Vendor & Device IDs on PCI system PCI_COMMON_HEADER Header = {0}; ULONG BytesRead; Status = m_DxgkInterface.DxgkCbReadDeviceSpace(m_DxgkInterface.DeviceHandle, DXGK_WHICHSPACE_CONFIG, &Header, 0, sizeof(Header), &BytesRead); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR1("DxgkCbReadDeviceSpace failed with status 0x%I64x", Status); return Status; } VendorID = Header.VendorID; DeviceID = Header.DeviceID; #endif // TODO: Replace 0x1414 with your Vendor ID if (VendorID == 0x1414) { switch (DeviceID) { // TODO: Replace the case statements below with the Device IDs supported by this driver case 0x0000: case 0xFFFF: return STATUS_SUCCESS; } } return STATUS_GRAPHICS_DRIVER_MISMATCH; } // Even though Sample Basic Display Driver does not support hardware cursors, and reports such // in QueryAdapterInfo. This function can still be called to set the pointer to not visible NTSTATUS BASIC_DISPLAY_DRIVER::SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition) { PAGED_CODE(); BDD_ASSERT(pSetPointerPosition != NULL); BDD_ASSERT(pSetPointerPosition->VidPnSourceId < MAX_VIEWS); if (!(pSetPointerPosition->Flags.Visible)) { return STATUS_SUCCESS; } else { BDD_LOG_ASSERTION0("SetPointerPosition should never be called to set the pointer to visible since BDD doesn't support hardware cursors."); return STATUS_UNSUCCESSFUL; } } // Basic Sample Display Driver does not support hardware cursors, and reports such // in QueryAdapterInfo. Therefore this function should never be called. NTSTATUS BASIC_DISPLAY_DRIVER::SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape) { PAGED_CODE(); BDD_ASSERT(pSetPointerShape != NULL); BDD_LOG_ASSERTION0("SetPointerShape should never be called since BDD doesn't support hardware cursors."); return STATUS_NOT_IMPLEMENTED; } NTSTATUS BASIC_DISPLAY_DRIVER::PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly) { PAGED_CODE(); BDD_ASSERT(pPresentDisplayOnly != NULL); BDD_ASSERT(pPresentDisplayOnly->VidPnSourceId < MAX_VIEWS); if (pPresentDisplayOnly->BytesPerPixel < MIN_BYTES_PER_PIXEL_REPORTED) { // Only >=32bpp modes are reported, therefore this Present should never pass anything less than 4 bytes per pixel BDD_LOG_ERROR1("pPresentDisplayOnly->BytesPerPixel is 0x%I64x, which is lower than the allowed.", pPresentDisplayOnly->BytesPerPixel); return STATUS_INVALID_PARAMETER; } // If it is in monitor off state or source is not supposed to be visible, don't present anything to the screen if ((m_MonitorPowerState > PowerDeviceD0) || (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.SourceNotVisible)) { return STATUS_SUCCESS; } // Present is only valid if the target is actively connected to this source if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.FrameBufferIsActive) { // If actual pixels are coming through, will need to completely zero out physical address next time in BlackOutScreen m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutStart.QuadPart = 0; m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutEnd.QuadPart = 0; D3DKMDT_VIDPN_PRESENT_PATH_ROTATION RotationNeededByFb = pPresentDisplayOnly->Flags.Rotate ? m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Rotation : D3DKMDT_VPPR_IDENTITY; BYTE* pDst = (BYTE*)m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].FrameBuffer.Ptr; UINT DstBitPerPixel = BPPFromPixelFormat(m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.ColorFormat); if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Scaling == D3DKMDT_VPPS_CENTERED) { UINT CenterShift = (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Height - m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeHeight)*m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Pitch; CenterShift += (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Width - m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeWidth)*DstBitPerPixel/8; pDst += (int)CenterShift/2; } return m_HardwareBlt[pPresentDisplayOnly->VidPnSourceId].ExecutePresentDisplayOnly(pDst, DstBitPerPixel, (BYTE*)pPresentDisplayOnly->pSource, pPresentDisplayOnly->BytesPerPixel, pPresentDisplayOnly->Pitch, pPresentDisplayOnly->NumMoves, pPresentDisplayOnly->pMoves, pPresentDisplayOnly->NumDirtyRects, pPresentDisplayOnly->pDirtyRect, RotationNeededByFb); } return STATUS_SUCCESS; } NTSTATUS BASIC_DISPLAY_DRIVER::StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo) { PAGED_CODE(); BDD_ASSERT(TargetId < MAX_CHILDREN); D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = FindSourceForTarget(TargetId, TRUE); // In case BDD is the next driver to run, the monitor should not be off, since // this could cause the BIOS to hang when the EDID is retrieved on Start. if (m_MonitorPowerState > PowerDeviceD0) { SetPowerState(TargetId, PowerDeviceD0, PowerActionNone); } // The driver has to black out the display and ensure it is visible when releasing ownership BlackOutScreen(SourceId); *pDisplayInfo = m_CurrentModes[SourceId].DispInfo; return StopDevice(); } NTSTATUS BASIC_DISPLAY_DRIVER::QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps) { PAGED_CODE(); BDD_ASSERT(pVidPnHWCaps != NULL); BDD_ASSERT(pVidPnHWCaps->SourceId < MAX_VIEWS); BDD_ASSERT(pVidPnHWCaps->TargetId < MAX_CHILDREN); pVidPnHWCaps->VidPnHWCaps.DriverRotation = 1; // BDD does rotation in software pVidPnHWCaps->VidPnHWCaps.DriverScaling = 0; // BDD does not support scaling pVidPnHWCaps->VidPnHWCaps.DriverCloning = 0; // BDD does not support clone pVidPnHWCaps->VidPnHWCaps.DriverColorConvert = 1; // BDD does color conversions in software pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0; // BDD does not support linked adapters pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay = 0; // BDD does not support remote displays return STATUS_SUCCESS; } NTSTATUS BASIC_DISPLAY_DRIVER::GetEdid(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId) { PAGED_CODE(); BDD_ASSERT_CHK(!m_Flags.EDID_Attempted); NTSTATUS Status = STATUS_SUCCESS; RtlZeroMemory(m_EDIDs[TargetId], sizeof(m_EDIDs[TargetId])); m_Flags.EDID_Attempted = TRUE; return Status; } VOID BASIC_DISPLAY_DRIVER::BlackOutScreen(D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId) { PAGED_CODE(); UINT ScreenHeight = m_CurrentModes[SourceId].DispInfo.Height; UINT ScreenPitch = m_CurrentModes[SourceId].DispInfo.Pitch; PHYSICAL_ADDRESS NewPhysAddrStart = m_CurrentModes[SourceId].DispInfo.PhysicAddress; PHYSICAL_ADDRESS NewPhysAddrEnd; NewPhysAddrEnd.QuadPart = NewPhysAddrStart.QuadPart + (ScreenHeight * ScreenPitch); if (m_CurrentModes[SourceId].Flags.FrameBufferIsActive) { BYTE* MappedAddr = reinterpret_cast<BYTE*>(m_CurrentModes[SourceId].FrameBuffer.Ptr); // Zero any memory at the start that hasn't been zeroed recently if (NewPhysAddrStart.QuadPart < m_CurrentModes[SourceId].ZeroedOutStart.QuadPart) { if (NewPhysAddrEnd.QuadPart < m_CurrentModes[SourceId].ZeroedOutStart.QuadPart) { // No overlap RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch); } else { RtlZeroMemory(MappedAddr, (UINT)(m_CurrentModes[SourceId].ZeroedOutStart.QuadPart - NewPhysAddrStart.QuadPart)); } } // Zero any memory at the end that hasn't been zeroed recently if (NewPhysAddrEnd.QuadPart > m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart) { if (NewPhysAddrStart.QuadPart > m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart) { // No overlap // NOTE: When actual pixels were the most recent thing drawn, ZeroedOutStart & ZeroedOutEnd will both be 0 // and this is the path that will be used to black out the current screen. RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch); } else { RtlZeroMemory(MappedAddr, (UINT)(NewPhysAddrEnd.QuadPart - m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart)); } } } m_CurrentModes[SourceId].ZeroedOutStart.QuadPart = NewPhysAddrStart.QuadPart; m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart = NewPhysAddrEnd.QuadPart; } NTSTATUS BASIC_DISPLAY_DRIVER::WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue) { PAGED_CODE(); NTSTATUS Status; ANSI_STRING AnsiStrValue; UNICODE_STRING UnicodeStrValue; UNICODE_STRING UnicodeStrValueName; // ZwSetValueKey wants the ValueName as a UNICODE_STRING RtlInitUnicodeString(&UnicodeStrValueName, pszwValueName); // REG_SZ is for WCHARs, there is no equivalent for CHARs // Use the ansi/unicode conversion functions to get from PSTR to PWSTR RtlInitAnsiString(&AnsiStrValue, pszValue); Status = RtlAnsiStringToUnicodeString(&UnicodeStrValue, &AnsiStrValue, TRUE); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR1("RtlAnsiStringToUnicodeString failed with Status: 0x%I64x", Status); return Status; } // Write the value to the registry Status = ZwSetValueKey(DevInstRegKeyHandle, &UnicodeStrValueName, 0, REG_SZ, UnicodeStrValue.Buffer, UnicodeStrValue.MaximumLength); // Free the earlier allocated unicode string RtlFreeUnicodeString(&UnicodeStrValue); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR1("ZwSetValueKey failed with Status: 0x%I64x", Status); } return Status; } NTSTATUS BASIC_DISPLAY_DRIVER::RegisterHWInfo() { PAGED_CODE(); NTSTATUS Status; // TODO: Replace these strings with proper information PCSTR StrHWInfoChipType = "Replace with the chip name"; PCSTR StrHWInfoDacType = "Replace with the DAC name or identifier (ID)"; PCSTR StrHWInfoAdapterString = "Replace with the name of the adapter"; PCSTR StrHWInfoBiosString = "Replace with information about the BIOS"; HANDLE DevInstRegKeyHandle; Status = IoOpenDeviceRegistryKey(m_pPhysicalDevice, PLUGPLAY_REGKEY_DRIVER, KEY_SET_VALUE, &DevInstRegKeyHandle); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("IoOpenDeviceRegistryKey failed for PDO: 0x%I64x, Status: 0x%I64x", m_pPhysicalDevice, Status); return Status; } Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.ChipType", StrHWInfoChipType); if (!NT_SUCCESS(Status)) { return Status; } Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.DacType", StrHWInfoDacType); if (!NT_SUCCESS(Status)) { return Status; } Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.AdapterString", StrHWInfoAdapterString); if (!NT_SUCCESS(Status)) { return Status; } Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.BiosString", StrHWInfoBiosString); if (!NT_SUCCESS(Status)) { return Status; } // MemorySize is a ULONG, unlike the others which are all strings UNICODE_STRING ValueNameMemorySize; RtlInitUnicodeString(&ValueNameMemorySize, L"HardwareInformation.MemorySize"); DWORD MemorySize = 0; // BDD has no access to video memory Status = ZwSetValueKey(DevInstRegKeyHandle, &ValueNameMemorySize, 0, REG_DWORD, &MemorySize, sizeof(MemorySize)); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR1("ZwSetValueKey for MemorySize failed with Status: 0x%I64x", Status); return Status; } return Status; } // // Non-Paged Code // #pragma code_seg(push) #pragma code_seg() D3DDDI_VIDEO_PRESENT_SOURCE_ID BASIC_DISPLAY_DRIVER::FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero) { UNREFERENCED_PARAMETER(TargetId); BDD_ASSERT_CHK(TargetId < MAX_CHILDREN); for (UINT SourceId = 0; SourceId < MAX_VIEWS; ++SourceId) { if (m_CurrentModes[SourceId].FrameBuffer.Ptr != NULL) { return SourceId; } } return DefaultToZero ? 0 : D3DDDI_ID_UNINITIALIZED; } VOID BASIC_DISPLAY_DRIVER::DpcRoutine(VOID) { m_DxgkInterface.DxgkCbNotifyDpc((HANDLE)m_DxgkInterface.DeviceHandle); } BOOLEAN BASIC_DISPLAY_DRIVER::InterruptRoutine(_In_ ULONG MessageNumber) { UNREFERENCED_PARAMETER(MessageNumber); // BDD cannot handle interrupts return FALSE; } VOID BASIC_DISPLAY_DRIVER::ResetDevice(VOID) { } // Must be Non-Paged, as it sets up the display for a bugcheck NTSTATUS BASIC_DISPLAY_DRIVER::SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, _Out_ UINT* pWidth, _Out_ UINT* pHeight, _Out_ D3DDDIFORMAT* pColorFormat) { UNREFERENCED_PARAMETER(Flags); m_SystemDisplaySourceId = D3DDDI_ID_UNINITIALIZED; BDD_ASSERT((TargetId < MAX_CHILDREN) || (TargetId == D3DDDI_ID_UNINITIALIZED)); // Find the frame buffer for displaying the bugcheck, if it was successfully mapped if (TargetId == D3DDDI_ID_UNINITIALIZED) { for (UINT SourceIdx = 0; SourceIdx < MAX_VIEWS; ++SourceIdx) { if (m_CurrentModes[SourceIdx].FrameBuffer.Ptr != NULL) { m_SystemDisplaySourceId = SourceIdx; break; } } } else { m_SystemDisplaySourceId = FindSourceForTarget(TargetId, FALSE); } if (m_SystemDisplaySourceId == D3DDDI_ID_UNINITIALIZED) { { return STATUS_UNSUCCESSFUL; } } if ((m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE90) || (m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE270)) { *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width; *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height; } else { *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width; *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height; } *pColorFormat = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat; return STATUS_SUCCESS; } // Must be Non-Paged, as it is called to display the bugcheck screen VOID BASIC_DISPLAY_DRIVER::SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource, _In_ UINT SourceWidth, _In_ UINT SourceHeight, _In_ UINT SourceStride, _In_ INT PositionX, _In_ INT PositionY) { // Rect will be Offset by PositionX/Y in the src to reset it back to 0 RECT Rect; Rect.left = PositionX; Rect.top = PositionY; Rect.right = Rect.left + SourceWidth; Rect.bottom = Rect.top + SourceHeight; // Set up destination blt info BLT_INFO DstBltInfo; DstBltInfo.pBits = m_CurrentModes[m_SystemDisplaySourceId].FrameBuffer.Ptr; DstBltInfo.Pitch = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Pitch; DstBltInfo.BitsPerPel = BPPFromPixelFormat(m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat); DstBltInfo.Offset.x = 0; DstBltInfo.Offset.y = 0; DstBltInfo.Rotation = m_CurrentModes[m_SystemDisplaySourceId].Rotation; DstBltInfo.Width = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width; DstBltInfo.Height = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height; // Set up source blt info BLT_INFO SrcBltInfo; SrcBltInfo.pBits = pSource; SrcBltInfo.Pitch = SourceStride; SrcBltInfo.BitsPerPel = 32; SrcBltInfo.Offset.x = -PositionX; SrcBltInfo.Offset.y = -PositionY; SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY; SrcBltInfo.Width = SourceWidth; SrcBltInfo.Height = SourceHeight; BltBits(&DstBltInfo, &SrcBltInfo, 1, // NumRects &Rect); } #pragma code_seg(pop) // End Non-Paged Code
C++程式檔案 bdd_ddi.cxx
/******************************Module*Header*******************************\ * Module Name: BDD_DDI.cxx * * Basic Display Driver DDI entry points redirects * * * Copyright (c) 2010 Microsoft Corporation \**************************************************************************/ #include "BDD.hxx" #pragma code_seg(push) #pragma code_seg("INIT") // BEGIN: Init Code // // Driver Entry point // 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; InitialData.DxgkDdiAddDevice = BddDdiAddDevice; InitialData.DxgkDdiStartDevice = BddDdiStartDevice; InitialData.DxgkDdiStopDevice = BddDdiStopDevice; InitialData.DxgkDdiResetDevice = BddDdiResetDevice; InitialData.DxgkDdiRemoveDevice = BddDdiRemoveDevice; InitialData.DxgkDdiDispatchIoRequest = BddDdiDispatchIoRequest; InitialData.DxgkDdiInterruptRoutine = BddDdiInterruptRoutine; InitialData.DxgkDdiDpcRoutine = BddDdiDpcRoutine; InitialData.DxgkDdiQueryChildRelations = BddDdiQueryChildRelations; InitialData.DxgkDdiQueryChildStatus = BddDdiQueryChildStatus; InitialData.DxgkDdiQueryDeviceDescriptor = BddDdiQueryDeviceDescriptor; InitialData.DxgkDdiSetPowerState = BddDdiSetPowerState; InitialData.DxgkDdiUnload = BddDdiUnload; InitialData.DxgkDdiQueryAdapterInfo = BddDdiQueryAdapterInfo; 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; InitialData.DxgkDdiQueryVidPnHWCapability = BddDdiQueryVidPnHWCapability; InitialData.DxgkDdiPresentDisplayOnly = BddDdiPresentDisplayOnly; InitialData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = BddDdiStopDeviceAndReleasePostDisplayOwnership; InitialData.DxgkDdiSystemDisplayEnable = BddDdiSystemDisplayEnable; InitialData.DxgkDdiSystemDisplayWrite = BddDdiSystemDisplayWrite; NTSTATUS Status = DxgkInitializeDisplayOnlyDriver(pDriverObject, pRegistryPath, &InitialData); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR1("DxgkInitializeDisplayOnlyDriver failed with Status: 0x%I64x", Status); return Status; } return Status; } // END: Init Code #pragma code_seg(pop) #pragma code_seg(push) #pragma code_seg("PAGE") // // PnP DDIs // VOID BddDdiUnload(VOID) { PAGED_CODE(); } 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; } 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); } 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); } // END: Non-Paged Code #pragma code_seg(pop)
C++程式檔案 bdd_dmm.cxx
/******************************Module*Header*******************************\ * Module Name: bdd_dmm.hxx * * Basic Display Driver display-mode management (DMM) function implementations * * * Copyright (c) 2010 Microsoft Corporation \**************************************************************************/ #include "BDD.hxx" #pragma code_seg("PAGE") // Display-Only Devices can only return display modes of D3DDDIFMT_A8R8G8B8. // Color conversion takes place if the app's fullscreen backbuffer has different format. // Full display drivers can add more if the hardware supports them. D3DDDIFORMAT gBddPixelFormats[] = { D3DDDIFMT_A8R8G8B8 }; // TODO: Need to also check pinned modes and the path parameters, not just topology NTSTATUS BASIC_DISPLAY_DRIVER::IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn) { PAGED_CODE(); BDD_ASSERT(pIsSupportedVidPn != NULL); if (pIsSupportedVidPn->hDesiredVidPn == 0) { // A null desired VidPn is supported pIsSupportedVidPn->IsVidPnSupported = TRUE; return STATUS_SUCCESS; } // Default to not supported, until shown it is supported pIsSupportedVidPn->IsVidPnSupported = FALSE; CONST DXGK_VIDPN_INTERFACE* pVidPnInterface; NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pIsSupportedVidPn->hDesiredVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hDesiredVidPn = 0x%I64x", Status, pIsSupportedVidPn->hDesiredVidPn); return Status; } D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology; CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface; Status = pVidPnInterface->pfnGetTopology(pIsSupportedVidPn->hDesiredVidPn, &hVidPnTopology, &pVidPnTopologyInterface); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hDesiredVidPn = 0x%I64x", Status, pIsSupportedVidPn->hDesiredVidPn); return Status; } // For every source in this topology, make sure they don't have more paths than there are targets for (D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = 0; SourceId < MAX_VIEWS; ++SourceId) { SIZE_T NumPathsFromSource = 0; Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, SourceId, &NumPathsFromSource); if (Status == STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY) { continue; } else if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR3("pfnGetNumPathsFromSource failed with Status = 0x%I64x. hVidPnTopology = 0x%I64x, SourceId = 0x%I64x", Status, hVidPnTopology, SourceId); return Status; } else if (NumPathsFromSource > MAX_CHILDREN) { // This VidPn is not supported, which has already been set as the default return STATUS_SUCCESS; } } // All sources succeeded so this VidPn is supported pIsSupportedVidPn->IsVidPnSupported = TRUE; return STATUS_SUCCESS; } NTSTATUS BASIC_DISPLAY_DRIVER::RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn) { PAGED_CODE(); BDD_ASSERT(pRecommendFunctionalVidPn == NULL); return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN; } NTSTATUS BASIC_DISPLAY_DRIVER::RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology) { PAGED_CODE(); BDD_ASSERT(pRecommendVidPnTopology == NULL); return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN; } NTSTATUS BASIC_DISPLAY_DRIVER::RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) { PAGED_CODE(); // This is always called to recommend modes for the monitor. The sample driver doesn't provide EDID for a monitor, so // the OS prefills the list with default monitor modes. Since the required mode might not be in the list, it should // be provided as a recommended mode. return AddSingleMonitorMode(pRecommendMonitorModes); } // Tell DMM about all the modes, etc. that are supported NTSTATUS BASIC_DISPLAY_DRIVER::EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality) { PAGED_CODE(); BDD_ASSERT(pEnumCofuncModality != NULL); D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0; D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0; D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet = 0; CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL; CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL; CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL; CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface = NULL; CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL; CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPathTemp = NULL; // Used for AcquireNextPathInfo CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo = NULL; CONST D3DKMDT_VIDPN_TARGET_MODE* pVidPnPinnedTargetModeInfo = NULL; // Get the VidPn Interface so we can get the 'Source Mode Set', 'Target Mode Set' and 'VidPn Topology' interfaces NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pEnumCofuncModality->hConstrainingVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn); return Status; } // Get the VidPn Topology interface so we can enumerate all paths Status = pVidPnInterface->pfnGetTopology(pEnumCofuncModality->hConstrainingVidPn, &hVidPnTopology, &pVidPnTopologyInterface); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn); return Status; } // Get the first path before we start looping through them Status = pVidPnTopologyInterface->pfnAcquireFirstPathInfo(hVidPnTopology, &pVidPnPresentPath); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("pfnAcquireFirstPathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology); return Status; } // Loop through all available paths. while (Status != STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET) { // Get the Source Mode Set interface so the pinned mode can be retrieved Status = pVidPnInterface->pfnAcquireSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, &hVidPnSourceModeSet, &pVidPnSourceModeSetInterface); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR3("pfnAcquireSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId); break; } // Get the pinned mode, needed when VidPnSource isn't pivot, and when VidPnTarget isn't pivot Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pVidPnPinnedSourceModeInfo); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet); break; } // SOURCE MODES: If this source mode isn't the pivot point, do work on the source mode set if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNSOURCE) && (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId))) { // If there's no pinned source add possible modes (otherwise they've already been added) if (pVidPnPinnedSourceModeInfo == NULL) { // Release the acquired source mode set, since going to create a new one to put all modes in Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR3("pfnReleaseSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); break; } hVidPnSourceModeSet = 0; // Successfully released it // Create a new source mode set which will be added to the constraining VidPn with all the possible modes Status = pVidPnInterface->pfnCreateNewSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, &hVidPnSourceModeSet, &pVidPnSourceModeSetInterface); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR3("pfnCreateNewSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId); break; } // Add the appropriate modes to the source mode set { Status = AddSingleSourceMode(pVidPnSourceModeSetInterface, hVidPnSourceModeSet, pVidPnPresentPath->VidPnSourceId); } if (!NT_SUCCESS(Status)) { break; } // Give DMM back the source modes just populated Status = pVidPnInterface->pfnAssignSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR4("pfnAssignSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet); break; } hVidPnSourceModeSet = 0; // Successfully assigned it (equivalent to releasing it) } }// End: SOURCE MODES // TARGET MODES: If this target mode isn't the pivot point, do work on the target mode set if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNTARGET) && (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId))) { // Get the Target Mode Set interface so modes can be added if necessary Status = pVidPnInterface->pfnAcquireTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, &hVidPnTargetModeSet, &pVidPnTargetModeSetInterface); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR3("pfnAcquireTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId); break; } Status = pVidPnTargetModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnTargetModeSet, &pVidPnPinnedTargetModeInfo); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet); break; } // If there's no pinned target add possible modes (otherwise they've already been added) if (pVidPnPinnedTargetModeInfo == NULL) { // Release the acquired target mode set, since going to create a new one to put all modes in Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); if (!NT_SUCCESS(Status)) { BDD_LOG_ASSERTION3("pfnReleaseTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); break; } hVidPnTargetModeSet = 0; // Successfully released it // Create a new target mode set which will be added to the constraining VidPn with all the possible modes Status = pVidPnInterface->pfnCreateNewTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, &hVidPnTargetModeSet, &pVidPnTargetModeSetInterface); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR3("pfnCreateNewTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId); break; } Status = AddSingleTargetMode(pVidPnTargetModeSetInterface, hVidPnTargetModeSet, pVidPnPinnedSourceModeInfo, pVidPnPresentPath->VidPnSourceId); if (!NT_SUCCESS(Status)) { break; } // Give DMM back the source modes just populated Status = pVidPnInterface->pfnAssignTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR4("pfnAssignTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet); break; } hVidPnTargetModeSet = 0; // Successfully assigned it (equivalent to releasing it) } else { // Release the pinned target as there's no other work to do Status = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo); if (!NT_SUCCESS(Status)) { BDD_LOG_ASSERTION3("pfnReleaseModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnPinnedTargetModeInfo = 0x%I64x", Status, hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo); break; } pVidPnPinnedTargetModeInfo = NULL; // Successfully released it // Release the acquired target mode set, since it is no longer needed Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); if (!NT_SUCCESS(Status)) { BDD_LOG_ASSERTION3("pfnReleaseTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); break; } hVidPnTargetModeSet = 0; // Successfully released it } }// End: TARGET MODES // Nothing else needs the pinned source mode so release it if (pVidPnPinnedSourceModeInfo != NULL) { Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo); if (!NT_SUCCESS(Status)) { BDD_LOG_ASSERTION3("pfnReleaseModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnPinnedSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo); break; } pVidPnPinnedSourceModeInfo = NULL; // Successfully released it } // With the pinned source mode now released, if the source mode set hasn't been released, release that as well if (hVidPnSourceModeSet != 0) { Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR3("pfnReleaseSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); break; } hVidPnSourceModeSet = 0; // Successfully released it } // If modifying support fields, need to modify a local version of a path structure since the retrieved one is const D3DKMDT_VIDPN_PRESENT_PATH LocalVidPnPresentPath = *pVidPnPresentPath; BOOLEAN SupportFieldsModified = FALSE; // SCALING: If this path's scaling isn't the pivot point, do work on the scaling support if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_SCALING) && (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) && (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId))) { // If the scaling is unpinned, then modify the scaling support field if (pVidPnPresentPath->ContentTransformation.Scaling == D3DKMDT_VPPS_UNPINNED) { // Identity and centered scaling are supported, but not any stretch modes RtlZeroMemory(&(LocalVidPnPresentPath.ContentTransformation.ScalingSupport), sizeof(D3DKMDT_VIDPN_PRESENT_PATH_SCALING_SUPPORT)); LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Identity = 1; LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Centered = 1; SupportFieldsModified = TRUE; } } // End: SCALING // ROTATION: If this path's rotation isn't the pivot point, do work on the rotation support if (!((pEnumCofuncModality->EnumPivotType != D3DKMDT_EPT_ROTATION) && (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) && (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId))) { // If the rotation is unpinned, then modify the rotation support field if (pVidPnPresentPath->ContentTransformation.Rotation == D3DKMDT_VPPR_UNPINNED) { LocalVidPnPresentPath.ContentTransformation.RotationSupport.Identity = 1; // Sample supports only Rotate90 LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate90 = 1; LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate180 = 0; LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate270 = 0; // Since clone is not supported, should not support path-independent rotations LocalVidPnPresentPath.ContentTransformation.RotationSupport.Offset0 = 1; SupportFieldsModified = TRUE; } } // End: ROTATION if (SupportFieldsModified) { // The correct path will be found by this function and the appropriate fields updated Status = pVidPnTopologyInterface->pfnUpdatePathSupportInfo(hVidPnTopology, &LocalVidPnPresentPath); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("pfnUpdatePathSupportInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology); break; } } // Get the next path... // (NOTE: This is the value of Status that will return STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET when it's time to quit the loop) pVidPnPresentPathTemp = pVidPnPresentPath; Status = pVidPnTopologyInterface->pfnAcquireNextPathInfo(hVidPnTopology, pVidPnPresentPathTemp, &pVidPnPresentPath); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR3("pfnAcquireNextPathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", Status, hVidPnTopology, pVidPnPresentPathTemp); break; } // ...and release the last path NTSTATUS TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp); if (!NT_SUCCESS(TempStatus)) { BDD_LOG_ERROR3("pfnReleasePathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", TempStatus, hVidPnTopology, pVidPnPresentPathTemp); Status = TempStatus; break; } pVidPnPresentPathTemp = NULL; // Successfully released it }// End: while loop for paths in topology // If quit the while loop normally, set the return value to success if (Status == STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET) { Status = STATUS_SUCCESS; } // Release any resources hanging around because the loop was quit early. // Since in normal execution everything should be released by this point, TempStatus is initialized to a bogus error to be used as an // assertion that if anything had to be released now (TempStatus changing) Status isn't successful. NTSTATUS TempStatus = STATUS_NOT_FOUND; if ((pVidPnSourceModeSetInterface != NULL) && (pVidPnPinnedSourceModeInfo != NULL)) { TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo); BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); } if ((pVidPnTargetModeSetInterface != NULL) && (pVidPnPinnedTargetModeInfo != NULL)) { TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo); BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); } if (pVidPnPresentPath != NULL) { TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath); BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); } if (pVidPnPresentPathTemp != NULL) { TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp); BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); } if (hVidPnSourceModeSet != 0) { TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); } if (hVidPnTargetModeSet != 0) { TempStatus = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); BDD_ASSERT_CHK(NT_SUCCESS(TempStatus)); } BDD_ASSERT_CHK(TempStatus == STATUS_NOT_FOUND || Status != STATUS_SUCCESS); return Status; } NTSTATUS BASIC_DISPLAY_DRIVER::SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility) { PAGED_CODE(); BDD_ASSERT(pSetVidPnSourceVisibility != NULL); BDD_ASSERT((pSetVidPnSourceVisibility->VidPnSourceId < MAX_VIEWS) || (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL)); UINT StartVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? 0 : pSetVidPnSourceVisibility->VidPnSourceId; UINT MaxVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? MAX_VIEWS : pSetVidPnSourceVisibility->VidPnSourceId + 1; for (UINT SourceId = StartVidPnSourceId; SourceId < MaxVidPnSourceId; ++SourceId) { if (pSetVidPnSourceVisibility->Visible) { m_CurrentModes[SourceId].Flags.FullscreenPresent = TRUE; } else { BlackOutScreen(SourceId); } // Store current visibility so it can be dealt with during Present call m_CurrentModes[SourceId].Flags.SourceNotVisible = !(pSetVidPnSourceVisibility->Visible); } return STATUS_SUCCESS; } // NOTE: The value of pCommitVidPn->MonitorConnectivityChecks is ignored, since BDD is unable to recognize whether a monitor is connected or not // The value of pCommitVidPn->hPrimaryAllocation is also ignored, since BDD is a display only driver and does not deal with allocations NTSTATUS BASIC_DISPLAY_DRIVER::CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn) { PAGED_CODE(); BDD_ASSERT(pCommitVidPn != NULL); BDD_ASSERT(pCommitVidPn->AffectedVidPnSourceId < MAX_VIEWS); NTSTATUS Status; SIZE_T NumPaths = 0; D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0; D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0; CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL; CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL; CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL; CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL; CONST D3DKMDT_VIDPN_SOURCE_MODE* pPinnedVidPnSourceModeInfo = NULL; // Check this CommitVidPn is for the mode change notification when monitor is in power off state. if (pCommitVidPn->Flags.PathPoweredOff) { // Ignore the commitVidPn call for the mode change notification when monitor is in power off state. Status = STATUS_SUCCESS; goto CommitVidPnExit; } // Get the VidPn Interface so we can get the 'Source Mode Set' and 'VidPn Topology' interfaces Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pCommitVidPn->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn); goto CommitVidPnExit; } // Get the VidPn Topology interface so can enumerate paths from source Status = pVidPnInterface->pfnGetTopology(pCommitVidPn->hFunctionalVidPn, &hVidPnTopology, &pVidPnTopologyInterface); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn); goto CommitVidPnExit; } // Find out the number of paths now, if it's 0 don't bother with source mode set and pinned mode, just clear current and then quit Status = pVidPnTopologyInterface->pfnGetNumPaths(hVidPnTopology, &NumPaths); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("pfnGetNumPaths failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology); goto CommitVidPnExit; } if (NumPaths != 0) { // Get the Source Mode Set interface so we can get the pinned mode Status = pVidPnInterface->pfnAcquireSourceModeSet(pCommitVidPn->hFunctionalVidPn, pCommitVidPn->AffectedVidPnSourceId, &hVidPnSourceModeSet, &pVidPnSourceModeSetInterface); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR3("pfnAcquireSourceModeSet failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x, SourceId = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn, pCommitVidPn->AffectedVidPnSourceId); goto CommitVidPnExit; } // Get the mode that is being pinned Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pPinnedVidPnSourceModeInfo); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn); goto CommitVidPnExit; } } else { // This will cause the successful quit below pPinnedVidPnSourceModeInfo = NULL; } if (m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr && !m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.DoNotMapOrUnmap) { Status = UnmapFrameBuffer(m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr, m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Pitch * m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Height); m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr = NULL; m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.FrameBufferIsActive = FALSE; if (!NT_SUCCESS(Status)) { goto CommitVidPnExit; } } if (pPinnedVidPnSourceModeInfo == NULL) { // There is no mode to pin on this source, any old paths here have already been cleared Status = STATUS_SUCCESS; goto CommitVidPnExit; } Status = IsVidPnSourceModeFieldsValid(pPinnedVidPnSourceModeInfo); if (!NT_SUCCESS(Status)) { goto CommitVidPnExit; } // Get the number of paths from this source so we can loop through all paths SIZE_T NumPathsFromSource = 0; Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, &NumPathsFromSource); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR2("pfnGetNumPathsFromSource failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology); goto CommitVidPnExit; } // Loop through all paths to set this mode for (SIZE_T PathIndex = 0; PathIndex < NumPathsFromSource; ++PathIndex) { // Get the target id for this path D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId = D3DDDI_ID_UNINITIALIZED; Status = pVidPnTopologyInterface->pfnEnumPathTargetsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex, &TargetId); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR4("pfnEnumPathTargetsFromSource failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, PathIndex = 0x%I64x", Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex); goto CommitVidPnExit; } // Get the actual path info Status = pVidPnTopologyInterface->pfnAcquirePathInfo(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId, &pVidPnPresentPath); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR4("pfnAcquirePathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, TargetId = 0x%I64x", Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId); goto CommitVidPnExit; } Status = IsVidPnPathFieldsValid(pVidPnPresentPath); if (!NT_SUCCESS(Status)) { goto CommitVidPnExit; } Status = SetSourceModeAndPath(pPinnedVidPnSourceModeInfo, pVidPnPresentPath); if (!NT_SUCCESS(Status)) { goto CommitVidPnExit; } Status = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath); if (!NT_SUCCESS(Status)) { BDD_LOG_ERROR3("pfnReleasePathInfo failed with Status = 0x%I64x, hVidPnTopoogy = 0x%I64x, pVidPnPresentPath = 0x%I64x", Status, hVidPnTopology, pVidPnPresentPath); goto CommitVidPnExit; } pVidPnPresentPath = NULL; // Successfully released it } CommitVidPnExit: NTSTATUS TempStatus; if ((pVidPnSourceModeSetInterface != NULL) && (hVidPnSourceModeSet != 0) && (pPinnedVidPnSourceModeInfo != NULL)) { TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pPinnedVidPnSourceModeInfo); NT_ASSERT(NT_SUCCESS(TempStatus)); } if ((pVidPnInterface != NULL) && (pCommitVidPn->hFunctionalVidPn != 0) && (hVidPnSourceModeSet != 0)) { TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pCommitVidPn->hFunctionalVidPn, hVidPnSourceModeSet); NT_ASSERT(NT_SUCCESS(TempStatus)); } if ((pVidPnTopologyInterface != NULL) && (hVidPnTopology != 0) && (pVidPnPresentPath != NULL)) { TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath); NT_ASSERT(NT_SUCCESS(TempStatus)); } return Status; } NTSTATUS BASIC_DISPLAY_DRIVER::UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath) { PAGED_CODE(); BDD_ASSERT(pUpdateActiveVidPnPresentPath != NULL); NTSTATUS Status = IsVidPnPathFieldsValid(&(pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo)); if (!NT_SUCCESS(Status)) { return Status; } // Mark the next present as fullscreen to make sure the full rotation comes through m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Flags.FullscreenPresent = TRUE; m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Rotation = pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.ContentTransformation.Rotation; return STATUS_SUCCESS; } // // Private BDD DMM functions // NTSTATUS BASIC_DISPLAY_DRIVER::SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode, CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) { PAGED_CODE(); CURRENT_BDD_MODE* pCurrentBddMode = &m_CurrentModes[pPath->VidPnSourceId]; NTSTATUS Status = STATUS_SUCCESS; pCurrentBddMode->Scaling = pPath->ContentTransformation.Scaling; pCurrentBddMode->SrcModeWidth = pSourceMode->Format.Graphics.PrimSurfSize.cx; pCurrentBddMode->SrcModeHeight = pSourceMode->Format.Graphics.PrimSurfSize.cy; pCurrentBddMode->Rotation = pPath->ContentTransformation.Rotation; if (!pCurrentBddMode->Flags.DoNotMapOrUnmap) { // Map the new frame buffer BDD_ASSERT(pCurrentBddMode->FrameBuffer.Ptr == NULL); Status = MapFrameBuffer(pCurrentBddMode->DispInfo.PhysicAddress, pCurrentBddMode->DispInfo.Pitch * pCurrentBddMode->DispInfo.Height, &(pCurrentBddMode->FrameBuffer.Ptr)); } if (NT_SUCCESS(Status)) { pCurrentBddMode->Flags.FrameBufferIsActive = TRUE; BlackOutScreen(pPath->VidPnSourceId); // Mark that the next present should be fullscreen so the screen doesn't go from black to actual pixels one dirty rect at a time. pCurrentBddMode->Flags.FullscreenPresent = TRUE; } return Status; } NTSTATUS BASIC_DISPLAY_DRIVER::IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const { PAGED_CODE(); if (pPath->VidPnSourceId >= MAX_VIEWS) { BDD_LOG_ERROR2("VidPnSourceId is 0x%I64x is too high (MAX_VIEWS is 0x%I64x)", pPath->VidPnSourceId, MAX_VIEWS); return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE; } else if (pPath->VidPnTargetId >= MAX_CHILDREN) { BDD_LOG_ERROR2("VidPnTargetId is 0x%I64x is too high (MAX_CHILDREN is 0x%I64x)", pPath->VidPnTargetId, MAX_CHILDREN); return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET; } else if (pPath->GammaRamp.Type != D3DDDI_GAMMARAMP_DEFAULT) { BDD_LOG_ERROR1("pPath contains a gamma ramp (0x%I64x)", pPath->GammaRamp.Type); return STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED; } else if ((pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_IDENTITY) && (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_CENTERED) && (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_NOTSPECIFIED) && (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_UNINITIALIZED)) { BDD_LOG_ERROR1("pPath contains a non-identity scaling (0x%I64x)", pPath->ContentTransformation.Scaling); return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED; } else if ((pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_IDENTITY) && (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_ROTATE90) && (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_NOTSPECIFIED) && (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_UNINITIALIZED)) { BDD_LOG_ERROR1("pPath contains a not-supported rotation (0x%I64x)", pPath->ContentTransformation.Rotation); return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED; } else if ((pPath->VidPnTargetColorBasis != D3DKMDT_CB_SCRGB) && (pPath->VidPnTargetColorBasis != D3DKMDT_CB_UNINITIALIZED)) { BDD_LOG_ERROR1("pPath has a non-linear RGB color basis (0x%I64x)", pPath->VidPnTargetColorBasis); return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; } else { return STATUS_SUCCESS; } } NTSTATUS BASIC_DISPLAY_DRIVER::IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const { PAGED_CODE(); if (pSourceMode->Type != D3DKMDT_RMT_GRAPHICS) { BDD_LOG_ERROR1("pSourceMode is a non-graphics mode (0x%I64x)", pSourceMode->Type); return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; } else if ((pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_SCRGB) && (pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_UNINITIALIZED)) { BDD_LOG_ERROR1("pSourceMode has a non-linear RGB color basis (0x%I64x)", pSourceMode->Format.Graphics.ColorBasis); return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; } else if (pSourceMode->Format.Graphics.PixelValueAccessMode != D3DKMDT_PVAM_DIRECT) { BDD_LOG_ERROR1("pSourceMode has a palettized access mode (0x%I64x)", pSourceMode->Format.Graphics.PixelValueAccessMode); return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; } else { for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx) { if (pSourceMode->Format.Graphics.PixelFormat == gBddPixelFormats[PelFmtIdx]) { return STATUS_SUCCESS; } } BDD_LOG_ERROR1("pSourceMode has an unknown pixel format (0x%I64x)", pSourceMode->Format.Graphics.PixelFormat); return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; } } // Add more mode from the table. struct SampleSourceMode { UINT ModeWidth; UINT ModeHeight; }; // The driver will advertise all modes that fit within the actual required mode (see AddSingleSourceMode below) const static SampleSourceMode C_SampleSourceMode[] = {{800,600},{1024,768},{1152,864},{1280,800},{1280,1024},{1400,1050},{1600,1200},{1680,1050},{1920,1200}}; const static UINT C_SampleSourceModeMax = sizeof(C_SampleSourceMode)/sizeof(C_SampleSourceMode[0]); NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface, D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet, D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId) { PAGED_CODE(); // There is only one source format supported by display-only drivers, but more can be added in a // full WDDM driver if the hardware supports them for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx) { // Create new mode info that will be populated D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL; NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo); if (!NT_SUCCESS(Status)) { // If failed to create a new mode info, mode doesn't need to be released since it was never created BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet); return Status; } // Populate mode info with values from current mode and hard-coded values // Always report 32 bpp format, this will be color converted during the present if the mode is < 32bpp pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS; pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = m_CurrentModes[SourceId].DispInfo.Width; pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = m_CurrentModes[SourceId].DispInfo.Height; pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize; pVidPnSourceModeInfo->Format.Graphics.Stride = m_CurrentModes[SourceId].DispInfo.Pitch; pVidPnSourceModeInfo->Format.Graphics.PixelFormat = gBddPixelFormats[PelFmtIdx]; pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB; pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT; // Add the mode to the source mode set Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo); if (!NT_SUCCESS(Status)) { // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked NTSTATUS TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo); UNREFERENCED_PARAMETER(TempStatus); NT_ASSERT(NT_SUCCESS(TempStatus)); if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) { BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo); return Status; } } } UINT WidthMax = m_CurrentModes[SourceId].DispInfo.Width; UINT HeightMax = m_CurrentModes[SourceId].DispInfo.Height; // Add all predefined modes that fit within the bounds of the required (POST) mode for (UINT ModeIndex = 0; ModeIndex < C_SampleSourceModeMax; ++ModeIndex) { if (C_SampleSourceMode[ModeIndex].ModeWidth > WidthMax) { break; } else if (C_SampleSourceMode[ModeIndex].ModeWidth == WidthMax) { if(C_SampleSourceMode[ModeIndex].ModeHeight >= HeightMax) { break; } } else { if(C_SampleSourceMode[ModeIndex].ModeHeight > HeightMax) { continue; } } // There is only one source format supported by display-only drivers, but more can be added in a // full WDDM driver if the hardware supports them for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx) { // Create new mode info that will be populated D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL; NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo); if (!NT_SUCCESS(Status)) { // If failed to create a new mode info, continuing to the next mode and trying again isn't going to be at all helpful, so return // Also, mode doesn't need to be released since it was never created BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet); return Status; } // Populate mode info with values from mode at ModeIndex and hard-coded values // Always report 32 bpp format, this will be color converted during the present if the mode at ModeIndex was < 32bpp pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS; pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = C_SampleSourceMode[ModeIndex].ModeWidth; pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = C_SampleSourceMode[ModeIndex].ModeHeight; pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize; pVidPnSourceModeInfo->Format.Graphics.Stride = 4*C_SampleSourceMode[ModeIndex].ModeWidth; pVidPnSourceModeInfo->Format.Graphics.PixelFormat = gBddPixelFormats[PelFmtIdx]; pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB; pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT; // Add the mode to the source mode set Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo); if (!NT_SUCCESS(Status)) { if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) { BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo); } // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked, continue to next mode anyway Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo); BDD_ASSERT_CHK(NT_SUCCESS(Status)); } } } return STATUS_SUCCESS; } // Add the current mode information (acquired from the POST frame buffer) as the target mode. NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface, D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet, _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo, D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId) { PAGED_CODE(); D3DKMDT_VIDPN_TARGET_MODE* pVidPnTargetModeInfo = NULL; NTSTATUS Status = pVidPnTargetModeSetInterface->pfnCreateNewModeInfo(hVidPnTargetModeSet, &pVidPnTargetModeInfo); if (!NT_SUCCESS(Status)) { // If failed to create a new mode info, mode doesn't need to be released since it was never created BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet); return Status; } pVidPnTargetModeInfo->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER; UNREFERENCED_PARAMETER(pVidPnPinnedSourceModeInfo); pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cx = m_CurrentModes[SourceId].DispInfo.Width; pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cy = m_CurrentModes[SourceId].DispInfo.Height; pVidPnTargetModeInfo->VideoSignalInfo.ActiveSize = pVidPnTargetModeInfo->VideoSignalInfo.TotalSize; pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; pVidPnTargetModeInfo->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED; pVidPnTargetModeInfo->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE; // We add this as PREFERRED since it is the only supported target pVidPnTargetModeInfo->Preference = D3DKMDT_MP_PREFERRED; Status = pVidPnTargetModeSetInterface->pfnAddMode(hVidPnTargetModeSet, pVidPnTargetModeInfo); if (!NT_SUCCESS(Status)) { if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) { BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnTargetModeInfo = 0x%I64x", Status, hVidPnTargetModeSet, pVidPnTargetModeInfo); } else { Status = STATUS_SUCCESS; } // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked NTSTATUS TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnTargetModeInfo); UNREFERENCED_PARAMETER(TempStatus); NT_ASSERT(NT_SUCCESS(TempStatus)); return Status; } else { // If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up return STATUS_SUCCESS; } } NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) { PAGED_CODE(); D3DKMDT_MONITOR_SOURCE_MODE* pMonitorSourceMode = NULL; NTSTATUS Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnCreateNewModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, &pMonitorSourceMode); if (!NT_SUCCESS(Status)) { // If failed to create a new mode info, mode doesn't need to be released since it was never created BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet); return Status; } D3DDDI_VIDEO_PRESENT_SOURCE_ID CorrespondingSourceId = FindSourceForTarget(pRecommendMonitorModes->VideoPresentTargetId, TRUE); // Since we don't know the real monitor timing information, just use the current display mode (from the POST device) with unknown frequencies pMonitorSourceMode->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER; pMonitorSourceMode->VideoSignalInfo.TotalSize.cx = m_CurrentModes[CorrespondingSourceId].DispInfo.Width; pMonitorSourceMode->VideoSignalInfo.TotalSize.cy = m_CurrentModes[CorrespondingSourceId].DispInfo.Height; pMonitorSourceMode->VideoSignalInfo.ActiveSize = pMonitorSourceMode->VideoSignalInfo.TotalSize; pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; pMonitorSourceMode->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED; pMonitorSourceMode->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE; // We set the preference to PREFERRED since this is the only supported mode pMonitorSourceMode->Origin = D3DKMDT_MCO_DRIVER; pMonitorSourceMode->Preference = D3DKMDT_MP_PREFERRED; pMonitorSourceMode->ColorBasis = D3DKMDT_CB_SRGB; pMonitorSourceMode->ColorCoeffDynamicRanges.FirstChannel = 8; pMonitorSourceMode->ColorCoeffDynamicRanges.SecondChannel = 8; pMonitorSourceMode->ColorCoeffDynamicRanges.ThirdChannel = 8; pMonitorSourceMode->ColorCoeffDynamicRanges.FourthChannel = 8; Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnAddMode(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); if (!NT_SUCCESS(Status)) { if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) { BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x, pMonitorSourceMode = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); } else { Status = STATUS_SUCCESS; } // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked NTSTATUS TempStatus = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnReleaseModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); UNREFERENCED_PARAMETER(TempStatus); NT_ASSERT(NT_SUCCESS(TempStatus)); return Status; } else { // If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up return STATUS_SUCCESS; } }
C++程式檔案 bdd_util.cxx
/******************************Module*Header*******************************\ * Module Name: bdd_util.cxx * * Basic Display Driver utility functions * * Created: 29-Mar-2011 * Author: Amos Eshel [amosesh] * * Copyright (c) 2011 Microsoft Corporation \**************************************************************************/ #include "BDD.hxx" #pragma code_seg("PAGE") // // EDID validation // BOOLEAN IsEdidHeaderValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid) { PAGED_CODE(); static const UCHAR EDID1Header[8] = {0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0}; return memcmp(pEdid, EDID1Header, sizeof(EDID1Header)) == 0; } BOOLEAN IsEdidChecksumValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid) { PAGED_CODE(); BYTE CheckSum = 0; for (const BYTE* pEdidStart = pEdid; pEdidStart < (pEdid + EDID_V1_BLOCK_SIZE); ++pEdidStart) { CheckSum += *pEdidStart; } return CheckSum == 0; } // // Frame buffer map/unmap // NTSTATUS MapFrameBuffer( _In_ PHYSICAL_ADDRESS PhysicalAddress, _In_ ULONG Length, _Outptr_result_bytebuffer_(Length) VOID** VirtualAddress) { PAGED_CODE(); // // Check for parameters // if ((PhysicalAddress.QuadPart == (ULONGLONG)0) || (Length == 0) || (VirtualAddress == NULL)) { BDD_LOG_ERROR3("One of PhysicalAddress.QuadPart (0x%I64x), Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0", PhysicalAddress.QuadPart, Length, VirtualAddress); return STATUS_INVALID_PARAMETER; } *VirtualAddress = MmMapIoSpaceEx(PhysicalAddress, Length, PAGE_READWRITE | PAGE_WRITECOMBINE); if (*VirtualAddress == NULL) { // The underlying call to MmMapIoSpace failed. This may be because, MmWriteCombined // isn't supported, so try again with MmNonCached *VirtualAddress = MmMapIoSpaceEx(PhysicalAddress, Length, PAGE_READWRITE | PAGE_NOCACHE); if (*VirtualAddress == NULL) { BDD_LOG_LOW_RESOURCE1("MmMapIoSpace returned a NULL buffer when trying to allocate 0x%I64x bytes", Length); return STATUS_NO_MEMORY; } } return STATUS_SUCCESS; } NTSTATUS UnmapFrameBuffer( _In_reads_bytes_(Length) VOID* VirtualAddress, _In_ ULONG Length) { PAGED_CODE(); // // Check for parameters // if ((VirtualAddress == NULL) && (Length == 0)) { // Allow this function to be called when there's no work to do, and treat as successful return STATUS_SUCCESS; } else if ((VirtualAddress == NULL) || (Length == 0)) { BDD_LOG_ERROR2("Only one of Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0", Length, VirtualAddress); return STATUS_INVALID_PARAMETER; } MmUnmapIoSpace(VirtualAddress, Length); return STATUS_SUCCESS; }
最後找出diagnostic tool關於 video & graphic card部分的測試
參考文章:
微軟 Getting started with Windows drivers
Steward
小z说:内核驱动的编译环境
VS2012开发驱动小Tip之:更改KMDF版本以支持XP系统