[701/906] display: move context creation into window

This commit is contained in:
Matthew Waters 2013-06-12 23:17:30 +10:00 committed by Tim-Philipp Müller
parent 9c633e658a
commit c6988cb064
12 changed files with 583 additions and 420 deletions

View file

@ -62,9 +62,7 @@ void gst_gl_display_thread_run_generic (GstGLDisplay * display);
struct _GstGLDisplayPrivate
{
/* conditions */
GCond cond_create_context;
GCond cond_destroy_context;
GstGLWindow *window;
/* generic gl code */
GstGLDisplayThreadFunc generic_callback;
@ -91,13 +89,8 @@ gst_gl_display_init (GstGLDisplay * display)
/* thread safe */
g_mutex_init (&display->mutex);
g_cond_init (&display->priv->cond_create_context);
g_cond_init (&display->priv->cond_destroy_context);
display->gl_vtable = g_slice_alloc0 (sizeof (GstGLFuncs));
display->gl_window = gst_gl_window_new ();
gst_gl_memory_init ();
}
@ -106,39 +99,8 @@ gst_gl_display_finalize (GObject * object)
{
GstGLDisplay *display = GST_GL_DISPLAY (object);
if (display->gl_window) {
gst_gl_display_lock (display);
gst_gl_window_set_resize_callback (display->gl_window, NULL, NULL);
gst_gl_window_set_draw_callback (display->gl_window, NULL, NULL);
gst_gl_window_set_close_callback (display->gl_window, NULL, NULL);
if (display->context_created) {
GST_INFO ("send quit gl window loop");
gst_gl_window_quit (display->gl_window,
GST_GL_WINDOW_CB (gst_gl_display_thread_destroy_context), display);
GST_INFO ("quit sent to gl window loop");
g_cond_wait (&display->priv->cond_destroy_context, &display->mutex);
GST_INFO ("quit received from gl window");
}
gst_gl_display_unlock (display);
}
if (display->gl_thread) {
gpointer ret = g_thread_join (display->gl_thread);
GST_INFO ("gl thread joined");
if (ret != NULL)
GST_ERROR ("gl thread returned a not null pointer");
display->gl_thread = NULL;
}
g_mutex_clear (&display->mutex);
g_cond_clear (&display->priv->cond_destroy_context);
g_cond_clear (&display->priv->cond_create_context);
if (display->error_message) {
g_free (display->error_message);
display->error_message = NULL;
@ -148,271 +110,13 @@ gst_gl_display_finalize (GObject * object)
g_slice_free (GstGLFuncs, display->gl_vtable);
display->gl_vtable = NULL;
}
}
static gboolean
_create_context_gles2 (GstGLDisplay * display, gint * gl_major, gint * gl_minor)
{
const GstGLFuncs *gl;
GLenum gl_err = GL_NO_ERROR;
gl = display->gl_vtable;
GST_INFO ("GL_VERSION: %s", gl->GetString (GL_VERSION));
GST_INFO ("GL_SHADING_LANGUAGE_VERSION: %s",
gl->GetString (GL_SHADING_LANGUAGE_VERSION));
GST_INFO ("GL_VENDOR: %s", gl->GetString (GL_VENDOR));
GST_INFO ("GL_RENDERER: %s", gl->GetString (GL_RENDERER));
gl_err = gl->GetError ();
if (gl_err != GL_NO_ERROR) {
gst_gl_display_set_error (display, "glGetString error: 0x%x", gl_err);
return FALSE;
}
#if GST_GL_HAVE_GLES2
if (!GL_ES_VERSION_2_0) {
gst_gl_display_set_error (display, "OpenGL|ES >= 2.0 is required");
return FALSE;
}
#endif
_gst_gl_feature_check_ext_functions (display, 0, 0,
(const gchar *) gl->GetString (GL_EXTENSIONS));
if (gl_major)
*gl_major = 2;
if (gl_minor)
*gl_minor = 0;
return TRUE;
}
gboolean
_create_context_opengl (GstGLDisplay * display, gint * gl_major,
gint * gl_minor)
{
const GstGLFuncs *gl;
guint maj, min;
GLenum gl_err = GL_NO_ERROR;
GString *opengl_version = NULL;
gl = display->gl_vtable;
GST_INFO ("GL_VERSION: %s", gl->GetString (GL_VERSION));
GST_INFO ("GL_SHADING_LANGUAGE_VERSION: %s",
gl->GetString (GL_SHADING_LANGUAGE_VERSION));
GST_INFO ("GL_VENDOR: %s", gl->GetString (GL_VENDOR));
GST_INFO ("GL_RENDERER: %s", gl->GetString (GL_RENDERER));
gl_err = gl->GetError ();
if (gl_err != GL_NO_ERROR) {
gst_gl_display_set_error (display, "glGetString error: 0x%x", gl_err);
return FALSE;
}
opengl_version =
g_string_truncate (g_string_new ((gchar *) gl->GetString (GL_VERSION)),
3);
sscanf (opengl_version->str, "%d.%d", &maj, &min);
g_string_free (opengl_version, TRUE);
/* OpenGL > 1.2.0 */
if ((maj < 1) || (maj < 2 && maj >= 1 && min < 2)) {
gst_gl_display_set_error (display, "OpenGL >= 1.2.0 required, found %u.%u",
maj, min);
return FALSE;
if (display->priv->window) {
gst_object_unref (display->priv->window);
display->priv->window = NULL;
}
_gst_gl_feature_check_ext_functions (display, maj, min,
(const gchar *) gl->GetString (GL_EXTENSIONS));
if (gl_major)
*gl_major = maj;
if (gl_minor)
*gl_minor = min;
return TRUE;
}
GstGLAPI
_compiled_api (void)
{
GstGLAPI ret = GST_GL_API_NONE;
#if GST_GL_HAVE_OPENGL
ret |= GST_GL_API_OPENGL;
#endif
#if GST_GL_HAVE_GLES2
ret |= GST_GL_API_GLES2;
#endif
return ret;
}
GstGLAPI
_parse_gl_api (const gchar * apis_s)
{
GstGLAPI ret = GST_GL_API_NONE;
gchar *apis = (gchar *) apis_s;
while (apis) {
if (apis[0] == '\0') {
break;
} else if (apis[0] == ' ' || apis[0] == ',') {
apis = &apis[1];
} else if (g_strstr_len (apis, 7, "opengl3")) {
ret |= GST_GL_API_OPENGL3;
apis = &apis[7];
} else if (g_strstr_len (apis, 6, "opengl")) {
ret |= GST_GL_API_OPENGL;
apis = &apis[6];
} else if (g_strstr_len (apis, 5, "gles1")) {
ret |= GST_GL_API_GLES;
apis = &apis[5];
} else if (g_strstr_len (apis, 5, "gles2")) {
ret |= GST_GL_API_GLES2;
apis = &apis[5];
} else if (g_strstr_len (apis, 5, "gles3")) {
ret |= GST_GL_API_GLES3;
apis = &apis[5];
} else {
break;
}
}
if (ret == GST_GL_API_NONE)
ret = GST_GL_API_ANY;
return ret;
}
gpointer
gst_gl_display_thread_create_context (GstGLDisplay * display)
{
GstGLFuncs *gl;
gint gl_major = 0;
gboolean ret = FALSE;
GError *error = NULL;
GstGLAPI compiled_api, user_api;
gchar *api_string;
gchar *compiled_api_s;
gchar *user_api_string;
const gchar *user_choice;
gst_gl_display_lock (display);
gl = display->gl_vtable;
compiled_api = _compiled_api ();
if (!display->gl_window) {
gst_gl_display_set_error (display, "Failed to create opengl window");
goto failure;
}
user_choice = g_getenv ("GST_GL_API");
user_api = _parse_gl_api (user_choice);
user_api_string = gst_gl_api_string (user_api);
compiled_api_s = gst_gl_api_string (compiled_api);
GST_INFO ("Attempting to create opengl context. user chosen api(s):%s, "
"compiled api support:%s", user_api_string, compiled_api_s);
if (!gst_gl_window_create_context (display->gl_window,
compiled_api & user_api, display->external_gl_context, &error)) {
gst_gl_display_set_error (display,
error ? error->message : "Failed to create gl window");
g_free (compiled_api_s);
g_free (user_api_string);
goto failure;
}
GST_INFO ("window created context");
display->gl_api = gst_gl_window_get_gl_api (display->gl_window);
g_assert (display->gl_api != GST_GL_API_NONE
&& display->gl_api != GST_GL_API_ANY);
api_string = gst_gl_api_string (display->gl_api);
GST_INFO ("available GL APIs: %s", api_string);
if (((compiled_api & display->gl_api) & user_api) == GST_GL_API_NONE) {
gst_gl_display_set_error (display, "failed to create context, window "
"could not provide correct api. user:%s, compiled:%s, window:%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_window_get_proc_address (display->gl_window, "glGetError");
gl->GetString =
gst_gl_window_get_proc_address (display->gl_window, "glGetString");
if (!gl->GetError || !gl->GetString) {
gst_gl_display_set_error (display,
"could not GetProcAddress core opengl functions");
goto failure;
}
/* gl api specific code */
if (!ret && USING_OPENGL (display))
ret = _create_context_opengl (display, &gl_major, NULL);
if (!ret && USING_GLES2 (display))
ret = _create_context_gles2 (display, &gl_major, NULL);
if (!ret || !gl_major) {
GST_WARNING ("GL api specific initialization failed");
goto failure;
}
g_cond_signal (&display->priv->cond_create_context);
display->isAlive = TRUE;
gst_gl_display_unlock (display);
gst_gl_window_run (display->gl_window);
GST_INFO ("loop exited\n");
gst_gl_display_lock (display);
display->isAlive = FALSE;
g_object_unref (G_OBJECT (display->gl_window));
display->gl_window = NULL;
g_cond_signal (&display->priv->cond_destroy_context);
gst_gl_display_unlock (display);
return NULL;
failure:
{
if (display->gl_window) {
g_object_unref (display->gl_window);
display->gl_window = NULL;
}
g_cond_signal (&display->priv->cond_create_context);
gst_gl_display_unlock (display);
return NULL;
}
}
void
gst_gl_display_thread_destroy_context (GstGLDisplay * display)
{
GST_INFO ("Context destroyed");
G_OBJECT_CLASS (gst_gl_display_parent_class)->finalize (object);
}
//------------------------------------------------------------
@ -434,8 +138,6 @@ gst_gl_display_set_error (GstGLDisplay * display, const char *format, ...)
va_end (args);
GST_WARNING ("%s", display->error_message);
display->isAlive = FALSE;
}
void
@ -470,83 +172,55 @@ gst_gl_display_new (void)
return g_object_new (GST_GL_TYPE_DISPLAY, NULL);
}
/* Create an opengl context (one context for one GstGLDisplay) */
gboolean
gst_gl_display_create_context (GstGLDisplay * display,
gulong external_gl_context)
{
gboolean isAlive = FALSE;
gst_gl_display_lock (display);
if (!display->context_created) {
display->external_gl_context = external_gl_context;
display->gl_thread = g_thread_new ("gstglcontext",
(GThreadFunc) gst_gl_display_thread_create_context, display);
g_cond_wait (&display->priv->cond_create_context, &display->mutex);
display->context_created = TRUE;
GST_INFO ("gl thread created");
}
isAlive = display->isAlive;
gst_gl_display_unlock (display);
return isAlive;
}
void
gst_gl_display_thread_add (GstGLDisplay * display,
GstGLDisplayThreadFunc func, gpointer data)
{
g_return_if_fail (GST_IS_GL_DISPLAY (display));
g_return_if_fail (GST_GL_IS_WINDOW (display->priv->window));
g_return_if_fail (func != NULL);
gst_gl_display_lock (display);
display->priv->data = data;
display->priv->generic_callback = func;
gst_gl_window_send_message (display->gl_window,
gst_gl_window_send_message (display->priv->window,
GST_GL_WINDOW_CB (gst_gl_display_thread_run_generic), display);
gst_gl_display_unlock (display);
}
guintptr
gst_gl_display_get_internal_gl_context (GstGLDisplay * display)
{
gulong external_gl_context = 0;
gst_gl_display_lock (display);
external_gl_context = gst_gl_window_get_gl_context (display->gl_window);
gst_gl_display_unlock (display);
return external_gl_context;
g_return_val_if_fail (GST_IS_GL_DISPLAY (display), 0);
g_return_val_if_fail (GST_GL_IS_WINDOW (display->priv->window), 0);
return gst_gl_window_get_gl_context (display->priv->window);
}
void
gst_gl_display_activate_gl_context (GstGLDisplay * display, gboolean activate)
{
g_return_if_fail (GST_IS_GL_DISPLAY (display));
g_return_if_fail (GST_GL_IS_WINDOW (display->priv->window));
if (!activate)
gst_gl_display_lock (display);
gst_gl_window_activate (display->gl_window, activate);
gst_gl_window_activate (display->priv->window, activate);
if (activate)
gst_gl_display_unlock (display);
}
GstGLAPI
gst_gl_display_get_gl_api_unlocked (GstGLDisplay * display)
{
return display->gl_api;
}
GstGLAPI
gst_gl_display_get_gl_api (GstGLDisplay * display)
{
GstGLAPI api;
g_return_val_if_fail (GST_IS_GL_DISPLAY (display), GST_GL_API_NONE);
gst_gl_display_lock (display);
api = gst_gl_display_get_gl_api_unlocked (display);
gst_gl_display_unlock (display);
return api;
return display->gl_api;
}
gpointer
@ -554,13 +228,50 @@ gst_gl_display_get_gl_vtable (GstGLDisplay * display)
{
gpointer gl;
gst_gl_display_lock (display);
g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL);
gl = display->gl_vtable;
gst_gl_display_unlock (display);
return gl;
}
//------------------------------------------------------------
//------------------------ END PUBLIC ------------------------
//------------------------------------------------------------
void
gst_gl_display_set_window (GstGLDisplay * display, GstGLWindow * window)
{
g_return_if_fail (GST_IS_GL_DISPLAY (display));
g_return_if_fail (GST_GL_IS_WINDOW (window));
gst_gl_display_lock (display);
if (display->priv->window)
gst_object_unref (display->priv->window);
display->priv->window = gst_object_ref (window);
gst_gl_display_unlock (display);
}
GstGLWindow *
gst_gl_display_get_window (GstGLDisplay * display)
{
GstGLWindow *window;
g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL);
gst_gl_display_lock (display);
window =
display->priv->window ? gst_object_ref (display->priv->window) : NULL;
gst_gl_display_unlock (display);
return window;
}
GstGLWindow *
gst_gl_display_get_window_unlocked (GstGLDisplay * display)
{
g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL);
return display->priv->window ? gst_object_ref (display->priv->window) : NULL;
}

View file

@ -28,6 +28,7 @@
#include <gst/video/video.h>
typedef struct _GstGLShader GstGLShader;
typedef struct _GstGLWindow GstGLWindow;
#include "gstglwindow.h"
#include "gstglshader.h"
@ -89,12 +90,6 @@ struct _GstGLDisplay
/* thread safe */
GMutex mutex;
/* gl context */
GThread *gl_thread;
GstGLWindow *gl_window;
gboolean isAlive;
gboolean context_created;
/* gl API we are using */
GstGLAPI gl_api;
/* foreign gl context */
@ -115,9 +110,6 @@ struct _GstGLDisplayClass
GstGLDisplay *gst_gl_display_new (void);
gboolean gst_gl_display_create_context (GstGLDisplay * display,
gulong external_gl_context);
void gst_gl_display_thread_add (GstGLDisplay * display,
GstGLDisplayThreadFunc func, gpointer data);
@ -126,15 +118,17 @@ void gst_gl_display_activate_gl_context (GstGLDisplay * display, gboolean activa
/* Must be called inside a lock/unlock on display, or within the glthread */
void gst_gl_display_set_error (GstGLDisplay * display, const char * format, ...);
gboolean gst_gl_display_check_framebuffer_status (GstGLDisplay * display);
void gst_gl_display_lock (GstGLDisplay * display);
void gst_gl_display_unlock (GstGLDisplay * display);
GstGLAPI gst_gl_display_get_gl_api (GstGLDisplay * display);
GstGLAPI gst_gl_display_get_gl_api_unlocked (GstGLDisplay * display);
gpointer gst_gl_display_get_gl_vtable (GstGLDisplay * display);
void gst_gl_display_set_window (GstGLDisplay * display, GstGLWindow * window);
GstGLWindow * gst_gl_display_get_window (GstGLDisplay * display);
GstGLWindow * gst_gl_display_get_window_unlocked (GstGLDisplay * display);
G_END_DECLS
#endif /* __GST_GL_H__ */

View file

@ -43,11 +43,11 @@
* calling thread.
*/
#define USING_OPENGL(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL)
#define USING_OPENGL3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL3)
#define USING_GLES(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES)
#define USING_GLES2(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES2)
#define USING_GLES3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES3)
#define USING_OPENGL(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL)
#define USING_OPENGL3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL3)
#define USING_GLES(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES)
#define USING_GLES2(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES2)
#define USING_GLES3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES3)
static void _do_download (GstGLDisplay * display, GstGLDownload * download);
static void _init_download (GstGLDisplay * display, GstGLDownload * download);

View file

@ -150,6 +150,7 @@ _gst_gl_feature_check (GstGLDisplay * display,
const char *suffix = NULL;
int func_num;
GstGLFuncs *gst_gl = display->gl_vtable;
GstGLWindow *window = NULL;
/* First check whether the functions should be directly provided by
GL */
@ -172,6 +173,9 @@ _gst_gl_feature_check (GstGLDisplay * display,
if (suffix == NULL)
goto error;
window = gst_gl_display_get_window (display);
g_assert (window);
/* Try to get all of the entry points */
for (func_num = 0; data->functions[func_num].name; func_num++) {
void *func;
@ -183,8 +187,7 @@ _gst_gl_feature_check (GstGLDisplay * display,
suffix, NULL);
GST_TRACE ("%s should %sbe in core", full_function_name,
in_core ? "" : "not ");
func =
gst_gl_window_get_proc_address (display->gl_window, full_function_name);
func = gst_gl_window_get_proc_address (window, full_function_name);
if (func == NULL && in_core) {
GST_TRACE ("%s was not found in core, trying the extension version",
@ -196,8 +199,7 @@ _gst_gl_feature_check (GstGLDisplay * display,
g_free (full_function_name);
full_function_name = g_strconcat ("gl", data->functions[func_num].name,
suffix, NULL);
func = gst_gl_window_get_proc_address (display->gl_window,
full_function_name);
func = gst_gl_window_get_proc_address (window, full_function_name);
}
}
@ -212,6 +214,7 @@ _gst_gl_feature_check (GstGLDisplay * display,
}
g_free (full_function_name);
gst_object_unref (window);
return TRUE;
@ -230,6 +233,9 @@ error:
g_free (full_function_name);
}
if (window)
gst_object_unref (window);
return FALSE;
}

View file

@ -253,11 +253,18 @@ gst_gl_filter_start (GstBaseTransform * bt)
filter->display =
g_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value)));
else {
GstGLWindow *window;
GError *error = NULL;
GST_INFO ("Creating GstGLDisplay");
filter->display = gst_gl_display_new ();
if (!gst_gl_display_create_context (filter->display, 0)) {
window = gst_gl_window_new (filter->display);
gst_gl_display_set_window (filter->display, window);
g_object_unref (window);
if (!gst_gl_window_create_context (window, 0, &error)) {
GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND,
GST_GL_DISPLAY_ERR_MSG (filter->display), (NULL));
("%s", error->message), (NULL));
return FALSE;
}
}
@ -727,9 +734,10 @@ gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps,
if (filter_class->display_init_cb != NULL) {
gst_gl_display_thread_add (filter->display, gst_gl_filter_start_gl, filter);
}
#if 0
if (!filter->display->isAlive)
goto error;
#endif
if (filter_class->onInitFBO) {
if (!filter_class->onInitFBO (filter))

View file

@ -25,6 +25,7 @@
#include <gst/video/video.h>
#include "gstglmemory.h"
#include "gstglutils.h"
/**
* SECTION:gstglmemory

View file

@ -935,11 +935,18 @@ gst_gl_mixer_activate (GstGLMixer * mix, gboolean activate)
mix->display =
g_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value)));
else {
GstGLWindow *window;
GError *error = NULL;
GST_INFO ("Creating GstGLDisplay");
mix->display = gst_gl_display_new ();
if (!gst_gl_display_create_context (mix->display, 0)) {
window = gst_gl_window_new (mix->display);
gst_gl_display_set_window (mix->display, window);
g_object_unref (window);
if (!gst_gl_window_create_context (window, 0, &error)) {
GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND,
GST_GL_DISPLAY_ERR_MSG (mix->display), (NULL));
("%s", error->message), (NULL));
return FALSE;
}
}

View file

@ -43,11 +43,11 @@
* calling thread.
*/
#define USING_OPENGL(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL)
#define USING_OPENGL3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL3)
#define USING_GLES(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES)
#define USING_GLES2(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES2)
#define USING_GLES3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES3)
#define USING_OPENGL(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL)
#define USING_OPENGL3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL3)
#define USING_GLES(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES)
#define USING_GLES2(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES2)
#define USING_GLES3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES3)
static void _do_upload (GstGLDisplay * display, GstGLUpload * upload);
static void _do_upload_fill (GstGLDisplay * display, GstGLUpload * upload);

View file

@ -234,18 +234,24 @@ void
gst_gl_display_gen_texture (GstGLDisplay * display, GLuint * pTexture,
GstVideoFormat v_format, GLint width, GLint height)
{
GstGLWindow *window;
gst_gl_display_lock (display);
if (display->isAlive) {
window = gst_gl_display_get_window_unlocked (display);
if (gst_gl_window_is_running (window)) {
gen_texture_width = width;
gen_texture_height = height;
gen_texture_video_format = v_format;
gst_gl_window_send_message (display->gl_window,
gst_gl_window_send_message (window,
GST_GL_WINDOW_CB (gst_gl_display_gen_texture_window_cb), display);
*pTexture = gen_texture;
} else
*pTexture = 0;
gst_object_unref (window);
gst_gl_display_unlock (display);
}
@ -263,21 +269,26 @@ gboolean
gst_gl_display_gen_fbo (GstGLDisplay * display, gint width, gint height,
GLuint * fbo, GLuint * depthbuffer)
{
gboolean isAlive = FALSE;
gboolean alive = FALSE;
GstGLWindow *window;
gst_gl_display_lock (display);
if (display->isAlive) {
window = gst_gl_display_get_window_unlocked (display);
if (gst_gl_window_is_running (window)) {
gen_fbo_width = width;
gen_fbo_height = height;
gst_gl_window_send_message (display->gl_window, GST_GL_WINDOW_CB (_gen_fbo),
display);
gst_gl_window_send_message (window, GST_GL_WINDOW_CB (_gen_fbo), display);
*fbo = generated_fbo;
*depthbuffer = generated_depth_buffer;
}
isAlive = display->isAlive;
alive = gst_gl_window_is_running (window);
gst_object_unref (window);
gst_gl_display_unlock (display);
return isAlive;
return alive;
}
@ -297,10 +308,13 @@ gst_gl_display_use_fbo (GstGLDisplay * display, gint texture_fbo_width,
gdouble proj_param2, gdouble proj_param3, gdouble proj_param4,
GstGLDisplayProjection projection, gpointer * stuff)
{
gboolean isAlive;
gboolean alive;
GstGLWindow *window;
gst_gl_display_lock (display);
if (display->isAlive) {
window = gst_gl_display_get_window_unlocked (display);
if (gst_gl_window_is_running (window)) {
use_fbo = fbo;
use_depth_buffer = depth_buffer;
use_fbo_texture = texture_fbo;
@ -316,13 +330,14 @@ gst_gl_display_use_fbo (GstGLDisplay * display, gint texture_fbo_width,
input_texture_width = input_tex_width;
input_texture_height = input_tex_height;
input_texture = input_tex;
gst_gl_window_send_message (display->gl_window, GST_GL_WINDOW_CB (_use_fbo),
display);
gst_gl_window_send_message (window, GST_GL_WINDOW_CB (_use_fbo), display);
}
isAlive = display->isAlive;
alive = gst_gl_window_is_running (window);
gst_object_unref (window);
gst_gl_display_unlock (display);
return isAlive;
return alive;
}
gboolean
@ -330,10 +345,13 @@ gst_gl_display_use_fbo_v2 (GstGLDisplay * display, gint texture_fbo_width,
gint texture_fbo_height, GLuint fbo, GLuint depth_buffer,
GLuint texture_fbo, GLCB_V2 cb, gpointer * stuff)
{
gboolean isAlive;
gboolean alive;
GstGLWindow *window;
gst_gl_display_lock (display);
if (display->isAlive) {
window = gst_gl_display_get_window_unlocked (display);
if (gst_gl_window_is_running (window)) {
use_fbo = fbo;
use_depth_buffer = depth_buffer;
use_fbo_texture = texture_fbo;
@ -341,26 +359,33 @@ gst_gl_display_use_fbo_v2 (GstGLDisplay * display, gint texture_fbo_width,
use_fbo_height = texture_fbo_height;
use_fbo_scene_cb_v2 = cb;
use_fbo_stuff = stuff;
gst_gl_window_send_message (display->gl_window,
gst_gl_window_send_message (window,
GST_GL_WINDOW_CB (_use_fbo_v2), display);
}
isAlive = display->isAlive;
alive = gst_gl_window_is_running (window);
gst_object_unref (window);
gst_gl_display_unlock (display);
return isAlive;
return alive;
}
/* Called by gltestsrc and glfilter */
void
gst_gl_display_del_fbo (GstGLDisplay * display, GLuint fbo, GLuint depth_buffer)
{
GstGLWindow *window;
gst_gl_display_lock (display);
if (display->isAlive) {
window = gst_gl_display_get_window_unlocked (display);
if (gst_gl_window_is_running (window)) {
del_fbo = fbo;
del_depth_buffer = depth_buffer;
gst_gl_window_send_message (display->gl_window, GST_GL_WINDOW_CB (_del_fbo),
display);
gst_gl_window_send_message (window, GST_GL_WINDOW_CB (_del_fbo), display);
}
gst_object_unref (window);
gst_gl_display_unlock (display);
}
@ -371,13 +396,16 @@ gst_gl_display_gen_shader (GstGLDisplay * display,
const gchar * shader_vertex_source,
const gchar * shader_fragment_source, GstGLShader ** shader)
{
gboolean isAlive;
gboolean alive;
GstGLWindow *window;
gst_gl_display_lock (display);
if (display->isAlive) {
window = gst_gl_display_get_window_unlocked (display);
if (gst_gl_window_is_running (window)) {
gen_shader_vertex_source = shader_vertex_source;
gen_shader_fragment_source = shader_fragment_source;
gst_gl_window_send_message (display->gl_window,
gst_gl_window_send_message (window,
GST_GL_WINDOW_CB (_gen_shader), display);
if (shader)
*shader = gen_shader;
@ -385,10 +413,12 @@ gst_gl_display_gen_shader (GstGLDisplay * display,
gen_shader_vertex_source = NULL;
gen_shader_fragment_source = NULL;
}
isAlive = display->isAlive;
alive = gst_gl_window_is_running (window);
gst_object_unref (window);
gst_gl_display_unlock (display);
return isAlive;
return alive;
}
@ -396,12 +426,18 @@ gst_gl_display_gen_shader (GstGLDisplay * display,
void
gst_gl_display_del_shader (GstGLDisplay * display, GstGLShader * shader)
{
GstGLWindow *window;
gst_gl_display_lock (display);
if (display->isAlive) {
window = gst_gl_display_get_window_unlocked (display);
if (gst_gl_window_is_running (window)) {
del_shader = shader;
gst_gl_window_send_message (display->gl_window,
gst_gl_window_send_message (window,
GST_GL_WINDOW_CB (_del_shader), display);
}
gst_object_unref (window);
gst_gl_display_unlock (display);
}

View file

@ -99,4 +99,6 @@ gboolean gst_gl_display_gen_shader (GstGLDisplay * display,
const gchar * shader_fragment_source, GstGLShader ** shader);
void gst_gl_display_del_shader (GstGLDisplay * display, GstGLShader * shader);
gboolean gst_gl_display_check_framebuffer_status (GstGLDisplay * display);
#endif /* __GST_GL_UTILS_H__ */

View file

@ -23,6 +23,7 @@
#endif
#include <gmodule.h>
#include <stdio.h>
#include "gstglwindow.h"
@ -39,12 +40,45 @@
#include "wayland/gstglwindow_wayland_egl.h"
#endif
#include "gstglfeature.h"
#define USING_OPENGL(display) (display->gl_api & GST_GL_API_OPENGL)
#define USING_OPENGL3(display) (display->gl_api & GST_GL_API_OPENGL3)
#define USING_GLES(display) (display->gl_api & GST_GL_API_GLES)
#define USING_GLES2(display) (display->gl_api & GST_GL_API_GLES2)
#define USING_GLES3(display) (display->gl_api & GST_GL_API_GLES3)
#define GST_CAT_DEFAULT gst_gl_window_debug
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
#define gst_gl_window_parent_class parent_class
G_DEFINE_ABSTRACT_TYPE (GstGLWindow, gst_gl_window, G_TYPE_OBJECT);
#define GST_GL_WINDOW_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_WINDOW, GstGLWindowPrivate))
struct _GstGLWindowPrivate
{
GstGLDisplay *display;
GThread *gl_thread;
/* conditions */
GMutex render_lock;
GCond cond_create_context;
GCond cond_destroy_context;
gboolean context_created;
gboolean alive;
guintptr external_gl_context;
GstGLAPI gl_api;
GError **error;
};
static gpointer _gst_gl_window_thread_create_context (GstGLWindow * window);
static void gst_gl_window_finalize (GObject * object);
GQuark
gst_gl_window_error_quark (void)
{
@ -54,19 +88,30 @@ gst_gl_window_error_quark (void)
static void
gst_gl_window_init (GstGLWindow * window)
{
window->priv = GST_GL_WINDOW_GET_PRIVATE (window);
g_mutex_init (&window->lock);
window->need_lock = TRUE;
g_mutex_init (&window->priv->render_lock);
g_cond_init (&window->priv->cond_create_context);
g_cond_init (&window->priv->cond_destroy_context);
window->priv->context_created = FALSE;
}
static void
gst_gl_window_class_init (GstGLWindowClass * klass)
{
g_type_class_add_private (klass, sizeof (GstGLWindowPrivate));
klass->get_proc_address =
GST_DEBUG_FUNCPTR (gst_gl_window_default_get_proc_address);
G_OBJECT_CLASS (klass)->finalize = gst_gl_window_finalize;
}
GstGLWindow *
gst_gl_window_new (void)
gst_gl_window_new (GstGLDisplay * display)
{
GstGLWindow *window = NULL;
const gchar *user_choice;
@ -106,9 +151,43 @@ gst_gl_window_new (void)
return NULL;
}
window->priv->display = display;
return window;
}
static void
gst_gl_window_finalize (GObject * object)
{
GstGLWindow *window = GST_GL_WINDOW (object);
if (window) {
gst_gl_window_set_resize_callback (window, NULL, NULL);
gst_gl_window_set_draw_callback (window, NULL, NULL);
gst_gl_window_set_close_callback (window, NULL, NULL);
if (window->priv->alive) {
GST_INFO ("send quit gl window loop");
gst_gl_window_quit (window, NULL, NULL);
}
}
if (window->priv->gl_thread) {
gpointer ret = g_thread_join (window->priv->gl_thread);
GST_INFO ("gl thread joined");
if (ret != NULL)
GST_ERROR ("gl thread returned a non-null pointer");
window->priv->gl_thread = NULL;
}
g_mutex_clear (&window->priv->render_lock);
g_cond_clear (&window->priv->cond_destroy_context);
g_cond_clear (&window->priv->cond_create_context);
G_OBJECT_CLASS (gst_gl_window_parent_class)->finalize (object);
}
guintptr
gst_gl_window_get_gl_context (GstGLWindow * window)
{
@ -209,10 +288,17 @@ gst_gl_window_quit (GstGLWindow * window, GstGLWindowCB callback, gpointer data)
GST_GL_WINDOW_LOCK (window);
window->priv->alive = FALSE;
window->close = callback;
window->close_data = data;
window_class->quit (window, callback, data);
GST_INFO ("quit sent to gl window loop");
g_cond_wait (&window->priv->cond_destroy_context, &window->priv->render_lock);
GST_INFO ("quit received from gl window");
GST_GL_WINDOW_UNLOCK (window);
}
@ -331,7 +417,7 @@ gst_gl_window_get_proc_address (GstGLWindow * window, const gchar * name)
gboolean
gst_gl_window_create_context (GstGLWindow * window, GstGLAPI gl_api,
_priv_gst_gl_window_create_context (GstGLWindow * window, GstGLAPI gl_api,
guintptr external_gl_context, GError ** error)
{
gboolean ret;
@ -368,3 +454,309 @@ gst_gl_window_default_get_proc_address (GstGLWindow * window,
return ret;
}
/* Create an opengl context (one context for one GstGLDisplay) */
gboolean
gst_gl_window_create_context (GstGLWindow * window,
guintptr external_gl_context, GError ** error)
{
gboolean alive = FALSE;
GstGLWindowClass *window_class;
g_return_val_if_fail (GST_GL_IS_WINDOW (window), FALSE);
window_class = GST_GL_WINDOW_GET_CLASS (window);
g_return_val_if_fail (window_class->create_context != NULL, FALSE);
g_mutex_lock (&window->priv->render_lock);
if (!window->priv->context_created) {
window->priv->external_gl_context = external_gl_context;
window->priv->error = error;
window->priv->gl_thread = g_thread_new ("gstglcontext",
(GThreadFunc) _gst_gl_window_thread_create_context, window);
g_cond_wait (&window->priv->cond_create_context,
&window->priv->render_lock);
window->priv->context_created = TRUE;
GST_INFO ("gl thread created");
}
alive = window->priv->alive;
g_mutex_unlock (&window->priv->render_lock);
return alive;
}
gboolean
gst_gl_window_is_running (GstGLWindow * window)
{
return window->priv->alive;
}
static gboolean
_create_context_gles2 (GstGLWindow * window, gint * gl_major, gint * gl_minor)
{
GstGLDisplay *display;
const GstGLFuncs *gl;
GLenum gl_err = GL_NO_ERROR;
GError **error;
display = window->priv->display;
gl = display->gl_vtable;
error = window->priv->error;
GST_INFO ("GL_VERSION: %s", gl->GetString (GL_VERSION));
GST_INFO ("GL_SHADING_LANGUAGE_VERSION: %s",
gl->GetString (GL_SHADING_LANGUAGE_VERSION));
GST_INFO ("GL_VENDOR: %s", gl->GetString (GL_VENDOR));
GST_INFO ("GL_RENDERER: %s", gl->GetString (GL_RENDERER));
gl_err = gl->GetError ();
if (gl_err != GL_NO_ERROR) {
g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_FAILED,
"glGetString error: 0x%x", gl_err);
return FALSE;
}
#if GST_GL_HAVE_GLES2
if (!GL_ES_VERSION_2_0) {
g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_OLD_LIBS,
"OpenGL|ES >= 2.0 is required");
return FALSE;
}
#endif
_gst_gl_feature_check_ext_functions (display, 0, 0,
(const gchar *) gl->GetString (GL_EXTENSIONS));
if (gl_major)
*gl_major = 2;
if (gl_minor)
*gl_minor = 0;
return TRUE;
}
gboolean
_create_context_opengl (GstGLWindow * window, gint * gl_major, gint * gl_minor)
{
GstGLDisplay *display;
const GstGLFuncs *gl;
guint maj, min;
GLenum gl_err = GL_NO_ERROR;
GString *opengl_version = NULL;
GError **error;
display = window->priv->display;
gl = display->gl_vtable;
error = window->priv->error;
GST_INFO ("GL_VERSION: %s", gl->GetString (GL_VERSION));
GST_INFO ("GL_SHADING_LANGUAGE_VERSION: %s",
gl->GetString (GL_SHADING_LANGUAGE_VERSION));
GST_INFO ("GL_VENDOR: %s", gl->GetString (GL_VENDOR));
GST_INFO ("GL_RENDERER: %s", gl->GetString (GL_RENDERER));
gl_err = gl->GetError ();
if (gl_err != GL_NO_ERROR) {
g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_FAILED,
"glGetString error: 0x%x", gl_err);
return FALSE;
}
opengl_version =
g_string_truncate (g_string_new ((gchar *) gl->GetString (GL_VERSION)),
3);
sscanf (opengl_version->str, "%d.%d", &maj, &min);
g_string_free (opengl_version, TRUE);
/* OpenGL > 1.2.0 */
if ((maj < 1) || (maj < 2 && maj >= 1 && min < 2)) {
g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_OLD_LIBS,
"OpenGL >= 1.2.0 required, found %u.%u", maj, min);
return FALSE;
}
_gst_gl_feature_check_ext_functions (display, maj, min,
(const gchar *) gl->GetString (GL_EXTENSIONS));
if (gl_major)
*gl_major = maj;
if (gl_minor)
*gl_minor = min;
return TRUE;
}
GstGLAPI
_compiled_api (void)
{
GstGLAPI ret = GST_GL_API_NONE;
#if GST_GL_HAVE_OPENGL
ret |= GST_GL_API_OPENGL;
#endif
#if GST_GL_HAVE_GLES2
ret |= GST_GL_API_GLES2;
#endif
return ret;
}
GstGLAPI
_parse_gl_api (const gchar * apis_s)
{
GstGLAPI ret = GST_GL_API_NONE;
gchar *apis = (gchar *) apis_s;
while (apis) {
if (apis[0] == '\0') {
break;
} else if (apis[0] == ' ' || apis[0] == ',') {
apis = &apis[1];
} else if (g_strstr_len (apis, 7, "opengl3")) {
ret |= GST_GL_API_OPENGL3;
apis = &apis[7];
} else if (g_strstr_len (apis, 6, "opengl")) {
ret |= GST_GL_API_OPENGL;
apis = &apis[6];
} else if (g_strstr_len (apis, 5, "gles1")) {
ret |= GST_GL_API_GLES;
apis = &apis[5];
} else if (g_strstr_len (apis, 5, "gles2")) {
ret |= GST_GL_API_GLES2;
apis = &apis[5];
} else if (g_strstr_len (apis, 5, "gles3")) {
ret |= GST_GL_API_GLES3;
apis = &apis[5];
} else {
break;
}
}
if (ret == GST_GL_API_NONE)
ret = GST_GL_API_ANY;
return ret;
}
static gpointer
_gst_gl_window_thread_create_context (GstGLWindow * window)
{
GstGLWindowClass *window_class;
GstGLDisplay *display;
GstGLFuncs *gl;
gint gl_major = 0;
gboolean ret = FALSE;
GstGLAPI compiled_api, user_api;
gchar *api_string;
gchar *compiled_api_s;
gchar *user_api_string;
const gchar *user_choice;
GError **error;
window_class = GST_GL_WINDOW_GET_CLASS (window);
error = window->priv->error;
display = window->priv->display;
g_mutex_lock (&window->priv->render_lock);
gl = display->gl_vtable;
compiled_api = _compiled_api ();
user_choice = g_getenv ("GST_GL_API");
user_api = _parse_gl_api (user_choice);
user_api_string = gst_gl_api_string (user_api);
compiled_api_s = gst_gl_api_string (compiled_api);
GST_INFO ("Attempting to create opengl context. user chosen api(s):%s, "
"compiled api support:%s", user_api_string, compiled_api_s);
if (!window_class->create_context (window, compiled_api & user_api,
window->priv->external_gl_context, error)) {
g_assert (error == NULL || *error != NULL);
g_free (compiled_api_s);
g_free (user_api_string);
goto failure;
}
GST_INFO ("window created context");
display->gl_api = gst_gl_window_get_gl_api (window);
g_assert (display->gl_api != GST_GL_API_NONE
&& display->gl_api != GST_GL_API_ANY);
api_string = gst_gl_api_string (display->gl_api);
GST_INFO ("available GL APIs: %s", api_string);
if (((compiled_api & display->gl_api) & user_api) == GST_GL_API_NONE) {
g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_WRONG_API,
"failed to create context, window "
"could not provide correct api. user:%s, compiled:%s, window:%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_window_get_proc_address (window, "glGetError");
gl->GetString = gst_gl_window_get_proc_address (window, "glGetString");
if (!gl->GetError || !gl->GetString) {
g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_FAILED,
"could not GetProcAddress core opengl functions");
goto failure;
}
/* gl api specific code */
if (!ret && USING_OPENGL (display))
ret = _create_context_opengl (window, &gl_major, NULL);
if (!ret && USING_GLES2 (display))
ret = _create_context_gles2 (window, &gl_major, NULL);
if (!ret || !gl_major) {
g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_CREATE_CONTEXT,
"GL api specific initialization failed");
goto failure;
}
g_cond_signal (&window->priv->cond_create_context);
window->priv->alive = TRUE;
g_mutex_unlock (&window->priv->render_lock);
gst_gl_window_run (window);
GST_INFO ("loop exited\n");
g_mutex_lock (&window->priv->render_lock);
window->priv->alive = FALSE;
// g_object_unref (G_OBJECT (display->gl_window));
// display->gl_window = NULL;
g_cond_signal (&window->priv->cond_destroy_context);
g_mutex_unlock (&window->priv->render_lock);
return NULL;
failure:
{
g_cond_signal (&window->priv->cond_create_context);
g_mutex_unlock (&window->priv->render_lock);
return NULL;
}
}

View file

@ -22,9 +22,12 @@
#ifndef __GST_GL_WINDOW_H__
#define __GST_GL_WINDOW_H__
typedef struct _GstGLDisplay GstGLDisplay;
#include <gst/gst.h>
#include "gstglapi.h"
#include "gstgldisplay.h"
G_BEGIN_DECLS
@ -90,6 +93,8 @@ struct _GstGLWindow {
/*< private >*/
gpointer _reserved[GST_PADDING];
GstGLWindowPrivate *priv;
};
struct _GstGLWindowClass {
@ -119,7 +124,7 @@ struct _GstGLWindowClass {
GQuark gst_gl_window_error_quark (void);
GType gst_gl_window_get_type (void);
GstGLWindow * gst_gl_window_new (void);
GstGLWindow * gst_gl_window_new (GstGLDisplay *display);
void gst_gl_window_set_draw_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data);
void gst_gl_window_set_resize_callback (GstGLWindow *window, GstGLWindowResizeCB callback, gpointer data);
@ -140,11 +145,12 @@ gpointer gst_gl_window_get_proc_address (GstGLWindow *window, const gchar *
GstGLPlatform gst_gl_window_get_platform (GstGLWindow *window);
GstGLAPI gst_gl_window_get_gl_api (GstGLWindow *window);
gboolean gst_gl_window_create_context (GstGLWindow *window, GstGLAPI gl_api,
guintptr external_gl_context, GError ** error);
gboolean gst_gl_window_create_context (GstGLWindow *window, guintptr external_gl_context, GError ** error);
gpointer gst_gl_window_default_get_proc_address (GstGLWindow *window, const gchar *name);
gboolean gst_gl_window_is_running (GstGLWindow *window);
GST_DEBUG_CATEGORY_EXTERN (gst_gl_window_debug);
G_END_DECLS