display: mesa: eglapi接口:createWindowSurface

接上一篇:display: mesa: eglapi接口:bind/query api_maze的专栏-CSDN博客

eglCreateWindowSurface/eglCreatePlatformWindowSurfaceEXT

EGLSurface EGLAPIENTRY
eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
                       EGLNativeWindowType window, const EGLint *attrib_list)
//返回是的EGLSurface
{
   _EGLDisplay *disp = _eglLockDisplay(dpy);

   return _eglCreateWindowSurfaceCommon(disp, config, (void*) window, attrib_list);
       _EGLConfig *conf = _eglLookupConfig(config, disp);
       _EGLSurface *surf;

       surf = disp->Driver->CreateWindowSurface(disp, conf, native_window, attrib_list);//对应egl_dri2.c :: dri2_create_window_surface
           struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);

           return dri2_dpy->vtbl->create_window_surface(disp, conf, native_window, attrib_list);//对应platform_drm.c :: dri2_drm_create_window_surface
               struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
               struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
               struct dri2_egl_surface *dri2_surf;
               struct gbm_surface *surface = native_surface;
               struct gbm_dri_surface *surf;
               const __DRIconfig *config;
      
               dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list, false, native_surface);
                   return _eglInitSurface(surf,disp,type,conf,attrib_list,native_surface);
                       surf->xxx = xxx;(全是这种赋值)
               真正初始化_EGLSurface object surf的地方。

               config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT, dri2_surf->base.GLColorspace);
                   return conf->dri_config[double_buffer][srgb];
               这个函数说明的double buffer的机制。如果是EGL_WINDOW_BIT,就是double buffer。返回的是__DRIconfig指针。

               dri2_drm_config_is_compatible(dri2_dpy, config, surface)
               如其名字,判断对应的config是否能正常。

               surf = gbm_dri_surface(surface);
               dri2_surf->gbm_surf = surf;
               dri2_surf->base.Width =  surf->base.v0.width;
               dri2_surf->base.Height = surf->base.v0.height;
               surf->dri_private = dri2_surf;

               dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf->gbm_surf) //假设接口是dri2_dpy->image_driver,egl_dri2.c
                   createNewDrawable = dri2_dpy->image_driver->createNewDrawable;
                   dri2_surf->dri_drawable = createNewDrawable(dri2_dpy->dri_screen, config, loaderPrivate);
                       driCreateNewDrawable(screen, config, data); //该接口在dri_util.c里面
                           __DRIdrawable *pdraw;
                           pdraw->xxx = xxx;//初始化 pdraw

                           dri_get_drawable(pdraw); //其实就是pdraw->refcount++;
                           
                           screen->driver->CreateBuffer(screen, pdraw, &config->modes. GL_FALSE);//调用的是gallium里面的dri2.c文件的galliumdrm_driver_api,具体位置是mesa/src/gallium/frontends/dri/dri2.c:: CreateBuffer = dri2_create_buffer;
                               struct dri2_drawable *drawable = NULL;
                               dri_create_buffer(sPriv, dPriv, visual, isPixmap);
                               //参看下个函数细节。
                               //参看下个函数细节。
                               //参看下个函数细节。
                               drawable = dPriv->driverPrivate;

                               drawable->allocate_textures = dri2_allocate_textures;
                               drawable->flush_frontbuffer = dri2_flush_frontbuffer;
                               drawable->update_tex_buffer = dri2_update_tex_buffer;
                               drawable->flush_swapbuffers = dri2_flush_swapbuffers;
                           return pdraw;                    
                        
               swrast我们不看,可能是image_driver或者dri2接口的一种。假设是image_driver
                

               return &dri2_surf->base;
       return surf;
}

创建一个离屏EGL window surface并返回其句柄。比eglCreateWindowSurface多个platforms,用来指定属于的平台。

dri_create_buffer::函数在dri_drawable.c

bool
dri_create_buffer(__DRIscreen * sPriv,
		  __DRIdrawable * dPriv,
		  const struct gl_config * visual, bool isPixmap)
{   
   struct dri_screen *screen = sPriv->driverPrivate;
   struct dri_drawable *drawable = NULL;

   if (isPixmap)
      goto fail;		       /* not implemented */
...

   dri_fill_st_visual(&drawable->stvis, screen, visual); //st_visual 的 struct注释是: represent the visual of a framebuffer.

   /* setup the st_framebuffer_iface */
   drawable->base.visual = &drawable->stvis;
   drawable->base.flush_front = dri_st_framebuffer_flush_front;
   drawable->base.validate = dri_st_framebuffer_validate;
   drawable->base.flush_swapbuffers = dri_st_framebuffer_flush_swapbuffers;
   drawable->base.st_manager_private = (void *) drawable;

   drawable->screen = screen;
   drawable->sPriv = sPriv;
   drawable->dPriv = dPriv;

   dPriv->driverPrivate = (void *)drawable;
   p_atomic_set(&drawable->base.stamp, 1);
   drawable->base.ID = p_atomic_inc_return(&drifb_ID);
   drawable->base.state_manager = &screen->base;

   return true;
}

 对drawable对象进行挂钩。

所以看下来,整个函数并没有创建显示的buffer,而是创建了相关的drawable结构体等等。


eglQuerySurface

EGLBoolean EGLAPIENTRY
eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
                EGLint attribute, EGLint *value)
{
   _EGLDisplay *disp = _eglLockDisplay(dpy);
   _EGLSurface *surf = _eglLookupSurface(surface, disp);
...
   if (disp->Driver->QuerySurface)
      ret = disp->Driver->QuerySurface(disp, surf, attribute, value);
          dri2_query_surface
              dri2_dpy->vtbl->query_surface
   else
      ret = _eglQuerySurface(disp, surf, attribute, value);
}

查询surface相关attribute,所谓的attribute在createwindowsurface的时候已经初始化完成了。目前mesa里面的query_surface里面的vtbl并没有实现对应接口,实际上调用的是_eglQuerySurface。可查询的属性非常多,具体可参看Eglsurface.c文件对应实现。下面随意列出一些:

EGLBoolean
_eglQuerySurface(_EGLDisplay *disp, _EGLSurface *surface,
                 EGLint attribute, EGLint *value)
{   
switch (attribute) {
   case EGL_WIDTH:
      *value = surface->Width;
      break;
   case EGL_HEIGHT:
      *value = surface->Height;
      break;
   case EGL_CONFIG_ID:
      *value = surface->Config->ConfigID;
      break;
   case EGL_LARGEST_PBUFFER:
      if (surface->Type == EGL_PBUFFER_BIT)
         *value = surface->LargestPbuffer;
      break;
   case EGL_TEXTURE_FORMAT:
      /* texture attributes: only for pbuffers, no error otherwise */
      if (surface->Type == EGL_PBUFFER_BIT)
         *value = surface->TextureFormat;
      break;
   case EGL_TEXTURE_TARGET:
      if (surface->Type == EGL_PBUFFER_BIT)
         *value = surface->TextureTarget;
      break;
...


eglDestroySurface

EGLBoolean EGLAPIENTRY
eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
{
   _EGLDisplay *disp = _eglLockDisplay(dpy);
   _EGLSurface *surf = _eglLookupSurface(surface, disp);
...
   _eglUnlinkSurface(surf);
       _eglUnlinkResource(&surf->Resource, _EGL_RESOURCE_SURFACE); //从_EGLDisplay中拿掉一个它的resource,我们这里传的的RESOURCE_SURFACE,所以是从display的ResourceLists里面拿掉对应的surface。

   ret = disp->Driver->DestroySurface(disp, surf);
       dri2_destroy_surface(disp, surf); //egl_dri2.c
           return dri2_dpy->vtbl->destroy_surface(disp, surf); //platform_drm.c
               dri2_drm_destroy_surface(disp, surf);
               //见下段。
}

dri2_drm_destroy_surface :: platform_drm.c

static EGLBoolean
dri2_drm_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
{
   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);

   dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);//对应实现在dri_util.c
       driDestroyDrawable(pdp) //pdp就是dri_drawable
           pdp-> loaderPrivate = NULL;
           dri_put_drawable(pdp); //pdp是 __DRIdrawable,有计数,如果refcount-1以后等于0,则释放对应pdp,如下:
               pdp->driScreenPriv->driver->DestroyBuffer(pdp);
                   dri_destroy_buffer // dri2.c, gallliumdrm_driver_api,这里面比较复杂。
               free(pdp);       

   for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
      if (dri2_surf->color_buffers[i].bo)
	 gbm_bo_destroy(dri2_surf->color_buffers[i].bo);
   }

   dri2_egl_surface_free_local_buffers(dri2_surf);

   dri2_fini_surface(surf);
   free(surf);

   return EGL_TRUE;
}

dri_destroy_buffer :: Dri_drawable.c


void
dri_destroy_buffer(__DRIdrawable * dPriv)
{
   struct dri_drawable *drawable = dri_drawable(dPriv);
   struct dri_screen *screen = drawable->screen;
   struct st_api *stapi = screen->st_api;
   int i;

   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
      pipe_resource_reference(&drawable->textures[i], NULL);
   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
      pipe_resource_reference(&drawable->msaa_textures[i], NULL);

   screen->base.screen->fence_reference(screen->base.screen,
         &drawable->throttle_fence, NULL);

   /* Notify the st manager that this drawable is no longer valid */
   stapi->destroy_drawable(stapi, &drawable->base);  //st_manager.c :: st_api_destory_drawable
       st_api_destroy_drawable 如下

   FREE(drawable->damage_rects);
   FREE(drawable);
}

####
/**
 * The framebuffer interface object is no longer valid.
 * Remove the object from the framebuffer interface hash table.
 */
static void
st_api_destroy_drawable(struct st_api *stapi,
                        struct st_framebuffer_iface *stfbi)
{
   if (!stfbi)
      return;

   st_framebuffer_iface_remove(stfbi->state_manager, stfbi);
}

eglCreateImage

EGLImage EGLAPIENTRY
eglCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target,
               EGLClientBuffer buffer, const EGLAttrib *attr_list)
{
   _EGLDisplay *disp = _eglLockDisplay(dpy);
   EGLImage image;
   EGLint *int_attribs;

   int_attribs = _eglConvertAttribsToInt(attr_list);
   image = _eglCreateImageCommon(disp, ctx, target, buffer, int_attribs);
   return image;
}

创建一个EGLImage对象
eglBindTexImage定义一个二维纹理图像,纹理图像数据用buffer指定,不需要数据拷贝。纹理的格式和surface保持一致,surface必须是支持EGL_BIND_TO_TEXTURE_RGB或EGL_BIND_TO_TEXTURE_RGBA属性的pbuffer。如果surface和display是线程当前的上下文状态,这个命令相当于glFlush,如果不是要等其他GL draw命令执行完。执行过这个命令之后,指定的surface就不能在读写了。这个函数调用之后eglSwapBuffers会失效。
eglDestroyImage


eglMakeCurrent

EGLBoolean EGLAPIENTRY
eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read,
               EGLContext ctx)
{
   _EGLDisplay *disp = _eglLockDisplay(dpy);
   _EGLContext *context = _eglLookupContext(ctx, disp);
   _EGLSurface *draw_surf = _eglLookupSurface(draw, disp);
   _EGLSurface *read_surf = _eglLookupSurface(read, disp);
...
...
...

   ret = disp->Driver->MakeCurrent(disp, draw_surf, read_surf, context);
       dri2_make_current //egl_dri2.c

   return;
}

将上下文绑定到当前渲染线程上,同时绑定到读写surface上.

dri2_make_currect :: egl_dri2.c

/**
 * Called via eglMakeCurrent(), drv->MakeCurrent().
 */
static EGLBoolean
dri2_make_current(_EGLDisplay *disp, _EGLSurface *dsurf,
                  _EGLSurface *rsurf, _EGLContext *ctx)
{
...

   /* make new bindings, set the EGL error otherwise */
   _eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf);

   if (old_ctx) {
      __DRIcontext *old_cctx = dri2_egl_context(old_ctx)->dri_context;
      old_disp = old_ctx->Resource.Display;
      old_dri2_dpy = dri2_egl_display(old_disp);

      /* flush before context switch */
      dri2_gl_flush();

      if (old_dsurf)
         dri2_surf_update_fence_fd(old_ctx, disp, old_dsurf);

      /* Disable shared buffer mode */
      if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) &&
          old_dri2_dpy->vtbl->set_shared_buffer_mode) {
         old_dri2_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, false);
      }

      dri2_dpy->core->unbindContext(old_cctx);
   }

   ddraw = (dsurf) ? dri2_dpy->vtbl->get_dri_drawable(dsurf) : NULL;
   rdraw = (rsurf) ? dri2_dpy->vtbl->get_dri_drawable(rsurf) : NULL;
   cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;

   if (cctx || ddraw || rdraw) {
      if (!dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
         _EGLContext *tmp_ctx;

         /* dri2_dpy->core->bindContext failed. We cannot tell for sure why, but
          * setting the error to EGL_BAD_MATCH is surely better than leaving it
          * as EGL_SUCCESS.
          */
         egl_error = EGL_BAD_MATCH;

         /* undo the previous _eglBindContext */
         _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &tmp_dsurf, &tmp_rsurf);
         assert(&dri2_ctx->base == ctx &&
                tmp_dsurf == dsurf &&
                tmp_rsurf == rsurf);

         _eglPutSurface(dsurf);
         _eglPutSurface(rsurf);
         _eglPutContext(ctx);

         _eglPutSurface(old_dsurf);
         _eglPutSurface(old_rsurf);
         _eglPutContext(old_ctx);

         ddraw = (old_dsurf) ? dri2_dpy->vtbl->get_dri_drawable(old_dsurf) : NULL;
         rdraw = (old_rsurf) ? dri2_dpy->vtbl->get_dri_drawable(old_rsurf) : NULL;
         cctx = (old_ctx) ? dri2_egl_context(old_ctx)->dri_context : NULL;

         /* undo the previous dri2_dpy->core->unbindContext */
         if (dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
            if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) &&
                old_dri2_dpy->vtbl->set_shared_buffer_mode) {
               old_dri2_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, true);
            }

            return _eglError(egl_error, "eglMakeCurrent");
         }

         /* We cannot restore the same state as it was before calling
          * eglMakeCurrent() and the spec isn't clear about what to do. We
          * can prevent EGL from calling into the DRI driver with no DRI
          * context bound.
          */
         dsurf = rsurf = NULL;
         ctx = NULL;

         _eglBindContext(ctx, dsurf, rsurf, &tmp_ctx, &tmp_dsurf, &tmp_rsurf);
         assert(tmp_ctx == old_ctx && tmp_dsurf == old_dsurf &&
                tmp_rsurf == old_rsurf);

         _eglLog(_EGL_WARNING, "DRI2: failed to rebind the previous context");
      } else {
         /* dri2_dpy->core->bindContext succeeded, so take a reference on the
          * dri2_dpy. This prevents dri2_dpy from being reinitialized when a
          * EGLDisplay is terminated and then initialized again while a
          * context is still bound. See dri2_intitialize() for a more in depth
          * explanation. */
         dri2_dpy->ref_count++;
      }
   }

   dri2_destroy_surface(disp, old_dsurf);
   dri2_destroy_surface(disp, old_rsurf);

   if (old_ctx) {
      dri2_destroy_context(disp, old_ctx);
      dri2_display_release(old_disp);
   }

   if (egl_error != EGL_SUCCESS)
      return _eglError(egl_error, "eglMakeCurrent");

   if (dsurf && _eglSurfaceHasMutableRenderBuffer(dsurf) &&
       dri2_dpy->vtbl->set_shared_buffer_mode) {
      /* Always update the shared buffer mode. This is obviously needed when
       * the active EGL_RENDER_BUFFER is EGL_SINGLE_BUFFER. When
       * EGL_RENDER_BUFFER is EGL_BACK_BUFFER, the update protects us in the
       * case where external non-EGL API may have changed window's shared
       * buffer mode since we last saw it.
       */
      bool mode = (dsurf->ActiveRenderBuffer == EGL_SINGLE_BUFFER);
      dri2_dpy->vtbl->set_shared_buffer_mode(disp, dsurf, mode);
   }

   return EGL_TRUE;
}

如果有old的context等相关内容,就先解绑old。再绑定new的。在完成new的绑定以后,free掉old的。

Buffer相关

eglCopyBuffers将surface的color buffer拷贝到native_pixmap. 相当以一个glFlush。
eglCreatePbufferFromClientBuffer创建一个EGL pixel buffer surface并绑定到一个OpenVG image

Surface相关

eglCreatePbufferSurface
创建一个离屏pixel buffer surface返回它的句柄
eglCreatePixmapSurface
创建一个离屏EGL pixmap surface返回它的句柄. 比eglCreatePixmapSurface多一个平台参数,用来指定属于的平台。
eglCreatePlatformPixmapSurface
创建一个离屏EGL pixmap surface并返回其句柄。
eglCreatePlatformWindowSurface
创建一个离屏EGL窗口surface并返回其句柄。


eglGetCurrentContext
返回当前EGL渲染上下文,当前EGL渲染上下文通过eglMakeCurrent指定.
eglGetCurrentDisplay
返回当前EGL渲染上下文的display connection。
eglGetCurrentSurface
返回当前EGL渲染上下文的read或draw surface

eglGetError
eglGetPlatformDisplay
返回一个EGL display connection
eglGetProcAddress
返回一个GL或EGL扩展函数

eglIntro
introduction to通过EGL API管理client API渲染。
eglQueryString
返回一个字符串,描述了EGL client或EGL display connection相关的属性,可以查询的参数包括:EGL_EXTENSIONS、EGL_VERSION、EGL_VENDOR和EGL_CLIENT_APIS
eglReleaseTexImage
释放作一个color buffer,这个buffer是用来做一幅纹理的, 指定的color buffer释放给了surface。
eglReleaseThread
释放EGL per-thread state. 将EGL的状态复位到初始化的情况,释放的值包括error status, currently bound rendering API以及每一个client API支持的当前上下文。The overhead of maintaining this state may be objectionable in applications which create and destroy many threads, but only call EGL or client APIs in a few of those threads at any given time.
eglSurfaceAttrib
设置EGL surface的属性
eglTerminate
中止一个EGL display连接,释放相关资源。如果当前的线程中display关联的contexts或surfaces, 得不关联或切换之后才能释放。中止之后可以通过eglInitialize再次激活。

同步相关:

在native rendering调用之前完成GL的执行,
eglWaitClient对应calls for the currently bound context, for the current rendering API.
eglWaitGL对应OpenGL ES rendering calls for the currently bound OpenGL ES context,同glFinish.
eglWaitNative对应Native rendering calls made prior to eglWaitNative are guaranteed to be executed before GL rendering calls made after eglWaitNative.保证原生窗口系统的渲染完成,参数engine指定需要等待的渲染引擎
eglClientWaitSyncblock调用的线程知道指定的sync信号收到,或者timeout设置的时间到了。
eglWaitSync在server等一个同步对象的触发信号,和eglClientWaitSync不同的地方是不会进行block和等待,会直接返回。
eglCreateSync创建一个EGL sync对象,sync对象使能线程间和API上下文之间的client API同步. 可以用来测试或称才应用程序线程。
eglGetSyncAttrib返回一个sync对象的属性。
eglDestroySync

Swap相关

eglSwapBuffers把EGL surface color buffer推送至native window,如果surface是back-buffered window surface, eglSwapBuffers then the color buffer is copied (posted) native window associated with that surface. 单buffer窗口或pixmap或buffer没有效果。
eglSwapInterval指定当前上下文关联的窗口中,每buffer swap的视频帧数的最小值。The interval takes effect when eglSwapBuffers is first called subsequent to the eglSwapInterval call.

作者:eric_la
链接:https://www.jianshu.com/p/bc84a293e254
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值