//gboolean //gst_gl_context_create (GstGLContext * context, GstGLContext * other_context, GError ** error) static gpointer gst_gl_context_create_thread (GstGLContext * context) { GstGLContextClass *context_class; GstGLWindowClass *window_class; GstGLFuncs *gl; gboolean ret = FALSE; GstGLAPI compiled_api, user_api, gl_api; gchar *api_string; gchar *compiled_api_s; gchar *user_api_string; const gchar *user_choice; GError **error; GstGLContext *other_context; GString *ext_g_str = NULL; const gchar *ext_const_c_str = NULL; g_mutex_lock (&context->priv->render_lock); error = context->priv->error; other_context = context->priv->other_context; context_class = GST_GL_CONTEXT_GET_CLASS (context); window_class = GST_GL_WINDOW_GET_CLASS (context->window); if (window_class->open) { if (!window_class->open (context->window, error)) { g_assert (error == NULL || *error != NULL); goto failure; } } gl = context->gl_vtable; compiled_api = _compiled_api (); user_choice = g_getenv ("GST_GL_API"); user_api = gst_gl_api_from_string (user_choice); user_api_string = gst_gl_api_to_string (user_api); compiled_api_s = gst_gl_api_to_string (compiled_api); if ((user_api & compiled_api) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "Cannot create context with the user requested api (%s). " "We have support for (%s)", user_api_string, compiled_api_s); g_free (user_api_string); g_free (compiled_api_s); goto failure; } if (context_class->choose_format && !context_class->choose_format (context, error)) { g_assert (error == NULL || *error != NULL); g_free (compiled_api_s); g_free (user_api_string); goto failure; } GST_INFO ("Attempting to create opengl context. user chosen api(s) (%s), " "compiled api support (%s)", user_api_string, compiled_api_s); if (!context_class->create_context (context, compiled_api & user_api, other_context, error)) { g_assert (error == NULL || *error != NULL); g_free (compiled_api_s); g_free (user_api_string); goto failure; } GST_INFO ("created context"); if (!context_class->activate (context, TRUE)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Failed to activate the GL Context"); g_free (compiled_api_s); g_free (user_api_string); goto failure; } gl_api = gst_gl_context_get_gl_api (context); g_assert (gl_api != GST_GL_API_NONE && gl_api != GST_GL_API_ANY); api_string = gst_gl_api_to_string (gl_api); GST_INFO ("available GL APIs: %s", api_string); if (((compiled_api & gl_api) & user_api) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "failed to create context, context " "could not provide correct api. user (%s), compiled (%s), context (%s)", user_api_string, compiled_api_s, api_string); g_free (api_string); g_free (compiled_api_s); g_free (user_api_string); goto failure; } g_free (api_string); g_free (compiled_api_s); g_free (user_api_string); gl->GetError = gst_gl_context_get_proc_address (context, "glGetError"); gl->GetString = gst_gl_context_get_proc_address (context, "glGetString"); gl->GetStringi = gst_gl_context_get_proc_address (context, "glGetStringi"); gl->GetIntegerv = gst_gl_context_get_proc_address (context, "glGetIntegerv"); if (!gl->GetError || !gl->GetString) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "could not GetProcAddress core opengl functions"); goto failure; } /* gl api specific code */ ret = _create_context_info (context, gl_api, &context->priv->gl_major, &context->priv->gl_minor, error); if (!ret) { g_assert (error == NULL || *error != NULL); goto failure; } /* GL core contexts and GLES3 */ if (gl->GetIntegerv && gl->GetStringi && context->priv->gl_major >= 3) ext_g_str = _build_extension_string (context); if (ext_g_str && ext_g_str->len) { GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_g_str->str); _gst_gl_feature_check_ext_functions (context, context->priv->gl_major, context->priv->gl_minor, ext_g_str->str); context->priv->gl_exts = g_string_free (ext_g_str, FALSE); } else { ext_const_c_str = (const gchar *) gl->GetString (GL_EXTENSIONS); if (!ext_const_c_str) ext_const_c_str = ""; GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_const_c_str); _gst_gl_feature_check_ext_functions (context, context->priv->gl_major, context->priv->gl_minor, ext_const_c_str); context->priv->gl_exts = g_strdup (ext_const_c_str); } context->priv->alive = TRUE; g_cond_signal (&context->priv->create_cond); // g_mutex_unlock (&context->priv->render_lock); gst_gl_window_send_message_async (context->window, (GstGLWindowCB) _unlock_create_thread, context, NULL); gst_gl_window_run (context->window); GST_INFO ("loop exited\n"); g_mutex_lock (&context->priv->render_lock); context->priv->alive = FALSE; context_class->activate (context, FALSE); context_class->destroy_context (context); /* User supplied callback */ if (context->window->close) context->window->close (context->window->close_data); /* window specific shutdown */ if (window_class->close) { window_class->close (context->window); } g_cond_signal (&context->priv->destroy_cond); g_mutex_unlock (&context->priv->render_lock); return NULL; failure: { g_cond_signal (&context->priv->create_cond); g_mutex_unlock (&context->priv->render_lock); return NULL; } }
static gboolean gst_gl_context_egl_create_context (GstGLContext * context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLContextEGL *egl; GstGLWindow *window = NULL; EGLNativeWindowType window_handle = (EGLNativeWindowType) 0; gint i = 0; EGLint context_attrib[5]; EGLint majorVersion; EGLint minorVersion; const gchar *egl_exts; gboolean need_surface = TRUE; guintptr external_gl_context = 0; GstGLDisplay *display; egl = GST_GL_CONTEXT_EGL (context); window = gst_gl_context_get_window (context); if (other_context) { if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_EGL) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Cannot share context with non-EGL context"); goto failure; } external_gl_context = gst_gl_context_get_gl_context (other_context); } if ((gl_api & (GST_GL_API_OPENGL | GST_GL_API_GLES2)) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "EGL supports opengl or gles2"); goto failure; } display = gst_gl_context_get_display (context); if (display->type == GST_GL_DISPLAY_TYPE_EGL) { egl->egl_display = (EGLDisplay) gst_gl_display_get_handle (display); } else { guintptr native_display = gst_gl_display_get_handle (display); if (!native_display) { GstGLWindow *window = NULL; GST_WARNING ("Failed to get a global display handle, falling back to " "per-window display handles. Context sharing may not work"); if (other_context) window = gst_gl_context_get_window (other_context); if (!window) window = gst_gl_context_get_window (context); if (window) { native_display = gst_gl_window_get_display (window); gst_object_unref (window); } } egl->egl_display = eglGetDisplay ((EGLNativeDisplayType) native_display); } gst_object_unref (display); if (eglInitialize (egl->egl_display, &majorVersion, &minorVersion)) { GST_INFO ("egl initialized, version: %d.%d", majorVersion, minorVersion); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Failed to initialize egl: %s", gst_gl_context_egl_get_error_string ()); goto failure; } if (gl_api & GST_GL_API_OPENGL) { /* egl + opengl only available with EGL 1.4+ */ if (majorVersion == 1 && minorVersion <= 3) { if ((gl_api & ~GST_GL_API_OPENGL) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_OLD_LIBS, "EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)", majorVersion, minorVersion); goto failure; } else { GST_WARNING ("EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)", majorVersion, minorVersion); if (gl_api & GST_GL_API_GLES2) { goto try_gles2; } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Failed to choose a suitable OpenGL API"); goto failure; } } } if (!eglBindAPI (EGL_OPENGL_API)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to bind OpenGL API: %s", gst_gl_context_egl_get_error_string ()); goto failure; } GST_INFO ("Using OpenGL"); egl->gl_api = GST_GL_API_OPENGL; } else if (gl_api & GST_GL_API_GLES2) { try_gles2: if (!eglBindAPI (EGL_OPENGL_ES_API)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to bind OpenGL|ES API: %s", gst_gl_context_egl_get_error_string ()); goto failure; } GST_INFO ("Using OpenGL|ES 2.0"); egl->gl_api = GST_GL_API_GLES2; } if (!gst_gl_context_egl_choose_config (egl, other_context, error)) { g_assert (error == NULL || *error != NULL); goto failure; } egl_exts = eglQueryString (egl->egl_display, EGL_EXTENSIONS); GST_DEBUG ("about to create gl context\n"); if (egl->gl_api & GST_GL_API_GLES2) { context_attrib[i++] = EGL_CONTEXT_CLIENT_VERSION; context_attrib[i++] = 2; } #if !defined(GST_DISABLE_GST_DEBUG) && defined(EGL_KHR_create_context) if (gst_gl_check_extension ("EGL_KHR_create_context", egl_exts)) { context_attrib[i++] = EGL_CONTEXT_FLAGS_KHR; context_attrib[i++] = EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; } #endif context_attrib[i++] = EGL_NONE; egl->egl_context = eglCreateContext (egl->egl_display, egl->egl_config, (EGLContext) external_gl_context, context_attrib); #ifdef EGL_KHR_create_context if (egl->egl_context == EGL_NO_CONTEXT && egl->gl_api & GST_GL_API_GLES2 && eglGetError () != EGL_SUCCESS) { /* try without EGL_CONTEXT_FLAGS flags as it was added to * EGL_KHR_create_context for gles contexts */ int i; for (i = 0; i < G_N_ELEMENTS (context_attrib); i++) { if (context_attrib[i] == EGL_CONTEXT_FLAGS_KHR || context_attrib[i] == EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR) context_attrib[i] = EGL_NONE; } egl->egl_context = eglCreateContext (egl->egl_display, egl->egl_config, (EGLContext) external_gl_context, context_attrib); } #endif if (egl->egl_context != EGL_NO_CONTEXT) { GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT, (guintptr) egl->egl_context); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create a OpenGL context: %s", gst_gl_context_egl_get_error_string ()); goto failure; } if (other_context == NULL) { /* FIXME do we want a window vfunc ? */ #if GST_GL_HAVE_WINDOW_X11 if (GST_GL_IS_WINDOW_X11 (context->window)) { gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window); } #endif #if GST_GL_HAVE_WINDOW_WIN32 if (GST_GL_IS_WINDOW_WIN32 (context->window)) { gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window); } #endif } if (window) window_handle = (EGLNativeWindowType) gst_gl_window_get_window_handle (window); if (window_handle) { egl->egl_surface = eglCreateWindowSurface (egl->egl_display, egl->egl_config, window_handle, NULL); } else if (!gst_gl_check_extension ("EGL_KHR_surfaceless_context", egl_exts)) { EGLint surface_attrib[7]; gint j = 0; /* FIXME: Width/height doesn't seem to matter but we can't leave them * at 0, otherwise X11 complains about BadValue */ surface_attrib[j++] = EGL_WIDTH; surface_attrib[j++] = 1; surface_attrib[j++] = EGL_HEIGHT; surface_attrib[j++] = 1; surface_attrib[j++] = EGL_LARGEST_PBUFFER; surface_attrib[j++] = EGL_TRUE; surface_attrib[j++] = EGL_NONE; egl->egl_surface = eglCreatePbufferSurface (egl->egl_display, egl->egl_config, surface_attrib); } else { egl->egl_surface = EGL_NO_SURFACE; need_surface = FALSE; } if (need_surface) { if (egl->egl_surface != EGL_NO_SURFACE) { GST_INFO ("surface created"); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to create window surface: %s", gst_gl_context_egl_get_error_string ()); goto failure; } } /* EGLImage functions */ if (GST_GL_CHECK_GL_VERSION (majorVersion, minorVersion, 1, 5)) { egl->eglCreateImage = gst_gl_context_get_proc_address (context, "eglCreateImage"); egl->eglDestroyImage = gst_gl_context_get_proc_address (context, "eglDestroyImage"); } else if (gst_gl_check_extension ("EGL_KHR_image_base", egl_exts)) { egl->eglCreateImage = gst_gl_context_get_proc_address (context, "eglCreateImageKHR"); egl->eglDestroyImage = gst_gl_context_get_proc_address (context, "eglDestroyImageKHR"); } if (egl->eglCreateImage == NULL || egl->eglDestroyImage == NULL) { egl->eglCreateImage = NULL; egl->eglDestroyImage = NULL; } if (window) gst_object_unref (window); return TRUE; failure: if (window) gst_object_unref (window); return FALSE; }
/** * gst_gl_context_fill_info: * @context: a #GstGLContext: * * Fills @context's info (version, extensions, vtable, etc) from the GL * context in the current thread. Typically used with wrapped contexts to * allow wrapped contexts to be used as regular #GstGLContext's. * * Since: 1.6 */ gboolean gst_gl_context_fill_info (GstGLContext * context, GError ** error) { GstGLFuncs *gl; GString *ext_g_str = NULL; const gchar *ext_const_c_str = NULL; GstGLAPI gl_api; gboolean ret; g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE); g_return_val_if_fail (context->priv->active_thread == g_thread_self (), FALSE); gl = context->gl_vtable; gl_api = gst_gl_context_get_gl_api (context); gl->GetError = gst_gl_context_get_proc_address (context, "glGetError"); gl->GetString = gst_gl_context_get_proc_address (context, "glGetString"); gl->GetStringi = gst_gl_context_get_proc_address (context, "glGetStringi"); gl->GetIntegerv = gst_gl_context_get_proc_address (context, "glGetIntegerv"); if (!gl->GetError || !gl->GetString) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "could not GetProcAddress core opengl functions"); goto failure; } /* gl api specific code */ ret = _create_context_info (context, gl_api, &context->priv->gl_major, &context->priv->gl_minor, error); if (!ret) { g_assert (error == NULL || *error != NULL); goto failure; } /* GL core contexts and GLES3 */ if (gl->GetIntegerv && gl->GetStringi && context->priv->gl_major >= 3) ext_g_str = _build_extension_string (context); if (ext_g_str && ext_g_str->len) { GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_g_str->str); _gst_gl_feature_check_ext_functions (context, context->priv->gl_major, context->priv->gl_minor, ext_g_str->str); context->priv->gl_exts = g_string_free (ext_g_str, FALSE); } else { ext_const_c_str = (const gchar *) gl->GetString (GL_EXTENSIONS); if (!ext_const_c_str) ext_const_c_str = ""; GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_const_c_str); _gst_gl_feature_check_ext_functions (context, context->priv->gl_major, context->priv->gl_minor, ext_const_c_str); context->priv->gl_exts = g_strdup (ext_const_c_str); } if (gl_api & GST_GL_API_OPENGL3 && !gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 4, 1) && !gst_gl_check_extension ("GL_ARB_ES2_compatibility", context->priv->gl_exts)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "An opengl3 context created but the required ES2 compatibility was not found"); goto failure; } /* Does not implement OES_vertex_array_object properly, see * https://bugzilla.gnome.org/show_bug.cgi?id=750185 */ if (g_strcmp0 ((const gchar *) gl->GetString (GL_VENDOR), "Imagination Technologies") == 0 && g_strcmp0 ((const gchar *) gl->GetString (GL_RENDERER), "PowerVR SGX 544MP") == 0) { gl->GenVertexArrays = NULL; gl->DeleteVertexArrays = NULL; gl->BindVertexArray = NULL; gl->IsVertexArray = NULL; } return TRUE; failure: return FALSE; }
static gboolean gst_gl_context_egl_create_context (GstGLContext * context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLContextEGL *egl; GstGLWindow *window = NULL; EGLNativeWindowType window_handle = (EGLNativeWindowType) 0; EGLint majorVersion; EGLint minorVersion; gboolean need_surface = TRUE; guintptr external_gl_context = 0; GstGLDisplay *display; egl = GST_GL_CONTEXT_EGL (context); window = gst_gl_context_get_window (context); GST_DEBUG_OBJECT (context, "Creating EGL context"); if (other_context) { if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_EGL) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Cannot share context with non-EGL context"); goto failure; } external_gl_context = gst_gl_context_get_gl_context (other_context); } if ((gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2)) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "EGL supports opengl or gles2"); goto failure; } display = gst_gl_context_get_display (context); if (display->type == GST_GL_DISPLAY_TYPE_EGL) { egl->egl_display = (EGLDisplay) gst_gl_display_get_handle (display); } else { guintptr native_display = gst_gl_display_get_handle (display); if (!native_display) { GstGLWindow *window = NULL; GST_WARNING ("Failed to get a global display handle, falling back to " "per-window display handles. Context sharing may not work"); if (other_context) window = gst_gl_context_get_window (other_context); if (!window) window = gst_gl_context_get_window (context); if (window) { native_display = gst_gl_window_get_display (window); gst_object_unref (window); } } egl->egl_display = eglGetDisplay ((EGLNativeDisplayType) native_display); } gst_object_unref (display); if (eglInitialize (egl->egl_display, &majorVersion, &minorVersion)) { GST_INFO ("egl initialized, version: %d.%d", majorVersion, minorVersion); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Failed to initialize egl: %s", gst_gl_context_egl_get_error_string (eglGetError ())); goto failure; } egl->egl_exts = eglQueryString (egl->egl_display, EGL_EXTENSIONS); if (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3)) { GstGLAPI chosen_gl_api = 0; gint i; /* egl + opengl only available with EGL 1.4+ */ if (majorVersion == 1 && minorVersion <= 3) { if ((gl_api & ~GST_GL_API_OPENGL) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_OLD_LIBS, "EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)", majorVersion, minorVersion); goto failure; } else { GST_WARNING ("EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)", majorVersion, minorVersion); if (gl_api & GST_GL_API_GLES2) { goto try_gles2; } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Failed to choose a suitable OpenGL API"); goto failure; } } } if (!eglBindAPI (EGL_OPENGL_API)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to bind OpenGL API: %s", gst_gl_context_egl_get_error_string (eglGetError ())); goto failure; } GST_INFO ("Bound OpenGL"); /* api, version only matters for gles */ if (!gst_gl_context_egl_choose_config (egl, GST_GL_API_OPENGL, 0, error)) { g_assert (error == NULL || *error != NULL); goto failure; } for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) { gint profileMask = 0; gint contextFlags = 0; if (GST_GL_CHECK_GL_VERSION (opengl_versions[i].major, opengl_versions[i].minor, 3, 2)) { /* skip gl3 contexts if requested */ if ((gl_api & GST_GL_API_OPENGL3) == 0) continue; chosen_gl_api = GST_GL_API_OPENGL3; #if defined(EGL_KHR_create_context) profileMask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; contextFlags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; #endif } else if (opengl_versions[i].major == 3 && opengl_versions[i].minor == 1) { /* skip 3.1, the implementation is free to give us either a core or a * compatibility context (we have no say) */ continue; } else { /* skip legacy contexts if requested */ if ((gl_api & GST_GL_API_OPENGL) == 0) continue; chosen_gl_api = GST_GL_API_OPENGL; } egl->egl_context = _create_context_with_flags (egl, (EGLContext) external_gl_context, chosen_gl_api, opengl_versions[i].major, opengl_versions[i].minor, contextFlags, profileMask); if (egl->egl_context) break; #if defined(EGL_KHR_create_context) profileMask &= ~EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; egl->egl_context = _create_context_with_flags (egl, (EGLContext) external_gl_context, chosen_gl_api, opengl_versions[i].major, opengl_versions[i].minor, contextFlags, profileMask); if (egl->egl_context) break; #endif } egl->gl_api = chosen_gl_api; } else if (gl_api & GST_GL_API_GLES2) { gint i; try_gles2: if (!eglBindAPI (EGL_OPENGL_ES_API)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to bind OpenGL|ES API: %s", gst_gl_context_egl_get_error_string (eglGetError ())); goto failure; } GST_INFO ("Bound OpenGL|ES"); for (i = 0; i < G_N_ELEMENTS (gles2_versions); i++) { gint profileMask = 0; gint contextFlags = 0; if (!gst_gl_context_egl_choose_config (egl, GST_GL_API_GLES2, gles2_versions[i].major, error)) { continue; } #if defined(EGL_KHR_create_context) /* try a debug context */ contextFlags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; egl->egl_context = _create_context_with_flags (egl, (EGLContext) external_gl_context, GST_GL_API_GLES2, gles2_versions[i].major, gles2_versions[i].minor, contextFlags, profileMask); if (egl->egl_context) break; /* try without a debug context */ contextFlags &= ~EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; #endif egl->egl_context = _create_context_with_flags (egl, (EGLContext) external_gl_context, GST_GL_API_GLES2, gles2_versions[i].major, gles2_versions[i].minor, contextFlags, profileMask); if (egl->egl_context) break; } egl->gl_api = GST_GL_API_GLES2; } if (egl->egl_context != EGL_NO_CONTEXT) { GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT, (guintptr) egl->egl_context); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create a OpenGL context: %s", gst_gl_context_egl_get_error_string (eglGetError ())); goto failure; } /* FIXME do we want a window vfunc ? */ #if GST_GL_HAVE_WINDOW_X11 if (GST_IS_GL_WINDOW_X11 (context->window)) { gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window); } #endif if (other_context == NULL) { #if GST_GL_HAVE_WINDOW_WAYLAND if (GST_IS_GL_WINDOW_WAYLAND_EGL (context->window)) { gst_gl_window_wayland_egl_create_window ((GstGLWindowWaylandEGL *) context->window); } #endif #if GST_GL_HAVE_WINDOW_WIN32 if (GST_IS_GL_WINDOW_WIN32 (context->window)) { gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window); } #endif #if GST_GL_HAVE_WINDOW_DISPMANX if (GST_IS_GL_WINDOW_DISPMANX_EGL (context->window)) { gst_gl_window_dispmanx_egl_create_window ((GstGLWindowDispmanxEGL *) context->window); } #endif } if (window) window_handle = (EGLNativeWindowType) gst_gl_window_get_window_handle (window); if (window_handle) { GST_DEBUG ("Creating EGLSurface from window_handle %p", (void *) window_handle); egl->egl_surface = eglCreateWindowSurface (egl->egl_display, egl->egl_config, window_handle, NULL); /* Store window handle for later comparision */ egl->window_handle = window_handle; } else if (!gst_gl_check_extension ("EGL_KHR_surfaceless_context", egl->egl_exts)) { EGLint surface_attrib[7]; gint j = 0; GST_DEBUG ("Surfaceless context, creating PBufferSurface"); /* FIXME: Width/height doesn't seem to matter but we can't leave them * at 0, otherwise X11 complains about BadValue */ surface_attrib[j++] = EGL_WIDTH; surface_attrib[j++] = 1; surface_attrib[j++] = EGL_HEIGHT; surface_attrib[j++] = 1; surface_attrib[j++] = EGL_LARGEST_PBUFFER; surface_attrib[j++] = EGL_TRUE; surface_attrib[j++] = EGL_NONE; egl->egl_surface = eglCreatePbufferSurface (egl->egl_display, egl->egl_config, surface_attrib); } else { GST_DEBUG ("No surface/handle !"); egl->egl_surface = EGL_NO_SURFACE; need_surface = FALSE; } if (need_surface) { if (egl->egl_surface != EGL_NO_SURFACE) { GST_INFO ("surface created"); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to create window surface: %s", gst_gl_context_egl_get_error_string (eglGetError ())); goto failure; } } /* EGLImage functions */ if (GST_GL_CHECK_GL_VERSION (majorVersion, minorVersion, 1, 5)) { egl->eglCreateImage = gst_gl_context_get_proc_address (context, "eglCreateImage"); egl->eglDestroyImage = gst_gl_context_get_proc_address (context, "eglDestroyImage"); } else if (gst_gl_check_extension ("EGL_KHR_image_base", egl->egl_exts)) { egl->eglCreateImage = gst_gl_context_get_proc_address (context, "eglCreateImageKHR"); egl->eglDestroyImage = gst_gl_context_get_proc_address (context, "eglDestroyImageKHR"); } if (egl->eglCreateImage == NULL || egl->eglDestroyImage == NULL) { egl->eglCreateImage = NULL; egl->eglDestroyImage = NULL; } if (window) gst_object_unref (window); return TRUE; failure: if (window) gst_object_unref (window); return FALSE; }
/** * gst_gl_context_fill_info: * @context: a #GstGLContext: * * Fills @context's info (version, extensions, vtable, etc) from the GL * context in the current thread. Typically used with wrapped contexts to * allow wrapped contexts to be used as regular #GstGLContext's. * * Since: 1.6 */ gboolean gst_gl_context_fill_info (GstGLContext * context, GError ** error) { GstGLFuncs *gl; GString *ext_g_str = NULL; const gchar *ext_const_c_str = NULL; GstGLAPI gl_api; gboolean ret; g_return_val_if_fail (GST_GL_IS_CONTEXT (context), FALSE); g_return_val_if_fail (context->priv->active_thread == g_thread_self (), FALSE); gl = context->gl_vtable; gl_api = gst_gl_context_get_gl_api (context); gl->GetError = gst_gl_context_get_proc_address (context, "glGetError"); gl->GetString = gst_gl_context_get_proc_address (context, "glGetString"); gl->GetStringi = gst_gl_context_get_proc_address (context, "glGetStringi"); gl->GetIntegerv = gst_gl_context_get_proc_address (context, "glGetIntegerv"); if (!gl->GetError || !gl->GetString) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "could not GetProcAddress core opengl functions"); goto failure; } /* gl api specific code */ ret = _create_context_info (context, gl_api, &context->priv->gl_major, &context->priv->gl_minor, error); if (!ret) { g_assert (error == NULL || *error != NULL); goto failure; } /* GL core contexts and GLES3 */ if (gl->GetIntegerv && gl->GetStringi && context->priv->gl_major >= 3) ext_g_str = _build_extension_string (context); if (ext_g_str && ext_g_str->len) { GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_g_str->str); _gst_gl_feature_check_ext_functions (context, context->priv->gl_major, context->priv->gl_minor, ext_g_str->str); context->priv->gl_exts = g_string_free (ext_g_str, FALSE); } else { ext_const_c_str = (const gchar *) gl->GetString (GL_EXTENSIONS); if (!ext_const_c_str) ext_const_c_str = ""; GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_const_c_str); _gst_gl_feature_check_ext_functions (context, context->priv->gl_major, context->priv->gl_minor, ext_const_c_str); context->priv->gl_exts = g_strdup (ext_const_c_str); } if (gl_api & GST_GL_API_OPENGL3 && !gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 4, 1) && !gst_gl_check_extension ("GL_ARB_ES2_compatibility", context->priv->gl_exts)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "An opengl3 context created but the required ES2 compatibility was not found"); goto failure; } return TRUE; failure: return FALSE; }