display: mesa: eglapi接口:eglswapbuffers

display: mesa: eglapi接口:getdisplay&initialize_maze的专栏-CSDN博客

最近项目上遇到一个问题:某一帧eglswapbuffer事件的时间格外长,达到300ms以上的情况

基于这个问题。因为是wayland/weston的体系。所以mesa支持的eglswapbuffer有两个部分:

1.client端的eglswapbuffer,这部分是有相关的wayland协议支持的。

2.weston内部gl-renderer模块的eglswapbuffer。

opensource/mesa/src/egl/drivers/dri2$ grep -rn "swap_buffers ="

platform_x11.c:1172: .swap_buffers = dri2_x11_swap_buffers,
platform_x11.c:1186: .swap_buffers = dri2_x11_swap_buffers,
platform_wayland.c:1379: .swap_buffers = dri2_wl_swap_buffers,
platform_wayland.c:1995: .swap_buffers = dri2_wl_swrast_swap_buffers,
platform_drm.c:675: .swap_buffers = dri2_drm_swap_buffers,
platform_x11_dri3.c:507: .swap_buffers = dri3_swap_buffers,
platform_android.c:1284: .swap_buffers = droid_swap_buffers, 

weston的client是platform_wayland实现;weston本身内部是platform_drm的实现。

需要一些概念性的东西:display:weston:weston-simple-egl_maze的专栏-CSDN博客

Display(EGLDisplay) 是对实际显示设备的抽象
Surface(EGLSurface)是对用来存储图像的内存区域 FrameBuffer 的抽象,包括 Color Buffer, Stencil Buffer ,Depth Buffer
Context (EGLContext) 存储 OpenGL ES绘图的一些状态信息
————————————————

Display
Display 是 OpenGL ES 应用运行平台的物理显示器的抽象

Rendering Context 
OpenGL ES 状态机,由EGL创建、并与Surface关联;Rendering Context含有OpenGL ES的客户端和服务器端状态;Rendering Context存在于客户端的地址空间。每个线程在同一时刻只能使用1个Rendering Context,每个Rendering Context在同一时刻只能被1个线程使用

Surface
OpenGL ES绘图的“画布”。EGL/OpenGL ES有3种Surface:

    window - 用于屏上(onscreen)渲染
    pbuffer - 用于离屏(offscreen)渲染
    pixmap - 离屏渲染,但本地渲染API也可以访问

OpenGL支持2种渲染模式:
    back buffered - 绘图的color buffer由EGL创建和管理,绘图完成后,EGL将后台color buffer交换/拷贝到窗口上
    single buffered - 其color buffer为本地Pixmap,EGL能使用但不维护。OpenGL ES绘图后,像素直接在Surface上呈现

window和pbuffer Surface是back buffered模式,pixmap Surface是single buffered模式


Config
用于创建Surface,包含了Surface的各个buffer的创建参数

    color buffer
    depth buffer
    multisample buffer
    stencil buffer

https://www.pianshen.com/article/6484561270/

先从simple-egl里面的eglSwapBuffers:

mesa/src/egl/main/eglapi.c:

EGLBoolean EGLAPIENTRY 
    eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
{
        _EGLContext *ctx = _eglGetCurrentContext();
        _EGLDisplay *disp = _eglLockDisplay(dpy);
        _EGLSurface *surf = _eglLookupSurface(surface, disp);
        //先获取三大项:eglcontext, egldisplay, eglsurface
...
        if (surf->Type != EGL_WINDOW_BIT)
            RETURN_EGL_EVAL(disp, EGL_TRUE);
        //不是window类型的surface直接退出,上面提到的屏上渲染,(没有双buffer,你调这个函数干啥)
...

        ret = disp->Driver->SwapBuffers(disp, surf);
        //回调
}

这个disp->Driver->SwapBuffers(disp, surf);

对应的driver为_EGLDriver:

mesa/src/egl/drviers/dri2/egl_dri2.c

static EGLBoolean
dri2_swap_buffers(_EGLDisplay *disp, _EGLSurface *surf)
{
   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
   __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
   _EGLContext *ctx = _eglGetCurrentContext();
   //换成了dri2_egl_display,__DRIdrawable,_EGLContext。

   if (ctx && surf)
      dri2_surf_update_fence_fd(ctx, disp, surf);//这一部分是fence相关,后续要细挖,学习一下。
   ret = dri2_dpy->vtbl->swap_buffers(disp, surf);

   /* SwapBuffers marks the end of the frame; reset the damage region for
    * use again next time.
    */
   if (ret && dri2_dpy->buffer_damage && dri2_dpy->buffer_damage->set_damage_region)
      dri2_dpy->buffer_damage->set_damage_region(dri_drawable, 0, NULL);
      //重设damage区域。·
   return ret;
}

关键在于ret = dri2_dpy->vtbl->swap_buffers(disp, surf);

不同的平台实现不一样,这里先说支持wayland这一种:src/egl/drivers/dri2/platform_wayland.c

static EGLBoolean
dri2_wl_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
{
   return dri2_wl_swap_buffers_with_damage(disp, draw, NULL, 0);
}

//下面就涉及了很多wayland的知识点。
static EGLBoolean
dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp,
                                 _EGLSurface *draw,
                                 const EGLint *rects,
                                 EGLint n_rects)
//先获取dri2_egl_display 和 dri2_egl_surface.
...
   while (dri2_surf->throttle_callback != NULL)
      if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
                                    dri2_surf->wl_queue) == -1)
         return -1;
    //这一段的意思是,如果callback不是空的,也就是上一帧还没有收到weston这边传来的callback done事件,那就继续从socket上读event给到client,也就是这一帧在这里忙等weston发event过来。
...
   for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
      if (dri2_surf->color_buffers[i].age > 0)
         dri2_surf->color_buffers[i].age++;
    //age++目前不清楚干啥的。
...
   /* Make sure we have a back buffer in case we're swapping without ever
    * rendering. */
   if (update_buffers_if_needed(dri2_surf) < 0)
      return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
    //没有back-buffer的话,就不会sw
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值