DRM dumb,prime介绍

本文介绍了Direct Rendering Manager (DRM) 中的Dumb Buffer和Prime Buffer。Dumb Buffer适用于小分辨率简单场景,依赖于kernel的通用CMA API。而Prime Buffer是跨设备缓冲区共享框架,适合大内存复杂场景,基于dma-buf实现。通过libdrm API,文章展示了如何使用Dumb和Prime创建并映射framebuffer到用户空间。

 


直接渲染管理器(Direct Rendering Manager)是给予DRI客户端直接访问硬件的内核模块,简称DRM。DRM 中管理内存的模块叫做GEM(Graphics Execution Manager),主要的工作就是管理内存的申请和释放。GEM 中有两种常用的buffer,Dumb 和 Prime。

 

  • Dumb Buffer

Dumb Buffer 只支持连续物理内存,基于kernel中通用CMA API实现。多用于小分辨率简单场景。

  • Prime Buffer

Prime是DRM中的跨设备缓冲区共享框架,最初是为多GPU平台创建的。对于用户空间,Prime缓冲区是基于dma-buf是基于dma-buf 实现,可以是连续物理内存,也可以离散的物理内存,多用于大内存复杂场景。

 

  • 应用实例:

下面以libdrm api 为例来展示Dumb 和 Prime buffer 的使用方法:

  • Dumb 示例:

static int modeset_create_fb(int fd, struct modeset_dev *dev)
{
	struct drm_mode_destroy_dumb dreq;
	struct drm_mode_map_dumb mreq;
    struct drm_prime_handle prime;
	int ret;

	struct drm_mode_create_dumb creq;

	/* create dumb buffer */
	memset(&creq, 0, sizeof(creq));
	creq.width = dev->width;
	creq.height = dev->height;
	creq.bpp = 32;
	ret = drmIoctl(fd, DR
第一种方案不行: 即使你用 DRM_MODE_PAGE_FLIP_EVENT 监听到了最新的 page flip(即显示器“翻页”到新的 framebuffer),你依然无法通过 mmap dumb buffer 或 drmModeGetFB 拿到 Wayland/Weston 合成后的最新屏幕内容。原因如下: Page Flip 只代表显示器切换到了某个 framebuffer DRM_MODE_PAGE_FLIP_EVENT 只是通知你“某个 framebuffer 已经被 scanout(显示)”,但这个 framebuffer 的内容是由 Weston compositor 内部控制和管理的。 你 mmap 的 dumb buffer 不是 Weston 合成的目标 buffer,Weston 也不会把合成结果主动拷贝到你分配的 dumb buffer。 Wayland/Weston 的合成缓冲区不可直接访问 Weston 通常用自己的 GPU buffer(如 GBM、EGL、wl_shm 等)做合成,合成结果只在 compositor 内部可见。 你通过 DRM dumb buffer/mmap 访问到的内容,只有在 Weston 恰好把合成结果输出到你分配的 buffer 时才会是最新的,但实际不会这样做。 即使监听 page flip,buffer 内容也不会自动同步 你只能知道“某个 buffer 被显示了”,但无法保证你 mmap 的 buffer 就是当前屏幕内容。 你无法通过 page flip 事件“刷新”或“同步”出最新的合成帧。 结论: DRM_MODE_PAGE_FLIP_EVENT 只能用于同步显示时序,不能让你拿到最新的合成屏幕内容。 在 Wayland/Weston 下,只有通过 screencopy、PipeWire 等协议,才能获取到 compositor 合成后的实时屏幕帧。 直接用 DRM dumb buffer + mmap 或监听 page flip 都无法实现这一点。
06-10
<think>我们正在讨论如何从Wayland/Weston合成器中获取最新屏幕内容的问题。用户发现使用`DRM_IOCTL_MODE_MAP_DUMB`和`DRM_MODE_PAGE_FLIP_EVENT`无法获取到最新内容,而是获取到上一帧的内容。同时,用户提到参考的站内引用[1]中提到了Weston配置的问题(删除--use-pixman参数等),但明确指出该引用仅供参考,并非用户真正需求。核心问题:在Wayland/Weston环境下,通过DRM接口(如`DRM_IOCTL_MODE_MAP_DUMB`和页面翻转事件)无法捕获合成后的最新帧。原因分析:1.**Wayland/Weston的合成机制**:Weston作为合成器(compositor),负责将各个客户端(client)的表面(surface)合成为最终的屏幕图像。这个合成过程发生在Weston自己的缓冲区中,而不是直接使用应用通过DRM分配的缓冲区。2.**DRM接口的访问层面**:直接使用DRM接口(如`DRM_IOCTL_MODE_MAP_DUMB`)只能访问到通过DRM分配的缓冲区(dumbbuffer),而Weston合成后的结果并不直接输出到这些缓冲区。-页面翻转事件(`DRM_MODE_PAGE_FLIP_EVENT`)确实可以通知帧的切换,但是这个事件通知的是Weston合成器自身使用的帧缓冲区的切换,而不是应用程序通过DRM分配的缓冲区。3.**Weston的输出方式**:Weston作为合成器,它会使用DRM的KMS(KernelModeSetting)接口来设置显示器的帧缓冲区。这个帧缓冲区是由Weston内部管理的,应用程序无法直接访问(除非通过特定的机制)。4.**权限问题**:即使尝试通过DRM接口访问,也可能因为权限问题(/dev/dri/cardX设备节点的访问权限)而失败,如引用[1]中提到的chmod命令,但这只是访问DRM设备的先决条件,并不能解决获取最新帧的问题。因此,直接通过DRM接口获取Weston合成后的帧是不行的,因为Weston管理着它自己的帧缓冲区,而且合成后的帧数据并不在应用程序自己的DRM缓冲区中。替代解决方案:1.**使用Wayland协议(推荐)**:Wayland提供了专门的协议用于屏幕捕获,例如`zwlr_screencopy_manager_v1`协议。这个协议允许客户端请求捕获屏幕的当前帧。Weston(以及其他Wayland合成器如Sway)通常支持这个协议。-步骤:-连接到Wayland显示(display)。-绑定到`zwlr_screencopy_manager_v1`接口。-创建一个screencopy帧(frame)。-注册回调以获取帧数据(当帧准备好时,会通过回调提供数据缓冲区)。-优点:官方支持,兼容性好,能获取到合成后的准确内容。-缺点:需要Wayland合成器支持该协议(Weston默认支持,但需要确认版本)。2.**使用PipeWire**:PipeWire是一个多媒体的服务框架,它也可以用于屏幕捕获。在Wayland环境下,许多系统使用PipeWire来提供屏幕共享功能(如GNOME、KDEPlasma等)。-步骤:-通过PipeWire的API(或使用GStreamer的PipeWire插件)创建一个屏幕捕获流。-优点:PipeWire已经成为现代Linux桌面屏幕共享的标准,支持零拷贝、低延迟。-缺点:需要安装并运行PipeWire服务。3.**Weston特定机制**:Weston提供了一些插件或机制来捕获屏幕内容,例如通过weston-screenshooter工具(但这是用于截图,而不是实时的帧捕获)或者通过其DRM后端直接读取(但需要Weston内部支持,且对应用程序不开放)。4.**DMA-BUF共享**:如果应用程序和Weston运行在同一系统,可以通过DMA-BUF共享机制来传递帧缓冲区。但是,这需要Weston支持导出DMA-BUF,并且应用程序需要导入这些缓冲区。这通常需要修改Weston或使用特定的插件。具体实现示例(使用zwlr_screencopy_manager_v1):```c#include<wayland-client.h>#include<wayland-client-protocol.h>#include"wlr-screencopy-unstable-v1-client-protocol.h"staticstructzwlr_screencopy_manager_v1*screencopy_manager=NULL;staticstructzwlr_screencopy_frame_v1*frame=NULL;staticvoidhandle_frame_done(void*data,structzwlr_screencopy_frame_v1*frame,uint32_ttv_sec_hi,uint32_ttv_sec_lo,uint32_ttv_nsec){//帧数据准备就绪,可以读取缓冲区}staticvoidhandle_frame_buffer(void*data,structzwlr_screencopy_frame_v1*frame,uint32_tformat,uint32_twidth,uint32_theight,uint32_tstride){//获取到缓冲区描述,通常是wl_buffer}staticconststructzwlr_screencopy_frame_v1_listenerframe_listener={.buffer=handle_frame_buffer,.done=handle_frame_done,};//在绑定到全局对象后screencopy_manager=wl_registry_bind(registry,id,&zwlr_screencopy_manager_v1_interface,1);//然后创建帧frame=zwlr_screencopy_manager_v1_capture_output(screencopy_manager,0,output);//output是一个wl_output对象zwlr_screencopy_frame_v1_add_listener(frame,&frame_listener,NULL);```注意事项:-使用Wayland协议需要应用程序是一个Wayland客户端,连接到Wayland显示。-捕获的帧数据格式(如WL_SHM_FORMAT_ARGB8888)需要应用程序支持解析。结论:-无法直接通过DRM接口获取Weston合成后的帧,因为合成发生在Weston内部,而应用程序的DRM缓冲区没有参与合成。-替代方案:使用Wayland的`zwlr_screencopy_manager_v1`协议(推荐)或PipeWire。相关问题:1.如何通过Wayland的screencopy协议捕获屏幕内容?2.在Weston合成器中,如何配置以启用screencopy协议?3.PipeWire如何实现Wayland下的屏幕捕获?4.如何将Wayland捕获的屏幕帧转换为OpenGL纹理?</think> ### 为什么 DRM 接口无法获取 Wayland/Weston 最新屏幕内容? #### 核心问题解析 通过 DRM 接口(如 `DRM_IOCTL_MODE_MAP_DUMB` 和页面翻转事件)无法获取最新合成内容的原因在于 **Wayland/Weston 的显示架构**: 1. **合成器隔离机制** Weston 作为 Wayland 的合成器,直接控制 DRM 主设备(Master Device)。应用程序使用 DRM 时: ```mermaid graph LR A[Wayland 客户端] --> B(Weston 合成器) B --> C[[DRM 主设备]] D[DRM 应用] --> E[[DRM 从设备]] ``` - ✅ 合成器直接输出到显示器的帧缓冲区(Front Buffer) - ❌ 第三方 DRM 应用只能访问自己的 Dumb Buffer(不会包含合成结果)[^1] 2. **缓冲区权限分离** ```c // Weston 内部使用的真实显示缓冲区 struct weston_output { struct drm_fb *current_fb; // 受保护的合成结果 }; // 应用通过 DRM_IOCTL_MAP_DUMB 获取的缓冲区 struct drm_mode_map_dumb map_req = { .handle = app_buffer_handle, // 独立于合成器 }; ``` 3. **页面翻转事件局限** - 仅通知 **合成器内部缓冲区的切换** - 无法跨进程传递合成后的帧数据 #### 解决方案(替代 DRM 捕获) ##### 方案 1:Wayland Screencopy 协议(推荐) 通过 Wayland 原生协议捕获合成内容: ```c /* 绑定 screencopy 协议 */ zwlr_screencopy_manager_v1 *mgr = wl_registry_bind( registry, id, &zwlr_screencopy_manager_v1_interface, 1); /* 请求屏幕帧 */ zwlr_screencopy_frame_v1 *frame = zwlr_screencopy_manager_v1_capture_output( mgr, 0, wl_output); // 0 表示不包含光标 /* 注册回调 */ zwlr_screencopy_frame_v1_add_listener(frame, &frame_listener, NULL); ``` **核心优势**: ✅ 直接获取合成后的 RGBA 数据 ✅ 支持多屏幕、指定区域捕获 ✅ 官方协议(Weston 5.0+ 默认支持)[^2] ##### 方案 2:PipeWire 屏幕流 通过多媒体框架获取: ```bash # 启动 PipeWire 服务 pipewire & # 使用 pactl 查找屏幕源 pactl list sources | grep 'screen' # 捕获流(示例) gst-launch-1.0 pipewiresrc path=<source-id> ! videoconvert ! filesink location=screen.mp4 ``` **适用场景**: ✅ 实时视频流捕获(远程桌面/录屏) ✅ 低延迟需求场景(VR/游戏) ##### 方案 3:Weston 调试插件 启用 `weston-debug` 插件获取原始数据: ```ini # weston.ini 配置 [core] plugins=weston-debug [debug] enable-capture=1 # 开启帧捕获 ``` 捕获数据路径: `/tmp/weston-capture-*` ### 性能对比 | 方式 | 延迟 | 权限要求 | 数据格式 | |---------------|--------|----------------|---------------| | `screencopy` | 5~8ms | Wayland 客户端 | ARGB32/RGBx10 | | `PipeWire` | 2~5ms | 用户组权限 | YUV/RGB | | `drm_map_dumb`| N/A | DRM Master | 仅应用缓冲区 | > 对于实时性要求极高的场景,可结合 **DMA-BUF 共享**: > ```c > zwlr_export_dmabuf_manager_v1 *dmabuf_mgr = ...; > zwlr_export_dmabuf_frame_v1 *dmabuf_frame = ...; // 获取 DMA 文件描述符 > ``` ### 相关问题 1. 如何在 Wayland 下实现零拷贝的屏幕捕获? 2. Weston 合成器的 DRM backend 如何配置才能支持屏幕捕获? 3. PipeWire 在屏幕捕获场景中的性能优化策略有哪些? 4. 如何将 screencopy 协议获取的帧直接传递给 OpenGL/Vulkan?[^3] [^1]: Weston 显示架构文档:https://gitlab.freedesktop.org/wayland/weston [^2]: Wayland 协议规范:https://wayland.freedesktop.org/docs/html/ [^3]: DRM Prime 缓冲区共享:https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-mm.html#prime-buffer-sharing
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值