[Mesa-dev] [PATCH 6/7] egl/android: Implement EGL_KHR_mutable_render_buffer

Tapani Pälli tapani.palli at intel.com
Thu Aug 9 09:48:04 UTC 2018


Reviewed-by: Tapani Pälli <tapani.palli at intel.com>

On 07/31/2018 09:18 PM, Chad Versace wrote:
> Specifically, implement the extension DRI_MutableRenderBufferLoader.
> However, the loader enables EGL_KHR_mutable_render_buffer only if the
> DRI driver implements its half of the extension,
> DRI_MutableRenderBufferDriver.
> ---
>   src/egl/drivers/dri2/egl_dri2.c         |  38 +++++-
>   src/egl/drivers/dri2/egl_dri2.h         |   7 +
>   src/egl/drivers/dri2/platform_android.c | 168 +++++++++++++++++++++++-
>   3 files changed, 206 insertions(+), 7 deletions(-)
> 
> diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
> index 1208ebb3156..1a7338aa51d 100644
> --- a/src/egl/drivers/dri2/egl_dri2.c
> +++ b/src/egl/drivers/dri2/egl_dri2.c
> @@ -272,7 +272,10 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
>            _eglSetConfigKey(&base, EGL_MAX_PBUFFER_HEIGHT,
>                             _EGL_MAX_PBUFFER_HEIGHT);
>            break;
> -
> +      case __DRI_ATTRIB_MUTABLE_RENDER_BUFFER:
> +         if (disp->Extensions.KHR_mutable_render_buffer)
> +            surface_type |= EGL_MUTABLE_RENDER_BUFFER_BIT_KHR;
> +         break;
>         default:
>            key = dri2_to_egl_attribute_map[attrib];
>            if (key != 0)
> @@ -432,6 +435,7 @@ static const struct dri2_extension_match optional_core_extensions[] = {
>      { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) },
>      { __DRI2_FLUSH_CONTROL, 1, offsetof(struct dri2_egl_display, flush_control) },
>      { __DRI2_BLOB, 1, offsetof(struct dri2_egl_display, blob) },
> +   { __DRI_MUTABLE_RENDER_BUFFER_DRIVER, 1, offsetof(struct dri2_egl_display, mutable_render_buffer) },
>      { NULL, 0, 0 }
>   };
>   
> @@ -1459,6 +1463,8 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
>   {
>      struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
>      struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
> +   _EGLDisplay *old_disp = NULL;
> +   struct dri2_egl_display *old_dri2_dpy = NULL;
>      _EGLContext *old_ctx;
>      _EGLSurface *old_dsurf, *old_rsurf;
>      _EGLSurface *tmp_dsurf, *tmp_rsurf;
> @@ -1475,6 +1481,11 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
>         return EGL_FALSE;
>      }
>   
> +   if (old_ctx) {
> +      old_disp = old_ctx->Resource.Display;
> +      old_dri2_dpy = dri2_egl_display(old_disp);
> +   }
> +
>      /* flush before context switch */
>      if (old_ctx)
>         dri2_gl_flush();
> @@ -1488,6 +1499,13 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
>   
>         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);
>      }
>   
> @@ -1500,6 +1518,11 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
>                tmp_dsurf == dsurf &&
>                tmp_rsurf == rsurf);
>   
> +      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);
> +      }
> +
>         _eglPutSurface(dsurf);
>         _eglPutSurface(rsurf);
>         _eglPutContext(ctx);
> @@ -1522,11 +1545,22 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
>         dri2_dpy->ref_count++;
>   
>      if (old_ctx) {
> -      EGLDisplay old_disp = _eglGetDisplayHandle(old_ctx->Resource.Display);
>         dri2_destroy_context(drv, disp, old_ctx);
>         dri2_display_release(old_disp);
>      }
>   
> +   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;
>   }
>   
> diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
> index 5d8fbfa2356..d8a65be7085 100644
> --- a/src/egl/drivers/dri2/egl_dri2.h
> +++ b/src/egl/drivers/dri2/egl_dri2.h
> @@ -151,6 +151,12 @@ struct dri2_egl_display_vtbl {
>      __DRIdrawable *(*get_dri_drawable)(_EGLSurface *surf);
>   
>      void (*close_screen_notify)(_EGLDisplay *dpy);
> +
> +   /* Used in EGL_KHR_mutable_render_buffer to update the native window's
> +    * shared buffer mode.
> +    */
> +   bool (*set_shared_buffer_mode)(_EGLDisplay *dpy, _EGLSurface *surf,
> +                                  bool mode);
>   };
>   
>   struct dri2_egl_display
> @@ -178,6 +184,7 @@ struct dri2_egl_display
>      const __DRI2blobExtension *blob;
>      const __DRI2rendererQueryExtension *rendererQuery;
>      const __DRI2interopExtension *interop;
> +   const __DRImutableRenderBufferDriverExtension *mutable_render_buffer;
>      int                       fd;
>   
>      /* dri2_initialize/dri2_terminate increment/decrement this count, so does
> diff --git a/src/egl/drivers/dri2/platform_android.c b/src/egl/drivers/dri2/platform_android.c
> index cc16fd8118f..247de013f0c 100644
> --- a/src/egl/drivers/dri2/platform_android.c
> +++ b/src/egl/drivers/dri2/platform_android.c
> @@ -303,6 +303,32 @@ droid_window_cancel_buffer(struct dri2_egl_surface *dri2_surf)
>      }
>   }
>   
> +static bool
> +droid_set_shared_buffer_mode(_EGLDisplay *disp, _EGLSurface *surf, bool mode)
> +{
> +#if ANDROID_API_LEVEL >= 24
> +   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> +   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
> +   struct ANativeWindow *window = dri2_surf->window;
> +
> +   assert(surf->Type == EGL_WINDOW_BIT);
> +   assert(_eglSurfaceHasMutableRenderBuffer(&dri2_surf->base));
> +
> +   _eglLog(_EGL_DEBUG, "%s: mode=%d", __func__, mode);
> +
> +   if (native_window_set_shared_buffer_mode(window, mode)) {
> +      _eglLog(_EGL_WARNING, "failed native_window_set_shared_buffer_mode"
> +              "(window=%p, mode=%d)", window, mode);
> +      return false;
> +   }
> +
> +   return true;
> +#else
> +   _eglLog(_EGL_FATAL, "%s:%d: internal error: unreachable", __FILE__, __LINE__);
> +   return false;
> +#endif
> +}
> +
>   static _EGLSurface *
>   droid_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
>   		    _EGLConfig *conf, void *native_window,
> @@ -593,6 +619,21 @@ droid_image_get_buffers(__DRIdrawable *driDrawable,
>      if (update_buffers(dri2_surf) < 0)
>         return 0;
>   
> +   if (_eglSurfaceInSharedBufferMode(&dri2_surf->base)) {
> +      if (get_back_bo(dri2_surf) < 0)
> +         return 0;
> +
> +      /* We have dri_image_back because this is a window surface and
> +       * get_back_bo() succeeded.
> +       */
> +      assert(dri2_surf->dri_image_back);
> +      images->back = dri2_surf->dri_image_back;
> +      images->image_mask |= __DRI_IMAGE_BUFFER_SHARED;
> +
> +      /* There exists no accompanying back nor front buffer. */
> +      return 1;
> +   }
> +
>      if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
>         if (get_front_bo(dri2_surf, format) < 0)
>            return 0;
> @@ -639,6 +680,21 @@ droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
>      if (dri2_surf->base.Type != EGL_WINDOW_BIT)
>         return EGL_TRUE;
>   
> +   const bool has_mutable_rb = _eglSurfaceHasMutableRenderBuffer(draw);
> +
> +   /* From the EGL_KHR_mutable_render_buffer spec (v12):
> +    *
> +    *    If surface is a single-buffered window, pixmap, or pbuffer surface
> +    *    for which there is no pending change to the EGL_RENDER_BUFFER
> +    *    attribute, eglSwapBuffers has no effect.
> +    */
> +   if (has_mutable_rb &&
> +       draw->RequestedRenderBuffer == EGL_SINGLE_BUFFER &&
> +       draw->ActiveRenderBuffer == EGL_SINGLE_BUFFER) {
> +      _eglLog(_EGL_DEBUG, "%s: remain in shared buffer mode", __func__);
> +      return EGL_TRUE;
> +   }
> +
>      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++;
> @@ -663,6 +719,18 @@ droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
>   
>      dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
>   
> +   /* Update the shared buffer mode */
> +   if (has_mutable_rb &&
> +       draw->ActiveRenderBuffer != draw->RequestedRenderBuffer) {
> +       bool mode = (draw->RequestedRenderBuffer == EGL_SINGLE_BUFFER);
> +      _eglLog(_EGL_DEBUG, "%s: change to shared buffer mode %d",
> +              __func__, mode);
> +
> +      if (!droid_set_shared_buffer_mode(disp, draw, mode))
> +         return EGL_FALSE;
> +      draw->ActiveRenderBuffer = draw->RequestedRenderBuffer;
> +   }
> +
>      return EGL_TRUE;
>   }
>   
> @@ -1157,6 +1225,7 @@ static const struct dri2_egl_display_vtbl droid_display_vtbl = {
>      .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
>      .get_sync_values = dri2_fallback_get_sync_values,
>      .get_dri_drawable = dri2_surface_get_dri_drawable,
> +   .set_shared_buffer_mode = droid_set_shared_buffer_mode,
>   };
>   
>   #ifdef HAVE_DRM_GRALLOC
> @@ -1183,14 +1252,94 @@ static const __DRIextension *droid_dri2_loader_extensions[] = {
>      &droid_dri2_loader_extension.base,
>      &image_lookup_extension.base,
>      &use_invalidate.base,
> +   /* No __DRI_MUTABLE_RENDER_BUFFER_LOADER because it requires
> +    * __DRI_IMAGE_LOADER.
> +    */
>      NULL,
>   };
>   #endif /* HAVE_DRM_GRALLOC */
>   
> +static void
> +droid_display_shared_buffer(__DRIdrawable *driDrawable, int fence_fd,
> +                            void *loaderPrivate)
> +{
> +   struct dri2_egl_surface *dri2_surf = loaderPrivate;
> +   struct ANativeWindowBuffer *old_buffer UNUSED = dri2_surf->buffer;
> +
> +   if (!_eglSurfaceInSharedBufferMode(&dri2_surf->base)) {
> +      _eglLog(_EGL_WARNING, "%s: internal error: buffer is not shared",
> +              __func__);
> +      return;
> +   }
> +
> +   if (fence_fd >= 0) {
> +      /* The driver's fence is more recent than the surface's out fence, if it
> +       * exists at all. So use the driver's fence.
> +       */
> +      if (dri2_surf->out_fence_fd >= 0) {
> +         close(dri2_surf->out_fence_fd);
> +         dri2_surf->out_fence_fd = -1;
> +      }
> +   } else if (dri2_surf->out_fence_fd >= 0) {
> +      fence_fd = dri2_surf->out_fence_fd;
> +      dri2_surf->out_fence_fd = -1;
> +   }
> +
> +   if (dri2_surf->window->queueBuffer(dri2_surf->window, dri2_surf->buffer,
> +                                      fence_fd)) {
> +      _eglLog(_EGL_WARNING, "%s: ANativeWindow::queueBuffer failed", __func__);
> +      close(fence_fd);
> +      return;
> +   }
> +
> +   fence_fd = -1;
> +
> +   if (dri2_surf->window->dequeueBuffer(dri2_surf->window, &dri2_surf->buffer,
> +                                        &fence_fd)) {
> +      /* Tear down the surface because it no longer has a back buffer. */
> +      struct dri2_egl_display *dri2_dpy =
> +         dri2_egl_display(dri2_surf->base.Resource.Display);
> +
> +      _eglLog(_EGL_WARNING, "%s: ANativeWindow::dequeueBuffer failed", __func__);
> +
> +      dri2_surf->base.Lost = true;
> +      dri2_surf->buffer = NULL;
> +      dri2_surf->back = NULL;
> +
> +      if (dri2_surf->dri_image_back) {
> +         dri2_dpy->image->destroyImage(dri2_surf->dri_image_back);
> +         dri2_surf->dri_image_back = NULL;
> +      }
> +
> +      dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
> +      return;
> +   }
> +
> +   if (fence_fd < 0)
> +      return;
> +
> +   /* Access to the buffer is controlled by a sync fence. Block on it.
> +    *
> +    * Ideally, we would submit the fence to the driver, and the driver would
> +    * postpone command execution until it signalled. But DRI lacks API for
> +    * that (as of 2018-04-11).
> +    *
> +    *  SYNC_IOC_WAIT waits forever if timeout < 0
> +    */
> +   sync_wait(fence_fd, -1);
> +   close(fence_fd);
> +}
> +
> +static const __DRImutableRenderBufferLoaderExtension droid_mutable_render_buffer_extension = {
> +   .base = { __DRI_MUTABLE_RENDER_BUFFER_LOADER, 1 },
> +   .displaySharedBuffer = droid_display_shared_buffer,
> +};
> +
>   static const __DRIextension *droid_image_loader_extensions[] = {
>      &droid_image_loader_extension.base,
>      &image_lookup_extension.base,
>      &use_invalidate.base,
> +   &droid_mutable_render_buffer_extension.base,
>      NULL,
>   };
>   
> @@ -1413,11 +1562,6 @@ dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *disp)
>       */
>      dri2_setup_swap_interval(disp, 1);
>   
> -   if (!droid_add_configs_for_visuals(drv, disp)) {
> -      err = "DRI2: failed to add configs";
> -      goto cleanup;
> -   }
> -
>      disp->Extensions.ANDROID_framebuffer_target = EGL_TRUE;
>      disp->Extensions.ANDROID_image_native_buffer = EGL_TRUE;
>      disp->Extensions.ANDROID_recordable = EGL_TRUE;
> @@ -1426,6 +1570,20 @@ dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *disp)
>      disp->Extensions.KHR_partial_update = EGL_TRUE;
>   #endif
>      disp->Extensions.KHR_image = EGL_TRUE;
> +#if ANDROID_API_LEVEL >= 24
> +   if (dri2_dpy->mutable_render_buffer &&
> +       dri2_dpy->loader_extensions == droid_image_loader_extensions) {
> +      disp->Extensions.KHR_mutable_render_buffer = EGL_TRUE;
> +   }
> +#endif
> +
> +   /* Create configs *after* enabling extensions because presence of DRI
> +    * driver extensions can affect the capabilities of EGLConfigs.
> +    */
> +   if (!droid_add_configs_for_visuals(drv, disp)) {
> +      err = "DRI2: failed to add configs";
> +      goto cleanup;
> +   }
>   
>      /* Fill vtbl last to prevent accidentally calling virtual function during
>       * initialization.
> 


More information about the mesa-dev mailing list