当前位置: 首页 > 工具软件 > Plane > 使用案例 >

DRM框架(vkms)分析(6)---- plane初始化

公羊灿
2023-12-01

一 drm_plane结构体

struct drm_plane {
	struct drm_device *dev;

    //挂载到&drm_mode_config.plane_list
	struct list_head head;

	char *name;
	struct drm_modeset_lock mutex;

	//表示plane的mode对象, 其包含了plane的各种属性
	struct drm_mode_object base;

	/**
	 * @possible_crtcs: pipes this plane can be bound to constructed from
	 * drm_crtc_mask()
	 */
    //绑定的crtc
	uint32_t possible_crtcs;
	//plane支持的fb像素format类型数组, format类型如DRM_FORMAT_ARGB8888
	uint32_t *format_types;
    //plane支持的fb像素format类型数组大小
	unsigned int format_count;
	bool format_default;

	//modifier数组,其存放的值如DRM_FORMAT_MOD_LINEAR/DRM_FORMAT_MOD_X_TILED等
	uint64_t *modifiers;
	unsigned int modifier_count;

	/**
	 * @crtc:
	 *
	 * Currently bound CRTC, only meaningful for non-atomic drivers. For
	 * atomic drivers this is forced to be NULL, atomic drivers should
	 * instead check &drm_plane_state.crtc.
	 */
    /*no-atomic drivers用来标识当前绑定的crtc。 对于atomic driver,该值应该为null
     *并使用 &drm_plane_state.crtc替代
     */
	struct drm_crtc *crtc;

    /*no-atomic drivers用来标识当前绑定的fb。 对于atomic driver,该值应该为null
     *并使用 &drm_plane_state.fb替代
     */
	struct drm_framebuffer *fb;

    /*对于non-atomic drivers, old_fb用于在modeset操作时跟踪老的fb
     * atomic drivers下,该值为Null
    */
	struct drm_framebuffer *old_fb;

    //plane funcs
	const struct drm_plane_funcs *funcs;

	/** @properties: property tracking for this plane */
    //plane的属性
	struct drm_object_properties properties;

    //如DRM_PLANE_TYPE_OVERLAY/DRM_PLANE_TYPE_PRIMARY/DRM_PLANE_TYPE_CURSOR
	enum drm_plane_type type;

    //mode_config.list中的序号
	unsigned index;

	const struct drm_plane_helper_funcs *helper_private;

    //表示plane的各种状态,如其绑定的crtc/fb等,用于atomic操作
	struct drm_plane_state *state;

    //这些属性待研究
	struct drm_property *alpha_property;
	struct drm_property *zpos_property;
	struct drm_property *rotation_property;
	struct drm_property *blend_mode_property;
	struct drm_property *color_encoding_property;
	struct drm_property *color_range_property;
	struct drm_property *scaling_filter_property;
};

二 drm_plane的初始化

vkms_plane_init
    //设置plane支持的fb formats
    fromats = vkms_formats
    //设置plane->helper_private
    funcs = &vkms_primary_helper_funcs
    
    ret = drm_universal_plane_init(dev, plane, 1<<index,
            &vkms_plane_funcs,
            formats, nformats,
            NULL, type, NULL);
        __drm_universal_plane_init
            //创建DRM_MODE_OBJECT_PLANE类型的drm_mode_object对象plane->base
            ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);            
            //绑定base.properties到plane->properties
            plane->base.properties = &plane->properties
            plane->funs = funcs; // vkms_plane_funcs;
            //.... 设置format_types/ modifiers/ possible_crtcs等
            // 将dev->mode_config->prop_fb_id等属性绑定到plane->base中
            drm_obj_attack_property(....)

    //设置plane->helper_private = vkms_primary_helper_funcs    
    drm_plane_helper_add(plane, funcs)

三  plane->funcs

/**
 * struct drm_plane_funcs - driver plane control functions
 */
struct drm_plane_funcs {

    /*使能配置plane的crtc和framebuffer.src_x/src_y/src_w/src_h指定fb的源区域
     *crtc_x/crtc_y/crtc_w/crtc_h指定其显示在crtc上的目标区域
     *atomic操作使用drm_atomic_helper_update_plane实现
    */
	int (*update_plane)(struct drm_plane *plane,
			    struct drm_crtc *crtc, struct drm_framebuffer *fb,
			    int crtc_x, int crtc_y,
			    unsigned int crtc_w, unsigned int crtc_h,
			    uint32_t src_x, uint32_t src_y,
			    uint32_t src_w, uint32_t src_h,
			    struct drm_modeset_acquire_ctx *ctx);

    /*DRM_IOCTL_MODE_SETPLANE IOCTL调用时,fb id参数,如果为0,就会调用该接口
     *关闭plane, atomic modeset使用drm_atomic_helper_disable_plane()实现该hook
     */
	int (*disable_plane)(struct drm_plane *plane,
			     struct drm_modeset_acquire_ctx *ctx);


    //该接口仅在driver卸载的时候通过drm_mode_config_cleanup()调用来清空plane资源
	void (*destroy)(struct drm_plane *plane);

    /*reset plane的软硬件状态, 通过drm_mode_config_reset接口调用
     *atomic drivers 使用drm_atomic_helper_plane_reset()实现该hook*/
	void (*reset)(struct drm_plane *plane);

    /*设置属性的legacy入口, atomic drivers不使用*/
	int (*set_property)(struct drm_plane *plane,
			    struct drm_property *property, uint64_t val);


    /*复制plane state, atomic driver必须要有该接口
     *drm_atomic_get_plane_state会调用到该hook*/
	struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane);

    //销毁plane state
	void (*atomic_destroy_state)(struct drm_plane *plane,
				     struct drm_plane_state *state);

	
    /*设置驱动自定义的属性, 通过drm_atomic_plane_set_property调用*/
	int (*atomic_set_property)(struct drm_plane *plane,
				   struct drm_plane_state *state,
				   struct drm_property *property,
				   uint64_t val);

    //获取驱动自定义的属性, 通过drm_atomic_plane_get_property调用
	int (*atomic_get_property)(struct drm_plane *plane,
				   const struct drm_plane_state *state,
				   struct drm_property *property,
				   uint64_t *val);
	
    //drm_dev_register接口调用后,调用该hook注册额外的用户接口
	int (*late_register)(struct drm_plane *plane);

    //drm_dev_unregister()前调用,unregister用户空间接口
	void (*early_unregister)(struct drm_plane *plane);


    //打印plane state, drm_atomic_plane_print_state()会调用
	void (*atomic_print_state)(struct drm_printer *p,
				   const struct drm_plane_state *state);

    //检查format和modifier是否有效
	bool (*format_mod_supported)(struct drm_plane *plane, uint32_t format,
				     uint64_t modifier);
};

常用接口的调用逻辑如下:

(1) update_plane

配置plane的crtc和framebuffer. src_x/src_y/src_w/src_h指定fb的源区域。crtc_x/crtc_y/crtc_w/crtc_h指定其显示在crtc上的目标区域。atomic操作使用drm_atomic_helper_update_plane实现


//用户态
drmModeSetPlane
    DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPLANE, ...)
//内核态
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, ...)
    //drm_mode_setplane
        setplane_internal
            if ( atomic )
            {
                __setplane_atomic
                    plane->funcs->update_plane
            }
            else
            {
                __setplane_internal
                    plane->funcs->update_plane
            }
                             

(2) disable_plane

 DRM_IOCTL_MODE_SETPLANE IOCTL调用时(对应drm_mode_setplane接口),fb id参数,如果为0,就会调用该接口关闭plane, atomic modeset使用drm_atomic_helper_disable_plane()实现该hook, 这里说的disable plane其实就是将plane的参数(crtc/fb/src_x/src_y/等)设置为空


//用户态
drmModeSetPlane
    DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPLANE, ...)
//内核态
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, ...)
    //drm_mode_setplane
        setplane_internal
            if ( atomic )
            {
                __setplane_atomic
                    //no fb means shut is down
                    if (!fb) plane->funcs->disable_plane
            }
            else
            {
                __setplane_internal
                    if (!fb) plane->funcs->disable_plane
            }
                    

(3)set_property

 设置属性的legacy入口, atomic drivers不使用, 用户态通过drmModeObjectSetProperty调用

//用户态
drmModeObjectSetProperty
    DRM_IOCTL(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &prop)
//内核态
    DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER)
    //drm_mode_obj_set_property_iotl
        set_property_legacy
            switch(obj->type)
            {
                case DRM_MODE_OBJECT_CONNECTOR:
                    //设置connector的属性
                    ret = drm_connector_set_obj_prop(obj, prop, prop_value)
                        connector->funcs->set_property
                case DRM_MODE_OBJECT_CRTC:
                    //设置crtc的属性
                    ret = drm_mode_crtc_set_obj_prop
                            crtc->funcs->set_property
                case DRM_MODE_OBJECT_PLANE:
                    //设置plane的属性
                    ret = drm_mode_plane_set_obj_prop
                            //调用plane的set_property hook
                            ret = plane->funcs->set_property(plane, property, value)
            }        

从上边的代码逻辑中也可以看出 conncect/crtc也都有自己的set_property接口

(4)atomic_duplicate_state/atomic_destroy_state

复制/销毁plane 的state, 这两个hook 是atomic driver必须要有的,一般驱动会自定义一个接口并在内部调用__drm_atomic_helper_plane_duplicate_state/__drm_atomic_helper_plane_destroy_state, 例子可以参考vkms_plane_duplicate_state/vkms_plane_destroy_state

(5)atomic_set_property/atomic_get_property

设置/获取驱动私有的属性,这里的私有的属性是指除了drm core框架指定的标准属性外的自定义属性, 私有属性的定义和使用如下:

a) 私有属性创建绑定, 以omap drm为例:

//私有属性创建绑定, 以omap drm为例:
omap_modeset_init
        omap_modeset_init_properties
            struct omap_drm_private *priv = dev->dev_private
            //创建一个zorder_prop属性实例
            priv->zorder_prop = drm_property_create_range(dev, 0, ...)
        omap_plane_init
            omap_plane_install_properties(plane, &plane->base)
                struct omap_drm_private *priv = dev->dev_private
                //将zorder_prop实例绑定到plane->base中
                drm_object_attach_property(obj, priv->zorder_prop, 0);

类似的crtc/connector私有属性也应该是这么创建绑定的

b) 私有属性的获取

用户态通过调用接口drmModeGetPlaneResources获取plane_id后,调用drmModeObjectGetProperties接口,会得到plane_id对应的所有属性,这里边就包括框架提供的(fb/src_x等)以及私有属性。在上文中,我们知道私有属性都绑定在plane->base这个drm_mode_object实例中,其有唯一标识的plane->base.id(即plane_id), 反过来也就可以更加plane_id找到其所有的属性,包括私有属性。

//user
drmModeObjectGetProperties(fd, object_id, object_type)
    drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties)

//kernel           
drm_mode_obj_get_properties_ioctl
    //根据obj_id找到obj对象(如plane->base)
    drm_mode_object* obj = drm_mode_object_find(arg->obj_id, arg->obj_type)
    //查找obj中的属性及其属性值
    drm_mode_object_get_properties(obj, arg->props_ptr, arg->prop_values_ptr, 
            &arg->count_props)
        __drm_object_property_get_value
            //获取属性值
            drm_atomic_get_property(obj, property, val)
                switch(obj->type)
                {
                    case DRM_MODE_OBJECT_CONNECTOR:
                        drm_atomic_connector_get_property
                    case DRM_MODE_OBJECT_CRTC:
                        drm_atomic_crtc_get_property
                    case DRM_MODE_OBJECT_PLANE:
                        drm_atomic_plane_get_property(plane, plane->state, property, val)
                            //1.获取标准属性值,如crtc_x/crtc_y/fb_id等
                            //2.获取私有属性
                            plane->funcs->atomic_get_property(plane, state, property,val)
                }
                        

类似的crtc/connector私有属性也应该是这么获取的

c) 私有属性的设置

和获取的逻辑基本相同。用户态接口是drmModeObjectSetProperty,对应内核态接口为

drm_mode_obj_set_property_ioctl---> set_property_atomic---> drm_atomic_set_property--->

drm_atomic_plane_set_property--->   plane->funcs->atomic_set_property

类似的crtc/connector私有属性也应该是这么设置的

四 plane->helper_private


struct drm_plane_helper_funcs {
	
    //准备fb,主要包括设置fb fence,  映射fb虚拟地址等
	int (*prepare_fb)(struct drm_plane *plane,
			  struct drm_plane_state *new_state);

    //和prepare_fb是相反的操作,比如解除fb虚拟地址的映射
	void (*cleanup_fb)(struct drm_plane *plane,
			   struct drm_plane_state *old_state);

    //可选的检查plane属性的约束项
	int (*atomic_check)(struct drm_plane *plane,
			    struct drm_atomic_state *state);

    /*更新plane的属性状态到软硬件中, 这个接口才是真正更新参数*/
	void (*atomic_update)(struct drm_plane *plane,
			      struct drm_atomic_state *state);
    //disable plane 非必需,不做介绍
	void (*atomic_disable)(struct drm_plane *plane,
			       struct drm_atomic_state *state);

    //异步检查 后续了解
	int (*atomic_async_check)(struct drm_plane *plane,
				  struct drm_atomic_state *state);
    //异步更新,后续了解
	void (*atomic_async_update)(struct drm_plane *plane,
				    struct drm_atomic_state *state);
};

(1)prepare_fb

准备fb,主要包括设置fb fence,  映射fb虚拟地址等, 以vkms_prepare_fb为例

vkms_prepare_fb(struct drm_plane *plane,
                    struct drm_plane_state *state)
        //根据drm_framebuffer实例(state->fb)找到实际的内存对象drm_gem_object * gem_obj
        //注意这两者之间的关联是通过drmModeAddFB接口,其参数handle(对应drm_gem_object实例),
        //fb_id对应drm_fframebuffer实例
        struct drm_gem_object *gem_obj = drm_gem_fb_get_obj(state->fb, 0)
        //1.映射虚拟地址
        ret = drm_gem_shmem_vmap(gem_obj, &map); 
        //2.设置fb的fence到state, 这里涉及到dma_fence的同步使用
        drm_gem_plane_helper_prepare_fb(plane, state)
            drm_gem_object* obj=drm_gem_fb_get_obj(state->fb, 0)
            dma_fence* fence = dma_resv_get_excl_rcu(obj->resv)
            drm_atomic_set_fece_for_plane(state, fence)
                    //设置fb的fence到state,
                    plane_state->fence = fence;

        

上边准备好dma-fence之后,会在atmic操作中,等待独占dma-fence被signal,如下:

 int drm_atomic_helper_wait_for_fences(struct drm_device *dev,
                          struct drm_atomic_state *state,
                          bool pre_swap)
    {
        for_each_new_plane_in_state(state, plane, new_plane_state, i) {
            if (!new_plane_state->fence)
                continue;
            ret = dma_fence_wait(new_plane_state->fence, pre_swap);
            if (ret)
                return ret;
 
            dma_fence_put(new_plane_state->fence);
            new_plane_state->fence = NULL;
        }

        return 0;
    }

dma-fence可以参考文章:

linux GPU上多个buffer间的同步之ww_mutex、dma_fence的使用 笔记 - -Yaong- - 博客园

prepare_fb在drm_atomic_helper_commit中被调用,逻辑如下:

drm_atomic_helper_commit
    ret = drm_atomic_helpr_prepare_planes(dev, state)
            funcs = plane->helper_private
            //调用prepare_fb 读取fb的独占dma-fence
            ret = funcs->prepare_fb(plane, new_plane_state)
    if (!nonblock)
         ret = drm_atomic_helper_wait_for_fences(dev, state, true)
                    //等待独占dma-fence被signal
                    ret = dma_fence_wait(new_plane_state->fence, pre_swap)   

(2)atomic_check

crtc/plane/connector/encoder都有atomic_check接口用来检查其约束项。从下边的逻辑可以看出这些接口都是在atomic modeset时通过drm_atomic_check_only调用的

drm_mode_atomic_ioctl
    drm_atomic_check_only
        config->funcs->atomic_check //drm_mode_config_funcs.atomic_check =                 drm_atomic_helper_check
        //调用connector/encoder的atomic_checK接口检查其约束项
        drm_atomic_helper_check_modeset
        drm_atomic_helper_check_planes
            //调用plane的atomic_check检查约束项
            funcs = plane->helper_private
            funcs->atomic_check
            //调用crtc的atomic——check检查约束项
            funcs = crtc->helper_private
            funcs->atomic_check
    //提交前也会调用drm_atomic_check_only接口,check失败的话,则不会提交modeset
    drm_atomic_commit
            ret = drm_atomic_check_only
            if (ret)
                return ret;
        

(3)atomic_update

更新plane的属性状态到软硬件中, 这个接口才是真正更新参数,通过drm_atomic_helper_commit触发调用流程。

以vkms_plane_atomic_update为例:

vkms_plane_atomic_update
    composer = vkms_plane_state->composer;
    //将modeset参数更新到composer中,在vkms_composer_worker工作队列中
    //会调用这些参数进行合成处理
    memcpy(&composer->src, &new_state->src, sizeof(struct drm_rect));
	memcpy(&composer->dst, &new_state->dst, sizeof(struct drm_rect));
	memcpy(&composer->fb, fb, sizeof(struct drm_framebuffer));
	memcpy(&composer->map, &shadow_plane_state->data, sizeof(composer->map));
	drm_framebuffer_get(&composer->fb);
	composer->offset = fb->offsets[0];
	composer->pitch = fb->pitches[0];
	composer->cpp = fb->format->cpp[0];
 类似资料: