DRM驱动(八)之crtc_state生命周期

之前的文章里说过,drm机制会将一次要更新的内容全部放到state中,然后在更新不同component时把xxx_state里面的值拿出来更新到硬件里。前段时间遇到了个问题,梳理了一下每个组件的state创建,使用,销毁。记录一下防止忘记。

再复习一下drm_atomic_state这个数据结构

struct drm_atomic_state {
    struct drm_device *dev;

    struct __drm_planes_state *planes;
    struct __drm_crtcs_state *crtcs;
    int num_connector;
    struct __drm_connnectors_state *connectors;
    int num_private_objs;
    struct __drm_private_objs_state *private_objs;
... ...
};

可以看到里面主要包含4个比较重要的结构__drm_planes_state,__drm_crtcs_state,__drm_connnectors_state,__drm_private_objs_state;每个结构大体相同,创建方式也基本一致,就单拎出来crtc_state来分析。

拿之前的一个图,展示一下各个数据结构的关系

77696e22a23e47ed9f793ddb75b6aae1.png

再来复习一下刷图过程,具体可以参看之前的文章《DRM驱动(五)之drm_atomic_state》

drm_mode_setcrtc ->__drm_mode_set_config_internal->drm_atomic_helper_set_config(这里会创建drm_atomic_state)->__drm_atomic_helper_set_config

在__drm_atomic_helper_set_config调用drm_atomic_get_crtc_state创建crtc_state

int __drm_atomic_helper_set_config(struct drm_mode_set *set,
        struct drm_atomic_state *state)
{
    struct drm_crtc_state *crtc_state;
    struct drm_plane_state *primary_state;
    struct drm_crtc *crtc = set->crtc;
    int hdisplay, vdisplay;
    int ret;

    crtc_state = drm_atomic_get_crtc_state(state, crtc);
    if (IS_ERR(crtc_state))
        return PTR_ERR(crtc_state);

    primary_state = drm_atomic_get_plane_state(state, crtc->primary);
    if (IS_ERR(primary_state))
        return PTR_ERR(primary_state);
... ...

commit:
    ret = update_output_state(state, set);
    if (ret)
        return ret;

    return 0;
}

接着来看下drm_atomic_get_crtc_state

struct drm_crtc_state *
drm_atomic_get_crtc_state(struct drm_atomic_state *state,
              struct drm_crtc *crtc)
{
    int ret, index = drm_crtc_index(crtc);
    struct drm_crtc_state *crtc_state;

    crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
    if (crtc_state)
        return crtc_state;

    crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
    if (!crtc_state)
        return ERR_PTR(-ENOMEM);

    state->crtcs[index].state = crtc_state;
    state->crtcs[index].old_state = crtc->state;
    state->crtcs[index].new_state = crtc_state;
    state->crtcs[index].ptr = crtc;
    crtc_state->state = state;


    return crtc_state;
}

drm_atomic_get_crtc_state中主要做三件事:

  1. 判断state->crtcs[index].state是否已经存在,存在就直接返回。这里一般为空
  2. 调用crtc中实现的atomic_duplicate_state来创建crtc_state,后面举个具体例子分析
  3. 将创建的crtc_state存放到state->crtcs[index].state和state->crtcs[index].new_state,并将crtc->state(保留的上次刷图的crtc_state)传给old_state

接下来分析由vendor实现的atomic_duplicate_state

比如rockchip的实现,也非常简单

static const struct drm_crtc_funcs vop_crtc_funcs = {
... ...

    .atomic_duplicate_state = vop_crtc_duplicate_state,
    .atomic_destroy_state = vop_crtc_destroy_state,
... ...

};

static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc)
{
    struct rockchip_crtc_state *rockchip_state;

    rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL);
    if (!rockchip_state)
        return NULL;

    __drm_atomic_helper_crtc_duplicate_state(crtc, &rockchip_state->base);
    return &rockchip_state->base;
}

static void vop_crtc_destroy_state(struct drm_crtc *crtc,
                   struct drm_crtc_state *state)
{
    struct rockchip_crtc_state *s = to_rockchip_crtc_state(state);

    __drm_atomic_helper_crtc_destroy_state(&s->base);
    kfree(s);
}

rockchip对drm_crtc_state进行了扩展,为了添加一些自己特有的属性,在另外的地方可以根据其中的base通过container_of找到扩展的结构。

可以看到vop_crtc_duplicate_state主要做了两个工作:

  1. 分配内存
  2. 将crtc->state copy到新创建的crtc_state然后将地址返回。所以叫duplicate

上面已经说过drm_atomic_get_crtc_state会将duplicate到的crtc_state赋值给state->crtcs[index].state和state->crtcs[index].new_state

plane_state和connector_state的创建方式相同,大家可以看下源码自行分析下。

然后进行刷图,drm_atomic_helper_commit中会调用drm_atomic_helper_swap_state也比较有意思(这里还是拿crtc_state举例)

int drm_atomic_helper_swap_state(struct drm_atomic_state *state,
                  bool stall)
{
    int i, ret;
    struct drm_crtc *crtc;
    struct drm_crtc_state *old_crtc_state, *new_crtc_state;
    struct drm_crtc_commit *commit;
... ...
    for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
        WARN_ON(crtc->state != old_crtc_state);

        old_crtc_state->state = state;
        new_crtc_state->state = NULL;

        state->crtcs[i].state = old_crtc_state;
        crtc->state = new_crtc_state;


    }
... ...
    return 0;
}

drm_atomic_helper_swap_state的主要目的遍历所有的crtc,将新创建的crtc_state赋值crtc->state;state->crtcs[i].state这里和duplicate state赋的是一样的值。

后面就会根据应用传下来的参数向crtc_state填充,驱动会根据crtc_state的参数配置硬件寄存器。

当所有的配置都完成之后,会调用drm_atomic_state_put

static void commit_tail(struct drm_atomic_state *old_state)
{
    struct drm_device *dev = old_state->dev;
    const struct drm_mode_config_helper_funcs *funcs;

    funcs = dev->mode_config.helper_private;

    drm_atomic_helper_wait_for_fences(dev, old_state, false);

    drm_atomic_helper_wait_for_dependencies(old_state);

    if (funcs && funcs->atomic_commit_tail)
        funcs->atomic_commit_tail(old_state);
    else
        drm_atomic_helper_commit_tail(old_state);

    drm_atomic_helper_commit_cleanup_done(old_state);

    drm_atomic_state_put(old_state);
}
static inline void drm_atomic_state_put(struct drm_atomic_state *state)
{
    kref_put(&state->ref, __drm_atomic_state_free);
}

这里是个引用计数,但是因为state只被get一次,所以调用到这里的时候就会执行__drm_atomic_state_free

然后__drm_atomic_state_free->drm_atomic_state_clear->drm_atomic_state_default_clear

void drm_atomic_state_default_clear(struct drm_atomic_state *state)
{
    struct drm_device *dev = state->dev;
    struct drm_mode_config *config = &dev->mode_config;
    int i;

    DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state);
... ...

    for (i = 0; i < config->num_crtc; i++) {
        struct drm_crtc *crtc = state->crtcs[i].ptr;

        if (!crtc)
            continue;

        crtc->funcs->atomic_destroy_state(crtc,
                          state->crtcs[i].state);

        if (state->crtcs[i].commit) {
            kfree(state->crtcs[i].commit->event);
            state->crtcs[i].commit->event = NULL;
            drm_crtc_commit_put(state->crtcs[i].commit);
        }

        state->crtcs[i].commit = NULL;
        state->crtcs[i].ptr = NULL;
        state->crtcs[i].state = NULL;
        state->crtcs[i].old_state = NULL;
        state->crtcs[i].new_state = NULL;
    }
... ...

}

drm_atomic_state_default_clear的主要工作是:

1. 调用vendor实现的atomic_destroy_state,包括crtc,plane,connector,private_obj。

2. 将指针置空,防止出现野指针。

但是这里有个细节,crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].state); 这里释放的是 state->crtcs[i].state而不是state->crtcs[i].new_state;还记得state->crtcs[i].state是保存的什么时候的crtc_state吗?

对,没错,是上一次的crtc_state,而不是这一次的;也就是说,销毁是落后一帧的。

 之前内容只是聊了大概的框架,这篇文章算是对之前内容的补充,把一些细节放大来阐述。最后用几张图总结xxx_state的生命周期

2e041b196ab246eda2ad966b24c3d3d2.jpeg

 

19a6f69cab014f8ab91683d2dfe07281.png

eb0affc29ad94e8f9a2e758f5e9dd7ae.png

8ab506fbc19c4c3391b487c4e34f4c9d.png

 (PS:我一直以为写过了分析具体drm驱动driver实现的内容,翻了好久发现好像没写;等有空了补上,手动狗头)

 

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值