static gboolean
reset_context (GstVaapiDisplayEGL * display, EGLContext gl_context)
{
  EglConfig *config;
  EglContext *ctx;

  egl_object_replace (&display->egl_context, NULL);

  if (gl_context != EGL_NO_CONTEXT)
    ctx = egl_context_new_wrapped (display->egl_display, gl_context);
  else {
    config = egl_config_new (display->egl_display, display->gles_version,
        GST_VIDEO_FORMAT_RGB);
    if (!config)
      return FALSE;

    ctx = egl_context_new (display->egl_display, config, NULL);
    egl_object_unref (config);
  }
  if (!ctx)
    return FALSE;

  egl_object_replace (&display->egl_context, ctx);
  egl_object_unref (ctx);
  return TRUE;
}
static gboolean
egl_display_run (EglDisplay * display, EglContextRunFunc func, gpointer args)
{
  EglMessage *msg;

  if (display->gl_thread == g_thread_self ()) {
    func (args);
    return TRUE;
  }

  msg = egl_object_new0 (egl_message_class ());
  if (!msg)
    return FALSE;

  msg->base.is_valid = TRUE;
  msg->func = func;
  msg->args = args;
  g_async_queue_push (display->gl_queue, egl_object_ref (msg));

  g_mutex_lock (&display->mutex);
  while (msg->base.is_valid)
    g_cond_wait (&display->gl_thread_ready, &display->mutex);
  g_mutex_unlock (&display->mutex);
  egl_object_unref (msg);
  return TRUE;
}
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;
}
gboolean
gst_vaapi_display_egl_set_current_display (GstVaapiDisplayEGL * display)
{
  EglDisplay *egl_display;

  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), FALSE);

  if (G_UNLIKELY (eglGetCurrentDisplay () == EGL_NO_DISPLAY))
    return TRUE;
  if (G_LIKELY (display->egl_display->base.handle.p == eglGetCurrentDisplay ()))
    return TRUE;

  egl_display = egl_display_new_wrapped (eglGetCurrentDisplay ());
  if (!egl_display)
    return FALSE;
  egl_object_replace (&display->egl_display, egl_display);
  egl_object_unref (egl_display);
  if (!gst_vaapi_display_egl_set_gl_context (display, eglGetCurrentContext ()))
    return FALSE;

  return TRUE;
}
static EglDisplay *
egl_display_new_full (gpointer handle, gboolean is_wrapped)
{
  EglDisplay *display;

  display = egl_object_new0 (egl_display_class ());
  if (!display)
    return NULL;

  display->base.handle.p = handle;
  display->base.is_wrapped = is_wrapped;
  if (!egl_display_init (display))
    goto error;
  return display;

  /* ERRORS */
error:
  {
    egl_object_unref (display);
    return NULL;
  }
}
EglContext *
egl_context_new_wrapped (EglDisplay * display, EGLContext gl_context)
{
  CreateContextArgs args;
  EglConfig *config;
  gboolean success;

  g_return_val_if_fail (display != NULL, NULL);
  g_return_val_if_fail (gl_context != EGL_NO_CONTEXT, NULL);

  config = egl_config_new_from_gl_context (display, gl_context);
  if (!config)
    return NULL;

  args.display = display;
  args.config = config;
  args.gl_parent_context = gl_context;
  success = egl_display_run (display, (EglContextRunFunc) do_egl_context_new,
      &args);
  egl_object_unref (config);
  if (!success)
    return NULL;
  return args.context;
}
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 gpointer
egl_display_thread (gpointer data)
{
  EglDisplay *const display = data;
  EGLDisplay gl_display = display->base.handle.p;
  EGLint major_version, minor_version;
  gchar **gl_apis, **gl_api;

  if (!display->base.is_wrapped) {
    gl_display = display->base.handle.p = eglGetDisplay (gl_display);
    if (!gl_display)
      goto error;
    if (!eglInitialize (gl_display, &major_version, &minor_version))
      goto error;
  }

  display->gl_vendor_string =
      g_strdup (eglQueryString (gl_display, EGL_VENDOR));
  display->gl_version_string =
      g_strdup (eglQueryString (gl_display, EGL_VERSION));
  display->gl_apis_string =
      g_strdup (eglQueryString (gl_display, EGL_CLIENT_APIS));

  GST_INFO ("EGL vendor: %s", display->gl_vendor_string);
  GST_INFO ("EGL version: %s", display->gl_version_string);
  GST_INFO ("EGL client APIs: %s", display->gl_apis_string);

  gl_apis = g_strsplit (display->gl_apis_string, " ", 0);
  if (!gl_apis)
    goto error;
  for (gl_api = gl_apis; *gl_api != NULL; gl_api++) {
    const GlVersionInfo *const vinfo =
        gl_version_info_lookup_by_api_name (*gl_api);

    if (vinfo)
      display->gl_apis |= vinfo->gl_api_bit;
  }
  g_strfreev (gl_apis);
  if (!display->gl_apis)
    goto error;

  display->base.is_valid = TRUE;
  g_cond_broadcast (&display->gl_thread_ready);

  while (!display->gl_thread_cancel) {
    EglMessage *const msg =
        g_async_queue_timeout_pop (display->gl_queue, 100000);

    if (msg) {
      if (msg->base.is_valid) {
        msg->func (msg->args);
        msg->base.is_valid = FALSE;
        g_cond_broadcast (&display->gl_thread_ready);
      }
      egl_object_unref (msg);
    }
  }

done:
  if (gl_display != EGL_NO_DISPLAY && !display->base.is_wrapped)
    eglTerminate (gl_display);
  display->base.handle.p = NULL;
  g_cond_broadcast (&display->gl_thread_ready);
  return NULL;

  /* ERRORS */
error:
  {
    display->base.is_valid = FALSE;
    goto done;
  }
}