static gboolean
gst_vaapi_window_egl_create (GstVaapiWindowEGL * window,
    guint * width, guint * height)
{
  GstVaapiDisplayEGL *const display =
      GST_VAAPI_DISPLAY_EGL (GST_VAAPI_OBJECT_DISPLAY (window));
  const GstVaapiDisplayClass *const native_dpy_class =
      GST_VAAPI_DISPLAY_GET_CLASS (display->display);
  CreateObjectsArgs args;

  g_return_val_if_fail (native_dpy_class != NULL, FALSE);

  window->window =
      native_dpy_class->create_window (GST_VAAPI_DISPLAY (display->display),
      GST_VAAPI_ID_INVALID, *width, *height);
  if (!window->window)
    return FALSE;

  gst_vaapi_window_get_size (window->window, width, height);

  args.window = window;
  args.width = *width;
  args.height = *height;
  args.egl_context = GST_VAAPI_DISPLAY_EGL_CONTEXT (display);
  return egl_context_run (args.egl_context,
      (EglContextRunFunc) do_create_objects, &args) && args.success;
}
static gboolean
gst_vaapi_display_egl_bind_display (GstVaapiDisplay * base_display,
    gpointer native_params)
{
  GstVaapiDisplay *native_display = NULL;
  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
  EglDisplay *egl_display;
  const InitParams *params = (InitParams *) native_params;

  if (params->display) {
    native_display = params->display;
  } else {
#if USE_X11
    native_display = gst_vaapi_display_x11_new (NULL);
#endif
#if USE_WAYLAND
    if (!native_display)
      native_display = gst_vaapi_display_wayland_new (NULL);
#endif
  }
  if (!native_display)
    return FALSE;

  gst_vaapi_display_replace (&display->display, native_display);

  egl_display = egl_display_new (GST_VAAPI_DISPLAY_NATIVE (display->display));
  if (!egl_display)
    return FALSE;

  egl_object_replace (&display->egl_display, egl_display);
  egl_object_unref (egl_display);
  display->gles_version = params->gles_version;
  return TRUE;
}
static guintptr
gst_vaapi_display_egl_get_visual_id (GstVaapiDisplay * base_display,
    GstVaapiWindow * window)
{
  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
  if (!ensure_context (display))
    return 0;
  return display->egl_context->config->visual_id;
}
static void
gst_vaapi_display_egl_finalize (GObject * object)
{
  GstVaapiDisplayEGL *dpy = GST_VAAPI_DISPLAY_EGL (object);

  if (dpy->texture_map)
    gst_object_unref (dpy->texture_map);
  G_OBJECT_CLASS (gst_vaapi_display_egl_parent_class)->finalize (object);
}
static void
gst_vaapi_display_egl_flush (GstVaapiDisplay * base_display)
{
  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
  GstVaapiDisplayClass *const klass =
      GST_VAAPI_DISPLAY_GET_CLASS (display->display);

  if (klass->flush)
    klass->flush (display->display);
}
static void
gst_vaapi_display_egl_get_size_mm (GstVaapiDisplay * base_display,
    guint * width_ptr, guint * height_ptr)
{
  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
  GstVaapiDisplayClass *const klass =
      GST_VAAPI_DISPLAY_GET_CLASS (display->display);

  if (klass->get_size_mm)
    klass->get_size_mm (display->display, width_ptr, height_ptr);
}
static gboolean
gst_vaapi_display_egl_get_display_info (GstVaapiDisplay * base_display,
    GstVaapiDisplayInfo * info)
{
  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
  GstVaapiDisplayClass *const klass =
      GST_VAAPI_DISPLAY_GET_CLASS (display->display);

  if (klass->get_display && !klass->get_display (display->display, info))
    return FALSE;
  return TRUE;
}
static void
gst_vaapi_display_egl_finalize (GObject * object)
{
  GstVaapiDisplayEGL *dpy = GST_VAAPI_DISPLAY_EGL (object);

  if (dpy->texture_map)
    gst_object_unref (dpy->texture_map);

  /* HACK to avoid to call twice vaTerminate() since this and the
   * proxied display share the same vaDisplay */
  GST_VAAPI_DISPLAY_VADISPLAY (object) = NULL;

  egl_object_replace (&dpy->egl_display, NULL);
  egl_object_replace (&dpy->egl_context, NULL);

  gst_vaapi_display_replace (&dpy->display, NULL);

  G_OBJECT_CLASS (gst_vaapi_display_egl_parent_class)->finalize (object);
}
static GstVaapiDisplay *
gst_vaapi_create_display_from_egl (GstGLDisplay * gl_display,
    GstGLContext * gl_context, GstVaapiDisplayType display_type,
    gpointer native_display)
{
  GstVaapiDisplay *display = NULL;
#if USE_EGL
  GstGLAPI gl_api;
  gint gles_version;
  guintptr egl_handler;

  gl_api = gst_gl_context_get_gl_api (gl_context);
  gles_version = gst_vaapi_get_gles_version_from_gl_api (gl_api);
  if (gles_version == -1)
    return NULL;

  egl_handler = gst_vaapi_get_egl_handle_from_gl_display (gl_display);
  if (egl_handler != 0) {
    gpointer native_display_egl = GSIZE_TO_POINTER (egl_handler);
    display = gst_vaapi_display_egl_new_with_native_display (native_display_egl,
        display_type, gles_version);
  }

  if (!display) {
    GstVaapiDisplay *wrapped_display;

    wrapped_display =
        gst_vaapi_create_display_from_handle (display_type, native_display);
    if (wrapped_display) {
      display = gst_vaapi_display_egl_new (wrapped_display, gles_version);
      gst_object_unref (wrapped_display);
    }
  }

  if (display) {
    gst_vaapi_display_egl_set_gl_context (GST_VAAPI_DISPLAY_EGL (display),
        GSIZE_TO_POINTER (gst_gl_context_get_gl_context (gl_context)));
  }
#endif
  return display;
}
static GstVaapiTexture *
gst_vaapi_display_egl_create_texture (GstVaapiDisplay * display, GstVaapiID id,
    guint target, guint format, guint width, guint height)
{
  GstVaapiDisplayEGL *dpy = GST_VAAPI_DISPLAY_EGL (display);
  GstVaapiTexture *texture;

  if (id == GST_VAAPI_ID_INVALID)
    return gst_vaapi_texture_egl_new (display, target, format, width, height);

  ensure_texture_map (dpy);
  if (!(texture = gst_vaapi_texture_map_lookup (dpy->texture_map, id))) {
    if ((texture =
            gst_vaapi_texture_egl_new_wrapped (display, id, target, format,
                width, height))) {
      gst_vaapi_texture_map_add (dpy->texture_map, texture, id);
    }
  }

  return texture;
}
static gboolean
gst_vaapi_display_egl_bind_display (GstVaapiDisplay * base_display,
    gpointer native_params)
{
  GstVaapiDisplay *native_vaapi_display;
  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
  EglDisplay *egl_display;
  EGLDisplay *native_egl_display;
  guint gl_platform = EGL_PLATFORM_UNKNOWN;
  const InitParams *params = (InitParams *) native_params;
  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);

  native_vaapi_display = params->display;
  native_egl_display = params->gl_display;

  if (!native_vaapi_display) {
#if USE_X11
    if (params->display_type == GST_VAAPI_DISPLAY_TYPE_ANY
        || params->display_type == GST_VAAPI_DISPLAY_TYPE_X11
        || params->display_type == GST_VAAPI_DISPLAY_TYPE_EGL)
      native_vaapi_display = gst_vaapi_display_x11_new (NULL);
#endif
#if USE_WAYLAND
    if (!native_vaapi_display)
      native_vaapi_display = gst_vaapi_display_wayland_new (NULL);
#endif
  } else {
    /* thus it could be assigned to parent */
    gst_object_ref (native_vaapi_display);
  }
  if (!native_vaapi_display)
    return FALSE;

  gst_vaapi_display_replace (&display->display, native_vaapi_display);
  priv->parent = native_vaapi_display;

  switch (GST_VAAPI_DISPLAY_GET_CLASS_TYPE (display->display)) {
    case GST_VAAPI_DISPLAY_TYPE_X11:
      gl_platform = EGL_PLATFORM_X11;
      break;
    case GST_VAAPI_DISPLAY_TYPE_WAYLAND:
      gl_platform = EGL_PLATFORM_WAYLAND;
      break;
    default:
      break;
  }

  if (native_egl_display) {
    egl_display = egl_display_new_wrapped (native_egl_display);
  } else {
    egl_display = egl_display_new (GST_VAAPI_DISPLAY_NATIVE (display->display),
        gl_platform);
  }
  if (!egl_display)
    return FALSE;

  egl_object_replace (&display->egl_display, egl_display);
  egl_object_unref (egl_display);
  display->gles_version = params->gles_version;
  return TRUE;
}
static GstVaapiTextureMap *
gst_vaapi_display_egl_get_texture_map (GstVaapiDisplay * display)
{
  return GST_VAAPI_DISPLAY_EGL (display)->texture_map;
}
static void
gst_vaapi_display_egl_close_display (GstVaapiDisplay * base_display)
{
  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
  gst_vaapi_display_replace (&display->display, NULL);
}
static GstVaapiDisplay *
gst_vaapi_create_display_from_gl_context (GstObject * gl_context_object)
{
#if USE_GST_GL_HELPERS
  GstGLContext *const gl_context = GST_GL_CONTEXT (gl_context_object);
  GstGLDisplay *const gl_display = gst_gl_context_get_display (gl_context);
  gpointer native_display =
      GSIZE_TO_POINTER (gst_gl_display_get_handle (gl_display));
  GstVaapiDisplay *display, *out_display;
  GstVaapiDisplayType display_type;

  switch (gst_gl_display_get_handle_type (gl_display)) {
#if USE_X11
    case GST_GL_DISPLAY_TYPE_X11:
      display_type = GST_VAAPI_DISPLAY_TYPE_X11;
      break;
#endif
#if USE_WAYLAND
    case GST_GL_DISPLAY_TYPE_WAYLAND:
      display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
      break;
#endif
    case GST_GL_DISPLAY_TYPE_ANY:{
      /* Derive from the active window */
      GstGLWindow *const gl_window = gst_gl_context_get_window (gl_context);
      const gchar *const gl_window_type = g_getenv ("GST_GL_WINDOW");

      display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
      if (!gl_window)
        break;
      native_display = GSIZE_TO_POINTER (gst_gl_window_get_display (gl_window));

      if (gl_window_type) {
#if USE_X11
        if (!display_type && g_strcmp0 (gl_window_type, "x11") == 0)
          display_type = GST_VAAPI_DISPLAY_TYPE_X11;
#endif
#if USE_WAYLAND
        if (!display_type && g_strcmp0 (gl_window_type, "wayland") == 0)
          display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
#endif
      } else {
#if USE_X11
        if (!display_type && GST_GL_HAVE_WINDOW_X11)
          display_type = GST_VAAPI_DISPLAY_TYPE_X11;
#endif
#if USE_WAYLAND
        if (!display_type && GST_GL_HAVE_WINDOW_WAYLAND)
          display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
#endif
      }
      break;
    }
    default:
      display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
      break;
  }
  if (!display_type)
    return NULL;

  display = gst_vaapi_create_display_from_handle (display_type, native_display);
  if (!display)
    return NULL;

  switch (gst_gl_context_get_gl_platform (gl_context)) {
#if USE_EGL
    case GST_GL_PLATFORM_EGL:{
      guint gles_version;

      switch (gst_gl_context_get_gl_api (gl_context)) {
        case GST_GL_API_GLES1:
          gles_version = 1;
          goto create_egl_display;
        case GST_GL_API_GLES2:
          gles_version = 2;
          goto create_egl_display;
        case GST_GL_API_OPENGL:
        case GST_GL_API_OPENGL3:
          gles_version = 0;
        create_egl_display:
          out_display = gst_vaapi_display_egl_new (display, gles_version);
          break;
        default:
          out_display = NULL;
          break;
      }
      if (!out_display)
        return NULL;
      gst_vaapi_display_egl_set_gl_context (GST_VAAPI_DISPLAY_EGL (out_display),
          GSIZE_TO_POINTER (gst_gl_context_get_gl_context (gl_context)));
      break;
    }
#endif
    default:
      out_display = gst_vaapi_display_ref (display);
      break;
  }
  gst_vaapi_display_unref (display);
  return out_display;
#endif
  GST_ERROR ("unsupported GStreamer version %s", GST_API_VERSION_S);
  return NULL;
}