Windows graphic driver

04 WDDM Architecture

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/windows-vista-and-later-display-driver-model-architecture

这是WDDM的显示驱动模型架构,vista可用,由UMD和KMD组成:

WDDM由user mode和kernel mode组成,

vendor厂商要提供UMD的display driver,和display miniport driver,

UMD display driver是一个动态库dynamic link library DDL,微软的Direct3D runtime会去load这个dll。

Display miniport driver 与微软 directX graphics kernel subsystem.相连接

更多信息看:

Windows Display Driver Model (WDDM) Reference.

 

05 Benefits of WDDM

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/benefits-of-the-windows-vista-and-later-display-driver-model

WDDM比win2000的XDDM更容易创建显示驱动程序,因为有以下增强:

提高了稳定性和安全性,因为KMD的代码更少了,KMD能够访问system address sapce,所以容易crash。Windows 2000 Display Driver Model (XDDM)

1,Direct3D runtime和DirectX graphics kernel subsystem执行了更多的显示任务,也就是说,更多的代码在runtime和子系统里面,而不是在driver里面。

Display processing(显示任务),包括:

Manages video memory

Schedules direct memory access(DMA) buffers for GPU

更多信息参考Video Memory Management and GPU Scheduling.

2,Surface的创建需要更少的KMD的阶段

vista之前,创建Sruface需要下面的KMD调用:

  1. DdCanCreateSurface
  2. DdCreateSurface
  3. D3dCreateSurfaceEx

而WDDM中

创建Surface,只需要UMD display driver的调用:CreateResource(),

它会反过来调用pfnAllocateCb函数,

然后发生对KMD的DxgkDdiCreateAllocatoin函数的调用。

CreateResource

pfnAllocateCb

DxgkDdiCreateAllocation

3,创建/销毁 surface,lock/unlock resource,更配对了,more evenly paired

4,WDDM中,对video mem, system mem , 和Surface的管理,具有identically(相同地)处理。

vista前,os处理这些组建的方式有些不同

5,Shader translation着色器转换,是在display driver的UMD部分执行的

这种方法消除了下列复杂性,他们发生在KMD的shader translation中:

hardware模型与device driver interface(DDI)抽象 不match

traslation中使用了复杂的compiler技术

因为shder processing完全发生在每个进程内,而且也不需要Hardware access,不需要KMD shader processing,所以,shafer translation 代码可以在UMD下处理(processed)

你必须为UMD translation代码编写try/except代码,

translation的错误应该导致app处理的return,

在UMD,编写background translation(就是运行在独立的线程的translation代码,与其他显示处理线程不同)更容易,

06 Migrating to the WDDM

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/migrating-to-the-windows-vista-and-later-display-driver-model

迁移到WDDM

迁移到WDDM需要编写完全不同的display和video minip driver。

和XDDM类似,WDDM需要配套的display driver和display miniport driver,(显示驱动和显示迷你端口驱动)

然而,在WDDM中,display driver运行在UMD,

而且,WDDM模型不使用GraphicsDeviceInterface(GDI) engine服务,

WDDM使用的是Direct3D runtime和DirectX graphics kernel sybsystem(Dxgkrml.sys)服务。

WDDM支持根据XDDM编写的display和video miniport driver。但应该进来以WDDM driver的形式编写,以使用Vista的sw/hw特性

虽然写驱动的人,可以在WDDM driver里重用low-level hardware-dependent 代码,

但他们要重写新的device driver interface(DDI)相关code,

编写WDDM驱动时,要考虑:

1,disp minip driver必须实现修改过的entry-point func入口函数,才能和os,以及DirectX graphics kernel subsystem进行交互。更多信息看DriverEntry of Display Miniport Driver. , disp minip driver可以调用任何文档化的内核函数

2,disp minip driver动态加载合适的DirectX graphics kernel subsystem,

disp minip driver和DirectX graphics kernel subsystem通过interface相互调用。

3,disp minip driver不再需要处理大量video i/o control codes(ioctl),

在XDDM中,KMD disp driver使用这些代码去与video minip driver通信,

在WDDM中,UMD disp driver 与Direct3D runtime通信;

代替的是,WDDM graphics kernel subsystem与disp minip driver通信。

注意,

下面的ioctl在WDDM还在用,disp minip driver必须处理:

IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS

4,UMD disp驱动必须实现和export一个OpenAdapter函数,

它用来打开一个graphics adapter的实例,

UMD disp还要实现CreateDevice函数,

它用来创建 disp dri显示驱动的代表,disp dri用来handle rendering state的集合

OpenAdapter

CreateDevice

5,UMD disp drv的CreateResource函数,和disp minip driver的DsgkDdiCreateAllocation函数,代替XDDM中的DdCanCreateSurface,DdCreateSurface,和3dCreateSurfaceEx

CreateResource

DxgkDdiCreateAllocation

DdCanCreateSurface, DdCreateSurface,

D3dCreateSurfaceEx

6,Most of the remaining user-mode display driver functions implement the same functionality that the kernel-mode display driver for XDDM implemented in the following:

07 WDDM Operation Flow

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/windows-vista-and-later-display-driver-model-operation-flow

这个图,描述了,WDDM中,从创建 rendering device,到present(显示)内容到display。

下面几节由更多关于operation flow的细节

Operation Flow:

一,Creating a Rendering Device

1,在一个AP请求创建一个rendering device后,disp minip driver会收到一个DxgkDdiCreateDevice调用。Disp miniport driver要初始化direct memory access(DMA),方法是通过返回一个指向 DXGARG_CREATEDEVICE结构体的pInfo成员中的DXGK_DEVICEINFO(被填充)结构体的指针。

DxgkDdiCreateDevice

DXGK_DEVICEINFO

DXGKARG_CREATEDEVICE

2,如果对disp minip dri的DxgkDdiCreateDevice的调用成功,

Direct3D runtime就会调用UMD disp dri的CreateDevice函数

DxgkDdiCreateDevice

CreateDevice

3,在CreateDevice调用中,UMD disp dri必须explicitly显示调用 pfnCreateContextCb函数,去创建一个,或者多个context --- 以在新创建的device上执行GPU线程。

Direct3D runtime从DDDICB_CREATECONTEXT结构体的pCommandBbuffer和CommandBUfferSize成员返回信息,以初始化command buffer。

pfnCreateContextCb

D3DDDICB_CREATECONTEXT

二,Creating Surfaces for a Device

4,AP请求 为rendering device创建surface后,Direct3D runtime调用UMD disp dri的CreateResource调用。

CreateResource

5,UMD disp dri的CreateResource调用pfnAllocateCb runtime-supplied函数(运行时提供的函数)

pfnAllocateCb

6,disp minip dri收到一个DxgkDdiCreateAllocation调用,

这个函数描述了要创建的allocation的数量和类型,

它返回一个存有allocation的数组,这是一个DXGARG_CREATEALLOCATION结构体的pAllocationInfo成员的DXGK_ALLOCATIONINFO结构体的数组

DxgkDdiCreateAllocation

DXGK_ALLOCATIONINFO

DXGKARG_CREATEALLOCATION

三,Submitting the Command BUffer to kernel Mode ,

7,在AP请求画一个surface后,Direct3D runtime调用与drawing操作有关的UMD disp dri函数,例如,DrawPrimitive2.

DrawPrimitive2

8,为submit command buffer到KMD,Direct3D runtime会调用UMD disp dri的Present 或者 Flush 函数。另外,如果command buffer满了,UMD disp dri会submit command buffer

Present

Flush

9,如果调用了Present,UMD disp dri会调用runtime-supplied函数pfnPresentCb,

如果调用了Flush,或者command buffer满了,则会调用pfnRenderCb

pfnPresentCb

pfnRenderCb

10,如果调用了pfnPresentCb,disp minip dri会收到DxgkDdiPresent的调用,

调用pfnRenderCb,disp minip dri会收到DxgkDdiRender的调用,

disp minip dri会

validate command buffer(使生效 commandbuffer),

以hw's format去写DMA buffer,

生成一个描述Surface使用的allocation的list

DxgkDdiRender

DxgkDdiRenderKm

四,Submitting the DMA Buffer to Hardware

11,DirectX graphics kernel sybsystem调用disp minip dri的DxgkDdiBuildPagingBuffer,以创建特殊用途的DMA buffers,称为paging buffers,

它将allocation list中指定的allocation,在GPU-accessible memory中来回移动

注意,不是每个grame都会调用DxgDdiDbuildPagingBuffer

DxgkDdiBuildPagingBuffer

12,DirectX kernel subsystem调用disp minip dri的DxgkDdiSubmitCommand函数,以queue the buffers to GPU执行单元

DxgkDdiSubmitCommand

13,DirectX graphics kernel subsystem调用disp minip dri的DxgkDdiPatch函数,去为DMA buffer的resource分配物理地址。 assign physical addresses to the resources in the DMA buffer.

DxgkDdiPatch

14,DirectX graphics kernel subsystem调用disp minip dri的DxgkDdiSubmitCommand,去queue the DMA buffer到GPU execution unit。每个被submit到GPU的DMA buffer都包含一个fence 识别符。在GPU完成对DMA buffer的处理后,GPU会产生一个中断。

DxgkDdiSubmitCommand

Supplying Fence Identifiers

15,disp minip dri被DxgkDdiInterruptRoutine函数的中断唤醒(notified by interrupt),在DMA buffer的fence识别符完成后,disp minip dri应该从GPU读。

DxgkDdiInterruptRoutine

16,disp minip dri应该调用DxgkCbNotifyInterrupt函数,去notify通知DirecX graphoics kernel subsystem - DMA buffer已经完成了。

再调用DxgkCbQueueDpc函数来queue一个defferred procedure call(DPC),延迟过程调用。

DxgkCbNotifyInterrupt

DxgkCbQueueDpc

10 Init disp minip dri

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/initializing-the-display-miniport-driver

OS load disp minip dri后,发生以下步骤来init disp minip dri,

1,os 调用disp minip dri的DriverEntry函数

2,DriverEntry会分配一个DRIVER_INITIALIZATION_DATA结构体,

用DXGKDDI_INTERFACE_VERSION去填充DRIVER_INITIALIZATION_DATA的version成员,

INITIALIZATION_DATA的其他成员指向disp minip dri的其他入口函数(这些函数就是disp minip dri的实现),

DRIVER_INITIALIZATION_DATA

3,DriverEntry调用DxgkInitialize()去load DirectX graphics kernel subsystem(Dxgkrnl.sys),

并为Dxgkrnl.sys提供指向disp minip dri的其他entry point func,

DxgkInitialize

4,DxgkInitialize返回后,DriverEntry 将DxgkInitialize的返回值 返回给os。

DIsp minip dri编写者不该嘉定Dxgkinitialize的返回值

11 init与Direct3D UMD disp dri的连接

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/initializing-communication-with-the-direct3d-user-mode-display-driver

为了init与微软Direct3D UMD dirsp driver(是一个DLL)的连接,

Direct3D runtime先load这个DLL,

,Direct3D runtime下一步调用UMD disp dri的OpenAdapter函数,通过DLL的export table,去打开一个graphisc adapter的实例。

OpenAdapter函数时DLL的唯一导出的函数

OpenAdapter fu

在对driver的OpenAdapter()调用中,runtime提供了D3DDIARG_OPENADAPTER结构体中的pAdapterCallbacks成员中的 adapter回调函数pfnQueryAdapterInfoCb()

runtime还会提供 接口中的version,和 D3DDDIARG_OPENADAPAPTER的version成员。

UMD disp dri必须 verify验证 它能够使用这个版本的runtime。

UMD disp dri返回一个D3DDDIARG_OPENADAPTER的pAdapterFuncs成员的 adapter-specific函数的table。

pfnQueryAdapterInfoCb

D3DDDIARG_OPENADAPTER

UMD disp dri应该调用adapter callback函数pfnQueryAdapterInfoCb (),以从disp minip dri去qeury graphics hardware的capability,

runtime调用UMD disp dri的CreateDevice函数(一个driver的adapter-specific函数) 去创建一个display device,用于处理render state的集合 和 完成初始化。

当init完成,Direct3D rumtime就可以调用disp dri-supplied函数,然后UMD disp dri可以调用runtime-supplied函数。

UMD disp dri的CreateDevice函数会被D3DDIARG_CREATEDEVICE结构体调用,

这个结构体会通过下列步骤,去Init UMD disp dri interface:

D3DDDIARG_CREATEDEVICE s

1,rumtime设置为UMD disp dri需要的把呢不能

2,runtime设置了version,方便driver使用,以识别runtime的编译时间,

例如,driver可以使用版本号去辨别runtime是从哪个service pack里release的,有什么修复

3,runtime 设置hDevice以指定 driver calls back 到tuntime应该使用的handle,

driver产生一个唯一的handle,然后pass it back to runtime in hDevice。

tunime接下来对driver的调用,需要使用返回的那个hDevice handle。

4,runtime提供了一个D3DDDI_DEVICECALLBACKS结构体中的device-specific回调的table,

pCallbacks会指向它。

UMD disp dri调用runtime-supplied回调,去访问disp minip dri提供的KMD service。

D3DDDI_DEVICECALLBACKS

5,UMD disp dri返回它的device-specific func的table,它在D3DDDI_DEVICEFUNCS结构体中,pDeviceFuncs指针指向它

D3DDDI_DEVICEFUNCS

Note,

能同时存在的display device(graphics context) 只受可用的system memory的限制。

12 init use of Mem Segments

Initializing Use of Memory Segments.

Memory Semgments的初始化

Memory segments,在drisp dri模型的context中,向vidmm manager描述GPU的addr空间,

mem segments generalize和virtualize了video memory resource,

mem segments根据硬件支持的mem type进行配置,例如,frame buffer memory 或者 system memory aperture

为初始化 如何使用mem segment,DirecrX graphics kernel subsystem(Dxgkrnl.sys)调用display miniport driver的DxgkDdiQueryAdapterInfo函数,

要指示dirp minip dri 在调用DxgkDdiQueryAdapterInfo时返回mem segment的信息,graphics subsystem要在DXGKARG_QUERYADAPTERINFO结构体的type成员中指定DXGKQAITYPE_QUERYSEGMENT

DxgkDdiQueryAdapterInfo

DXGKARG_QUERYADAPTERINFO

graphics subsystem调用disp minip dri的DxgkDdiQueryAdapterInfo函数两次,来获取segment信息。

第一次对DxgkDdiQueryAdapterInfo的调用时为了检索 driver支持的segment数量,

第二次调用检索每个segment的细节信息。

调用DxgkDdiQueryAdapterInfo时,driver将DXGKARG_QUERYADAPTERINFO的pOutputData成员指向已经填充的DXGK_QUERYSEGMENTOUT结构体。

DXGK_QUERYSEGMENTOUT

第一次调用时,DXGK_QUERYSEGMENTOUT的pSegmentDescirptor成员置为NULL,

driver只应该向DXGK_QUERYSEGMENTOUT的NbSegment成员填它支持的segment类型的数量。

这个数量也代表了DXGK_SEGMENTDESCRIPTOR没填的数量,

driver在第二次调用DxgkDdQueryAdapterInfo的时候需要他们

DXGK_SEGMENTDESCRIPTOR

第二次调用中,driver要填DXGK_QUERYSEGMENTOUT的所有成员。

在第二次调用,driver需要填 DXGK_QUERYSEGMENTOUT的pSegmentDescriptor成员的DXGK_SEGMENTDESCRIPTOR的NbSement大小的一个数组,其中包含driver支持的segment的信息。

两次对DxgkDdiQueryAdapterInfo的调用中,

DXGKARG_QUERYADAPTERINFO的pInputData成员指向DXGK_QUERYSEGMENTIN结构体,这个结构体包含了AGP aperture的location和properties。

如果没有可用的AGP aperture,或者有AGP aperture被present但是没有合适的GART driver被安装的话,AGP aperture的information就置0 .

如果没有present的AGP aperture,disp minip dri就不该在DXGK_QUERYSEGMENTOUT的pSegmentDescriptor数组中表示它支持一个AGP-type aperture segment。

这时如果表示支持,就会init失败。

DXGKARG_QUERYADAPTERINFO

DXGK_QUERYSEGMENTIN

在init期间,因为memory充足,对于paging buffer的memory可以从指定的segment去allocated。

vidmm manager从DXGK_QUERYSEGMENTOUT的PagingBUfferSegmentId指定的segment去 为paging buffer去allocate memory。

在第二次嗲用DxgkDdiQueryAdapterInfo时,driver会指定 paging buffer segment的identifier标识符,

driver还应该指定DXGK_QUERYSEGMENTOUT的PagingBufferSize成员的paging buffer应该allocate的大小(字节)。

更多mem segment和paging buffer的信息:

see Handling Memory Segments and Paging Video Memory Resources.

13 Enumerat枚举 GPU engine功能

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/enumerating-gpu-nodes

win8开始,disp minip dri必须实现DxgkDdiGetNodeMetadata(),它用来query GPU node的engine capability。

这个信息有助于评估工作负载如何在节点之间调度和分布,并改进debug APP的能力

Engine capabilities device driver interface DDI

这些接口提供了 特定GPU node的 engine capability:

DRIVER_INITIALIZATION_DATA结构体的DxgkDdiGetNodeMetadata提供了一个指向DxgkDdiGetNodeMetadata()函数的指针。

GPU node architecture

每个disp adapter都有许多不同的engine,用来调度任务(schedule tasks on)。

每个engine都分配到唯一的Node上,

但如果一个node与多个adapter关联,每个node却可以包含多个engine,比如在 linked disp adapter(LDA)配置中,多个物理GPU连接形成一个更快的virtual GPU。

不同的node代表了GPU的asymmetrical processing cores(不对称处理核)。

而每个node内的engines代表了adapters间的symmetrical processing cores(对称处理核)。

也就是说,不同的adapert上,3-D node只包含相同的3-D engins,不会有不同的类型。

因为engeins总是根据engins类型被按组一起放在node中,所以可以根据指定的node查询engine type的信息。disp minip driv可以指定的engine的type被列在了DXGK_ENGINE_TYPE枚举中。

node metadata函数的实现的例子

这段代码展示了disp minip dri如何实现可以被DxgkDdiGetNodeMetadata()返回的engine types。

NTSTATUS

IHVGetNodeDescription(

IN_CONST_HANDLE hAdapter,

UINT NodeOrdinal,

OUT_PDXGKARG_GETNODEMETADATA pGetNodeMetadata

)

{

DDI_FUNCTION();

PAGED_CODE();

if(NULL == pGetNodeMetadata)

{

return STATUS_INVALID_PARAMETER;

}

CAdapter *pAdapter = GetAdapterFromHandle(hAdapter);

//Invalid handle

if(NULL == pAdapter)

{

return STATUS_INVALID_PARAMETER;

}

//Node ordinal is out of bounds. Required to return

//STATUS_INVALID_PARAMETER

if(NodeOrdinal >= pAdapter->GetNumNodes())

{

return STATUS_INVALID_PARAMETER;

}

switch(pAdapter->GetEngineType(NodeOrdinal))

{

//This is the adapter's 3-D engine. This engine handles a large number

//of different workloads, but it also handles the adapter's 3-D

//workloads. Therefore the 3-D capability is what must be exposed.

case GPU_ENGINE_3D:

{

pGetNodeMetadata->EngineType = DXGK_ENGINE_TYPE_3D;

break;

}

//This is the adapter's video decoding engine

case GPU_ENGINE_VIDEO_DECODE:

{

pGetNodeMetadata->EngineType = DXGK_ENGINE_TYPE_VIDEO_DECODE;

break;

}

//This engine is proprietary and contains no functionality that

//fits the DXGK_ENGINE_TYPE enumeration

case GPU_ENGINE_PROPRIETARY_ENGINE_1:

{

pGetNodeMetadata->EngineType = DXGK_ENGINE_TYPE_OTHER;

//Copy over friendly name associated with this engine

SetFriendlyNameForEngine(pGetNodeMetadata->FriendlyName,

DXGK_MAX_METADATA_NAME_LENGTH,

PROPRIETARY_ENGINE_1_NAME);

break;

}

}

return STATUS_SUCCESS;

}

25 Using Memory Segments to Describe the GPU Address Space

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/using-memory-segments-to-describe-the-gpu-address-space

Memory Segment描述了GPU addr

在video memory manager可以管理GPU的地址空间前,

Display miniport driver必须通过memory semgnets向video memory manager描述GPU地址空间。

Display miniport driver创建memory segments,以generalize和virtualize  video memory resources。

driver可以根据硬件支持的memory types来配置memory segments,比如,frame buffer memory或者system memory aperture

Driver init时,driver必须返回描述vidmm manager管理mem resource的segment types list。

driver指定它支持的segment types的数量,通过响应对其QueryAdapterInfo函数的调用来描述每个semgent type,

driver使用SEGMENTDESCRIPTOR结构体描述每个segment

更新init的信息:Initializing Use of Memory Segments.

DxgkDdiQueryAdapterInfo

DXGK_SEGMENTDESCRIPTOR

然后,segment的类型和数量是不变的,

vidmm manager保证,在任何特定segment,每个进程能公平的分享resource。

vidmm manager独立管理所有segment,而且segment没有overlap重叠。

因此,不管AP当前在另一个segment持有多少resource,vidmm manager都会从一个segment去allocate同样数量的vidmm resource给AP。

driver为它的每个memory segement分配了一个segment identifier段描述符。

然后,当vidmm manager为video resource去request请求create allocations和render这些resource时,driver会去识别支持这种需求的segment,按顺序给出driver perfer期待vidmm manager使用的segment。

更多信息:Specifying Segments When Creating Allocations.

driver不需要去指定它的memory segments中所有GPU可用的vidmm resource,然而,

driver必须指定vidmm manger管理的在系统上运行的进程之间使用的memory resource.

例如,一个vertex shader顶点着色器microcode 实现的固定功能pipeline能够reside驻留在GPU addr space里,但不在vidmm manager管理的mem之中,

因为microcode总是对所有进程available,而且从来都不是进程间的source of contention,

然而,vidmm manager必须从一个driver的mem segment里面allocate出vidmm resource(比如vertex buffer, texture, render target,和特定AP的shader code),

因为resource 类型必须对所有进程公平地可用

下图说明了如何从GPU addr space去配置mem segment

NOTE:对vidmm manager hidden隐藏的 vidmm不可以map到user space,

这样做违反了virtual mem的基本原则:系统上运行的所有进程都可以访问所有内存(虚拟内存的)

不能map有什么意义呢?

26! Configuring Memory Segment Types

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/configuring-memory-segment-types

vidmm manager和display hw只支持memory segment的某些类型,

所以disp minip driver只能配置这些类型的segment,

disp minip driver可以配置memory-space和aperture-space segments,

memory-sapce segment由保存allocation的bits 的medium(介质)组成

而aperture-space segment是一个virtual address sapce。

当allocate了一段memory-space segment,则实际的memory已经被allocate,virtual address sapce会被redirected(重定向)到physical pages,这个physical page已经被allocate到video memory pool或者是system memory

disp minip driver可以配置下面类型的memory segment:

Linear Memory-Space Segments.

linear memory sapce segment(线性内存空间段)是典型的segment的类型,

线性内存空间段符合以下模型:

virtualizes video memory located on graphics adapter

被GPU直接访问(就是说不需要通过page mapping去重定向)

在一维的addr space里被线性的管理

driver设置SEGMENTDESCRIPTOR结构体的Flags,为0,代表指定一个linear memory-space segment.

然后driver可以设置以下bit-field flags来表示对additional segment 的支持:

CpuVisible,代表segment是CPU-accessible的

UseBanking,segment is divided into banks

figure shows a visual representation of linear memory-space segment

在RAM里面分了一个segment段,

在linear range里分的allocation,可以被GPU直接使用

Linear Aperture-Space Segments

linear aperture-space segment与linear memorry-space segment很相似,

然而,aperture-space segment指示一个addr space,不能hold bit持有位。

为了能hold the bits,必须allocate system memory page,

而且addr-space空间必须重定向到对这些page的引用上。

disp minip driver必须实现DxgkDdiBuildPagingBuffer,为了OPERATION_MAP_APERTURE_SEGMENT和OPERATION_UNMAP_APERTURE_SEGMENT操作,来处理重定向,他在Disp minip dirver的DriverEntry中被描述。

BuildPagingBuffer接收要重定向的范围和引用allocate的physical system mem page。

DxgkDdiBuildPagingBuffer

DriverEntry of Display Miniport Driver

disp minip driver通常通过programmng一个page table来完成对addr-space range的重定向,vidmm manager并不知道这个page table

driver要在SEGMENTDESCRIPTOR的Fliags中set Aperture bit flag,来指定linear aperture-space segment。driver也可以set下面的flag bit来指定额外的segment支持:

CpuVisible

CacheCoherent:segment维护segment重定向的page,在cache与CPU之间的一致性

DXGK_SEGMENTDESCRIPTOR

video mem与system mem之间有一个page table,

看起来,allocation在linear addr里面,GPU可以直接用,

但是实际allocation保存在system memory的discontiguous page中,不连贯页中。

AGP-Type Aperture-Space Segments

与linear aperture-space类似,但是对于这个segment,disp minip driver在BuildPagingBUffer()不会expose MAP_APERTURE_SEGMENT和UNMAP_APERTURE_SEGMNT,

而是vidmm manager使用GART driver来map / unmap system pages,

也就是说,vidmm manager不会涉及到disp minip driver。

28! Mapping Virtual Addresses to a Memory Segment

Mapping Virtual Addresses to Memory Segment

Mapping Virtual Addresses to a Memory Segment

disp minip driver可以为每个它定义的memory-sapce或者aperture-space segment去指定:GPU virtual addr是否可以直接map到一个segment中的allocation,

为了把一个GPU virtual addr映射到一个segment,segment应该通过PCI aperture有linear access(线性的访问权限)。

换句话说,segment内的任何allocation的offset,都应该与PCI aperture中的offset相同。

这样,vidmm manager才能通过给定的segment的allocation的offset来计算任何allocation的bus相对物理地址。

下图说明了virtual addr如何map到linear mem-space segment

CPU使用virtual addr,

virtual addr通过CPU page table转换成physiacal addr,

physiacal addr叫做aperture,

aperture physiacal addr的offset与video RAM中segment中的offset一一对应

下面表示virtual addr如何map到linear aperture-space segment的underlying pages底层page

GPU的virt addr通过page table 转换为physical addr,

然后就直接对应video aperture的segment和system RAM了,

所以这是system RAM的用法,上面是video RAM的用法?

33 Command和DMA buffers介绍

Command和DMA buffer非常相似,

然而,command buffer被UMD disp dri使用,

DMA buffer被disp minip dri使用

command buffer有下面的特性:

从来不会被GPU直接访问

hw vendor控制format

它是从redner APP的私有addr空间的 regular pageable memory中分配的,为UMD disp dri去分分配的。

DMA buffer特性:

它基于command buffer的validated content(使生效)

它被disp minip dri从kernel的pageable memory里被allocation出来

在GPU可以从DMA buffer读之前,disp minip dri必须page-lock这个DMA buffer,然后通过一个aperture去map这个DMA buffer。

34! 使用有保证契约的DMA buffer模型

Using the Guaranteed Contract DMA Buffer Model

disp dri模型保证了DMA buffer的大小,和render device的patch-location列表

在guarantee contract模式下,,当UMD disp driver填了command buffers,并且调用了pfnRenderCb去submit这些command buffer给display minip driver的时候,UMD disp driver会知道DMA buffer的确切大小,和patch-location列表,用于translation转换。

在每个pfnRenderCb调用后,UMD disp driver接收后续translation(也就是后续fpnRenderCb的调用)可用的 DMA buffer的大小,和patch-location的列表,

vidmm manager保证,知道下一个translation完成前,不会trim修剪 DMA buffer和patch-location列表。

disp minip driver必须能将一个command buffer translate转换为 一个准确的DMA buffer和一个patch-locaion列表。

如果无法进行translation,UMD command buffer就被定义为invalid无效的。

disp minip driver在translation期间,无法通过返回状态去指示超出了DMA buffer空间和patch-locaion列表;

这会导致vidmm manager check system出bug,因为memory manager没有满足 保证DMA协议 的需求。

35! Paging video memory resources

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/paging-video-memory-resources

不像XDDM,WDDM允许创建比所有可用physical video memory更多的video memory resource出来。

然后可以在需要的时候,从video memory中去page in或者page out。

换句话说,不是所有的video memory resource同时存在于video memory。

GPU在它的pipeline里可以同时有多个DMA buffer,

由这些active活动的DMA buffer引用的video memory resource必须存在于video memory中。

其他的idle空闲状态的video memory resource可以被page out到system memory。

在GPU scheduler可以调用disp minip driver的DxgkDdiSbmitCommand() 以submit一个DMA buffer给GPU之前,scheduler必须确保所有DMA buffer在使用的video memory resource真的在video memory中。

如果一些resource不在video memory,则他们必须从system memory里page in回来。

GPU scheduler必须调用vidmm manager,去查找video memory的空间,用于从system memory向video memory transfer转换 所需的video memory resource。

当video memory需求高时,GPU scheduler必须调用vidmm manager将vidmm resource数据transfer转换到system memory,来为所需的video mem resource数据make room(创造空间)。

特殊目的的DMA buffer:包含了 在video和system mem之间做transfer的command, 这种类型的DMA buffer被称为paging buffers。

video mem manager调用disp minip dri的DxgkDdiBuildPagingBuffer函数去创建一个paging buffer,

driver会写 hw-specific data transfer commands。

DxgkDdiSubmitCommand

DxgkDdiBuildPagingBuffer

36!! Submit a command buffer

https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/submitting-a-command-buffer

要向vista graphics stack传递command buffer ,必须做下面操作:

1,当Direct3D runtine调用了下面的UMD disp driver函数之一去执行指定的操作,则UMD disp dirver就会发起一个command buffer submission:

Present函数 去显示图形

Flush函数 去submit hw command

Lock函数 去lock一个resoure,这个resource是当前command batch(批次)在用的,

  • The Present function to display graphics.
  • The Flush function to submit hardware commands.
  • The Lock function to lock a resource, which is used in the current command batch.

注意,command buffer满了的时候,UMD disp driver也会发出一次command buffer submission。

2,UMD disp driver 调用 Direct3D runtime的 pfnRenderCb() 去 submit command buffer到runtime。

pfnRenderCb

3,DirectX graphics kernel sybsystem调用disp minip driver的DxgkDdiRender() 去 validate command buffer,以hw的format去写 DMA buffer,并生成一个描述Surface used 的allocation list。

注意这时 DMA buffer还没有 patched(就是分配physical addr)。

注意如果runtime通过调用UMD disp driver的Present() 发出了一次command buffer submission,则graphisc subsystem会调用disp minip driver的DxgkDdiPresent()而不是DxgkDdiRender()。

DxgkDdiRender

Present

DxgkDdiPresent

4,vidmm manager调用disp minip dri的DxgkDdiBuildPagingBuffer()去创建特殊目的的DMA buffer, 这种DMA buffer叫做 pagingbuffers,将DMA buffer伴随的allocation list中指定的allications 从GPU-accessible memory移入移出。

DxgkDdiBuildPagingBuffer

Paging Video Memory Resources.

5,GPU scheduler调用disp minip driver的DxgkDdiPatch()去给DMA buffer的resource分配一个物理地址。

然而,paging buffer并不需要scheduler去调用DxgkDdiPatch去分配物理地址,因为在调用DxgkDdiBuildPagingBuffer()的时候,paging buffer的物理地址已经传入并分配好了。

DxgkDdiPatch

6,GPU cheduler调用disp minip driver的DxgkDdiSubmitCommand()去请求driver把paging buffer queue进GPU executin unit。

7,GPU cheduler调用disp minip driver的DxgkDdiSubmitCommand()去请求driver把DMA buffer queue进GPU executin unit。

每个submit到GPU的DMA buffer包含一个fence identifier,

在GPU完成对DMA buffer的处理后,GPU产生一个interrupt,

DxgkDdiSubmitCommand

8,disp minip driver被DxgkDdiInterruptRoutine()中的中断唤醒,

disp minip driver要从GPU读取刚刚完成的DMA buffer的fence标识符。是fence value?

DxgkDdiInterruptRoutine

9,disp minip driver要调用DxgkCbNotifyInterrupt()去通知GPU scheduler,DMA buffer做完了

10,disp minip driver调用DxgkCbQueueDpc()去queue一个deferred precedure call(DPC)

DxgkCbQueueDpc

11,disp minip driver的DPC被唤醒,去处理大部分DMA buffer processing

猜你喜欢

转载自blog.csdn.net/u012654756/article/details/88817087
今日推荐