X C Bindings

XCB 是应用与 X 服务器交互使用的 C 绑定函数集,它里面的一些 C 函数是通过 python3-xcbgen 工具生成的,不经过编译在它的源码库是找不到的。而且 XCB 古老到仍然使用 autotools 那套构建系统,想要看到某些函数的“真容”,你还得“千呼万唤”。

Build

  • 安装工具

    • sudo apt install python3-xcbgen autoconf automake libtool xutils-dev xcb-proto
    • xutils-dev 里包含 xorg-macros
    • libxcb 的版本与 *xcb-proto 软件包的版本有依赖关系,如果你安装的 xcb-proto 版本是 1.14-2, 那么最好将 libxcb 的 tag 也检出到 libxcb-1.14
  • 构建

    • ./autogen.sh
    • make
  • 千呼万唤始出来

Bindings

xcb_create_pixmap

sequenceDiagram
    autonumber
    participant Mesa
    participant X11

    Mesa-->>X11: xcb_generate_id()
    X11-->>Mesa: uint32_t pid (pixmap id)
    Mesa-->>X11: xcb_create_pixmap()
    X11->>X11: ProcCreatePixmap()
    note left of X11: CreatePixmapProcPtr 接口,有各种实现<br/>glamor, dri2, xwayland, xnest<br/>当初的 pixmap id 会<br/>记录在创建好的 Pixmap 的 drawable->id
    X11->>X11: glamor_create_pixmap(usage=0)
    X11->>X11: glamor_create_fbo()
    rect rgb(191, 223, 255)
    X11->>X11: _glamor_create_tex()
    X11-->>Mesa: glGenTextures()
    end
    Mesa-->>X11: xcb_dri3_buffers_from_pixmap(pid)

xcb_dri3_buffers_from_pixmap

sequenceDiagram
    autonumber
    participant Mesa
    participant X11

    Mesa-->>X11: xcb_dri3_buffers_from_pixmap(pid)
    rect rgb(191, 223, 255)
    X11->>X11: proc_dri3_buffers_from_pixmap()
    X11->>X11: dixLookupResourceByType(pid)
    note left of X11: 通过 pid 找到当初的 PixmapPtr
    X11->>X11: dri3_fds_from_pixmap(PixmapPtr)
    rect rgb(200, 150, 255)
    note left of X11: X11 导出 FD
    X11->>X11: glamor_egl_fds_from_pixmap()
    X11->>X11: glamor_make_pixmap_exportable()
    X11->>X11: glamor_gbm_bo_from_pixmap_internal()
    note left of X11: 通过 PixmapPtr 获取 gbm_bo
    X11-->>Mesa: gbm_bo_get_fd()
    Mesa-->>X11: xcb_dri3_buffers_from_pixmap_reply()
    Mesa-->>X11: xcb_dri3_buffers_from_pixmap_reply_fds()
    note right of Mesa: 拿到导出的 FD 需要两步<br/> reply_fds() 才是真正拿到 FD
    end
    rect rgb(200, 150, 255)
    note right of Mesa: Mesa 导入 FD
    Mesa->>Mesa: dri2_from_dma_bufs2()
    Mesa->>Mesa: dri2_create_image_from_fd()
    Mesa->>Mesa: dri2_create_image_from_winsys(winsys_handle)
    loop Every FD
        Mesa->>Mesa: xxx_resource_from_handle()
        Mesa->>Mesa: xxx_bo_import()
        note right of Mesa: resource_from_handle() 返回的<br/>pipe_resource 给 __DRIimage.texture
    end
    end
    end

glamor_make_pixmap_exportable

函数功能:

  • 100 创建一个新的 Pixmap exported 用来 export
  • 200 同时创建一个 gbm_bo, 将 exported 的 header 设置成刚创建的 gbm_bo
  • 300 将原来的 Pixmap 的内容 CopyArea()exported
  • 400 glamor_egl_exchange_buffers(pixmap, exported), 将 exported 里的 tex/gbm_bo/EGLImage 换到原来的 Pixmap 结构体中
  • 500 销毁 exported Pixmap

步骤 300 暗藏 bug, 因为 CopyArea() 会调用 glamor_copy_fbo_fbo_draw() 将原 Pixmap 作为纹理采样到新的 Pixmap exported, 也就是会调入 _mesa_DrawArrays(), 进而导致这个即将被导出的 BO, 被重新设置成 drawcall 的 render target buffer。 但是 glamor_copy_fbo_fbo_draw() 在调用 _mesa_DrawArrays() 进行"拷贝"后,并不会 glFlush(), 只能等到 X11 定时触发 Screen->BlockHandler()glFlush()

另外一个进程导入 BO 后,同样会设置它为 render target buffer, 这就造成 X11 进程和 App 进程为同一个 render target buffer 都创建了 CommandBuffer, 而提交给 GPU 的先后顺序却变得不确定了(有可能 X11 后提交,取决于 BlockHandler() 触发点)。