住房与城乡建设部网站建造师,什么平台引流最快,软件设计专业,百度学术论文查重官网入口DRM系统
DRM是direct rendering manager的简称。DRM是linux kernel中与负责video cards功能的GPU打交道的子系统。DRM给出了一组API#xff0c;可以供用户程序来发送命令和数据给GPU设备从而来控制比如display、render等功能。
render-node由来
在以前#xff0c;DRM子系统…DRM系统
DRM是direct rendering manager的简称。DRM是linux kernel中与负责video cards功能的GPU打交道的子系统。DRM给出了一组API可以供用户程序来发送命令和数据给GPU设备从而来控制比如display、render等功能。
render-node由来
在以前DRM子系统中给每个DRM device注册的device-node就是/dev/dri/cardX 通过该节点来作mode-setting和rendering的控制。后来发现这么做有问题 mode-setting和rendering是通过同一个文件节点node来控制的 单卡的mode-setting资源不能在多个graphics-servers之间切分使用 在多cards之间共享display-controller实现过于复杂
然后就有了一些改进来解决这些问题。最终是mode-setting 和 render节点分家。
render node
render-node架构大概是2009年左右提出来的。站在用户程序角度来看render node的作用是用来加速computing和renderingrender node可以通过 /dev/dri/renderDX 被访问并且提供了基本的DRM rendering interface。与 /dev/dri/cardX 节点相比/dev/dri/renderDX 少了一些特性 没有mode-settingKMSioctls功能 用dma-buf替换掉gem-flink非安全的 不再需要DRM-auth认证 不再支持pre-KMS DRM-API
这样一来当应用程序需要hardware-acclerated rendering、访问GPGPU、offscreen rendering等时就不需要通过DRI或者wl_drm来访问graphics-server而是直接打开某个render node就开始使用即可。对于render node的访问权限控制则通过标注的file-system modes来控制了。
render-node并没有提供新的API它们只是将原有的DRM-API分出了一部分到一个新的device-node原来的node也保留了下来用于如mode-setting等控制。
render-node也没有和任何一个card进行绑定它是由原有node的同一个driver创建的所以尝试在原有node和render-node之间进行connect连接通信没有意义。当应用程序需要和graphics-server进行通信时可以通过dma-buf。
mode-setting node
虽然从原有的node中分离出一个render-node简化了应用程序的访问但对于mode-setting程序的访问没有简化。当一个graphics-server想要编程一个display-controller时它需要是给定card的DRM-Master可以通过drmSetMaster()接口来获得身份但同时只能有一个DRM-Master而且必须是由CAP_SYS_ADMIN特权的程序才能成为DRM-Master这会带来问题 不能以非root权限运行XServer 不能在同一个card上使用两个不同的XServer来控制两个不同的独立的显示器
首先想到的解决办法就是分离出mode-setting node类似render-node的方式/dev/dri/modesetD1 和 /dev/dri/modesetD2 节点来分割KMS CRTC和Connector资源。
另一种方法是将所有的mode-setting资源绑定到一个DRM-Master对象然后谁要访问mode-setting资源就可以通过访问该DRM-Master对象来实现。
DRM infrastructure
不管是render-node还是mode-setting-node在kernel角度是如何体现的
如果hardware没有display-controller则可以不设置DRIVER_MODESET flag只设置DRIVER_RENDER flag这样内核DRM只会创建render-node。如果一个hardware只有display-controller而没有rendering hardware可以设置DRIVER_MODESET而不设置DRIVER_RENDER。
大概回顾了下render node的由来。那么render node由kernel来负责创建其编号为何从128开始答案估计还要到kernel中寻找。
drm_dev_init
linux kernel中 drivers/gpu/drm/drm_drv.c中定义了drm_dev_init()函数其中创建drm设备编号的代码如下 if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) {ret drm_minor_alloc(dev, DRM_MINOR_ACCEL);if (ret)goto err;} else {if (drm_core_check_feature(dev, DRIVER_RENDER)) {ret drm_minor_alloc(dev, DRM_MINOR_RENDER);if (ret)goto err;}ret drm_minor_alloc(dev, DRM_MINOR_PRIMARY);if (ret)goto err;}涉及到两个枚举类型结构体
enum drm_driver_feature {DRIVER_GEM BIT(0),DRIVER_MODESET BIT(1),DRIVER_RENDER BIT(3),DRIVER_ATOMIC BIT(4),DRIVER_SYNCOBJ BIT(5),DRIVER_SYNCOBJ_TIMELINE BIT(6),DRIVER_COMPUTE_ACCEL BIT(7),DRIVER_USE_AGP BIT(25),DRIVER_LEGACY BIT(26),DRIVER_PCI_DMA BIT(27),DRIVER_SG BIT(28),DRIVER_HAVE_DMA BIT(29),DRIVER_HAVE_IRQ BIT(30),
};enum drm_minor_type {DRM_MINOR_PRIMARY,DRM_MINOR_CONTROL,DRM_MINOR_RENDER,DRM_MINOR_ACCEL 32,
};当drm core检查到device设置了DRIVER_RENDER标签时就通过drm_minor_alloc(dev, DRM_MINOR_RENDER)来分配ID而drm_minor_alloc()函数中最终分配ID是通过idr_alloc()函数来实现这里的type传入的就是DRM_MINOR_RENDER也就是2。
r idr_alloc(drm_minors_idr,NULL,64 * type,64 * (type 1),GFP_NOWAIT);//idr_alloc又是调用idr_alloc_u32来实现
int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
{u32 id start;int ret;if (WARN_ON_ONCE(start 0))return -EINVAL;ret idr_alloc_u32(idr, ptr, id, end 0 ? end - 1 : INT_MAX, gfp);if (ret)return ret;return id;
}
EXPORT_SYMBOL_GPL(idr_alloc);* idr_alloc() - Allocate an ID.* idr: IDR handle.* ptr: Pointer to be associated with the new ID.* start: The minimum ID (inclusive).* end: The maximum ID (exclusive).* gfp: Memory allocation flags.idr_alloc()的底3个参数就是ID的start第4个参数是ID范围的end。所以对于DRIVER_RENDER属性的device来说其ID范围是
DRM_MINOR_RENDER * 64 128 至 DRM_MINOR_RENDER 1) * 64 192 之间。
所以才有renderD128、renderD129。
内核如何管理render-node的编号
问题DRM中如何做到一个已经分配了的ID比如128下一个device来分配时就不使用128而是129呢换句话说kernel中如何记忆ID的分配结果的
int idr_alloc_u32(struct idr *idr, void *ptr, u32 *nextid,unsigned long max, gfp_t gfp)
{struct radix_tree_iter iter;void __rcu **slot;unsigned int base idr-idr_base;unsigned int id *nextid;if (WARN_ON_ONCE(!(idr-idr_rt.xa_flags ROOT_IS_IDR)))idr-idr_rt.xa_flags | IDR_RT_MARKER;id (id base) ? 0 : id - base;radix_tree_iter_init(iter, id);slot idr_get_free(idr-idr_rt, iter, gfp, max - base);if (IS_ERR(slot))return PTR_ERR(slot);*nextid iter.index base;/* there is a memory barrier inside radix_tree_iter_replace() */radix_tree_iter_replace(idr-idr_rt, iter, slot, ptr);radix_tree_iter_tag_clear(idr-idr_rt, iter, IDR_FREE);return 0;
}
EXPORT_SYMBOL_GPL(idr_alloc_u32);这里使用了基数树radix-tree。
两个显卡其分配render-node的顺序
比如我这个pc上有两个显卡intel UHD Graphics 630和Nvidia GTX 1050 Ti然后/dev/dri/下也有两个render-noderenderD128和renderD129内核分配它们的顺序是如何确定的
应该是扫描PCI设备的时候就确定顺序了。
ubuntu上查看哪个card和哪个GPU绑定
drm_info #该命令可以查看/dev/dri/card0对应的GPU驱动比如我这里两个显卡card0对应intel 630 card1对应nvidia GTX 1050Ti。
那么如何确定render node和GPU对应关系
ls /sys/class/drm/card0/device/drm/
#可以看到card0中有card0, controlD64, renderD128
ls /sys/class/drm/card1/device/drm/
#可以看到card1中有card1, controlD65, renderD129参考 DRM render node number