From 42255b64aa73152e0c2beebe6c511d9cdb7e1d16 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Thu, 23 Oct 2008 01:40:52 +0200 Subject: [PATCH] [249/906] begin GstGLWindow in order to totally remove gstfreeglut --- gst-libs/gst/gl/CMakeLists.txt | 13 +- gst-libs/gst/gl/gstgldisplay.c | 616 ++++------------------------ gst-libs/gst/gl/gstgldisplay.h | 23 +- gst-libs/gst/gl/gstglwindow.h | 88 ++++ gst-libs/gst/gl/gstglwindow_win32.c | 542 ++++++++++++++++++++++++ 5 files changed, 721 insertions(+), 561 deletions(-) create mode 100644 gst-libs/gst/gl/gstglwindow.h create mode 100644 gst-libs/gst/gl/gstglwindow_win32.c diff --git a/gst-libs/gst/gl/CMakeLists.txt b/gst-libs/gst/gl/CMakeLists.txt index bd7120e304..badd1a80fe 100644 --- a/gst-libs/gst/gl/CMakeLists.txt +++ b/gst-libs/gst/gl/CMakeLists.txt @@ -16,8 +16,19 @@ add_library (gstgl STATIC gstglfilter.c gstglshader.c) +#FIXME: get ride of this condition +if (WIN32) target_link_libraries(gstgl - general gstfreeglut + general ${OPENGL_LIBRARIES} + general ${GLEW_LIBRARY} + general ${GLIB2_LIBRARIES} + general ${GSTREAMER_LIBRARIES} + gdi32 + winmm) +else (WIN32) +target_link_libraries(gstgl + general ${OPENGL_LIBRARIES} general ${GLEW_LIBRARY} general ${GLIB2_LIBRARIES} general ${GSTREAMER_LIBRARIES}) +endif (WIN32) diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c index 6275402b87..3a3e35872a 100644 --- a/gst-libs/gst/gl/gstgldisplay.c +++ b/gst-libs/gst/gl/gstgldisplay.c @@ -44,19 +44,10 @@ GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug); GST_BOILERPLATE_FULL (GstGLDisplay, gst_gl_display, GObject, G_TYPE_OBJECT, DEBUG_INIT); static void gst_gl_display_finalize (GObject* object); -/* GL thread loop */ -static gpointer gst_gl_display_thread_func (GstGLDisplay* display); -static void gst_gl_display_thread_loop (void); -static void gst_gl_display_thread_dispatch_action (GstGLDisplayMsg *msg); -static gboolean gst_gl_display_thread_check_msg_validity (GstGLDisplayMsg *msg); - /* Called in the gl thread, protected by lock and unlock */ -static void gst_gl_display_thread_create_context (GstGLDisplay* display); +static gpointer gst_gl_display_thread_create_context (GstGLDisplay* display); static void gst_gl_display_thread_destroy_context (GstGLDisplay* display); static void gst_gl_display_thread_change_context (GstGLDisplay* display); -static void gst_gl_display_thread_set_visible_context (GstGLDisplay* display); -static void gst_gl_display_thread_resize_context (GstGLDisplay* display); -static void gst_gl_display_thread_redisplay (GstGLDisplay* display); static void gst_gl_display_thread_run_generic (GstGLDisplay *display); static void gst_gl_display_thread_gen_texture (GstGLDisplay* display); static void gst_gl_display_thread_del_texture (GstGLDisplay* display); @@ -73,10 +64,9 @@ static void gst_gl_display_thread_del_shader (GstGLDisplay *display); /* private methods */ void gst_gl_display_lock (GstGLDisplay* display); void gst_gl_display_unlock (GstGLDisplay* display); -void gst_gl_display_post_message (GstGLDisplayAction action, GstGLDisplay* display); -void gst_gl_display_on_resize(gint width, gint height); -void gst_gl_display_on_draw (void); -void gst_gl_display_on_close (void); +void gst_gl_display_on_resize(GstGLDisplay* display, gint width, gint height); +void gst_gl_display_on_draw (GstGLDisplay* display); +void gst_gl_display_on_close (GstGLDisplay* display); void gst_gl_display_glgen_texture (GstGLDisplay* display, GLuint* pTexture, GLint width, GLint height); void gst_gl_display_gldel_texture (GstGLDisplay* display, GLuint* pTexture, GLint width, GLint height); gboolean gst_gl_display_texture_pool_func_clean (gpointer key, gpointer value, gpointer data); @@ -91,19 +81,6 @@ static void gst_gl_display_thread_do_upload_draw (GstGLDisplay *display); static void gst_gl_display_thread_do_download_draw_rgb (GstGLDisplay *display); static void gst_gl_display_thread_do_download_draw_yuv (GstGLDisplay *display); -//------------------------------------------------------------ -//-------------------- GL context management ----------------- -//------------------------------------------------------------ - -//(key=int glutWinId) and (value=GstGLDisplay *display) -static GHashTable* gst_gl_display_map = NULL; - -//all glut functions and opengl primitives are called in this thread -static GThread* gst_gl_display_gl_thread = NULL; - -//-timepoped by glutIdleFunc -static GAsyncQueue* gst_gl_display_messageQueue = NULL; - //------------------------------------------------------------ //---------------------- For klass GstGLDisplay --------------- @@ -128,9 +105,9 @@ gst_gl_display_init (GstGLDisplay *display, GstGLDisplayClass *klass) display->mutex = g_mutex_new (); //gl context - display->glutWinId = -1; + display->gl_thread = NULL; + display->gl_window = NULL; display->winId = 0; - display->title = g_string_new ("OpenGL renderer "); display->win_xpos = 0; display->win_ypos = 0; display->visible = FALSE; @@ -139,20 +116,6 @@ gst_gl_display_init (GstGLDisplay *display, GstGLDisplayClass *klass) //conditions display->cond_create_context = g_cond_new (); - display->cond_destroy_context = g_cond_new (); - display->cond_change_context = g_cond_new (); - display->cond_generic = g_cond_new (); - display->cond_gen_texture = g_cond_new (); - display->cond_del_texture = g_cond_new (); - display->cond_init_upload = g_cond_new (); - display->cond_do_upload = g_cond_new (); - display->cond_init_download = g_cond_new (); - display->cond_do_download = g_cond_new (); - display->cond_gen_fbo = g_cond_new (); - display->cond_use_fbo = g_cond_new (); - display->cond_del_fbo = g_cond_new (); - display->cond_gen_shader = g_cond_new (); - display->cond_del_shader = g_cond_new (); //action redisplay display->redisplay_texture = 0; @@ -386,8 +349,7 @@ gst_gl_display_finalize (GObject* object) //request glut window destruction //blocking call because display must be alive gst_gl_display_lock (display); - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_DESTROY_CONTEXT, display); - g_cond_wait (display->cond_destroy_context, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_destroy_context, display); gst_gl_display_unlock (display); if (display->texture_pool) { @@ -396,70 +358,10 @@ gst_gl_display_finalize (GObject* object) g_hash_table_unref (display->texture_pool); display->texture_pool = NULL; } - if (display->title) { - g_string_free (display->title, TRUE); - display->title = NULL; - } if (display->mutex) { g_mutex_free (display->mutex); display->mutex = NULL; } - if (display->cond_del_shader) { - g_cond_free (display->cond_del_shader); - display->cond_del_shader = NULL; - } - if (display->cond_gen_shader) { - g_cond_free (display->cond_gen_shader); - display->cond_gen_shader = NULL; - } - if (display->cond_del_fbo) { - g_cond_free (display->cond_del_fbo); - display->cond_del_fbo = NULL; - } - if (display->cond_use_fbo) { - g_cond_free (display->cond_use_fbo); - display->cond_use_fbo = NULL; - } - if (display->cond_gen_fbo) { - g_cond_free (display->cond_gen_fbo); - display->cond_gen_fbo = NULL; - } - if (display->cond_do_download) { - g_cond_free (display->cond_do_download); - display->cond_do_download = NULL; - } - if (display->cond_init_download) { - g_cond_free (display->cond_init_download); - display->cond_init_download = NULL; - } - if (display->cond_do_upload) { - g_cond_free (display->cond_do_upload); - display->cond_do_upload = NULL; - } - if (display->cond_init_upload) { - g_cond_free (display->cond_init_upload); - display->cond_init_upload = NULL; - } - if (display->cond_del_texture) { - g_cond_free (display->cond_del_texture); - display->cond_del_texture = NULL; - } - if (display->cond_gen_texture) { - g_cond_free (display->cond_gen_texture); - display->cond_gen_texture = NULL; - } - if (display->cond_gen_texture) { - g_cond_free (display->cond_gen_texture); - display->cond_gen_texture = NULL; - } - if (display->cond_change_context) { - g_cond_free (display->cond_change_context); - display->cond_change_context = NULL; - } - if (display->cond_destroy_context) { - g_cond_free (display->cond_destroy_context); - display->cond_destroy_context = NULL; - } if (display->cond_create_context) { g_cond_free (display->cond_create_context); display->cond_create_context = NULL; @@ -473,196 +375,16 @@ gst_gl_display_finalize (GObject* object) if (display->use_fbo_stuff) display->use_fbo_stuff = NULL; - //at this step, the next condition implies that - //the last display has been removed - if (g_hash_table_size (gst_gl_display_map) == 0) + if (display->gl_thread) { - g_thread_join (gst_gl_display_gl_thread); + g_thread_join (display->gl_thread); GST_INFO ("gl thread joined"); - gst_gl_display_gl_thread = NULL; - g_async_queue_unref (gst_gl_display_messageQueue); - g_hash_table_unref (gst_gl_display_map); - gst_gl_display_map = NULL; - } -} - - -//------------------------------------------------------------ -//----------------- BEGIN GL THREAD LOOP --------------------- -//------------------------------------------------------------ - - -/* The gl thread handles GstGLDisplayMsg messages - * Every OpenGL code lines are called in the gl thread */ -static gpointer -gst_gl_display_thread_func (GstGLDisplay *display) -{ - static char *argv = "gst-launch-0.10"; - static gint argc = 1; - - //-display DISPLAY - //Specify the X server to connect to. If not specified, the value of the DISPLAY environment variable is used. - //Should be pass through a glimagesink property - glutInit(&argc, &argv); - glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); - //glutSetOption(GLUT_RENDERING_CONTEXT, GLUT_USE_CURRENT_CONTEXT); - - glutIdleFunc (gst_gl_display_thread_loop); - - gst_gl_display_lock (display); - gst_gl_display_thread_create_context (display); - gst_gl_display_unlock (display); - - GST_INFO ("gl mainLoop started"); - glutMainLoop (); - GST_INFO ("gl mainLoop exited"); - - return NULL; -} - - -/* Called in the gl thread */ -static void -gst_gl_display_thread_loop (void) -{ - GTimeVal timeout; - GstGLDisplayMsg *msg; - - //check for pending actions that require a glut context - g_get_current_time (&timeout); - g_time_val_add (&timeout, 1000000L); //timeout 1 sec - msg = g_async_queue_timed_pop (gst_gl_display_messageQueue, &timeout); - if (msg) - { - if (gst_gl_display_thread_check_msg_validity (msg)) - gst_gl_display_thread_dispatch_action (msg); - while (g_async_queue_length (gst_gl_display_messageQueue)) - { - msg = g_async_queue_pop (gst_gl_display_messageQueue); - if (gst_gl_display_thread_check_msg_validity (msg)) - gst_gl_display_thread_dispatch_action (msg); - } - } - else GST_INFO ("timeout reached in idle func"); -} - - -/* Called in the gl thread loop */ -static void -gst_gl_display_thread_dispatch_action (GstGLDisplayMsg* msg) -{ - gst_gl_display_lock (msg->display); - switch (msg->action) - { - case GST_GL_DISPLAY_ACTION_CREATE_CONTEXT: - gst_gl_display_thread_create_context (msg->display); - break; - case GST_GL_DISPLAY_ACTION_DESTROY_CONTEXT: - gst_gl_display_thread_destroy_context (msg->display); - break; - case GST_GL_DISPLAY_ACTION_CHANGE_CONTEXT: - gst_gl_display_thread_change_context (msg->display); - break; - case GST_GL_DISPLAY_ACTION_VISIBLE_CONTEXT: - gst_gl_display_thread_set_visible_context (msg->display); - break; - case GST_GL_DISPLAY_ACTION_RESIZE_CONTEXT: - gst_gl_display_thread_resize_context (msg->display); - break; - case GST_GL_DISPLAY_ACTION_REDISPLAY_CONTEXT: - gst_gl_display_thread_redisplay (msg->display); - break; - case GST_GL_DISPLAY_ACTION_GENERIC: - gst_gl_display_thread_run_generic (msg->display); - break; - case GST_GL_DISPLAY_ACTION_GEN_TEXTURE: - gst_gl_display_thread_gen_texture (msg->display); - break; - case GST_GL_DISPLAY_ACTION_DEL_TEXTURE: - gst_gl_display_thread_del_texture (msg->display); - break; - case GST_GL_DISPLAY_ACTION_INIT_UPLOAD: - gst_gl_display_thread_init_upload (msg->display); - break; - case GST_GL_DISPLAY_ACTION_DO_UPLOAD: - gst_gl_display_thread_do_upload (msg->display); - break; - case GST_GL_DISPLAY_ACTION_INIT_DOWNLOAD: - gst_gl_display_thread_init_download (msg->display); - break; - case GST_GL_DISPLAY_ACTION_DO_DOWNLOAD: - gst_gl_display_thread_do_download (msg->display); - break; - case GST_GL_DISPLAY_ACTION_GEN_FBO: - gst_gl_display_thread_gen_fbo (msg->display); - break; - case GST_GL_DISPLAY_ACTION_USE_FBO: - gst_gl_display_thread_use_fbo (msg->display); - break; - case GST_GL_DISPLAY_ACTION_DEL_FBO: - gst_gl_display_thread_del_fbo (msg->display); - break; - case GST_GL_DISPLAY_ACTION_GEN_SHADER: - gst_gl_display_thread_gen_shader (msg->display); - break; - case GST_GL_DISPLAY_ACTION_DEL_SHADER: - gst_gl_display_thread_del_shader (msg->display); - break; - default: - g_assert_not_reached (); - } - gst_gl_display_unlock (msg->display); - g_free (msg); -} - - -/* Called in the gl thread loop - * Return false if the message is out of date */ -static gboolean -gst_gl_display_thread_check_msg_validity (GstGLDisplayMsg *msg) -{ - gboolean valid = TRUE; - - switch (msg->action) - { - case GST_GL_DISPLAY_ACTION_CREATE_CONTEXT: - //display is not in the map only when we want create one - valid = TRUE; - break; - case GST_GL_DISPLAY_ACTION_DESTROY_CONTEXT: - case GST_GL_DISPLAY_ACTION_CHANGE_CONTEXT: - case GST_GL_DISPLAY_ACTION_VISIBLE_CONTEXT: - case GST_GL_DISPLAY_ACTION_RESIZE_CONTEXT: - case GST_GL_DISPLAY_ACTION_REDISPLAY_CONTEXT: - case GST_GL_DISPLAY_ACTION_GENERIC: - case GST_GL_DISPLAY_ACTION_GEN_TEXTURE: - case GST_GL_DISPLAY_ACTION_DEL_TEXTURE: - case GST_GL_DISPLAY_ACTION_INIT_UPLOAD: - case GST_GL_DISPLAY_ACTION_DO_UPLOAD: - case GST_GL_DISPLAY_ACTION_INIT_DOWNLOAD: - case GST_GL_DISPLAY_ACTION_DO_DOWNLOAD: - case GST_GL_DISPLAY_ACTION_GEN_FBO: - case GST_GL_DISPLAY_ACTION_USE_FBO: - case GST_GL_DISPLAY_ACTION_DEL_FBO: - case GST_GL_DISPLAY_ACTION_GEN_SHADER: - case GST_GL_DISPLAY_ACTION_DEL_SHADER: - //msg is out of date if the associated display is not in the map - if (!g_hash_table_lookup (gst_gl_display_map, GINT_TO_POINTER (msg->glutWinId))) - valid = FALSE; - break; - default: - g_assert_not_reached (); + display->gl_thread = NULL; } - return valid; } -//------------------------------------------------------------ -//------------------ END GL THREAD LOOP ---------------------- -//------------------------------------------------------------ - - //------------------------------------------------------------ //------------------ BEGIN GL THREAD ACTIONS ----------------- //------------------------------------------------------------ @@ -672,30 +394,16 @@ gst_gl_display_thread_check_msg_validity (GstGLDisplayMsg *msg) //in a lock/unlock scope. /* Called in the gl thread */ -static void +static gpointer gst_gl_display_thread_create_context (GstGLDisplay *display) { - gint glutWinId = 0; - gchar buffer[5]; GLenum err = 0; - //prepare opengl context - glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); - glutInitWindowPosition(display->win_xpos, display->win_ypos); - glutInitWindowSize(display->upload_width, display->upload_height); + display->gl_window = gst_gl_window_new (display->upload_width, display->upload_height); - //create opengl context - sprintf(buffer, "%d", glutWinId); + GST_INFO ("gl window created"); - display->title = g_string_append (display->title, buffer); - glutWinId = glutCreateWindow (display->title->str, display->winId); - - GST_INFO ("Context %d created", glutWinId); - - if (display->visible) - glutShowWindow (); - else - glutHideWindow (); + gst_gl_window_visible (display->gl_window, display->visible); //Init glew err = glewInit(); @@ -736,20 +444,21 @@ gst_gl_display_thread_create_context (GstGLDisplay *display) } //setup callbacks - glutReshapeFunc (gst_gl_display_on_resize); - glutDisplayFunc (gst_gl_display_on_draw); - glutCloseFunc (gst_gl_display_on_close); + gst_gl_window_set_resize_callback (display->gl_window, gst_gl_display_on_resize, display); + gst_gl_window_set_draw_callback (display->gl_window, gst_gl_display_on_draw, display); + gst_gl_window_set_close_callback (display->gl_window, gst_gl_display_on_close, display); - //insert glut context to the map - display->glutWinId = glutWinId; - g_hash_table_insert (gst_gl_display_map, GUINT_TO_POINTER (glutWinId), display); - - //check glut id validity - g_assert (glutGetWindow() == glutWinId); - GST_INFO ("Context %d initialized", display->glutWinId); - - //release display constructor g_cond_signal (display->cond_create_context); + + gst_gl_window_run_loop (display->gl_window); + + GST_DEBUG ("loop exited\n"); + + g_object_unref (G_OBJECT (display->gl_window)); + + display->gl_window; + + return NULL; } @@ -757,10 +466,6 @@ gst_gl_display_thread_create_context (GstGLDisplay *display) static void gst_gl_display_thread_destroy_context (GstGLDisplay *display) { - glutSetWindow (display->glutWinId); - glutReshapeFunc (NULL); - glutDestroyWindow (display->glutWinId); - //colorspace_conversion specific switch (display->upload_colorspace_conversion) { @@ -871,74 +576,30 @@ gst_gl_display_thread_destroy_context (GstGLDisplay *display) g_hash_table_foreach_remove (display->texture_pool, gst_gl_display_texture_pool_func_clean, NULL); - g_hash_table_remove (gst_gl_display_map, GINT_TO_POINTER (display->glutWinId)); - GST_INFO ("Context %d destroyed", display->glutWinId); + 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 the map is empty, leaveMainloop and join the thread - if (g_hash_table_size (gst_gl_display_map) == 0) - glutLeaveMainLoop (); - - //release display destructor - g_cond_signal (display->cond_destroy_context); + gst_gl_window_quit_loop (display->gl_window); + + GST_INFO ("Context destroyed"); } -/* Called in the gl thread */ -static void -gst_gl_display_thread_change_context (GstGLDisplay *display) -{ - glutSetWindow (display->glutWinId); - glutChangeWindow (display->winId); - g_cond_signal (display->cond_change_context); -} - - -/* Called in the gl thread */ -static void -gst_gl_display_thread_set_visible_context (GstGLDisplay *display) -{ - glutSetWindow (display->glutWinId); - if (display->visible) - glutShowWindow (); - else - glutHideWindow (); -} - - -/* Called by the idle function */ -static void -gst_gl_display_thread_resize_context (GstGLDisplay* display) -{ - glutSetWindow (display->glutWinId); - glutReshapeWindow (display->resize_width, display->resize_height); -} - - -/* Called in the gl thread */ -static void -gst_gl_display_thread_redisplay (GstGLDisplay * display) -{ - glutSetWindow (display->glutWinId); - glutPostRedisplay (); -} - static void gst_gl_display_thread_run_generic (GstGLDisplay *display) { - glutSetWindow (display->glutWinId); display->generic_callback (display, display->data); - g_cond_signal (display->cond_generic); } + /* Called in the gl thread */ static void gst_gl_display_thread_gen_texture (GstGLDisplay * display) { - glutSetWindow (display->glutWinId); //setup a texture to render to (this one will be in a gl buffer) gst_gl_display_glgen_texture (display, &display->gen_texture, display->gen_texture_width, display->gen_texture_height); - g_cond_signal (display->cond_gen_texture); } @@ -946,10 +607,8 @@ gst_gl_display_thread_gen_texture (GstGLDisplay * display) static void gst_gl_display_thread_del_texture (GstGLDisplay* display) { - glutSetWindow (display->glutWinId); gst_gl_display_gldel_texture (display, &display->del_texture, display->del_texture_width, display->del_texture_height); - g_cond_signal (display->cond_del_texture); } @@ -957,8 +616,6 @@ gst_gl_display_thread_del_texture (GstGLDisplay* display) static void gst_gl_display_thread_init_upload (GstGLDisplay *display) { - glutSetWindow (display->glutWinId); - switch (display->upload_video_format) { case GST_VIDEO_FORMAT_RGBx: @@ -989,7 +646,7 @@ gst_gl_display_thread_init_upload (GstGLDisplay *display) /* shouldn't we require ARB_shading_language_100? --Filippo */ if (GLEW_ARB_fragment_shader) { - GST_INFO ("Context %d, ARB_fragment_shader supported: yes", display->glutWinId); + GST_INFO ("Context, ARB_fragment_shader supported: yes"); display->upload_colorspace_conversion = GST_GL_DISPLAY_CONVERSION_GLSL; @@ -1066,8 +723,8 @@ gst_gl_display_thread_init_upload (GstGLDisplay *display) else if (GLEW_MESA_ycbcr_texture) { //GLSL and Color Matrix are not available on your drivers, switch to YCBCR MESA - GST_INFO ("Context %d, ARB_fragment_shader supported: no", display->glutWinId); - GST_INFO ("Context %d, GLEW_MESA_ycbcr_texture supported: yes", display->glutWinId); + GST_INFO ("Context, ARB_fragment_shader supported: no"); + GST_INFO ("Context, GLEW_MESA_ycbcr_texture supported: yes"); display->upload_colorspace_conversion = GST_GL_DISPLAY_CONVERSION_MESA; @@ -1097,9 +754,9 @@ gst_gl_display_thread_init_upload (GstGLDisplay *display) else if (GLEW_ARB_imaging) { //GLSL is not available on your drivers, switch to Color Matrix - GST_INFO ("Context %d, ARB_fragment_shader supported: no", display->glutWinId); - GST_INFO ("Context %d, GLEW_MESA_ycbcr_texture supported: no", display->glutWinId); - GST_INFO ("Context %d, GLEW_ARB_imaging supported: yes", display->glutWinId); + GST_INFO ("Context, ARB_fragment_shader supported: no"); + GST_INFO ("Context, GLEW_MESA_ycbcr_texture supported: no"); + GST_INFO ("Context, GLEW_ARB_imaging supported: yes"); display->upload_colorspace_conversion = GST_GL_DISPLAY_CONVERSION_MATRIX; @@ -1109,9 +766,9 @@ gst_gl_display_thread_init_upload (GstGLDisplay *display) } else { - GST_WARNING ("Context %d, ARB_fragment_shader supported: no", display->glutWinId); - GST_WARNING ("Context %d, GLEW_ARB_imaging supported: no", display->glutWinId); - GST_WARNING ("Context %d, GLEW_MESA_ycbcr_texture supported: no", display->glutWinId); + GST_WARNING ("Context, ARB_fragment_shader supported: no"); + GST_WARNING ("Context, GLEW_ARB_imaging supported: no"); + GST_WARNING ("Context, GLEW_MESA_ycbcr_texture supported: no"); //turn off the pipeline because colorspace conversion is not possible display->isAlive = FALSE; @@ -1121,8 +778,6 @@ gst_gl_display_thread_init_upload (GstGLDisplay *display) default: g_assert_not_reached (); } - - g_cond_signal (display->cond_init_upload); } @@ -1130,8 +785,6 @@ gst_gl_display_thread_init_upload (GstGLDisplay *display) static void gst_gl_display_thread_do_upload (GstGLDisplay *display) { - glutSetWindow (display->glutWinId); - gst_gl_display_thread_do_upload_fill (display); switch (display->upload_video_format) @@ -1185,8 +838,6 @@ gst_gl_display_thread_do_upload (GstGLDisplay *display) default: g_assert_not_reached (); } - - g_cond_signal (display->cond_do_upload); } @@ -1194,8 +845,6 @@ gst_gl_display_thread_do_upload (GstGLDisplay *display) static void gst_gl_display_thread_init_download (GstGLDisplay *display) { - glutSetWindow (display->glutWinId); - switch (display->download_video_format) { case GST_VIDEO_FORMAT_RGBx: @@ -1220,7 +869,7 @@ gst_gl_display_thread_init_download (GstGLDisplay *display) if (GLEW_EXT_framebuffer_object) { - GST_DEBUG ("Context %d, EXT_framebuffer_object supported: yes", display->glutWinId); + GST_DEBUG ("Context, EXT_framebuffer_object supported: yes"); //-- init output frame buffer object (GL -> video) @@ -1310,7 +959,7 @@ gst_gl_display_thread_init_download (GstGLDisplay *display) { //turn off the pipeline because Frame buffer object is a requirement when using filters //or when using GLSL colorspace conversion - GST_WARNING ("Context %d, EXT_framebuffer_object supported: no", display->glutWinId); + GST_WARNING ("Context, EXT_framebuffer_object supported: no"); display->isAlive = FALSE; } } @@ -1404,7 +1053,7 @@ gst_gl_display_thread_init_download (GstGLDisplay *display) else { //turn off the pipeline because colorspace conversion is not possible - GST_DEBUG ("Context %d, ARB_fragment_shader supported: no", display->glutWinId); + GST_DEBUG ("Context, ARB_fragment_shader supported: no"); display->isAlive = FALSE; } } @@ -1412,8 +1061,6 @@ gst_gl_display_thread_init_download (GstGLDisplay *display) default: g_assert_not_reached (); } - - g_cond_signal (display->cond_init_download); } @@ -1421,8 +1068,6 @@ gst_gl_display_thread_init_download (GstGLDisplay *display) static void gst_gl_display_thread_do_download (GstGLDisplay * display) { - glutSetWindow (display->glutWinId); - switch (display->download_video_format) { case GST_VIDEO_FORMAT_RGBx: @@ -1449,7 +1094,6 @@ gst_gl_display_thread_do_download (GstGLDisplay * display) default: g_assert_not_reached (); } - g_cond_signal (display->cond_do_download); } @@ -1460,8 +1104,6 @@ gst_gl_display_thread_gen_fbo (GstGLDisplay *display) //a texture must be attached to the FBO GLuint fake_texture = 0; - glutSetWindow (display->glutWinId); - //-- generate frame buffer object //setup FBO @@ -1495,8 +1137,6 @@ gst_gl_display_thread_gen_fbo (GstGLDisplay *display) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDeleteTextures (1, &fake_texture); - - g_cond_signal (display->cond_gen_fbo); } @@ -1504,8 +1144,6 @@ gst_gl_display_thread_gen_fbo (GstGLDisplay *display) static void gst_gl_display_thread_use_fbo (GstGLDisplay *display) { - glutSetWindow (display->glutWinId); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, display->use_fbo); //setup a texture to render to @@ -1562,8 +1200,6 @@ gst_gl_display_thread_use_fbo (GstGLDisplay *display) glPopAttrib(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - g_cond_signal (display->cond_use_fbo); } @@ -1571,8 +1207,6 @@ gst_gl_display_thread_use_fbo (GstGLDisplay *display) static void gst_gl_display_thread_del_fbo (GstGLDisplay* display) { - glutSetWindow (display->glutWinId); - if (display->del_fbo) { glDeleteFramebuffersEXT (1, &display->del_fbo); @@ -1583,8 +1217,6 @@ gst_gl_display_thread_del_fbo (GstGLDisplay* display) glDeleteRenderbuffersEXT(1, &display->del_depth_buffer); display->del_depth_buffer = 0; } - - g_cond_signal (display->cond_del_fbo); } @@ -1592,7 +1224,6 @@ gst_gl_display_thread_del_fbo (GstGLDisplay* display) static void gst_gl_display_thread_gen_shader (GstGLDisplay* display) { - glutSetWindow (display->glutWinId); if (GLEW_ARB_fragment_shader) { if (display->gen_shader_vertex_source || @@ -1633,7 +1264,6 @@ gst_gl_display_thread_gen_shader (GstGLDisplay* display) display->isAlive = FALSE; display->gen_shader = NULL; } - g_cond_signal (display->cond_gen_shader); } @@ -1641,13 +1271,11 @@ gst_gl_display_thread_gen_shader (GstGLDisplay* display) static void gst_gl_display_thread_del_shader (GstGLDisplay* display) { - glutSetWindow (display->glutWinId); if (display->del_shader) { g_object_unref (G_OBJECT (display->del_shader)); display->del_shader = NULL; } - g_cond_signal (display->cond_del_shader); } @@ -1675,37 +1303,9 @@ gst_gl_display_unlock (GstGLDisplay * display) } -/* Post a message that will be handled by the gl thread - * Must be preceded by gst_gl_display_lock - * and followed by gst_gl_display_unlock - * Called in the public functions */ void -gst_gl_display_post_message (GstGLDisplayAction action, GstGLDisplay* display) +gst_gl_display_on_resize (GstGLDisplay* display, gint width, gint height) { - GstGLDisplayMsg* msg = g_new0 (GstGLDisplayMsg, 1); - msg->action = action; - msg->glutWinId = display->glutWinId; - msg->display = display; - g_async_queue_push (gst_gl_display_messageQueue, msg); -} - - -/* glutReshapeFunc callback */ -void -gst_gl_display_on_resize (gint width, gint height) -{ - gint glutWinId = 0; - GstGLDisplay *display = NULL; - - //retrieve the display associated to the glut context - glutWinId = glutGetWindow (); - display = g_hash_table_lookup (gst_gl_display_map, GINT_TO_POINTER (glutWinId)); - - //glutGetWindow return 0 if no windows exists, then g_hash_table_lookup return NULL - if (display == NULL) return; - - gst_gl_display_lock (display); - //check if a client reshape callback is registered if (display->clientReshapeCallback) display->clientReshapeCallback(width, height); @@ -1719,33 +1319,14 @@ gst_gl_display_on_resize (gint width, gint height) gluOrtho2D(0, width, 0, height); glMatrixMode(GL_MODELVIEW); } - - gst_gl_display_unlock (display); } -/* glutDisplayFunc callback */ -void gst_gl_display_on_draw(void) + +void gst_gl_display_on_draw(GstGLDisplay* display) { - gint glutWinId = 0; - GstGLDisplay *display = NULL; - - //retrieve the display associated to the glut context - glutWinId = glutGetWindow (); - display = g_hash_table_lookup (gst_gl_display_map, GINT_TO_POINTER (glutWinId)); - - //glutGetWindow return 0 if no windows exists, then g_hash_table_lookup return NULL - if (display == NULL) return; - - //lock the display because gstreamer elements - //(and so the main thread) may modify it - gst_gl_display_lock (display); - //check if video format has been setup if (!display->redisplay_texture) - { - gst_gl_display_unlock (display); return; - } //opengl scene @@ -1759,14 +1340,11 @@ void gst_gl_display_on_draw(void) if (display->clientDrawCallback) { gboolean doRedisplay = - display->clientDrawCallback(display->redisplay_texture, + display->clientDrawCallback (display->redisplay_texture, display->redisplay_texture_width, display->redisplay_texture_height); - glFlush(); - glutSwapBuffers(); - if (doRedisplay) - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_REDISPLAY_CONTEXT, display); + gst_gl_window_draw (display->gl_window); } //default opengl scene else @@ -1792,31 +1370,13 @@ void gst_gl_display_on_draw(void) glEnd (); glDisable(GL_TEXTURE_RECTANGLE_ARB); - - glFlush(); - glutSwapBuffers(); - }//end default opengl scene - - gst_gl_display_unlock (display); } -/* glutCloseFunc callback */ -void gst_gl_display_on_close (void) +void gst_gl_display_on_close (GstGLDisplay* display) { - gint glutWinId = 0; - GstGLDisplay* display = NULL; - - //retrieve the display associated to the glut context - glutWinId = glutGetWindow (); - display = g_hash_table_lookup (gst_gl_display_map, GINT_TO_POINTER (glutWinId)); - - //glutGetWindow return 0 if no windows exists, then g_hash_table_lookup return NULL - if (display == NULL) return; - GST_INFO ("on close"); - gst_gl_display_lock (display); display->isAlive = FALSE; gst_gl_display_unlock (display); @@ -2034,22 +1594,11 @@ gst_gl_display_create_context (GstGLDisplay *display, display->upload_height = height; display->visible = visible; - //if no glut_thread exists, create it with a window associated to the display - if (!gst_gl_display_map) - { - gst_gl_display_messageQueue = g_async_queue_new (); - gst_gl_display_map = g_hash_table_new (g_direct_hash, g_direct_equal); - gst_gl_display_gl_thread = g_thread_create ( - (GThreadFunc) gst_gl_display_thread_func, display, TRUE, NULL); - g_cond_wait (display->cond_create_context, display->mutex); - } - //request glut window creation - else - { - //blocking call because glut context must be alive - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_CREATE_CONTEXT, display); - g_cond_wait (display->cond_create_context, display->mutex); - } + display->gl_thread = g_thread_create ( + (GThreadFunc) gst_gl_display_thread_create_context, display, TRUE, NULL); + + g_cond_wait (display->cond_create_context, display->mutex); + gst_gl_display_unlock (display); } @@ -2062,7 +1611,7 @@ gst_gl_display_set_visible_context (GstGLDisplay* display, gboolean visible) if (display->visible != visible) { display->visible = visible; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_VISIBLE_CONTEXT, display); + gst_gl_window_visible (display->gl_window, visible); } gst_gl_display_unlock (display); } @@ -2075,14 +1624,14 @@ gst_gl_display_resize_context (GstGLDisplay* display, gint width, gint height) gst_gl_display_lock (display); display->resize_width = width; display->resize_height = height; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_RESIZE_CONTEXT, display); + gst_gl_window_resize (display->gl_window, display->resize_width, display->resize_height); gst_gl_display_unlock (display); } /* Called by the glimagesink element */ gboolean -gst_gl_display_redisplay (GstGLDisplay* display, GLuint texture, gint width , gint height) +gst_gl_display_redisplay (GstGLDisplay* display, GLuint texture, gint width, gint height) { gboolean isAlive = TRUE; @@ -2096,7 +1645,7 @@ gst_gl_display_redisplay (GstGLDisplay* display, GLuint texture, gint width , gi display->redisplay_texture_width = width; display->redisplay_texture_height = height; } - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_REDISPLAY_CONTEXT, display); + gst_gl_window_draw (display->gl_window); } gst_gl_display_unlock (display); @@ -2110,8 +1659,7 @@ gst_gl_display_thread_add (GstGLDisplay *display, gst_gl_display_lock (display); display->data = data; display->generic_callback = func; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_GENERIC, display); - g_cond_wait (display->cond_generic, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_run_generic, display); gst_gl_display_unlock (display); } @@ -2122,8 +1670,7 @@ gst_gl_display_gen_texture (GstGLDisplay* display, GLuint* pTexture, GLint width gst_gl_display_lock (display); display->gen_texture_width = width; display->gen_texture_height = height; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_GEN_TEXTURE, display); - g_cond_wait (display->cond_gen_texture, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_gen_texture, display); *pTexture = display->gen_texture; gst_gl_display_unlock (display); } @@ -2139,8 +1686,7 @@ gst_gl_display_del_texture (GstGLDisplay* display, GLuint texture, GLint width, display->del_texture = texture; display->del_texture_width = width; display->del_texture_height = height; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_DEL_TEXTURE, display); - g_cond_wait (display->cond_del_texture, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_del_texture, display); } gst_gl_display_unlock (display); } @@ -2158,8 +1704,7 @@ gst_gl_display_init_upload (GstGLDisplay* display, GstVideoFormat video_format, display->upload_height = gl_height; display->upload_data_width = video_width; display->upload_data_height = video_height; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_INIT_UPLOAD, display); - g_cond_wait (display->cond_init_upload, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_init_upload, display); gst_gl_display_unlock (display); } @@ -2180,8 +1725,7 @@ gst_gl_display_do_upload (GstGLDisplay *display, GLuint texture, display->upload_data_width = data_width; display->upload_data_height = data_height; display->upload_data = data; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_DO_UPLOAD, display); - g_cond_wait (display->cond_do_upload, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_do_upload, display); } gst_gl_display_unlock (display); @@ -2198,8 +1742,7 @@ gst_gl_display_init_download (GstGLDisplay* display, GstVideoFormat video_format display->download_video_format = video_format; display->download_width = width; display->download_height = height; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_INIT_DOWNLOAD, display); - g_cond_wait (display->cond_init_download, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_init_download, display); gst_gl_display_unlock (display); } @@ -2221,8 +1764,7 @@ gst_gl_display_do_download (GstGLDisplay* display, GLuint texture, display->ouput_texture = texture; display->ouput_texture_width = width; display->ouput_texture_height = height; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_DO_DOWNLOAD, display); - g_cond_wait (display->cond_do_download, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_do_download, display); } gst_gl_display_unlock (display); @@ -2240,8 +1782,7 @@ gst_gl_display_gen_fbo (GstGLDisplay* display, gint width, gint height, { display->gen_fbo_width = width; display->gen_fbo_height = height; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_GEN_FBO, display); - g_cond_wait (display->cond_gen_fbo, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_gen_fbo, display); *fbo = display->generated_fbo; *depthbuffer = display->generated_depth_buffer; } @@ -2286,8 +1827,7 @@ gst_gl_display_use_fbo (GstGLDisplay* display, gint texture_fbo_width, gint text display->input_texture_width = input_texture_width; display->input_texture_height = input_texture_height; display->input_texture = input_texture; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_USE_FBO, display); - g_cond_wait (display->cond_use_fbo, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_use_fbo, display); } gst_gl_display_unlock (display); @@ -2303,8 +1843,7 @@ gst_gl_display_del_fbo (GstGLDisplay* display, GLuint fbo, gst_gl_display_lock (display); display->del_fbo = fbo; display->del_depth_buffer = depth_buffer; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_DEL_FBO, display); - g_cond_wait (display->cond_del_fbo, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_del_fbo, display); gst_gl_display_unlock (display); } @@ -2319,8 +1858,7 @@ gst_gl_display_gen_shader (GstGLDisplay* display, gst_gl_display_lock (display); display->gen_shader_vertex_source = shader_vertex_source; display->gen_shader_fragment_source = shader_fragment_source; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_GEN_SHADER, display); - g_cond_wait (display->cond_gen_shader, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_gen_shader, display); if (shader) *shader = display->gen_shader; display->gen_shader = NULL; @@ -2336,8 +1874,7 @@ gst_gl_display_del_shader (GstGLDisplay* display, GstGLShader* shader) { gst_gl_display_lock (display); display->del_shader = shader; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_DEL_SHADER, display); - g_cond_wait (display->cond_del_shader, display->mutex); + gst_gl_window_send_message (display->gl_window, gst_gl_display_thread_del_shader, display); gst_gl_display_unlock (display); } @@ -2350,8 +1887,7 @@ gst_gl_display_set_window_id (GstGLDisplay* display, gulong winId) //otehrwise it can directly create the gl context using the winId gst_gl_display_lock (display); display->winId = winId; - gst_gl_display_post_message (GST_GL_DISPLAY_ACTION_CHANGE_CONTEXT, display); - g_cond_wait (display->cond_change_context, display->mutex); + gst_gl_window_set_external_window_id (display->gl_window, display->winId); gst_gl_display_unlock (display); } @@ -2389,7 +1925,7 @@ void gst_gl_display_thread_init_upload_fbo (GstGLDisplay *display) //a texture must be attached to the FBO GLuint fake_texture = 0; - GST_INFO ("Context %d, EXT_framebuffer_object supported: yes", display->glutWinId); + GST_INFO ("Context, EXT_framebuffer_object supported: yes"); //-- init intput frame buffer object (video -> GL) @@ -2433,7 +1969,7 @@ void gst_gl_display_thread_init_upload_fbo (GstGLDisplay *display) else { //turn off the pipeline because Frame buffer object is a not present - GST_WARNING ("Context %d, EXT_framebuffer_object supported: no", display->glutWinId); + GST_WARNING ("Context, EXT_framebuffer_object supported: no"); display->isAlive = FALSE; } } diff --git a/gst-libs/gst/gl/gstgldisplay.h b/gst-libs/gst/gl/gstgldisplay.h index 6fc9776322..ee81188457 100644 --- a/gst-libs/gst/gl/gstgldisplay.h +++ b/gst-libs/gst/gl/gstgldisplay.h @@ -23,10 +23,7 @@ #ifndef __GST_GL_H__ #define __GST_GL_H__ -#include -#include - -#include +#include #include #include "gstglshader.h" @@ -114,9 +111,9 @@ struct _GstGLDisplay { GMutex* mutex; //gl context - gint glutWinId; + GThread* gl_thread; + GstGLWindow* gl_window; gulong winId; - GString* title; gint win_xpos; gint win_ypos; gboolean visible; @@ -125,20 +122,6 @@ struct _GstGLDisplay { //conditions GCond* cond_create_context; - GCond* cond_destroy_context; - GCond* cond_change_context; - GCond* cond_generic; - GCond* cond_gen_texture; - GCond* cond_del_texture; - GCond* cond_init_upload; - GCond* cond_do_upload; - GCond* cond_init_download; - GCond* cond_do_download; - GCond* cond_gen_fbo; - GCond* cond_use_fbo; - GCond* cond_del_fbo; - GCond* cond_gen_shader; - GCond* cond_del_shader; //generic gl code GstGLDisplayThreadFunc generic_callback; diff --git a/gst-libs/gst/gl/gstglwindow.h b/gst-libs/gst/gl/gstglwindow.h new file mode 100644 index 0000000000..1f04758372 --- /dev/null +++ b/gst-libs/gst/gl/gstglwindow.h @@ -0,0 +1,88 @@ +/* + * GStreamer + * Copyright (C) 2008 Julien Isorce + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_GL_WINDOW_H__ +#define __GST_GL_WINDOW_H__ + + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_GL_TYPE_WINDOW (gst_gl_window_get_type()) +#define GST_GL_WINDOW(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_WINDOW, GstGLWindow)) +#define GST_GL_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_WINDOW, GstGLWindowClass)) +#define GST_GL_IS_WINDOW(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_WINDOW)) +#define GST_GL_IS_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_WINDOW)) +#define GST_GL_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_WINDOW, GstGLWindowClass)) + +#define GST_GL_WINDOW_ERROR (gst_gl_window_error_quark ()) + +typedef void (* GstGLWindowCB) ( gpointer ); +typedef void (* GstGLWindowCB2) ( gpointer, gint, gint ); + +typedef struct _GstGLWindow GstGLWindow; +typedef struct _GstGLWindowPrivate GstGLWindowPrivate; +typedef struct _GstGLWindowClass GstGLWindowClass; + +struct _GstGLWindow { + /*< private >*/ + GObject parent; + GstGLWindowPrivate *priv; +}; + +struct _GstGLWindowClass { + /*< private >*/ + GObjectClass parent_class; + guint64 instance; +}; + +/* methods */ + +GQuark gst_gl_window_error_quark (void); +GType gst_gl_window_get_type (void); + +GstGLWindow * gst_gl_window_new (gint width, gint height); + +void gst_gl_window_set_external_window_id (GstGLWindow *window, guint64 id); +void gst_gl_window_set_external_gl_context (GstGLWindow *window, guint64 context); +void gst_gl_window_set_draw_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data); +void gst_gl_window_set_resize_callback (GstGLWindow *window, GstGLWindowCB2 callback, gpointer data); +void gst_gl_window_set_close_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data); + +gboolean gst_gl_window_has_internal_window_id (GstGLWindow *window); +gboolean gst_gl_window_has_internal_gl_context (GstGLWindow *window); + +guint64 gst_gl_window_get_window_id (GstGLWindow *window); +guint64 gst_gl_window_get_gl_context (GstGLWindow *window); + +void gst_gl_window_visible (GstGLWindow *window, gboolean visible); +void gst_gl_window_draw (GstGLWindow *window); +void gst_gl_window_resize (GstGLWindow *window, gint width, gint height); +void gst_gl_window_run_loop (GstGLWindow *window); +void gst_gl_window_quit_loop (GstGLWindow *window); + +void gst_gl_window_send_message (GstGLWindow *window, GstGLWindowCB callback, gpointer data); + +G_END_DECLS + +#endif /* __GST_GL_WINDOW_H__ */ diff --git a/gst-libs/gst/gl/gstglwindow_win32.c b/gst-libs/gst/gl/gstglwindow_win32.c new file mode 100644 index 0000000000..6b1467028f --- /dev/null +++ b/gst-libs/gst/gl/gstglwindow_win32.c @@ -0,0 +1,542 @@ +/* + * GStreamer + * Copyright (C) 2008 Julien Isorce + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#undef UNICODE +#include +#define UNICODE + +#include "gstglwindow.h" + + +#define WM_GSTGLWINDOW (WM_APP+1) + +void gst_gl_window_set_pixel_format (GstGLWindow *window); +LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#define GST_GL_WINDOW_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_WINDOW, GstGLWindowPrivate)) + +enum +{ + PROP_0 +}; + +struct _GstGLWindowPrivate +{ + HWND internal_win_id; + HWND external_win_id; + HDC device; + HGLRC gl_context; + gboolean has_external_window_id; + gboolean has_external_gl_context; + GstGLWindowCB draw_cb; + gpointer draw_data; + GstGLWindowCB2 resize_cb; + gpointer resize_data; + GstGLWindowCB close_cb; + gpointer close_data; +}; + +G_DEFINE_TYPE (GstGLWindow, gst_gl_window, G_TYPE_OBJECT); + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "GstGLWindow" + +gboolean _gst_gl_window_debug = FALSE; + +/* Must be called in the gl thread */ +static void +gst_gl_window_finalize (GObject * object) +{ + GstGLWindow *window = GST_GL_WINDOW (object); + GstGLWindowPrivate *priv = window->priv; + + G_OBJECT_CLASS (gst_gl_window_parent_class)->finalize (object); +} + +static void +gst_gl_window_log_handler (const gchar *domain, GLogLevelFlags flags, + const gchar *message, gpointer user_data) +{ + if (_gst_gl_window_debug) { + g_log_default_handler (domain, flags, message, user_data); + } +} + +static void +gst_gl_window_class_init (GstGLWindowClass * klass) +{ + WNDCLASS wc; + GObjectClass *obj_class = G_OBJECT_CLASS (klass); + klass->instance = (guint64) GetModuleHandle (NULL); + + g_type_class_add_private (klass, sizeof (GstGLWindowPrivate)); + + obj_class->finalize = gst_gl_window_finalize; + + GetClassInfo ((HINSTANCE)klass->instance, "GSTGL", &wc); + + ZeroMemory (&wc, sizeof(WNDCLASS)); + + wc.lpfnWndProc = window_proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = (HINSTANCE) klass->instance; + wc.hIcon = LoadIcon( NULL, IDI_WINLOGO ); + wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wc.hCursor = LoadCursor( NULL, IDC_ARROW ); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = "GSTGL"; + + RegisterClass (&wc); +} + +static void +gst_gl_window_init (GstGLWindow *window) +{ + window->priv = GST_GL_WINDOW_GET_PRIVATE (window); + + if (g_getenv ("GST_GL_WINDOW_DEBUG") != NULL) + _gst_gl_window_debug = TRUE; + + g_log_set_handler ("GstGLWindow", G_LOG_LEVEL_DEBUG, + gst_gl_window_log_handler, NULL); +} + +/* Must be called in the gl thread */ +GstGLWindow * +gst_gl_window_new (gint width, gint height) +{ + GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL); + GstGLWindowPrivate *priv = window->priv; + GstGLWindowClass* klass = GST_GL_WINDOW_GET_CLASS (window); + + static gint x = 50; + static gint y = 0; + y = 50 + height * y++; + + priv->internal_win_id = 0; + priv->external_win_id = 0; + priv->device = 0; + priv->gl_context = 0; + priv->has_external_window_id = FALSE; + priv->has_external_gl_context = FALSE; + priv->draw_cb = NULL; + priv->draw_data = NULL; + priv->resize_cb = NULL; + priv->resize_data = NULL; + priv->close_cb = NULL; + priv->close_data = NULL; + + width += 2 * GetSystemMetrics (SM_CXSIZEFRAME); + height += 2 * GetSystemMetrics (SM_CYSIZEFRAME) + GetSystemMetrics (SM_CYCAPTION); + + priv->internal_win_id = CreateWindowEx ( + 0, + "GSTGL", + "OpenGL renderer", + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, + x, y, width, height, + (HWND) NULL, + (HMENU) NULL, + (HINSTANCE) klass->instance, + window + ); + + g_assert (priv->internal_win_id); + + //device is set in the window_proc + g_assert (priv->device); + + UpdateWindow (priv->internal_win_id); + ShowCursor (TRUE); + + wglMakeCurrent (priv->device, priv->gl_context); + + return window; +} + +GQuark +gst_gl_window_error_quark (void) +{ + return g_quark_from_static_string ("gst-gl-window-error"); +} + +void +gst_gl_window_set_external_window_id (GstGLWindow *window, guint64 id) +{ + g_warning ("gst_gl_window_set_external_window_id: not implemented\n"); +} + +void +gst_gl_window_set_external_gl_context (GstGLWindow *window, guint64 context) +{ + g_warning ("gst_gl_window_set_external_gl_context: not implemented\n"); +} + +/* Must be called in the gl thread */ +void +gst_gl_window_set_draw_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data) +{ + GstGLWindowPrivate *priv = window->priv; + + priv->draw_cb = callback; + priv->draw_data = data; +} + +/* Must be called in the gl thread */ +void +gst_gl_window_set_resize_callback (GstGLWindow *window, GstGLWindowCB2 callback , gpointer data) +{ + GstGLWindowPrivate *priv = window->priv; + + priv->resize_cb = callback; + priv->resize_data = data; +} + +/* Must be called in the gl thread */ +void +gst_gl_window_set_close_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data) +{ + GstGLWindowPrivate *priv = window->priv; + + priv->close_cb = callback; + priv->close_data = data; +} + +/* Must be called in the gl thread */ +gboolean +gst_gl_window_has_external_window_id (GstGLWindow *window) +{ + gboolean has_internal_window_id = TRUE; + GstGLWindowPrivate *priv = window->priv; + + has_internal_window_id = priv->has_external_window_id; + + return has_internal_window_id; +} + +/* Must be called in the gl thread */ +gboolean +gst_gl_window_has_internal_gl_context (GstGLWindow *window) +{ + gboolean has_external_gl_context = TRUE; + GstGLWindowPrivate *priv = window->priv; + + + has_external_gl_context = priv->has_external_gl_context; + + + return has_external_gl_context; +} + +/* Must be called in the gl thread */ +guint64 gst_gl_window_get_window_id (GstGLWindow *window) +{ + g_warning ("gst_gl_window_get_window_id: not implemented\n"); + + return 0; +} + +/* Must be called in the gl thread */ +guint64 +gst_gl_window_get_gl_context (GstGLWindow *window) +{ + g_warning ("gst_gl_window_get_gl_context: not implemented\n"); + + return 0; +} + +/* Thread safe */ +void +gst_gl_window_visible (GstGLWindow *window, gboolean visible) +{ + GstGLWindowPrivate *priv = window->priv; + BOOL ret = FALSE; + + if (visible) + ret = ShowWindow (priv->internal_win_id, SW_SHOW); + else + ret = ShowWindow (priv->internal_win_id, SW_HIDE); +} + +/* Thread safe */ +void +gst_gl_window_draw (GstGLWindow *window) +{ + GstGLWindowPrivate *priv = window->priv; + + if (!priv->has_external_window_id) + RedrawWindow (priv->internal_win_id, NULL, NULL, + RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE /*| RDW_UPDATENOW*/); + else + { + PAINTSTRUCT ps; + + /*RECT destsurf_rect; + POINT dest_surf_point; + + dest_surf_point.x = 0; + dest_surf_point.y = 0; + ClientToScreen (priv->external_win_id, &dest_surf_point); + GetClientRect (priv->external_win_id, &destsurf_rect); + OffsetRect (&destsurf_rect, dest_surf_point.x, dest_surf_point.y); + + if (window->State.Width != (destsurf_rect.right - destsurf_rect.left) || + window->State.Height != (destsurf_rect.bottom - destsurf_rect.top)) + { + window->State.Width = destsurf_rect.right - destsurf_rect.left; + window->State.Height = destsurf_rect.bottom - destsurf_rect.top; + window->State.NeedToResize = GL_FALSE; + if( FETCH_WCB( *window, Reshape ) ) + INVOKE_WCB( *window, Reshape, ( window->State.Width, window->State.Height ) ); + glViewport( 0, 0, window->State.Width, window->State.Height ); + }*/ + + BeginPaint (priv->external_win_id, &ps); + priv->draw_cb (priv->draw_data); //FIXME: wrong thread caller + //glFlush(); + SwapBuffers (priv->device); + EndPaint (priv->external_win_id, &ps); + } +} + +/* Thread safe */ +void +gst_gl_window_resize (GstGLWindow *window, gint width, gint height) +{ + GstGLWindowPrivate *priv = window->priv; + gint x = 0; + gint y = 0; + RECT winRect; + + GetWindowRect (priv->internal_win_id, &winRect); + x = winRect.left; + y = winRect.top; + + width += 2 * GetSystemMetrics (SM_CXSIZEFRAME); + height += 2 * GetSystemMetrics (SM_CYSIZEFRAME) + GetSystemMetrics (SM_CYCAPTION); + + SetWindowPos (priv->internal_win_id, HWND_TOP, x, y, width, height, + SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOZORDER); +} + +void +gst_gl_window_run_loop (GstGLWindow *window) +{ + GstGLWindowPrivate *priv = window->priv; + gboolean running = TRUE; + gboolean bRet = FALSE; + MSG msg; + + g_debug ("start loop\n"); + + while (running && (bRet = GetMessage (&msg, NULL, 0, 0)) != 0) + { + if (bRet == -1) + { + g_debug ("error in gst_gl_window_run_loop\n"); + running = FALSE; + } + else + { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + } + /*while (GetMessage (&msg, priv->internal_win_id, 0, 0)) + { + TranslateMessage (&msg); + DispatchMessage (&msg); + }*/ + g_debug ("loop terminated\n"); +} + +/* Must be called in the gl thread */ +void +gst_gl_window_quit_loop (GstGLWindow *window) +{ + PostQuitMessage(0); +} + +void +gst_gl_window_send_message (GstGLWindow *window, GstGLWindowCB callback, gpointer data) +{ + GstGLWindowPrivate *priv = NULL; + LRESULT res; + g_assert (window); + priv = window->priv; + res = SendMessage (priv->internal_win_id, WM_GSTGLWINDOW, (WPARAM) data, (LPARAM) callback); + g_assert (SUCCEEDED (res)); +} + +/* PRIVATE */ + +void +gst_gl_window_set_pixel_format (GstGLWindow *window) +{ + GstGLWindowPrivate *priv = window->priv; + PIXELFORMATDESCRIPTOR pfd; + gint pixelformat = 0; + gboolean res = FALSE; + + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + pfd.cRedBits = 0; + pfd.cRedShift = 0; + pfd.cGreenBits = 0; + pfd.cGreenShift = 0; + pfd.cBlueBits = 0; + pfd.cBlueShift = 0; + pfd.cAlphaBits = 0; + pfd.cAlphaShift = 0; + pfd.cAccumBits = 0; + pfd.cAccumRedBits = 0; + pfd.cAccumGreenBits = 0; + pfd.cAccumBlueBits = 0; + pfd.cAccumAlphaBits = 0; + pfd.cDepthBits = 24; + pfd.cStencilBits = 8; + pfd.cAuxBuffers = 0; + pfd.iLayerType = PFD_MAIN_PLANE; + pfd.bReserved = 0; + pfd.dwLayerMask = 0; + pfd.dwVisibleMask = 0; + pfd.dwDamageMask = 0; + + pfd.cColorBits = (BYTE) GetDeviceCaps (priv->device, BITSPIXEL); + + pixelformat = ChoosePixelFormat (priv->device, &pfd ); + + g_assert (pixelformat); + + res = SetPixelFormat (priv->device, pixelformat, &pfd); + + g_assert (res); +} + +LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static gboolean created = FALSE; + + if (uMsg == WM_CREATE) { + + GstGLWindow *window = (GstGLWindow *) (((LPCREATESTRUCT) lParam)->lpCreateParams); + + g_debug ("WM_CREATE\n"); + + SetWindowLongPtr (hWnd, GWLP_USERDATA, (LONG)(guint64)(gpointer) window); + + g_assert (window); + + { + GstGLWindowPrivate *priv = window->priv; + priv->device = GetDC (hWnd); + gst_gl_window_set_pixel_format (window); + priv->gl_context = wglCreateContext (priv->device); + ReleaseDC (hWnd, priv->device); + } + + created = TRUE; + } + else if (created) { + + GstGLWindow *window = (GstGLWindow *) (guint64) GetWindowLongPtr(hWnd, GWLP_USERDATA); + GstGLWindowPrivate *priv = NULL; + + g_assert (window); + + priv = window->priv; + + g_assert (priv); + + switch ( uMsg ) { + + case WM_SIZE: + { + g_debug ("WM_SIZE\n"); + if (priv->resize_cb) + priv->resize_cb (priv->resize_data, LOWORD(lParam), HIWORD(lParam)); + break; + } + + case WM_PAINT: + { + g_debug ("WM_PAINT\n"); + if (priv->draw_cb) + { + PAINTSTRUCT ps; + BeginPaint (hWnd, &ps); + priv->draw_cb (priv->draw_data); + SwapBuffers (priv->device); + EndPaint (hWnd, &ps); + } + break; + } + + case WM_CLOSE: + { + g_debug ("WM_CLOSE\n"); + if (priv->close_cb) + priv->close_cb (priv->close_data); + DestroyWindow(hWnd); + break; + } + + case WM_DESTROY: + { + g_debug ("WM_DESTROY\n"); + created = FALSE; + PostQuitMessage (0); + break; + } + + case WM_CAPTURECHANGED: + { + g_debug ("WM_CAPTURECHANGED\n"); + if (priv->draw_cb) + priv->draw_cb (priv->draw_data); + break; + } + + case WM_GSTGLWINDOW: + { + GstGLWindowCB custom_cb = (GstGLWindowCB) lParam; + + g_debug ("WM_GSTGLWINDOW\n"); + custom_cb ((gpointer) wParam); + break; + } + + default: + break; + } + } + + return DefWindowProc( hWnd, uMsg, wParam, lParam ); +}