【转】DRM(三)libdrm库

2020-10-22  本文已影响0人  RonZheng2010

1. DRM driver 与 libdrm库

DRM是Linux内核层的显示驱动框架。它把显示功能封装成 open/close/ioctl 等标准接口,用户空间的程序调用这些接口,驱动设备,显示数据。

libdrm库封装了DRM driver提供的这些接口。通过libdrm库,程序可以间接调用DRM Driver。

2. 打开设备

DRM驱动会在/dev/dri下创建3个设备节点:

card0
controlD64
renderD128

使用drmOpen()打开设备。它根据指定的name和busid,在上述三个设备中选择匹配的节点。

// 打开DRM设备
int drmOpen(const char *name, const char *busid);

也可以使用open(),直接打开指定设备。

int fd;
fd = open ("/dev/dri/card0", O_RDWR, 0);

3. Capability

得到、设置capability。

// 得到指定的capability
int drmGetCap(int fd, uint64_t capability, uint64_t *value);

// 设置指定的capability
int drmSetClientCap(int fd, uint64_t capability, uint64_t value);

4. DRM组件

下图显示各个组件,以及组件之间的关联关系。在DRM的函数名中称作资源(Resource)。如drmModeGetResources()。

每种资源的结构都定义了一个成员,唯一标识这个资源。如drmModeCrtc的crtc_id、drmModeConnector的connector_id、drmModeEncoder的encoder_id、drmModePlane的plane_id。

显示设备的设置、状态,保存在若干结构、变量中,如下图。如drmModeModeInfo,保存设备大小,刷新率。drmModeConnection保存连接状态。

4. 得到资源

drmModeRes结构保存DRM设备的资源集。

drmModeRes的成员fbs、crtcs、connectors、encoders是变长数组,数组长度保存在对应的变量,如count_fbs中。数组中保存的是资源ID。

函数drmModeGetResources()用于得到资源集。

// 得到资源集
drmModeResPtr drmModeGetResources(int fd);

根据资源 ID 得到对应的资源,包括connector、encoder、crtc。

// 得到connector
drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id);
// 得到encoder
drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id);
// 得到crtc
drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId);

与其他资源不同,plane资源不在drmModeRes结构中,而是保存在drmModePlaneRes结构。

成员planes是变长数组,数组长度保存在count_planes中。这里保存是plane的资源ID。

drmModeGetPlaneResources()得到plane资源集。

// 得到plane资源集
drmModePlaneResPtr drmModeGetPlaneResources(int fd);

drmModeGetPlane() 根据Plane ID得到Plane。

// 根据plane ID得到Plane资源
drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id);

5. 资源Property

drmModeProperty结构保存属性。

drmModeObjectProperties保存资源的属性集。

drmModeObjectGetProperties()得到资源属性集。

drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd,
                              uint32_t object_id,
                              uint32_t object_type);

drmModeGetProperty()得到属性,drmModeObjectSetProperty()设置属性。

drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id);

int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type,
                 uint32_t property_id, uint64_t value);

5. framebuffer ioctl操作

使用drmIoctl()创建、映射framebuffer。

// requests
#define DRM_IOCTL_MODE_CREATE_DUMB ...   // 创建framebuffer
#define DRM_IOCTL_MODE_MAP_DUMB    ...      // 映射framebuffer

int drmIoctl(int fd, unsigned long request, void *arg)

使用Linux API函数 mmap(),将framebuffer映射到用户空间。

void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset);

5. 加入framebuffer

加入framebuffer(不是提交显示!)。

int drmModeAddFB2(int fd, uint32_t width, uint32_t height,
                  uint32_t pixel_format, // framebuffer图像格式
                  uint32_t bo_handles[4], 
                  uint32_t pitches[4], uint32_t offsets[4],
                  uint32_t *buf_id,  // framebuffer ID
                  uint32_t flags);

5. 提交DRM请求

drmModeAtomicReq保存DRM请求。

drmModeAtomicCommit()提交请求。比如,将framebuffer保存的图像提交显示。

int drmModeAtomicCommit(int fd,
                   drmModeAtomicReqPtr req,
                   uint32_t flags,
                   void *user_data);

5. 绑定framebuffer到Plane

将framebuffer绑定到plane。程序更新framebuffer,就是更新plane。

// 将framebuffer绑定到plane
int drmModeSetPlane(int fd, 
            uint32_t plane_id, // plane id
            uint32_t crtc_id,
            uint32_t fb_id, // frambuffer id
            uint32_t flags,
            int32_t crtc_x, int32_t crtc_y, uint32_t crtc_w, uint32_t crtc_h, // 目标区域RECT
            uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h); // 源区域RECT

参考资料

Linux DRM API - NVIDIA
DRM示例工程 zizimumu/DRM_test

上一篇 下一篇

猜你喜欢

热点阅读