Windows Display Driver Model (WDDM) Operation Flow
下图显示了WDDM从渲染设备的创建到内容被显示的流程。
Creating a Rendering Device
1. | 在应用程序请求创建渲染设备之后,KMD会收到DxgkDdiCreateDevice调用DxgkDdiCreateDevice调用。KMD会初始化DMA信息(PS:包含DMA buffer大小等信息),将其指针填充DXGKARG_CREATEDEVICE 中的DXGK_DEVICEINFO(PS:其中会包含KMD Process的句柄)类型的pInfo成员, |
2. | 如果调用KMD DxgkDdiCreateDevice成功,MSFT D3D RT 会调用UMD的CreateDevice。 |
3. | 在CreateDevice中,UMD必须显式调用pfnCreateContextCb来创建一个或多个Context - 代表创建新设备上执行的GPU 线程。D3D RT在D3DDDICB_CREATECONTEXT的 pCommandBuffer 和 CommandBufferSize 发成员中返回Command Buffer的信息用于初始化Command Buffer。 |
Creating Surfaces for a Device
4. | 在Application请求创建渲染设备使用的Surface之后,D3D RT会调用UMD的CreateResource。 |
5. | UMD的CreateResource中会调用RT 的 pfnAllocateCb。 |
6. | KMD在收到DxgkDdiCreateAllocation时,会指定创建allocation的类型和数量。DxgkDdiCreateAllocation 会返回关于Allocation的信息,该信息保存在DXGKARG_CREATEALLOCATION的成员 DXGK_ALLOCATIONINFO类型数组 pAllocationInfo中。 |
Submitting the Command Buffer to Kernel Mode
7. | 在Application请求在surface上绘制时,D3D RT会调用UMD中关于绘制的的函数, 例如DrawPrimitive2。 |
8. | D3D RT会调用UMD的Present或Flush来提交Command Buffer给KMD。如果Command buffer被写满UMD也会提交Command buffer。 |
9. | UMD会在Present被调用时,调用RT提供的pfnPresentCb函数,或者在command buffer被写满或被调用Flush时调用pfnRenderCb函数。 |
10. | 如果调用了RT的pfnPresent函数, 则DXGK会调用KMD的DxgkDdiPresent函数,或者,调用RT的pfnRenderCb被调用时,DXGK会调用KMD的DxgkDdiRender或DxgkDdiRenderKm函数。KMD会校验Command buffer并转换成硬件能识别的内容写入DMA buffer中,同时会产生allocation list,其中描述了DMA buffer中使用到的Surface资源。 |
Submitting the DMA Buffer to Hardware
11. | MSFT DXGK子系统会调用KMD的DxgkDdiBuildPagingBuffer 来创建特殊功能的DMA buffer,即Paging Buffer,其中的命令会将allocation list里面指定的allocation移出或移进到 GPU 能够访问的内存中。 Note DXGK不会为每一帧调用DxgkDdiBuildPagingBuffer |
12. | DXGK子系统调用KMD的DxgkDdiSubmitCommand函数来将Paging Buffer插入GPU的执行单元的队列中。 |
13. | DXGK调用KMD的DxgkDdiPatch函数来为DMA buffer中的资源指定物理地址。 |
14. | DXGK调用KMD的DxgkDdiSubmitCommand来将DMA buffer插入到GPU 执行单元的队列之中。每个被提交的DMA buffer包含一个Fence id,该ID为一个数字。再GPU处理完DMA buffer之后, GPU会生成一个中断。 |
15. | DXGK会调用 KMD的DxgkDdiInterruptRoutine来通知中断。KMD应该从GPU硬件中读取刚刚完成的DMA buffer 的 fence id。 |
16. | KMD应该再DMA buffer执行完成时调用DxgkCbNotifyInterrupt来通知DXGK。同时,KMD应该调用DxgkCbQueueDpc插入一个任务到DPC队列中。(PS:会在其中处理有关刚完成的DMA buffer相关的处理, 因为不应该在中断中处理太多事务) |