drm中如何找crtc,vblank page flip实现

/* retrieve resources */

drmModeRes *res;

res = drmModeGetResources(fd);

通过drmModeGetResources能获取到有限个connector和crtc。而某个connector是否能与某个crtc一起协同工作,需要encoder的支持。每个connector都有有限个可供使用的encoder列表,而encoder需要与crtc适配上才能工作。

每个连接器都有一个可供使用的编码器的有限列表,可以通过conn->count_encoders来遍历每个连接器对应的编码器。每个编码器只能与有限的crtc列表一起工作,crtc只有有限个:res->count_crtcs,与连接器一样的少 res->count_connectors。

 

/*
 * modeset_find_crtc(fd, res, conn, dev): This small helper tries to find a
 * suitable CRTC for the given connector. We have actually have to introduce one
 * more DRM object to make this more clear: Encoders.
 * Encoders help the CRTC to convert data from a framebuffer into the right
 * format that can be used for the chosen connector. We do not have to
 * understand any more of these conversions to make use of it. However, you must
 * know that each connector has a limited list of encoders that it can use. And
 * each encoder can only work with a limited list of CRTCs. So what we do is
 * trying each encoder that is available and looking for a CRTC that this
 * encoder can work with. If we find the first working combination, we are happy
 * and write it into the @dev structure.
 * But before iterating all available encoders, we first try the currently
 * active encoder+crtc on a connector to avoid a full modeset.
 *
 * However, before we can use a CRTC we must make sure that no other device,
 * that we setup previously, is already using this CRTC. Remember, we can only
 * drive one connector per CRTC! So we simply iterate through the "modeset_list"
 * of previously setup devices and check that this CRTC wasn't used before.
 * Otherwise, we continue with the next CRTC/Encoder combination.
 */

static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
                 struct modeset_dev *dev)
{
    drmModeEncoder *enc;
    unsigned int i, j;
    int32_t crtc;
    struct modeset_dev *iter;

    /* first try the currently conected encoder+crtc */
    if (conn->encoder_id)
        enc = drmModeGetEncoder(fd, conn->encoder_id);
    else
        enc = NULL;

    if (enc) {
        if (enc->crtc_id) {
            crtc = enc->crtc_id;
            for (iter = modeset_list; iter; iter = iter->next) {
                if (iter->crtc == crtc) {
                    crtc = -1;
                    break;
                }
            }

            if (crtc >= 0) {
                drmModeFreeEncoder(enc);
                dev->crtc = crtc;
                return 0;
            }
        }

        drmModeFreeEncoder(enc);
    }

    /* If the connector is not currently bound to an encoder or if the
     * encoder+crtc is already used by another connector (actually unlikely
     * but lets be safe), iterate all other available encoders to find a
     * matching CRTC. */
    for (i = 0; i < conn->count_encoders; ++i) {
        enc = drmModeGetEncoder(fd, conn->encoders[i]);
        if (!enc) {
            fprintf(stderr, "cannot retrieve encoder %u:%u (%d): %m\n",
                i, conn->encoders[i], errno);
            continue;
        }

        /* iterate all global CRTCs */
        for (j = 0; j < res->count_crtcs; ++j) {
            /* check whether this CRTC works with the encoder */
            if (!(enc->possible_crtcs & (1 << j)))
                continue;

            /* check that no other device already uses this CRTC */
            crtc = res->crtcs[j];
            for (iter = modeset_list; iter; iter = iter->next) {
                if (iter->crtc == crtc) {
                    crtc = -1;
                    break;
                }
            }

            /* we have found a CRTC, so save it and return */
            if (crtc >= 0) {
                drmModeFreeEncoder(enc);
                dev->crtc = crtc;
                return 0;
            }
        }

        drmModeFreeEncoder(enc);
    }

    fprintf(stderr, "cannot find suitable CRTC for connector %u\n",
        conn->connector_id);
    return -ENOENT;
}

vblank:垂直空白是时间段:当显示控制器暂停扫描帧缓冲区时。之后垂直空白结束后,帧缓冲区再次逐行扫描并接着是一个垂直空白。


调用者调用drmModePageFlip函数为下一个vblank安排缓冲区翻转,当下一个vblank时间段到了后,内核会使用上次drmModePageFlip传入的buf->fb以完成下一次的缓冲区扫描操作.
当内核完成页面翻转工作后,DRM fd将变得可读.此时调用者可以再次调用drmModePageFlip函数为下一个vblank安排缓冲区翻转。

drm中如何找crtc,vblank page flip实现_第1张图片

drm中如何找crtc,vblank page flip实现_第2张图片

 

你可能感兴趣的:(rk3399)