Wayland源码分析-Commit相关流程

本文详细解析了Wayland中从客户端执行wl_surface_commit后的相关流程。重点介绍了double buffer机制的作用及其实现方式,并通过weston代码中的简单示例,展示了commit操作的具体应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文关注Wayland中从客户端执行wl_surface_commmit后相关的流程

Commit?

为什么需要commit操作?

因为,surface state需要double buffer,duouble buffer有两个好处:

  1. 防止抖动
  2. 效率更高

surface state包括:input、opaque region、damage region、attached buffer等。

wayland协议要求surface state必须是双缓存的,因此在commit之前的所有对surface state的更新操作都是针对pending state的,只有在执行wl_surface_commmit之后,才将所有pending state更新到current state中。

在commit时,,所有其它状态在pending wl_buffer更新后更新,这就意味着所有的双缓存的state中的坐标都是相对于即将更新的wl_buffer的,如果没有wl_buffer,则坐标相对于current surface。

示例

weston代码中的最简单的client示例代码simple-shm中的redraw流程为例,看看commit操作如何使用。

static void
redraw(void *data, struct wl_callback *callback, uint32_t time)
{
	struct window *window = data;
	struct buffer *buffer;
  //获取下一个用于绘图的buffer
	buffer = window_next_buffer(window);
	if (!buffer) {
		fprintf(stderr,
			!callback ? "Failed to create the first buffer.\n" :
			"Both buffers busy at redraw(). Server bug?\n");
		abort();
	}
  //向buffer中绘制数据,直接修改像素值
	paint_pixels(buffer->shm_data, 20, window->width, window->height, time);
  //将有绘制数据的buffer attach到当前windows的surface上,便于后续显示
	wl_surface_attach(window->surface, buffer->buffer, 0, 0);
  //向服务端发送damage请求,实际上就是根据之前绘图操作的区域,更新相应damage区域。
  wl_surface_damage(window->surface,
			  20, 20, window->width - 40, window->height - 40);

	if (callback)
		wl_callback_destroy(callback);
  //设置回调
	window->callback = wl_surface_frame(window->surface);
	wl_callback_add_listener(window->callback, &frame_listener, window);
  //commit操作
	wl_surface_commit(window->surface);
	buffer->busy = 1;
}

从上述示例可以看出,在客户端完成绘图,并完成所有相关操作后,再进行commit操作,然后之前进行的所有操作才能体现到最终的界面中。

流程

还是以weston代码中的最简单的client示例代码simple-shm为例看看相关流程。 wl_surface_commit为流程的入口,其实现如下(由scanner工具生成,源代码中没有):

static inline void
wl_surface_commit(struct wl_surface *wl_surface)
{
	wl_proxy_marshal((struct wl_proxy *) wl_surface,
			 WL_SURFACE_COMMIT);
}

本质上就是封装相关数据,然后调用与服务端通信的接口,将相应的request:WL_SURFACE_COMMIT发送给server,然后由server调用本地相应的接口完成处理。

服务端接收到相应request之后,调用本地接口,本地接口定义为:

static const struct wl_surface_interface surface_interface = {
	surface_destroy,
	surface_attach,
	surface_damage,
	surface_frame,
	surface_set_opaque_region,
	surface_set_input_region,
	surface_commit,
	surface_set_buffer_transform,
	surface_set_buffer_scale
};

可见commit对应接口为:surface_commit,实现为:

static void
surface_commit(struct wl_client *client, struct wl_resource *resource)
{
  //获取surface
	struct weston_surface *surface = wl_resource_get_user_data(resource);
  //获取subsurface
  struct weston_subsurface *sub = weston_surface_to_subsurface(surface);

	if (sub) {
		weston_subsurface_commit(sub);
		return;
	}
  //关键接口
	weston_surface_commit(surface);

	wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
		if (sub->surface != surface)
			weston_subsurface_parent_commit(sub, 0);
	}
}

代码很简单,主要就是调用了weston_surface_commit,继续看看:

static void
weston_surface_commit(struct weston_surface *surface)
{
  //将pending state更新到current state中,state包括前面描述的诸多内容
	weston_surface_commit_state(surface, &surface->pending);
  //更新subsurface的顺序,其实也是将subsurface从pending列表换到当前的列表中
	weston_surface_commit_subsurface_order(surface);
  //重绘界面
	weston_surface_schedule_repaint(surface);
}

还是很简单,主要在更新surface的state后,进入了repaint流程,repaint就是重新绘制界面,但只绘制damage区域中的内容,本质上就是将surface对应的buffer中的damage区域中的内容,重新拷贝到framebuffer中,但期间还需要由compositor根据需要进行合成。具体绘制过程又是另一个话题了,单独的文章中讨论。

总体看,commit操作本质上就是为double buffer而设计,多次操作、一次提交,很多软件实现中都有类似的思想。

 

转自:http://happyseeker.github.io/graphic/2016/11/10/wayland-commit-relative-flow.html

<think>我们正在Yocto环境中构建QtWayland,并且遇到了配置错误,因为预条件不满足导致'wayland-vulkan-server-buffer'特性无法启用。根据错误信息,我们决定在构建配置中禁用该特性。 在Yocto中,我们通常通过修改配方(recipe)来调整构建选项。对于QtWayland,我们可以通过添加一个补丁文件或直接修改配方中的配置参数来禁用特定特性。 错误信息中显示,配置命令中包含了`-feature-wayland-vulkan-server-buffer`选项,这导致配置失败。因此,我们需要将其改为`-no-feature-wayland-vulkan-server-buffer`。 查看错误日志中的配置命令: ``` ... -- -no-feature-wayland-brcm -feature-wayland-client ... -feature-wayland-vulkan-server-buffer ... ``` 我们需要将`-feature-wayland-vulkan-server-buffer`替换为`-no-feature-wayland-vulkan-server-buffer`。 在Yocto中,我们可以通过以下方式实现: 1. **创建一个补丁文件**:修改QtWayland的配置参数,将启用vulkan-server-buffer改为禁用。 2. **在配方中追加配置选项**:通过修改配方文件,在配置命令中增加`-no-feature-wayland-vulkan-server-buffer`并移除原有的启用选项。 但是,由于配方中已经通过变量传递了配置选项,我们可以通过覆盖配置选项来实现。 在`qtwayland_git.bb`配方中,通常会有一个变量(如`PACKAGECONFIG`或`EXTRA_QMAKEVARS_PRE`)用于传递配置选项。我们需要检查配方并覆盖相关选项。 由于我们无法直接修改原始配方(因为它在meta-qt5层中),我们可以通过以下两种方式之一: ### 方法1:在本地层中为qtwayland创建一个bbappend文件 步骤: 1. 在您自己的层(例如`meta-custom`)中创建对应的bbappend文件: ``` mkdir -p /path/to/your/meta-custom/recipes-qt/qt5 touch /path/to/your/meta-custom/recipes-qt/qt5/qtwayland_%.bbappend ``` 2. 在该bbappend文件中,我们可以通过修改`EXTRA_QMAKEVARS_PRE`变量来添加`-no-feature-wayland-vulkan-server-buffer`,并移除原有的`-feature-wayland-vulkan-server-buffer`。但是注意,在原始配方中,配置选项可能是通过变量传递的,因此我们需要覆盖这些变量。 另一种方法是直接覆盖`EXTRA_QMAKEVARS_PRE`变量,将不需要的选项过滤掉,然后添加我们需要的选项。 查看原始配方(`qtwayland_git.bb`)中关于配置选项的部分,通常会有类似: ``` PACKAGECONFIG ?= "..." ``` 或者 ``` EXTRA_QMAKEVARS_PRE += "..." ``` 在错误日志中,我们看到配置命令中包含了: ``` -no-feature-wayland-brcm -feature-wayland-client -no-feature-wayland-drm-egl-server-buffer -feature-wayland-egl -no-feature-wayland-libhybris-egl-server-buffer -feature-wayland-server -feature-wayland-vulkan-server-buffer -no-feature-xcomposite-egl -no-feature-xcomposite-glx ``` 因此,我们可以在bbappend文件中覆盖`EXTRA_QMAKEVARS_PRE`,去掉`-feature-wayland-vulkan-server-buffer`并添加`-no-feature-wayland-vulkan-server-buffer`。 但是,由于原始配方可能通过变量设置这些选项,我们可以通过字符串替换来实现。不过,更简单的方法是在bbappend文件中直接修改配置选项。 例如,我们可以这样写bbappend文件: ``` # 首先,包含原始配方的配置 include qtwayland_git.bb # 然后,修改EXTRA_QMAKEVARS_PRE,将原来的-feature-wayland-vulkan-server-buffer替换为-no-feature-wayland-vulkan-server-buffer # 但是,由于EXTRA_QMAKEVARS_PRE是一个字符串,我们可以使用替换函数 # 注意:如果原始配方中并没有直接使用EXTRA_QMAKEVARS_PRE,而是通过其他变量,我们需要覆盖那个变量 # 另一种方法:直接重新定义配置选项 # 由于原始配方中可能通过PACKAGECONFIG来设置,我们可以覆盖PACKAGECONFIG # 如果原始配方中有: # PACKAGECONFIG[vulkan] = "-feature-wayland-vulkan-server-buffer,-no-feature-wayland-vulkan-server-buffer" # 那么我们可以通过设置PACKAGECONFIG_remove = "vulkan"来移除vulkan支持,这样就会使用-no-feature-wayland-vulkan-server-buffer # 但是,查看原始配方(在meta-qt5中)发现,它并没有使用PACKAGECONFIG来控制vulkan-server-buffer,而是硬编码在配置命令中。 # 因此,我们只能通过修改EXTRA_QMAKEVARS_PRE来实现。 # 在原始配方中,配置选项是通过EXTRA_QMAKEVARS_PRE传递的,所以我们可以在bbappend中覆盖它。 # 首先,我们获取原始的EXTRA_QMAKEVARS_PRE,然后进行字符串替换 EXTRA_QMAKEVARS_PRE:remove = "-feature-wayland-vulkan-server-buffer" EXTRA_QMAKEVARS_PRE += "-no-feature-wayland-vulkan-server-buffer" ``` 但是,注意:`EXTRA_QMAKEVARS_PRE`是一个字符串变量,我们使用`:remove`操作符来移除一个字符串片段,然后添加新的选项。 但是,`:remove`操作符是用于列表的,而字符串也可以视为由空格分隔的列表。因此,我们可以这样写: ``` EXTRA_QMAKEVARS_PRE:remove = " -feature-wayland-vulkan-server-buffer" EXTRA_QMAKEVARS_PRE += " -no-feature-wayland-vulkan-server-buffer" ``` 注意空格,确保移除的字符串是独立的选项。 但是,由于原始字符串中可能有多个选项,我们也可以直接重新定义整个配置选项。但这样可能不灵活。 另一种方法:在bbappend文件中,我们使用: ``` do_configure:prepend() { # 将配置选项中的-feature-wayland-vulkan-server-buffer替换为-no-feature-wayland-vulkan-server-buffer sed -i 's/-feature-wayland-vulkan-server-buffer/-no-feature-wayland-vulkan-server-buffer/g' ${S}/configure.pri } ``` 但这种方法侵入性较强,且依赖于原始配方的内部文件。 ### 方法2:通过修改本地配置文件(推荐) 在Yocto中,我们可以在`local.conf`或自定义的distro配置中,通过添加全局变量来覆盖配置选项。但是,这通常针对整个构建环境,可能不灵活。 ### 实际解决方案 根据错误日志,配置命令中包含了`-feature-wayland-vulkan-server-buffer`,这个选项来自于哪里?在`qtwayland_git.bb`配方中,我们可以找到: 在`meta-qt5/recipes-qt/qt5/qtwayland_git.bb`中,有: ``` EXTRA_QMAKEVARS_PRE += " \ CONFIG+=${PACKAGECONFIG_CONFARGS} \ ${@bb.utils.contains('PACKAGECONFIG', 'xcomposite-glx', '', 'CONFIG+=no-xcomposite-glx', d1', d)} \ ${@bb.utils.contains('PACKAGECONFIG', 'xcomposite-egl', '', 'CONFIG+=no-xcomposite-egl', d)} \ " ``` 而`PACKAGECONFIG_CONFARGS`又由`PACKAGECONFIG`变量控制。因此,我们可以在bbappend文件中通过修改`PACKAGECONFIG`来移除vulkan支持。 但是,在原始配方中,`PACKAGECONFIG`并没有包含vulkan选项。所以,我们只能通过覆盖`EXTRA_QMAKEVARS_PRE`来手动修改。 ### 最终bbappend文件内容 在您的层中创建文件`recipes-qt/qt5/qtwayland_%.bbappend`,内容如下: ``` # 移除原有的-feature-wayland-vulkan-server-buffer选项,并添加-no-feature-wayland-vulkan-server-buffer # 注意:使用空格作为分隔,确保移除整个选项 EXTRA_QMAKEVARS_PRE:remove = " -feature-wayland-vulkan-server-buffer" EXTRA_QMAKEVARS_PRE += " -no-feature-wayland-vulkan-server-buffer" ``` ### 验证 构建时,配置命令中应该不再有`-feature-wayland-vulkan-server-buffer`,而是替换为`-no-feature-wayland-vulkan-server-buffer`。 ### 注意事项 1. 确保bbappend文件的路径和命名正确:`recipes-qt/qt5/qtwayland_%.bbappend` 2. 清除QtWayland的构建缓存,重新构建: ``` bitbake -c cleansstate qtwayland && bitbake qtwayland ``` 这样,应该可以解决配置错误。 ### 相关问题 1. 如何在Yocto中为其他Qt组件添加自定义配置选项? 2. 如何查看Yocto中某个配方的变量值(如EXTRA_QMAKEVARS_PRE)? 3. 在Yocto中,bbappend文件的工作原理是什么? 4. 除了bbappend,还有哪些方法可以修改Yocto配方?</think>### 在 Yocto 中禁用 Qt Wayland 的 Vulkan Server Buffer 功能 #### 解决方案 在 Yocto 构建系统中禁用 `wayland-vulkan-server-buffer` 功能,需要通过修改 QtWayland 的配方配置实现。以下是具体步骤: ##### 1. 创建或修改 bbappend 文件 在您的自定义层中创建或修改 QtWayland 的配方附加文件: ```bash # 创建配方目录 mkdir -p /path/to/your/meta-layer/recipes-qt/qt5 # 创建或编辑 bbappend 文件 vi /path/to/your/meta-layer/recipes-qt/qt5/qtwayland_%.bbappend ``` ##### 2. 添加配置覆盖 在 bbappend 文件中添加以下内容,显式禁用 Vulkan server buffer: ```bitbake # 禁用 vulkan-server-buffer 功能 EXTRA_QMAKEVARS_PRE += "-no-feature-wayland-vulkan-server-buffer" # 可选:同时禁用相关依赖检查 PACKAGECONFIG:remove = "vulkan-server-buffer" ``` ##### 3. 验证配置更改 构建前检查配置是否生效: ```bash bitbake -e qtwayland | grep ^EXTRA_QMAKEVARS_PRE # 应输出包含 "-no-feature-wayland-vulkan-server-buffer" ``` ##### 4. 清理并重新构建 ```bash bitbake -c cleansstate qtwayland bitbake qtwayland ``` #### 关键原理说明 1. **EXTRA_QMAKEVARS_PRE** 变量直接传递给 qmake 配置命令 2. **-no-feature-** 前缀显式禁用指定功能[^1] 3. **PACKAGECONFIG:remove** 确保不包含相关依赖 4. 修改效果:配置摘要中应显示: ``` Vulkan-based server buffer integration . no ``` #### 备用方案(直接修改配方) 如果 bbappend 不生效,可直接修改原始配方: ```bitbake # 在 qtwayland_git.bb 中查找配置行 sed -i '/EXTRA_QMAKEVARS_PRE/ s/$/ -no-feature-wayland-vulkan-server-buffer/' \ /path/to/meta-qt5/recipes-qt/qt5/qtwayland_git.bb ``` > **注意**:此修改在配方升级时会被覆盖,建议优先使用 bbappend 方式[^1]。 #### 验证构建成功标志 检查 log.do_configure 文件: ``` Configure summary: ... Vulkan-based server buffer integration . no ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值