DRM实例教程

作者: 夕月风 | 来源:发表于2019-06-17 14:17 被阅读0次

    DRM实例教程

    DRM是一个显示驱动框架,也就是把功能封装成 open/close/ioctl 等标准接口,应用程序调用这些接口来驱动设备,显示数据。我们这里将从使用的角度来看看,怎么验证和使用DRM驱动。

    DRM设备节点

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

    card0
    controlD64
    renderD128
    

    libdrm库

    DRM驱动,对用户空间,提供了专门的的调用库libdrm.so,用户空间通过该库可以间接的调用和使用驱动。

    打开设备

        int fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
        if (fd < 0) {
            ret = -errno;
            fprintf(stderr, "cannot open '%s': %m\n", node);
            return ret;
        }
    

    打开设备有专门的接口:drmOpen

    检查DRM的能力

    DRM的能力通过drmGetCap接口获取,用drm_get_cap结构描述:

    /** DRM_IOCTL_GET_CAP ioctl argument type */
    struct drm_get_cap {
        __u64 capability;
        __u64 value;
    };
    
    int drmGetCap(int fd, uint64_t capability, uint64_t *value)
    {
        struct drm_get_cap cap;
        int ret;
    
        memclear(cap);
        cap.capability = capability;
    
        ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
        if (ret)
            return ret;
    
        *value = cap.value;
        return 0;
    }
    
    

    使用示例:

            uint64_t has_dumb;
        if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 ||
            !has_dumb) {
            fprintf(stderr, "drm device '%s' does not support dumb buffers\n",
                node);
            close(fd);
            return -EOPNOTSUPP;
        }
    

    检索Resource

    Resource的获取需要两次,第一次,获取数量大小,第二次才真正获取具体的Resource。具体看这个函数:

    drmModeResPtr drmModeGetResources(int fd)
    

    Resource结构封装:

    struct drm_mode_card_res {
        __u64 fb_id_ptr;
        __u64 crtc_id_ptr;
        __u64 connector_id_ptr;
        __u64 encoder_id_ptr;
        __u32 count_fbs;
        __u32 count_crtcs;
        __u32 count_connectors;
        __u32 count_encoders;
        __u32 min_width, max_width;
        __u32 min_height, max_height;
    };
    
    typedef struct _drmModeRes {
    
        int count_fbs;
        uint32_t *fbs;
    
        int count_crtcs;
        uint32_t *crtcs;
    
        int count_connectors;
        uint32_t *connectors;
    
        int count_encoders;
        uint32_t *encoders;
    
        uint32_t min_width, max_width;
        uint32_t min_height, max_height;
    } drmModeRes, *drmModeResPtr;
    

    实例

        /* retrieve resources */
        int ret = drmModeGetResources(fd);
        if (!res) {
            fprintf(stderr, "cannot retrieve DRM resources (%d): %m\n",
                errno);
            return -errno;
        }
    

    获取Connector

    _drmModeConnector描述结构:

    typedef struct _drmModeConnector {
        uint32_t connector_id;
        uint32_t encoder_id; /**< Encoder currently connected to */
        uint32_t connector_type;
        uint32_t connector_type_id;
        drmModeConnection connection;
        uint32_t mmWidth, mmHeight; /**< HxW in millimeters */
        drmModeSubPixel subpixel;
    
        int count_modes;
        drmModeModeInfoPtr modes;
    
        int count_props;
        uint32_t *props; /**< List of property ids */
        uint64_t *prop_values; /**< List of property values */
    
        int count_encoders;
        uint32_t *encoders; /**< List of encoder ids */
    } drmModeConnector, *drmModeConnectorPtr;
    

    示例:

            drmModeConnector *conn = drmModeGetConnector(fd, res->connectors[i]);
            if (!conn) {
                fprintf(stderr, "cannot retrieve DRM connector %u:%u (%d): %m\n",
                    i, res->connectors[i], errno);
                continue;
            }
    

    Encoder

    Encoder的结构描述:

    typedef struct _drmModeEncoder {
        uint32_t encoder_id;
        uint32_t encoder_type;
        uint32_t crtc_id;
        uint32_t possible_crtcs;
        uint32_t possible_clones;
    } drmModeEncoder, *drmModeEncoderPtr;
    

    示例:

        if (conn->encoder_id)
            drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoder_id);
        }
    
    drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
    {
        struct drm_mode_get_encoder enc;
        drmModeEncoderPtr r = NULL;
    
        memclear(enc);
        enc.encoder_id = encoder_id;
    
        if (drmIoctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc))
            return 0;
    
        if (!(r = drmMalloc(sizeof(*r))))
            return 0;
    
        r->encoder_id = enc.encoder_id;
        r->crtc_id = enc.crtc_id;
        r->encoder_type = enc.encoder_type;
        r->possible_crtcs = enc.possible_crtcs;
        r->possible_clones = enc.possible_clones;
    
        return r;
    }
    

    crtc

    CRTC结构描述:

    struct crtc {
        drmModeCrtc *crtc;
        drmModeObjectProperties *props;
        drmModePropertyRes **props_info;
        drmModeModeInfo *mode;
    };
    
    typedef struct _drmModeCrtc {
        uint32_t crtc_id;
        uint32_t buffer_id; /**< FB id to connect to 0 = disconnect */
    
        uint32_t x, y; /**< Position on the framebuffer */
        uint32_t width, height;
        int mode_valid;
        drmModeModeInfo mode;
    
        int gamma_size; /**< Number of gamma stops */
    
    } drmModeCrtc, *drmModeCrtcPtr;
    

    FrameBuffer

    创建DUMB Buffer

        ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
        if (ret < 0) {
            fprintf(stderr, "cannot create dumb buffer (%d): %m\n",
                errno);
            return -errno;
        }
    

    添加FB

        /* create framebuffer object for the dumb-buffer */
        ret = drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride,
                   dev->handle, &dev->fb);
        if (ret) {
            fprintf(stderr, "cannot create framebuffer (%d): %m\n",
                errno);
            ret = -errno;
            goto err_destroy;
        }
    

    准备map

        /* prepare buffer for memory mapping */
        memset(&mreq, 0, sizeof(mreq));
        mreq.handle = dev->handle;
        ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
        if (ret) {
            fprintf(stderr, "cannot map dumb buffer (%d): %m\n",
                errno);
            ret = -errno;
            goto err_fb;
        }
    

    做map操作:

        /* perform actual memory mapping */
        dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED,
                    fd, mreq.offset);
        if (dev->map == MAP_FAILED) {
            fprintf(stderr, "cannot mmap dumb buffer (%d): %m\n",
                errno);
            ret = -errno;
            goto err_fb;
        }
    

    CRTC的准备

    drmModeGetCrtc
    drmModeSetCrtc

    drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
    {
        struct drm_mode_crtc crtc;
        drmModeCrtcPtr r;
    
        memclear(crtc);
        crtc.crtc_id = crtcId;
    
        if (drmIoctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc))
            return 0;
    
        /*
         * return
         */
    
        if (!(r = drmMalloc(sizeof(*r))))
            return 0;
    
        r->crtc_id         = crtc.crtc_id;
        r->x               = crtc.x;
        r->y               = crtc.y;
        r->mode_valid      = crtc.mode_valid;
        if (r->mode_valid) {
            memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo));
            r->width = crtc.mode.hdisplay;
            r->height = crtc.mode.vdisplay;
        }
        r->buffer_id       = crtc.fb_id;
        r->gamma_size      = crtc.gamma_size;
        return r;
    }
    
    int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
               uint32_t x, uint32_t y, uint32_t *connectors, int count,
               drmModeModeInfoPtr mode)
    {
        struct drm_mode_crtc crtc;
    
        memclear(crtc);
        crtc.x             = x;
        crtc.y             = y;
        crtc.crtc_id       = crtcId;
        crtc.fb_id         = bufferId;
        crtc.set_connectors_ptr = VOID2U64(connectors);
        crtc.count_connectors = count;
        if (mode) {
          memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));
          crtc.mode_valid = 1;
        }
    
        return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
    }
    

    绘制

    static void modeset_draw(void)
    {
        uint8_t r, g, b;
        bool r_up, g_up, b_up;
        unsigned int i, j, k, off;
        struct modeset_dev *iter;
    
        srand(time(NULL));
        r = rand() % 0xff;
        g = rand() % 0xff;
        b = rand() % 0xff;
        r_up = g_up = b_up = true;
    
        for (i = 0; i < 50; ++i) {
            r = next_color(&r_up, r, 20);
            g = next_color(&g_up, g, 10);
            b = next_color(&b_up, b, 5);
    
            for (iter = modeset_list; iter; iter = iter->next) {
                for (j = 0; j < iter->height; ++j) {
                    for (k = 0; k < iter->width; ++k) {
                        off = iter->stride * j + k * 4;
                        *(uint32_t*)&iter->map[off] =
                                 (r << 16) | (g << 8) | b;
                    }
                }
            }
    
            usleep(100000);
        }
    }
    

    具体的代码,可以参考how-to实例:
    how-to代码实例

    相关文章

      网友评论

        本文标题:DRM实例教程

        本文链接:https://www.haomeiwen.com/subject/hzsafctx.html