Wayland学习记录

Waylandx学习记录
写这篇文章的主要目的是为了记录一下自己的个人理解,便于以后回忆起来
一手资料肯定是推荐:Wayland官网
我们知道Wayland的初衷是为了颠覆X,而提出的一种架构
我们先大致了解一下X的架构(Linux下面主要的代表是Xorg)
介绍一个点击事件场景在X架构下是怎样的

  1. 首先内核收到硬件的点击事件,发送一个udev事件给到X server
  2. X server决定哪个客户端会被影响(这个客户端需要注册对应的事件),然后发送给这个客户端
  3. 客户端收到这个事件,通常一些UI应用会根据这个事件做出对应的处理,例如鼠标点击后会高亮,客户端如果想实现这个效果,就需要发送一个请求给到X Server
  4. X Server收到这个请求,就会把这个请求发送给driver,让它去渲染
  5. driver处理完后,就会发送一个damage信息给到compositor,compositor就知道哪个window需要change,compositor负责整个屏幕的渲染,把每个window的内容,根据图层,合成一张图片
  6. X Server从compositor收到这个渲染请求,讲这部分内容拷贝到CRTC扫描的帧存地址,或者如果开启了page flip,就会切换前后缓存区
    在这里插入图片描述
    Wayland架构下
    通过两个架构图,你可以明显看到Wayland的架构更简洁明了
    1、内核收到输入设备的事件,内核将这个事件发送给compositor
    2、compositor会决定发送给哪个compositor客户端
    3、客户端收到这个事件,就直接处理这个事件了,包括渲染,然后将damage区域通知给到compositor
    4、compositor收到damage信息,然后更新整个画面,compositor能直接通过DRM跟内核交互,实现page flip
    在这里插入图片描述从上面两种架构的对比,我们可以看到明显的性能差别
    在X的架构下,client、compositor、X Server都是属于单独的进程,跨进程频繁的交互,必然会导致性能下降
    在Wayland的架构下,compositor和X Server合并成为一个compositor,跨进程的交互减少,必然导致性能的提升

Wayland架构下,weston是compositor的一个实现,类似于Xorg是X Server的一个实现
下面我们介绍一下westond应用是怎么渲染然后上屏的
直接上simple-dmabuf-egl的源码吧

int
main(int argc, char **argv)
{
	....
	display = create_display(drm_render_node, format, opts); // 创建display
	....
	window = create_window(display, window_size, window_size, opts); // 创建window,然后配置
	....
	if (!window->wait_for_configure)
		redraw(window, NULL, 0); // 渲染
}

static struct display *
create_display(char const *drm_render_node, uint32_t format, int opts)
{
....
	display->display = wl_display_connect(NULL); // 类似于EGL创建display
	// 注册监听
	display->registry = wl_display_get_registry(display->display);
	wl_registry_add_listener(display->registry,
				 &registry_listener, display);
	wl_display_roundtrip(display->display);
....
	// 启动gbm(帧存管理相关),主要是打开DRM设备节点,创建gbm设备,这里开始跟GPU硬件厂商关联起来了
	if (!display_set_up_gbm(display, drm_render_node))
		goto error;
	// 启动egl(上屏相关),主要是创建上下文,查询拓展支持情况,加载一些EGL相关的函数表
	if (!display_set_up_egl(display))
		goto error;
	// 查询是否支持dma buffer,必须得支持,否则share memory无法做到
	if (!display_update_supported_modifiers_for_egl(display))
		goto error;
....
}

static struct window *
create_window(struct display *display, int width, int height, int opts)
{
....
	// 启动gl(渲染相关),
	if (!window_set_up_gl(window))
		goto error;
....
}

// 通过OpenGL渲染到之前EGL创建的surface里面,其实可以简单得把weston应用理解成一个3D应用
static bool
window_set_up_gl(struct window *window)
{
	GLuint vert = create_shader(
		window->render_mandelbrot ? vert_shader_mandelbrot_text :
					    vert_shader_text,
		GL_VERTEX_SHADER);
	GLuint frag = create_shader(
		window->render_mandelbrot ? frag_shader_mandelbrot_text :
					    frag_shader_text,
		GL_FRAGMENT_SHADER);

	window->gl.program = create_and_link_program(vert, frag);

	glDeleteShader(vert);
	glDeleteShader(frag);

	window->gl.pos = glGetAttribLocation(window->gl.program, "pos");
	window->gl.color = glGetAttribLocation(window->gl.program, "color");

	glUseProgram(window->gl.program);

	window->gl.offset_uniform =
		glGetUniformLocation(window->gl.program, "offset");
	window->gl.reflection_uniform =
		glGetUniformLocation(window->gl.program, "reflection");

	return window->gl.program != 0;
}

当一次渲染完成后,怎么把这次渲染的内容,提交给到Wayland server端(compositor)呢?

static void
redraw(void *data, struct wl_callback *callback, uint32_t time)
{
....
	if (window->render_mandelbrot)
		render_mandelbrot(window, buffer);
	else
		render(window, buffer); // 渲染
....
	wl_surface_attach(window->surface, buffer->buffer, 0, 0); // buffer跟surface建立联系
	wl_surface_damage(window->surface, 0, 0, window->width, window->height); // 通知compositor某个部分已经发生损坏,需要更新内容
....
	wl_surface_commit(window->surface); // 提交surface,告诉compositor可以真正上屏了
....
}

上面三个操作client端和compositor端对应关系

client端compositor端
wl_surface_attachweston_surface_attach
wl_surface_damageweston_surface_damage
wl_surface_commitweston_surface_commit

其实关键的地方主要是weston_surface_damage和weston_surface_commit

weston_surface_damage
idle_repaint -> weston_output_schedule_repaint_restart -> weston_output_damage
static enum weston_surface_status
weston_surface_commit(struct weston_surface *surface)
{
	enum weston_surface_status status;

	status = weston_surface_commit_state(surface, &surface->pending);

	if (status & WESTON_SURFACE_DIRTY_SUBSURFACE_CONFIG)
		weston_surface_commit_subsurface_order(surface);

	weston_surface_schedule_repaint(surface);

	return status;
}


weston_surface_commit -> weston_surface_schedule_repaint -> weston_output_schedule_repaint
WL_EXPORT void
weston_output_schedule_repaint(struct weston_output *output)
{
....
	output->repaint_status = REPAINT_BEGIN_FROM_IDLE; // 这个是关键
	assert(!output->idle_repaint_source);
	output->idle_repaint_source = wl_event_loop_add_idle(loop, idle_repaint,
							     output);
....
}

static void
idle_repaint(void *data)
{
	struct weston_output *output = data;
	int ret;

	assert(output->repaint_status == REPAINT_BEGIN_FROM_IDLE); // 跟上面对上了
	output->repaint_status = REPAINT_AWAITING_COMPLETION;
	output->idle_repaint_source = NULL;
	ret = output->start_repaint_loop(output);
	if (ret == -EBUSY)
		weston_output_schedule_repaint_restart(output);
	else if (ret != 0)
		weston_output_schedule_repaint_reset(output);
}

// 这么长一个流程
weston_output_schedule_repaint_restart -> output_repaint_timer_arm
-> output_repaint_timer_handler -> weston_output_maybe_repaint
-> gl_renderer_repaint_output -> repaint_views
-> draw_paint_node -> repaint_region

repaint_region 分为pixmap和OpenGL两种
static void
repaint_region(struct gl_renderer *gr,
	       struct weston_paint_node *pnode,
	       pixman_region32_t *region,
	       pixman_region32_t *surf_region,
	       const struct gl_shader_config *sconf)
{
....
	nfans = texture_region(pnode, region, surf_region); // 通过OpenGL贴纹理的形式贴上去
....
	for (i = 0, first = 0; i < nfans; i++) {
		glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
		if (gr->fan_debug)
			triangle_fan_debug(gr, sconf, output, first, vtxcnt[i]);
		first += vtxcnt[i];
	}
....
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值