display:wesotn:clienst:simple-dmabuf-drm & simple-dmabuf-egl

赵昊阳
2023-12-01

这套协议的本质,是绑定wl_buffer与linux_dmabuf_buffer。

接口:linux_dmabuf_unstable_v1

https://gitlab.freedesktop.org/wayland/wayland-protocols/raw/1.18/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml

<interface name="zwp_linux_dmabuf_v1" version="3">
该接口提供了创建基于dmabuf的通用wl_buffers的方法。客户端绑定到此接口后,将立即通过“ format”和“ modifier”事件发送受支持的格式和格式修饰符集。

客户需要以下内容:
      -客户端必须确保dma-buf中的所有数据对于所有后续读取访问都是一致的,或者确保基础内核端dma-buf实现正确地处理了一致性。
      -将buffer发送到compositor后,请勿再做任何添加。以后制作更多附件会增加合成器无法使用(重新导入)基于dmabuf的现有wl_buffer的风险。

基础图形堆栈必须确保以下各项:
      -传递到到服务器的dmabuf文件描述符将在wl_buffer的整个生命周期内保持有效。这意味着服务器可以随时使用这些fds将dmabuf导入可能接受它的任何内核子系统中。
      要从一个或多个dmabuf创建wl_buffer,客户端将使用zwp_linux_dmabuf_v1.create_params请求创建一个zwp_linux_dmabuf_params_v1对象。预期格式所需的所有平面均与“add”请求一起添加。最后,发出一个“ create”或“ create_immed”请求,根据导入成功,其结果如下。

“create”请求,
      -成功后,触发“创建”事件,该事件将最终的wl_buffer提供给客户端。
      -失败时,触发“失败”事件以表示服务器无法使用从客户端收到的dmabuf。

“ create_immed”请求,
      -成功后,服务器立即导入添加的dmabuf,以创建wl_buffer。在这种情况下,不会从服务器发送任何事件。
      -发生故障时,服务器可以选择以下任一项:
        -通过引发致命错误来终止客户端。
        -将wl_buffer标记为失败,然后向客户端发送“失败”事件。如果客户端使用失败的wl_buffer作为任何请求的参数,则该行为是合成器实现定义的。 


<event name =“ format”>
      <description summary =“支持的缓冲区格式”>
        此事件通告服务器支持的一种缓冲区格式。当客户端绑定到此接口时,所有支持的格式都将发布一次。绑定后的往返保证了客户端已收到所有受支持的格式。

        有关格式代码的定义,请参见
        zwp_linux_buffer_params_v1 :: create请求。

        警告:可能不建议使用'format'事件,并用zwp_linux_dmabuf_v1第3版中介绍的'modifier'事件代替,如下所述。请不要使用从此事件中收到的信息。
      </ description>
      <arg name =“ format” type =“ uint” summary =“ DRM_FORMAT代码” />
</ event>

<event name =“ modifier” since =“ 3”>
      <description summary =“支持的缓冲区格式修饰符”>
        此事件通告服务器支持的格式,以及每种格式支持的修饰符。当客户端绑定到此接口时,将发布所有受支持格式的所有受支持修饰符。绑定后的往返保证了客户端已经收到所有受支持的格式修饰符对。

        对于旧版支持,此事件中允许DRM_FORMAT_MOD_INVALID(即,modifier_hi == 0x00ffffff和modifier_lo == 0xffffffff)。它指示服务器可以使用隐式修饰符支持格式。当plane以DRM_FORMAT_MOD_INVALID作为其修改器时,就好像未指定任何显式修改器一样。有效修饰符将从dmabuf派生。

        有关格式和修饰符代码的定义,请参见zwp_linux_buffer_params_v1 :: create和zwp_linux_buffer_params_v1 :: add请求。
      </ description>
      <arg name =“ format” type =“ uint” summary =“ DRM_FORMAT代码” />
      <arg name =“ modifier_hi” type =“ uint”
           summary =“高32位的布局修改器” />
      <arg name =“ modifier_lo” type =“ uint”
           summary =“低32位的布局修改器” />
</ event> 
<interface name =“ zwp_linux_buffer_params_v1” version =“ 3”>
     <description summary =“用于创建基于dmabuf的wl_buffer的参数”>
       此临时对象是dmabuf和其他参数的集合,它们共同形成一个逻辑缓冲区。 临时对象最终可能会创建一个wl_buffer,除非在请求“create”之前通过销毁它来取消它。

       单平面格式仅需要一个dmabuf,但是多平面格式可能需要多个dmabuf。 对于所有格式,每个平面都必须调用一次“add”请求(即使基础dmabuf fd相同)。

       您必须使用从零到drm_fourcc格式代码使用的平面数的连续平面索引(“ add”的“ plane_idx”参数)。
       格式要求的所有平面必须精确地给出一次,但是可以以任何顺序给出。 每个平面索引只能设置一次。
     </ description> 

<request name =“ add”>
       <description summary =“将dmabuf添加到临时集中”>
         该请求将一个dmabuf添加到此zwp_linux_buffer_params_v1中的集合中。

         由modifier_hi和modifier_lo组合而成的64位无符号值是dmabuf布局修饰符。 DRM AddFB2 ioctl将此称为fb修饰符,该修饰符在Linux UAPI的drm_mode.h中定义.这是一个不透明的令牌。 驱动程序使用此令牌来表示切片,压缩等。驱动程序特定的修改是对DRM fourcc代码定义的基本格式的。

         警告:如果未使用format/modifier的modifier事件,则应该是一个错误。 由于某些实现始终接受DRM_FORMAT_MOD_INVALID,因此尚未强制执行此操作。 此协议的版本2也不包含Modifyer事件。

         如果plane_idx太大,此请求将引发PLANE_IDX错误。
         如果尝试设置已经设置的平面,则会引发错误PLANE_SET。
       </ description> 


<request name =“ create”>
      <description summary =“从给定的dmabufs创建wl_buffer”>
        这要求从添加的dmabuf缓冲区中创建wl_buffer。 wl_buffer不会立即创建,但是如果dmabuf共享成功,则会通过'created'事件返回。由于客户端无法预测的原因,共享可能会在运行时失败,在这种情况下会触发“失败”事件。
“格式”参数是DRM_FORMAT代码,由libdrm的drm_fourcc.h定义。 Linux内核的DRM子系统是有关格式代码如何工作的权威资料。
“标志”是枚举“标志”中定义的标志的位域。 “ y_invert”表示图像需要y翻转。

标志“隔行扫描”表示缓冲区中的帧不像往常一样是逐行扫描的,而是隔行扫描的。此处支持的隔行缓冲区必须始终包含顶部和底部字段。顶部字段始终始于第一像素行。除非指定了“ bottom_first”,否则两个字段之间的时间顺序首先是顶层字段。如果未设置“隔行扫描”,是否忽略“ bottom_first”是不确定的。

除了一个缓冲区中两个字段之间的相对顺序以外,该协议不传达有关字段速率,持续时间或时序的任何信息。合成器可能必须根据传入的缓冲速率来估计预期的场速率。尚不确定使用附加的新缓冲区接收wl_surface.commit的时间,应用wl_surface状态,wl_surface.frame回调触发器,表示或合成器周期中的任何其他时间来测量帧或字段时间。也没有支持检测丢失或较晚的帧/场/缓冲区,也没有支持与隔行合成器输出配合使用。

        由于使用隔行缓冲区而产生的合成图像质量是明确未定义的。合成器可能会使用复杂的硬件功能或软件来取消隔行扫描,并从一系列隔行输入缓冲区中创建逐行输出帧,或者可能会产生不合格的图像质量。但是,建议在所有情况下都不能保证合理图像质量的合成器仅拒绝所有隔行缓冲区。

        任何参数错误,包括非正宽度或高度,平面数与格式之间的不匹配,错误的格式,错误的偏移或跨度,都可能由致命的协议错误指示:INCOMPLETE,INVALID_FORMAT,INVALID_DIMENSIONS,OUT_OF_BOUNDS。

        服务器中的Dmabuf导入错误(不是明显的客户端错误)会通过“ failed”事件作为非致命错误返回。这允许尝试dmabuf共享,如果失败则回退到客户端。

        该请求在对象的生存期内只能发送一次,此后唯一的合法请求将被销毁。发出“创建”请求后,应销毁该对象。在发出“创建”之后尝试使用此对象会引发ALREADY_USED协议错误。

        发出“创建”不是强制性的。如果客户端要取消缓冲区创建,则可以销毁该对象。
      </ description>


<request name =“ create_immed” since =“ 2”>
      <description summary =“立即从给定的dmabufs创建wl_buffer”>
        这要求通过导入添加的dmabufs立即创建wl_buffer。

        如果导入成功,则不会从服务器发送任何事件,并且wl_buffer准备好供客户端使用。

        导入失败后,可能会发生以下情况之一,具体取决于实现:
        -客户端终止,出现以下致命协议错误之一:
          -不完整,INVALID_FORMAT,INVALID_DIMENSIONS,OUT_OF_BOUNDS,以防参数错误,例如平面数与格式不匹配,格式错误,宽度或高度非正数,偏移或跨度错误。
          -INVALID_WL_BUFFER,以防失败原因未知或平台特定。
        -服务器创建无效的wl_buffer,将其标记为失败,然后向客户端发送“失败”事件。合成器实现定义了在客户端的任何请求中将此无效的wl_buffer用作参数的结果。

        它接受与“创建”请求相同的参数,并遵守相同的限制。
      </ description> 

 

simple-dmabuf-drm在19年的mainline里面被废弃,原因如下

ommit 0a4f6e7d6d63585d287e4f4e2edbc39228d6eed1
Author: Simon Ser <contact@emersion.fr>
Date:   Tue Jul 16 15:18:25 2019 +0300

    clients: drop simple-dmabuf-drm
    
    This client contains driver-specific code to allocate buffers. However clients
    shouldn't contain driver-specific code and should rely on e.g. mesa to allocate
    buffers via standard interfaces.
    
    Additionally, because the build system always tries to enable all features, some
    experimental drivers and drivers that aren't included in amd64 distribution
    packages were required. Users would need to manually disable some drivers.
    Releasers would need to install libdrm from source (because the release process
    forbids adding custom build flags). Dropping simple-dmabuf-drm simplifies both
    building and releasing.
    
    The functionality previously tested via simple-dmabuf-drm can now be tested with
    simple-dmabuf-egl.
    
    Signed-off-by: Simon Ser <contact@emersion.fr>

simple-dmabuf-drm

main函数

1.解析外部参数

2.create_display
        a.绑定zwp_linux_dmabuf_v1

3.create_window
        a.create_dmabuf_buffer
            1.drm_connect
                    a.open /dev/dri/renderD128  获取drm_fd
                    b.drm_device_init 假设为freedreno,初始化操作函数;链接libdrm的接口

            2.drm_dev->alloc_bo    [GEM强相关]
                    a.fd_alloc_bo
                            1.fd_device_new
                            //初始化对应的操作函数;通过drm_fd注册msm_device;获取fd_dev
                            2.fd_bo_new
                            //bo_new_handle + bo_from_handle
                            //高通调用ioctl,高通平台是一个封装api,创建gem-buffer-obj和userspace-handle;
                            //gem-buffer-obj里关联着dma-buf 
                            //通过fd_dev获取fd_bo[先获取handle,通过handle和dev获取bo];
                            //如果bucket列表有回收的就直接用回收的[green-recycle]
                            //最终把这个handle装进fd_bo     
  
            3.drm_dev->map_bo
                            //通过之前创建的handle找到对应的offset
                            //通过fd[/dev/dri/renderd128]和offset;mmap映射buffer到用户空间

            4.fill_content
                            //对3里面的mmap的返回地址进行填充

            5.drm_dev->unmap_bo
                            //画(填充)好了,取消map,交出buffer的执行权

            6.drm_dev->export_bo_to_prime
                            //调用drmPrimeHandleToFD把handle传下去,从dma那边拿到对应的dmabuf_fd 
                            //get_dma_buf + dma_buf_fd
                            //返回buffer->dmabuf_fd
                            //[把fd交给别的用户端,然后别的用户端通过这个fd拿到handle,就实现了共享buffer]

            7.zwp_linux_dmabuf_v1_create_params
                            //具体server实现参照https://blog.csdn.net/u012839187/article/details/107861193 找到对应的server函数
                            //libweston/linux-dmabuf.c::linux_dmabuf_create_params
                            //初始化 linux_dmabuf_buffer 对象;将buffer->attributes.fd统统置零

            8.zwp_linux_buffer_params_v1_add
                            //将之前export_bo_to_prime的fd传递给server,调用一次此函数对应一个plane;如果yuv格式,多个plane,还会传递offset值
                            //buffer->attributes.fd[plane_idx] = name_fd;
                            //buffer->attributes.offset[plane_idx] = offset;
                            //不同format的图像,对应的plane不同,调用此函数的次数对应plane的数量[rgb统一为1,yuv可能多个,因为他们的yuv可能分开存放]

            9.zwp_linux_buffer_params_v1_add_listener
                            //监听params创捷结果,做出对应的反应
            10.zwp_linux_buffer_params_v1_create
                            //调用params_create_common;遍历plane检查之前的fd是否正常获得,再次填充buffer结构体        
                    a.weston_compositor_import
                            //weston_compositor_import_dmabuf[Import dmabuf buffer into current renderer]
                            a.gl_renderer_import_dmabuf
                                    a.import_dmabuf
                                            a.dmabuf_image_create
                                                    //创建dmabuf_image实例,后续将linux_dmabuf_buffer关联dmabuf_image->dmabuf
                                            b.import_simple_dmabuf如果此函数执行失败,则import_yuv_dmabuf
                                                    //把dma-fd以及其他属性传给EGLint
                                                    a.egl_image_create
                                    b.linux_dmabuf_buffer_set_user_data
                                            //把通过egl_image_create的dmabuf_image[包含EGLImageKHR实例],和linux_dmabuf_buffer绑定:buffer->user_data=image

往后的redraw和dispatch都是一样的,不再叙述

NOTE:

上述dma的创捷以及使用部分可查看:

https://blog.csdn.net/u012839187/article/details/113558156

https://blog.csdn.net/u012839187/article/details/107614516   ”libdrm与内核的交互“ 章节

一般情况,gem-object依赖于idr机制去创建独一无二的handle;fd/handle通过dma API去得到对应的handle/fd。

2.3.4.5.6,实现了创建buffer,拿到handle,获取offset,mmap绘画,关联dma获取fd整个逻辑

simple-dmabuf-egl

1.解析外部参数

2.create_display
        a.绑定全局对象
            1.zwp_linux_dmabuf_v1;绑定zwp_linux_explicit_synchronization_v1;绑定weston_direct_display_v1;监听传过来的format和mofifiers事件;
            2.zwp_linux_explicit_synchronization_v1;
            3.weston_direct_display_v1;
        /* GBM需要在EGL之前初始化,以便我们有一个有效的渲染节点gbm_device来创建EGL显示。* /
        b.display_set_up_gbm
            1.open(drm_render_node, O_RDWR);
            2.gbm_create_device(display->gbm.drm_fd);
        c.display_set_up_egl
        d.display_update_supported_modifiers_for_egl
        e.fence

3.create_window
        a.fence
        b.create_dmabuf_buffer
            1.gbm_bo_create
            2.gbm_bo_get_plane_count
            3.gbm_bo_get_handle_for_plane
            4.drmPrimeHandleToFD

            7.params = zwp_linux_dmabuf_v1_create_params(display->dmabuf);
            //要从一个或多个dmabuf创建wl_buffer,客户端将使用zwp_linux_dmabuf_v1.create_params请求创建一个zwp_linux_dmabuf_params_v1对象
            8.zwp_linux_buffer_params_v1_add(params,
					   buffer->dmabuf_fds[i],
					   i,
					   buffer->offsets[i],
					   buffer->strides[i],
					   buffer->modifier >> 32,
					   buffer->modifier & 0xffffffff);
            //不同format的图像,对应的plane不同,调用此函数的次数对应plane的数量[*rgb统一为1,yuv可能多个,因为他们的yuv可能分开存放],填充linux_dmabuf_buffer结构体
            9.zwp_linux_buffer_params_v1_add_listener(params, &params_listener, buffer);
            //监听params创捷结果,做出对应的反应
            10.
            buffer->buffer =
			zwp_linux_buffer_params_v1_create_immed(params,
								buffer->width,
								buffer->height,
								buffer->format,
								flags);
            wl_buffer_add_listener(buffer->buffer,
					       &buffer_listener,
					       buffer);
        或者
            10.zwp_linux_buffer_params_v1_create(params,
				    buffer->width,
					buffer->height,
					buffer->format,
					flags);
            11.create_fbo_for_buffer(display, buffer)

往后的redraw和dispatch都是一样的,不再叙述

1.creat_params:create linux_dmabuf_buffer

2.params_add:init linux_dmabuf_buffer:  =>fd,offset,stride,modifier

3.params_create :

fd传递路径:

1->2->3->4->8->10
server:
if (!weston_compositor_import_dmabuf(buffer->compositor, buffer))  -->
    gl_renderer.c::import_dmabuf
        egl_image = import_simple_dmabuf(gr, &dmabuf->attributes);
                ...
                attribs[atti++] = attributes->fd[0];
                ...
                image = egl_image_create(gr, EGL_LINUX_DMA_BUF_EXT, NULL, attribs);

NOTE:如下内容决定weston是否支持dmabuf

	if (weston_check_egl_extension(extensions, "EGL_EXT_image_dma_buf_import"))
		gr->has_dmabuf_import = true;
|
|...
	if (compositor->renderer->import_dmabuf) {
		if (linux_dmabuf_setup(compositor) < 0)
			weston_log("Error: initializing dmabuf "
				   "support failed.\n");
		if (weston_direct_display_setup(compositor) < 0)
			weston_log("Error: initializing direct-display "
				   "support failed.\n");
	}

 

 
 

 

 

 类似资料: