在扫描输出过程中,一个平面(plane)代表一个图像源,CRTC 可以对平面进行混合(blend)或叠加(overlaid)显示。plane 从 drm_framebuffer 获取输入数据。平面本身定义了图像的裁剪(cropping)和缩放(scaling)方式,以及它在 display pipeline 可见区域中的位置。平面还可以具有额外的属性来指定平面像素的定位和混合方式,比如旋转(rotation)或 Z 轴位置(Z-position)。所有这些属性都存储在 drm_plane_state 中。

plane 由 struct drm_plane 表示,使用drm_universal_plane_init() 初始化。

每个 plane 都有一个类型,参考 enum drm_plane_type

每个 CRTC 都必须要有一个 primary plane。

Data structure and api

struct drm_plane {
	struct drm_device *dev;
	struct list_head head;
	char *name;
	struct drm_modeset_lock mutex;
	struct drm_mode_object base;
	uint32_t possible_crtcs;
	uint32_t *format_types;
	unsigned int format_count;
	uint64_t *modifiers;
	unsigned int modifier_count;
	const struct drm_plane_funcs *funcs;
	struct drm_object_properties properties;
	enum drm_plane_type type;
	unsigned index;
	const struct drm_plane_helper_funcs *helper_private;
	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;
	struct drm_property *hotspot_x_property;
	struct drm_property *hotspot_y_property;
};

possible_crtcs: 该 plane 支持的 crtc 类型,在 plane 初始化时传入。

format_types: plane 支持的 pixel format 数组,在 plane 初始化时传入。

format_count: format_types 数组的大小。

modifiers: plane 支持的 modifier 数组,在 plane 初始化时传入。

modifier_count: modifiers 数组的大小。

struct drm_plane_state {
	struct drm_plane *plane;
	struct drm_crtc *crtc;
	struct drm_framebuffer *fb;
	int32_t crtc_x;
	int32_t crtc_y;
	uint32_t crtc_w, crtc_h;
	uint32_t src_x;
	uint32_t src_y;
	uint32_t src_h, src_w;
	int32_t hotspot_x, hotspot_y;
	u16 alpha;
	uint16_t pixel_blend_mode;
	unsigned int rotation;
	unsigned int zpos;
	unsigned int normalized_zpos;
	enum drm_color_encoding color_encoding;
	enum drm_color_range color_range;
	struct drm_property_blob *fb_damage_clips;
	bool ignore_damage_clips;
	struct drm_rect src, dst;
	bool visible;
	struct drm_crtc_commit *commit;
	struct drm_atomic_state *state;
	bool color_mgmt_changed : 1;
};

crtc: 通过 drm_atomic_set_crtc_for_plane 绑定的 crtc

fb: 通过 drm_atomic_set_fb_for_plane 绑定的 fb

crtc_x/y/w/h: 设置该 plane 可见区域的起始位置和大小。

src_x/y/w/h: 从 framebuffer 中取 pixels 的区域起始位置和大小

当 SRC 与 CRTC 的 X/Y 不相等时,则实现了平移的效果; 当 SRC 与 CRTC 的 W/H 不相等时,则实现了缩放的效果; 当 SRC 与 FrameBuffer 的 W/H 不相等时,则实现了裁剪的效果;

hotspot_x/y:

alpha: 该 plane 的透明度,0x0 为全透明,0xff 为不透明。需要调用 drm_plane_create_alpha_property() 来创建该 property。

pixel_blend_mode: 当前 plane 和背景 blend 的模式。有三种 blend mode, DRM_MODE_BLEND_PIXEL_NONE, DRM_MODE_BLEND_PREMULTI, DRM_MODE_BLEND_COVERAGE。 三者计算公式不同,具体参考 drm_blend.c 注释。

rotation: 旋转/镜像 plane,需要通过 drm_plane_create_rotation_property() 创建该 property。

zpos: plane 的叠加优先顺序。需要通过 drm_plane_create_zpos_property() 或 drm_plane_create_zpos_immutable_property() 创建该 property。

normalized_zpos: 相比于 zpos 可以自行设定值,normalize 后的 zpos 在范围 0~N-1, N 为 plane 的数量。

color_encoding: 平面 YUV 编码,包括 BT601, BT709, BT2020。

color_range: 平面 YUV 颜色范围,包括 limited range, full range。

fb_damage_clips:

ignore_damage_clips:

src/dst: 经过 drm_atomic_helper_check_plane_state clip 后的 fb 源地址和 plane 目标地址。硬件编程最好使用这个属性,而不是前面的 crtc_x/y/w/h 和 src_x/y/w/h。

visible: 表示该 plane 是否可见,可在 plane atomic_check, atomic_update 中来检查一下该属性。

scaling_filter: 参考 enum drm_scaling_filter。大部分 driver 都不支持。

color_mgmt_changed: 表示 color management 属性是否被改变。注意这边 crtc_state 中也有一样的 color_mgmt_changed,在代码中看到一般都是操作 crtc_state 的 color_mgmt_changed。

struct drm_plane_funcs {
  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);
  int (*disable_plane)(struct drm_plane *plane,
			struct drm_modeset_acquire_ctx *ctx);			
  void (*destroy)(struct drm_plane *plane);
  void (*reset)(struct drm_plane *plane);
  struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane);
  void (*atomic_destroy_state)(struct drm_plane *plane,
             struct drm_plane_state *state);
  int (*atomic_set_property)(struct drm_plane *plane,
           struct drm_plane_state *state,
           struct drm_property *property,
           uint64_t val);
  int (*atomic_get_property)(struct drm_plane *plane,
           const struct drm_plane_state *state,
           struct drm_property *property,
           uint64_t *val);
  int (*late_register)(struct drm_plane *plane);
  void (*early_unregister)(struct drm_plane *plane);
  void (*atomic_print_state)(struct drm_printer *p,
           const struct drm_plane_state *state);
  bool (*format_mod_supported)(struct drm_plane *plane, uint32_t format,
             uint64_t modifier);
};

destroy: optional, 在 drm_mode_config_cleanup() 中被调用,设置为 drm_plane_cleanup 即可。 如果使用的 drmm_xxx 初始化 plane 那么就不用设置该回调。

reset: optional,reset plane state。通用接口 drm_atomic_helper_plane_reset。 如果 driver 有 private plane state 结构体,那么需要使用自己的回调。

atomic_duplicate_state: 和 crtc 相关回调类似,drm_atomic_helper_plane_duplicate_state

atomic_destroy_state: 同上,drm_atomic_helper_plane_destroy_state

atomic_set_property: 同上

atomic_get_property: 同上

late_register: 同上

early_unregister: 同上

atomic_print_state: 同上

format_mod_supported: 检查某个 format 和某个 modifier 的组合是否支持,单独检查 format 是否支持在 drm_plane_check_pixel_format() 就做过了。

struct drm_plane_helper_funcs {
	int (*prepare_fb)(struct drm_plane *plane,
			  struct drm_plane_state *new_state);
	void (*cleanup_fb)(struct drm_plane *plane,
			   struct drm_plane_state *old_state);
	int (*begin_fb_access)(struct drm_plane *plane, struct drm_plane_state *new_plane_state);
	void (*end_fb_access)(struct drm_plane *plane, struct drm_plane_state *new_plane_state);
	int (*atomic_check)(struct drm_plane *plane,
			    struct drm_atomic_state *state);
	void (*atomic_update)(struct drm_plane *plane,
			      struct drm_atomic_state *state);
	void (*atomic_enable)(struct drm_plane *plane,
			      struct drm_atomic_state *state);
	void (*atomic_disable)(struct drm_plane *plane,
			       struct drm_atomic_state *state);
};

prepare_fb: optional hook, framebuffer 准备工作,包括 pin framebuffer backing storage, relocate into contiguous VRAM, flush cache 等。如果没实现,那么在 drm_atomic_helper_prepare_planes 中会自动调用 drm_gem_plane_helper_prepare_fb(). 如果有额外的任务,那么 driver 自行实现该回调,并在该回调中调用 drm_gem_plane_helper_prepare_fb。

cleanup_fb: optional hook, 清理 .prepare_fb 分配的 resource。

begin_fb_access: optional hook, 和 prepare_fb 类似。这两组回调用的 driver 目前很少。 end_fb_access: optional hook, free resources in begin_fb_access。

注意这边 prepare_fb/cleanup_fb 和 begin_fb_access/end_fb_access 这两组回调函数的区别在于 cleanup_fb 和 end_fb_access 的调用实时机不同。end_fb_access 在 drm_atomic_helper_commit_planes() 完成后就会调用,这时候还没 enable crtc,在 commit 完成后就释放。而 cleanup_fb 在 drm_atomic_helper_cleanup_planes() 所有完成才会被调用。

atomic_check: optional hook, check plane specific constraints。可在回调中调用 drm_atomic_helper_check_plane_state()。

atomic_update: 更新 plane state。

atomic_enable: enable plane。

atomic_disable: disable plane。

API:

int drm_universal_plane_init(struct drm_device *dev,
			     struct drm_plane *plane,
			     uint32_t possible_crtcs,
			     const struct drm_plane_funcs *funcs,
			     const uint32_t *formats,
			     unsigned int format_count,
			     const uint64_t *format_modifiers,
			     enum drm_plane_type type,
			     const char *name, ...);
#define drmm_universal_plane_alloc(dev, type, member, possible_crtcs, funcs, formats, \
				   format_count, format_modifiers, plane_type, name, ...)
static inline unsigned int drm_plane_index(const struct drm_plane *plane);
static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
		struct drm_file *file_priv,
		uint32_t id);
#define drm_for_each_plane(plane, dev);
bool drm_any_plane_has_format(struct drm_device *dev,
			      u32 format, u64 modifier);