Overview

一篇关于垂直同步 V-Sync 解释的文章:https://daily.elepover.com/2021/03/27/vsync/index.html

当 GPU 渲染的速度 > 显示器刷新的速度时,GPU 在显示器还来不及完成渲染完一帧时,就切换了 framebuffer,会导致出现撕裂现象。

帧率大于显示器刷新率时,启用垂直同步。
帧率小于显示器刷新率时,禁用垂直同步。


为了支持 vblank,底层 drvier 需要调用 drm_vblank_init()初始化,另外需要实现 drm_crtc_funcs.enable_vblank 和 drm_crtc_funcs.disable_vblank 两个回调函数,并且在 vblank 中断中调用 drm_crtc_handle_vblank()。

数据结构

struct drm_vblank_crtc {
	struct drm_device *dev;
	wait_queue_head_t queue;
	struct timer_list disable_timer;
	seqlock_t seqlock;
	atomic64_t count;
	ktime_t time;
	atomic_t refcount;
	u32 last;
	u32 max_vblank_count;
	unsigned int inmodeset;
	unsigned int pipe;
	int framedur_ns;
	int linedur_ns;
	struct drm_display_mode hwmode;
	bool enabled;
	struct kthread_worker *worker;
	struct list_head pending_work;
	wait_queue_head_t work_wait_queue;
};

pipe: 表示第几个 crtc,在 drm_vblank_init 中初始化。

refcount: vblank interrupt user/waiter 数量。

max_vblank_count: vblank register 最大的范围,如果不为 0 表示支持硬件 vblank count 计数,底层 driver 初始化该数值,并且 drm_crtc_funcs.get_vblank_counter 必须提供。

inmodeset: 表示是否在 modeset 过程中,1 vblank is disabled, 0 vblank is enabled.

struct drm_pending_vblank_event {
	struct drm_pending_event base;
	unsigned int pipe;
	u64 sequence;
	union {
		struct drm_event base;
		struct drm_event_vblank vbl;
		struct drm_event_crtc_sequence seq;
	} event;
};

sequence: 硬件 vblank 应该在该数量 trigger

函数

drm_crtc_arm_vblank_event: 需要保证在 atomic commit 所有硬件改动完成后,才会触发 vblank 中断。

drm_crtc_send_vblank_event