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;
};
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)
/**
* 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);
};
常用接口的调用逻辑如下:
配置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
}
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
}
设置属性的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接口
复制/销毁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
设置/获取驱动私有的属性,这里的私有的属性是指除了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私有属性也应该是这么设置的
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);
};
准备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];