下面这幅图显示了关于WDDM从渲染设备的创建一直到内容最终被显示的整个流程。详细的调用顺序我们可以参看下面的描述。
1, 当一个应用程序请求创建了一个渲染设备,显示的小端口驱动会接收到DxgkDdiCreateDevice的调用。下面给出其MSDN中的
定义。
PDXGKDDI_CREATEDEVICE DxgkDdiCreateDevice;
NTSTATUS APIENTRY DxgkDdiCreateDevice(
_In_ const HANDLE hAdapter,
_Inout_ DXGKARG_CREATEDEVICE *pCreateDevice
)
这个函数一看,就是创建一个设备,写过驱动的都应该知道,这个其实就相当于设备对象。这个hAdapter是我们小端口驱动的于谦提
供给DirectX图形子系统的,在DxgkDdiAddDevice函数的MiniportDeviceContext这个输出参数。具体的显示的小端口驱动在里面初始
化DMA,并返回一个填充DXGKARG_CREATEDEVICE结构体的指向DXGK_DEVICEINFO结构体的pInfo成员指针指针。
下面给出这两个结构的说明
typedef struct _DXGKARG_CREATEDEVICE {
HANDLE hDevice;
union {
DXGK_CREATEDEVICEFLAGS Flags;
DXGK_DEVICEINFO *pInfo;
};
} DXGKARG_CREATEDEVICE;
typedef struct _DXGK_DEVICEINFO {
UINT DmaBufferSize;
UINT DmaBufferSegmentSet;
UINT DmaBufferPrivateDataSize;
UINT AllocationListSize;
UINT PatchLocationListSize;
DXGK_DEVICEINFOFLAGS Flags;
} DXGK_DEVICEINFO;
2, 如果调用DxgDdiCreateDevice成功,实时Direct3D引擎会调用用户模式驱动的CreateDevice函数。下面给出MSDN中的定义
PFND3DDDI_CREATEDEVICE CreateDevice;
__checkReturn HRESULT APIENTRY CreateDevice(
_In_ HANDLE hAdapter,
_Inout_ D3DDDIARG_CREATEDEVICE *pCreateData
)
在这个调用中创建一个图形上下文
typedef struct _D3DDDIARG_CREATEDEVICE {
HANDLE hDevice;
UINT Interface;
UINT Version;
const D3DDDI_DEVICECALLBACKS *pCallbacks;
VOID *pCommandBuffer;
UINT CommandBufferSize;
D3DDDI_ALLOCATIONLIST *pAllocationList;
UINT AllocationListSize;
D3DDDI_PATCHLOCATIONLIST *pPatchLocationList;
UINT PatchLocationListSize;
D3DDDI_DEVICEFUNCS *pDeviceFuncs;
D3DDDI_CREATEDEVICEFLAGS Flags;
#if (D3D_UMD_INTERFACE_VERSION >= D3D_UMD_INTERFACE_VERSION_WIN7)
D3DGPU_VIRTUAL_ADDRESS CommandBuffer;
#endif
} D3DDDIARG_CREATEDEVICE;
我们可以了解一下这个输入输出参数,我们可以得到,或者设置这个参数,一般在Direct3D中对其进行设置。
3, 在CreateDevice调用中,用户模式显示驱动必须调用pfnCreateContextCb函数为新创建的设备创建一个或多个GPU执行线程
。实时Direct3D返回D3DDDICB_CREATECONTEX结构体中的pCommandBuffer和CommandBufferSize成员,用来初始化command buffer.下
面给出MSDN的结构体说明
typedef struct _D3DDDICB_CREATECONTEXT {
UINT NodeOrdinal;
UINT EngineAffinity;
D3DDDI_CREATECONTEXTFLAGS Flags;
VOID *pPrivateDriverData;
UINT PrivateDriverDataSize;
HANDLE hContext;
VOID *pCommandBuffer;
UINT CommandBufferSize;
D3DDDI_ALLOCATIONLIST *pAllocationList;
UINT AllocationListSize;
D3DDDI_PATCHLOCATIONLIST *pPatchLocationList;
UINT PatchLocationListSize;
#if D3D_UMD_INTERFACE_VERSION >= D3D_UMD_INTERFACE_VERSION_WIN7
D3DGPU_VIRTUAL_ADDRESS CommandBuffer;
#endif
} D3DDDICB_CREATECONTEXT;
为设备创建接口
4,在应用程序发出请求为渲染设备创建接口后,实时Direct3D就调用用户模式显示驱动的
CreateResource函数。
5,用户模式显示驱动的CreateResource函数调用pfnAllocateCb实时函数.
6,内核模式显示的小端口驱动会接收到DxgkDdiCreateAllocation调用,包含为设备分配的资源的数量和类型。函数返回的分配信息
在DXGKARG_CREATEALLOCATION结构体的DXGK_ALLOCATIONINFO结构的pAllocationInfo指针列表。
发送Command Buffer给内核模式。
7,应用程序发出一个画图接口后,实时Direct3D会调用用户模式显示驱动相关的画图操作,比如,DrawPrimitive2.
8, 为了发出command buffer到内核模式,实时Direct3D调用用户模式显示驱动的Present或Flush函数,如果command buffer如果是
满的,用户模式显示驱动发出command buffer.
9, 用户模式显示驱动调用pfnPresentCb如果Present被调用,或者调用pfnRenderCb函数如果Flush调用或command buffer 是满的。
10,内核模式的小端口驱动会接收到DxgkDdiPresent调用如果pfnPresentCb被调用,或者DxgkDdiRender或DxgkDdiRendrKm函数调用
如果pfnRenderCb被调用。小端口驱动检查command buffer,然后以硬件支持的格式写进DMA buffer中,如果生产传分配列表,用来
描述接口已经使用的。
从DMA buffer到硬件。
11,微软的DirectX 图形子系统调用小端口驱动的DxgkDdiBuildPagingBuffer函数创建一个期望的DMA 空间,做为分页空间,这段分
页空间被用来在已经分配好的显示资源列表和GPU映射的内存中进行交换和搬移。
DxgDdiBuildPagingBuffer并不是每一帧的显示都需要调用。
12,DirectX 图形子系统调用小端口驱动的DxgkDdiSubmitComand函数,将分页空间排队到GPU的执行单元中。
13,DirectX图形子系统调用小端口驱动的DxgkDdiPatch函数为DMA 空间中的资源分配物理地址。
14, DirectX 内核图形子系统调用小端口驱动的DxgDdiSubmitCommand函数,将DMA空间排队到GPU执行单元中。每一个发送到GPU中
的DMA空间都包含一个标识,相当于一个数字号,当GPU完成相关的DMA空间的处理,GPU会产生一个中断。
15,显示的小端口驱动在DxgkDdiInterruptRoutine函数中得到中断的通知,显示的小端口驱动应该对这个被用来表示DMA空间的数字
号,来查看GPU最近完成的处理。
16,显示的小端口驱动应该调用DxgCbNotifyInterrupt函数通知DirectX 内核图形子系统,DMA操作完成。小端口驱动也应该调用
DxgkCbQueueDpc函数排队DPC中进行后面的处理。