* 前情提要之本文另一篇: 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系统