From 61a8f3444226fd561f5c16f2cdc9a3d069568620 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Sun, 15 Mar 2009 14:48:19 +0100 Subject: [PATCH] [321/906] add OpenGL ES 2.x support. In OpenGL 2.x for Embedded System, a lot of basic scene/draw functions have been removed. It means that everything is made using vertex and fragment shaders. I have also added a gstglwindow backend for winCE that uses EGL (Native Platform Graphics Intercace) (which is a full part of OpenGL ES specification). It remove the use of wgl/glx functions. --- gst-libs/gst/gl/gstgldisplay.c | 730 +++++++++++++++++++++++++++- gst-libs/gst/gl/gstgldisplay.h | 22 + gst-libs/gst/gl/gstgles2.h | 117 +++++ gst-libs/gst/gl/gstglshader.c | 16 + gst-libs/gst/gl/gstglshader.h | 9 + gst-libs/gst/gl/gstglwindow.h | 10 + gst-libs/gst/gl/gstglwindow_winCE.c | 610 +++++++++++++++++++++++ 7 files changed, 1491 insertions(+), 23 deletions(-) create mode 100644 gst-libs/gst/gl/gstgles2.h create mode 100644 gst-libs/gst/gl/gstglwindow_winCE.c diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c index e250117939..42f3abfdb9 100644 --- a/gst-libs/gst/gl/gstgldisplay.c +++ b/gst-libs/gst/gl/gstgldisplay.c @@ -51,6 +51,9 @@ void gst_gl_display_thread_destroy_context (GstGLDisplay * display); void gst_gl_display_thread_run_generic (GstGLDisplay * display); void gst_gl_display_thread_gen_texture (GstGLDisplay * display); void gst_gl_display_thread_del_texture (GstGLDisplay * display); +#ifdef OPENGL_ES2 +void gst_gl_display_thread_init_redisplay (GstGLDisplay * display); +#endif void gst_gl_display_thread_init_upload (GstGLDisplay * display); void gst_gl_display_thread_do_upload (GstGLDisplay * display); void gst_gl_display_thread_init_download (GstGLDisplay * display); @@ -122,6 +125,11 @@ gst_gl_display_init (GstGLDisplay * display, GstGLDisplayClass * klass) display->redisplay_texture = 0; display->redisplay_texture_width = 0; display->redisplay_texture_height = 0; +#ifdef OPENGL_ES2 + display->redisplay_shader = NULL; + display->redisplay_attr_position_loc = 0; + display->redisplay_attr_texture_loc = 0; +#endif //action gen and del texture display->gen_texture = 0; @@ -197,78 +205,142 @@ gst_gl_display_init (GstGLDisplay * display, GstGLDisplayClass * klass) display->gen_shader = NULL; display->del_shader = NULL; - //fragement shader upload + //fragment shader upload display->shader_upload_YUY2 = NULL; display->shader_upload_UYVY = NULL; display->shader_upload_I420_YV12 = NULL; display->shader_upload_AYUV = NULL; - //fragement shader download +#ifdef OPENGL_ES2 + display->shader_upload_attr_position_loc = 0; + display->shader_upload_attr_texture_loc = 0; +#endif + + //fragment shader download display->shader_download_YUY2 = NULL; display->shader_download_UYVY = NULL; display->shader_download_I420_YV12 = NULL; display->shader_download_AYUV = NULL; +#ifdef OPENGL_ES2 + display->shader_download_attr_position_loc = 0; + display->shader_download_attr_texture_loc = 0; + display->shader_download_RGB = NULL; +#endif + //YUY2:r,g,a //UYVY:a,b,r display->text_shader_upload_YUY2_UYVY = +#ifndef OPENGL_ES2 "#extension GL_ARB_texture_rectangle : enable\n" "uniform sampler2DRect Ytex, UVtex;\n" +#else + "precision mediump float;\n" + "varying vec2 v_texCoord;\n" + "uniform sampler2D Ytex, UVtex;\n" +#endif "void main(void) {\n" " float fx, fy, y, u, v, r, g, b;\n" - " fx = gl_TexCoord[0].x;\n" - " fy = gl_TexCoord[0].y;\n" +#ifndef OPENGL_ES2 + " fx = gl_TexCoord[0].x;\n" + " fy = gl_TexCoord[0].y;\n" " y = texture2DRect(Ytex,vec2(fx,fy)).%c;\n" " u = texture2DRect(UVtex,vec2(fx*0.5,fy)).%c;\n" " v = texture2DRect(UVtex,vec2(fx*0.5,fy)).%c;\n" +#else + " fx = v_texCoord.x;\n" + " fy = v_texCoord.y;\n" + " y = texture2D(Ytex,vec2(fx,fy)).%c;\n" + " u = texture2D(UVtex,vec2(fx*0.5,fy)).%c;\n" + " v = texture2D(UVtex,vec2(fx*0.5,fy)).%c;\n" +#endif " y=1.164*(y-0.0627);\n" " u=u-0.5;\n" " v=v-0.5;\n" " r = y+1.5958*v;\n" " g = y-0.39173*u-0.81290*v;\n" - " b = y+2.017*u;\n" " gl_FragColor = vec4(r, g, b, 1.0);\n" "}\n"; + " b = y+2.017*u;\n" + " gl_FragColor = vec4(r, g, b, 1.0);\n" + "}\n"; //ATI: "*0.5", "" //normal: "", "*0.5" display->text_shader_upload_I420_YV12 = +#ifndef OPENGL_ES2 "#extension GL_ARB_texture_rectangle : enable\n" "uniform sampler2DRect Ytex,Utex,Vtex;\n" +#else + "precision mediump float;\n" + "varying vec2 v_texCoord;\n" + "uniform sampler2D Ytex,Utex,Vtex;\n" +#endif "void main(void) {\n" " float r,g,b,y,u,v;\n" - " vec2 nxy=gl_TexCoord[0].xy;\n" +#ifndef OPENGL_ES2 + " vec2 nxy = gl_TexCoord[0].xy;\n" " y=texture2DRect(Ytex,nxy%s).r;\n" " u=texture2DRect(Utex,nxy%s).r;\n" " v=texture2DRect(Vtex,nxy*0.5).r;\n" +#else + " vec2 nxy = v_texCoord.xy;\n" + " y=texture2D(Ytex,nxy).r;\n" + " u=texture2D(Utex,nxy).r;\n" + " v=texture2D(Vtex,nxy).r;\n" +#endif " y=1.1643*(y-0.0625);\n" " u=u-0.5;\n" " v=v-0.5;\n" " r=y+1.5958*v;\n" " g=y-0.39173*u-0.81290*v;\n" - " b=y+2.017*u;\n" " gl_FragColor=vec4(r,g,b,1.0);\n" "}\n"; + " b=y+2.017*u;\n" + " gl_FragColor=vec4(r,g,b,1.0);\n" + "}\n"; display->text_shader_upload_AYUV = +#ifndef OPENGL_ES2 "#extension GL_ARB_texture_rectangle : enable\n" "uniform sampler2DRect tex;\n" +#else + "precision mediump float;\n" + "varying vec2 v_texCoord;\n" + "uniform sampler2D tex;\n" +#endif "void main(void) {\n" " float r,g,b,y,u,v;\n" +#ifndef OPENGL_ES2 " vec2 nxy=gl_TexCoord[0].xy;\n" " y=texture2DRect(tex,nxy).r;\n" " u=texture2DRect(tex,nxy).g;\n" " v=texture2DRect(tex,nxy).b;\n" +#else + " vec2 nxy = v_texCoord.xy;\n" + " y=texture2D(tex,nxy).g;\n" + " u=texture2D(tex,nxy).b;\n" + " v=texture2D(tex,nxy).a;\n" +#endif " y=1.1643*(y-0.0625);\n" " u=u-0.5;\n" " v=v-0.5;\n" - " r=clamp(y+1.5958*v, 0, 1);\n" - " g=clamp(y-0.39173*u-0.81290*v, 0, 1);\n" - " b=clamp(y+2.017*u, 0, 1);\n" " gl_FragColor=vec4(r,g,b,1.0);\n" "}\n"; + " r=y+1.5958*v;\n" + " g=y-0.39173*u-0.81290*v;\n" + " b=y+2.017*u;\n" + " gl_FragColor=vec4(r,g,b,1.0);\n" + "}\n"; //YUY2:y2,u,y1,v //UYVY:v,y1,u,y2 display->text_shader_download_YUY2_UYVY = +#ifndef OPENGL_ES2 "#extension GL_ARB_texture_rectangle : enable\n" "uniform sampler2DRect tex;\n" +#else + "precision mediump float;\n" + "varying vec2 v_texCoord;\n" + "uniform sampler2D tex;\n" +#endif "void main(void) {\n" " float fx,fy,r,g,b,r2,g2,b2,y1,y2,u,v;\n" +#ifndef OPENGL_ES2 " fx = gl_TexCoord[0].x;\n" " fy = gl_TexCoord[0].y;\n" " r=texture2DRect(tex,vec2(fx*2.0,fy)).r;\n" @@ -277,14 +349,29 @@ gst_gl_display_init (GstGLDisplay * display, GstGLDisplayClass * klass) " r2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).r;\n" " g2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).g;\n" " b2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).b;\n" +#else + " fx = v_texCoord.x;\n" + " fy = v_texCoord.y;\n" + " r=texture2D(tex,vec2(fx*2.0,fy)).r;\n" + " g=texture2D(tex,vec2(fx*2.0,fy)).g;\n" + " b=texture2D(tex,vec2(fx*2.0,fy)).b;\n" + " r2=texture2D(tex,vec2(fx*2.0+1.0,fy)).r;\n" + " g2=texture2D(tex,vec2(fx*2.0+1.0,fy)).g;\n" + " b2=texture2D(tex,vec2(fx*2.0+1.0,fy)).b;\n" +#endif " y1=0.299011*r + 0.586987*g + 0.114001*b;\n" " y2=0.299011*r2 + 0.586987*g2 + 0.114001*b2;\n" " u=-0.148246*r -0.29102*g + 0.439266*b;\n" " v=0.439271*r - 0.367833*g - 0.071438*b ;\n" " y1=0.858885*y1 + 0.0625;\n" " y2=0.858885*y2 + 0.0625;\n" - " u=u + 0.5;\n" " v=v + 0.5;\n" " gl_FragColor=vec4(%s);\n" "}\n"; - + " u=u + 0.5;\n" + " v=v + 0.5;\n" + " gl_FragColor=vec4(%s);\n" + "}\n"; + + //no OpenGL ES 2.0 support because for now it's not possible + //to attach multiple textures to a frame buffer object display->text_shader_download_I420_YV12 = "#extension GL_ARB_texture_rectangle : enable\n" "uniform sampler2DRect tex;\n" @@ -307,23 +394,93 @@ gst_gl_display_init (GstGLDisplay * display, GstGLDisplayClass * klass) " v=v + 0.5;\n" " gl_FragData[0] = vec4(y, 0.0, 0.0, 1.0);\n" " gl_FragData[1] = vec4(u, 0.0, 0.0, 1.0);\n" - " gl_FragData[2] = vec4(v, 0.0, 0.0, 1.0);\n" "}\n"; + " gl_FragData[2] = vec4(v, 0.0, 0.0, 1.0);\n" + "}\n"; display->text_shader_download_AYUV = +#ifndef OPENGL_ES2 "#extension GL_ARB_texture_rectangle : enable\n" "uniform sampler2DRect tex;\n" +#else + "precision mediump float;\n" + "varying vec2 v_texCoord;\n" + "uniform sampler2D tex;\n" +#endif "void main(void) {\n" " float r,g,b,y,u,v;\n" +#ifndef OPENGL_ES2 " vec2 nxy=gl_TexCoord[0].xy;\n" " r=texture2DRect(tex,nxy).r;\n" " g=texture2DRect(tex,nxy).g;\n" " b=texture2DRect(tex,nxy).b;\n" +#else + " vec2 nxy=v_texCoord.xy;\n" + " r=texture2D(tex,nxy).r;\n" + " g=texture2D(tex,nxy).g;\n" + " b=texture2D(tex,nxy).b;\n" +#endif " y=0.299011*r + 0.586987*g + 0.114001*b;\n" " u=-0.148246*r -0.29102*g + 0.439266*b;\n" " v=0.439271*r - 0.367833*g - 0.071438*b ;\n" " y=0.858885*y + 0.0625;\n" " u=u + 0.5;\n" - " v=v + 0.5;\n" " gl_FragColor=vec4(y,u,v,1.0);\n" "}\n"; + " v=v + 0.5;\n" +#ifndef OPENGL_ES2 + " gl_FragColor=vec4(y,u,v,1.0);\n" +#else + " gl_FragColor=vec4(1.0,y,u,v);\n" +#endif + "}\n"; + +#ifdef OPENGL_ES2 + display->redisplay_vertex_shader_str = + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " v_texCoord = a_texCoord; \n" + "} \n"; + + display->redisplay_fragment_shader_str = + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform sampler2D s_texture; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D( s_texture, v_texCoord );\n" + "} \n"; + + display->text_vertex_shader_upload = + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " v_texCoord = a_texCoord; \n" + "} \n"; + + display->text_vertex_shader_download = + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " v_texCoord = a_texCoord; \n" + "} \n"; + + display->text_fragment_shader_download_RGB = + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform sampler2D s_texture; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D( s_texture, v_texCoord );\n" + "} \n"; +#endif } static void @@ -441,6 +598,7 @@ gst_gl_display_thread_create_context (GstGLDisplay * display) g_string_free (opengl_version, TRUE); +#ifndef OPENGL_ES2 if ((opengl_version_major < 1) || (GLEW_VERSION_MAJOR < 1) || (opengl_version_major < 2 && opengl_version_major >= 1 @@ -450,6 +608,12 @@ gst_gl_display_thread_create_context (GstGLDisplay * display) GST_WARNING ("Required OpenGL >= 1.2.0 and Glew >= 1.4.0"); display->isAlive = FALSE; } +#else + if (!GL_ES_VERSION_2_0) { + GST_WARNING ("Required OpenGL ES > 2.0"); + display->isAlive = FALSE; + } +#endif } //setup callbacks @@ -526,6 +690,12 @@ gst_gl_display_thread_destroy_context (GstGLDisplay * display) g_object_unref (G_OBJECT (display->shader_download_AYUV)); display->shader_download_AYUV = NULL; } +#ifdef OPENGL_ES2 + if (display->shader_download_RGB) { + g_object_unref (G_OBJECT (display->shader_download_RGB)); + display->shader_download_RGB = NULL; + } +#endif } break; default: @@ -573,6 +743,13 @@ gst_gl_display_thread_destroy_context (GstGLDisplay * display) display->upload_intex_v = 0; } +#ifdef OPENGL_ES2 + if (display->redisplay_shader) { + g_object_unref (G_OBJECT (display->redisplay_shader)); + display->redisplay_shader = NULL; + } +#endif + GST_INFO ("Cleaning texture pool"); //clean up the texture pool @@ -608,6 +785,37 @@ gst_gl_display_thread_del_texture (GstGLDisplay * display) display->del_texture_width, display->del_texture_height); } +#ifdef OPENGL_ES2 +/* Called in the gl thread */ +void +gst_gl_display_thread_init_redisplay (GstGLDisplay * display) +{ + GError *error = NULL; + display->redisplay_shader = gst_gl_shader_new (); + + gst_gl_shader_set_vertex_source(display->redisplay_shader, + display->redisplay_vertex_shader_str); + gst_gl_shader_set_fragment_source(display->redisplay_shader, + display->redisplay_fragment_shader_str); + + gst_gl_shader_compile (display->redisplay_shader, &error); + if (error) { + GST_ERROR ("%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + display->isAlive = FALSE; + } else { + display->redisplay_attr_position_loc = + gst_gl_shader_get_attribute_location (display->redisplay_shader, + "a_position"); + display->redisplay_attr_texture_loc = + gst_gl_shader_get_attribute_location (display->redisplay_shader, + "a_texCoord"); + } +} +#endif + /* Called in the gl thread */ void @@ -641,6 +849,11 @@ gst_gl_display_thread_init_upload (GstGLDisplay * display) //check if fragment shader is available, then load them /* shouldn't we require ARB_shading_language_100? --Filippo */ if (GLEW_ARB_fragment_shader) { + +#ifdef OPENGL_ES2 + GError *error = NULL; +#endif + GST_INFO ("Context, ARB_fragment_shader supported: yes"); display->upload_colorspace_conversion = GST_GL_DISPLAY_CONVERSION_GLSL; @@ -657,32 +870,88 @@ gst_gl_display_thread_init_upload (GstGLDisplay * display) display->text_shader_upload_YUY2_UYVY, 'r', 'g', 'a'); display->shader_upload_YUY2 = gst_gl_shader_new (); +#ifndef OPENGL_ES2 if (!gst_gl_shader_compile_and_check (display->shader_upload_YUY2, text_shader_upload_YUY2, GST_GL_SHADER_FRAGMENT_SOURCE)) { display->isAlive = FALSE; g_object_unref (G_OBJECT (display->shader_upload_YUY2)); display->shader_upload_YUY2 = NULL; } +#else + gst_gl_shader_set_vertex_source(display->shader_upload_YUY2, + display->text_vertex_shader_upload); + gst_gl_shader_set_fragment_source(display->shader_upload_YUY2, + text_shader_upload_YUY2); + + gst_gl_shader_compile (display->shader_upload_YUY2, &error); + if (error) { + GST_ERROR ("%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + display->isAlive = FALSE; + g_object_unref (G_OBJECT (display->shader_upload_YUY2)); + display->shader_upload_YUY2 = NULL; + } else { + display->shader_upload_attr_position_loc = + gst_gl_shader_get_attribute_location (display->shader_upload_YUY2, + "a_position"); + display->shader_upload_attr_texture_loc = + gst_gl_shader_get_attribute_location (display->shader_upload_YUY2, + "a_texCoord"); + } +#endif } break; case GST_VIDEO_FORMAT_UYVY: { gchar text_shader_upload_UYVY[2048]; sprintf (text_shader_upload_UYVY, +#ifndef OPENGL_ES2 display->text_shader_upload_YUY2_UYVY, 'a', 'b', 'r'); +#else + display->text_shader_upload_YUY2_UYVY, 'a', 'r', 'b'); +#endif display->shader_upload_UYVY = gst_gl_shader_new (); + +#ifndef OPENGL_ES2 if (!gst_gl_shader_compile_and_check (display->shader_upload_UYVY, text_shader_upload_UYVY, GST_GL_SHADER_FRAGMENT_SOURCE)) { display->isAlive = FALSE; g_object_unref (G_OBJECT (display->shader_upload_UYVY)); display->shader_upload_UYVY = NULL; } +#else + gst_gl_shader_set_vertex_source(display->shader_upload_UYVY, + display->text_vertex_shader_upload); + gst_gl_shader_set_fragment_source(display->shader_upload_UYVY, + text_shader_upload_UYVY); + + gst_gl_shader_compile (display->shader_upload_UYVY, &error); + if (error) { + GST_ERROR ("%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + display->isAlive = FALSE; + g_object_unref (G_OBJECT (display->shader_upload_UYVY)); + display->shader_upload_UYVY = NULL; + } else { + display->shader_upload_attr_position_loc = + gst_gl_shader_get_attribute_location (display->shader_upload_UYVY, + "a_position"); + display->shader_upload_attr_texture_loc = + gst_gl_shader_get_attribute_location (display->shader_upload_UYVY, + "a_texCoord"); + } +#endif } break; case GST_VIDEO_FORMAT_I420: case GST_VIDEO_FORMAT_YV12: { +#ifndef OPENGL_ES2 gchar text_shader_upload_I420_YV12[2048]; if (g_ascii_strncasecmp ("ATI", (gchar *) glGetString (GL_VENDOR), 3) == 0) @@ -691,8 +960,11 @@ gst_gl_display_thread_init_upload (GstGLDisplay * display) else sprintf (text_shader_upload_I420_YV12, display->text_shader_upload_I420_YV12, "", "*0.5"); +#endif display->shader_upload_I420_YV12 = gst_gl_shader_new (); + +#ifndef OPENGL_ES2 if (!gst_gl_shader_compile_and_check (display->shader_upload_I420_YV12, text_shader_upload_I420_YV12, GST_GL_SHADER_FRAGMENT_SOURCE)) { @@ -700,10 +972,37 @@ gst_gl_display_thread_init_upload (GstGLDisplay * display) g_object_unref (G_OBJECT (display->shader_upload_I420_YV12)); display->shader_upload_I420_YV12 = NULL; } +#else + gst_gl_shader_set_vertex_source(display->shader_upload_I420_YV12, + display->text_vertex_shader_upload); + gst_gl_shader_set_fragment_source(display->shader_upload_I420_YV12, + display->text_shader_upload_I420_YV12); + + gst_gl_shader_compile (display->shader_upload_I420_YV12, &error); + if (error) { + GST_ERROR ("%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + display->isAlive = FALSE; + g_object_unref (G_OBJECT (display->shader_upload_I420_YV12)); + display->shader_upload_I420_YV12 = NULL; + } else { + display->shader_upload_attr_position_loc = + gst_gl_shader_get_attribute_location (display->shader_upload_I420_YV12, + "a_position"); + display->shader_upload_attr_texture_loc = + gst_gl_shader_get_attribute_location (display->shader_upload_I420_YV12, + "a_texCoord"); + } +#endif } break; case GST_VIDEO_FORMAT_AYUV: + { display->shader_upload_AYUV = gst_gl_shader_new (); + +#ifndef OPENGL_ES2 if (!gst_gl_shader_compile_and_check (display->shader_upload_AYUV, display->text_shader_upload_AYUV, GST_GL_SHADER_FRAGMENT_SOURCE)) { @@ -711,6 +1010,31 @@ gst_gl_display_thread_init_upload (GstGLDisplay * display) g_object_unref (G_OBJECT (display->shader_upload_AYUV)); display->shader_upload_AYUV = NULL; } +#else + gst_gl_shader_set_vertex_source(display->shader_upload_AYUV, + display->text_vertex_shader_upload); + gst_gl_shader_set_fragment_source(display->shader_upload_AYUV, + display->text_shader_upload_AYUV); + + gst_gl_shader_compile (display->shader_upload_AYUV, &error); + if (error) { + GST_ERROR ("%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + display->isAlive = FALSE; + g_object_unref (G_OBJECT (display->shader_upload_AYUV)); + display->shader_upload_AYUV = NULL; + } else { + display->shader_upload_attr_position_loc = + gst_gl_shader_get_attribute_location (display->shader_upload_AYUV, + "a_position"); + display->shader_upload_attr_texture_loc = + gst_gl_shader_get_attribute_location (display->shader_upload_AYUV, + "a_texCoord"); + } +#endif + } break; default: g_assert_not_reached (); @@ -990,6 +1314,36 @@ gst_gl_display_thread_init_download (GstGLDisplay * display) case GST_VIDEO_FORMAT_RGB: case GST_VIDEO_FORMAT_BGR: //color space conversion is not needed +#ifdef OPENGL_ES2 + { + //glGetTexImage2D no available in OpenGL ES 2.0 + GError *error = NULL; + display->shader_download_RGB = gst_gl_shader_new (); + + gst_gl_shader_set_vertex_source(display->shader_download_RGB, + display->text_vertex_shader_download); + gst_gl_shader_set_fragment_source(display->shader_download_RGB, + display->text_fragment_shader_download_RGB); + + gst_gl_shader_compile (display->shader_download_RGB, &error); + if (error) { + GST_ERROR ("%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + display->isAlive = FALSE; + g_object_unref (G_OBJECT (display->shader_download_RGB)); + display->shader_download_RGB = NULL; + } else { + display->shader_download_attr_position_loc = + gst_gl_shader_get_attribute_location (display->shader_download_RGB, + "a_position"); + display->shader_download_attr_texture_loc = + gst_gl_shader_get_attribute_location (display->shader_download_RGB, + "a_texCoord"); + } + } +#endif break; case GST_VIDEO_FORMAT_YUY2: case GST_VIDEO_FORMAT_UYVY: @@ -1001,6 +1355,11 @@ gst_gl_display_thread_init_download (GstGLDisplay * display) //check if fragment shader is available, then load them //GLSL is a requirement for donwload if (GLEW_ARB_fragment_shader) { + +#ifdef OPENGL_ES2 + GError *error = NULL; +#endif + switch (display->download_video_format) { case GST_VIDEO_FORMAT_YUY2: { @@ -1009,12 +1368,37 @@ gst_gl_display_thread_init_download (GstGLDisplay * display) display->text_shader_download_YUY2_UYVY, "y2,u,y1,v"); display->shader_download_YUY2 = gst_gl_shader_new (); +#ifndef OPENGL_ES2 if (!gst_gl_shader_compile_and_check (display->shader_download_YUY2, text_shader_download_YUY2, GST_GL_SHADER_FRAGMENT_SOURCE)) { display->isAlive = FALSE; g_object_unref (G_OBJECT (display->shader_download_YUY2)); display->shader_download_YUY2 = NULL; } +#else + gst_gl_shader_set_vertex_source(display->shader_download_YUY2, + display->text_vertex_shader_download); + gst_gl_shader_set_fragment_source(display->shader_download_YUY2, + text_shader_download_YUY2); + + gst_gl_shader_compile (display->shader_download_YUY2, &error); + if (error) { + GST_ERROR ("%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + display->isAlive = FALSE; + g_object_unref (G_OBJECT (display->shader_download_YUY2)); + display->shader_download_YUY2 = NULL; + } else { + display->shader_download_attr_position_loc = + gst_gl_shader_get_attribute_location (display->shader_download_YUY2, + "a_position"); + display->shader_download_attr_texture_loc = + gst_gl_shader_get_attribute_location (display->shader_download_YUY2, + "a_texCoord"); + } +#endif } break; case GST_VIDEO_FORMAT_UYVY: @@ -1024,12 +1408,39 @@ gst_gl_display_thread_init_download (GstGLDisplay * display) display->text_shader_download_YUY2_UYVY, "v,y1,u,y2"); display->shader_download_UYVY = gst_gl_shader_new (); + +#ifndef OPENGL_ES2 if (!gst_gl_shader_compile_and_check (display->shader_download_UYVY, text_shader_download_UYVY, GST_GL_SHADER_FRAGMENT_SOURCE)) { display->isAlive = FALSE; g_object_unref (G_OBJECT (display->shader_download_UYVY)); display->shader_download_UYVY = NULL; } +#else + gst_gl_shader_set_vertex_source(display->shader_download_UYVY, + display->text_vertex_shader_download); + gst_gl_shader_set_fragment_source(display->shader_download_UYVY, + text_shader_download_UYVY); + + gst_gl_shader_compile (display->shader_download_UYVY, &error); + if (error) { + GST_ERROR ("%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + display->isAlive = FALSE; + g_object_unref (G_OBJECT (display->shader_download_UYVY)); + display->shader_download_UYVY = NULL; + } else { + display->shader_download_attr_position_loc = + gst_gl_shader_get_attribute_location (display->shader_download_UYVY, + "a_position"); + display->shader_download_attr_texture_loc = + gst_gl_shader_get_attribute_location (display->shader_download_UYVY, + "a_texCoord"); + } +#endif + } break; case GST_VIDEO_FORMAT_I420: @@ -1046,6 +1457,8 @@ gst_gl_display_thread_init_download (GstGLDisplay * display) break; case GST_VIDEO_FORMAT_AYUV: display->shader_download_AYUV = gst_gl_shader_new (); + +#ifndef OPENGL_ES2 if (!gst_gl_shader_compile_and_check (display->shader_download_AYUV, display->text_shader_download_AYUV, GST_GL_SHADER_FRAGMENT_SOURCE)) { @@ -1053,6 +1466,30 @@ gst_gl_display_thread_init_download (GstGLDisplay * display) g_object_unref (G_OBJECT (display->shader_download_AYUV)); display->shader_download_AYUV = NULL; } +#else + gst_gl_shader_set_vertex_source(display->shader_download_AYUV, + display->text_vertex_shader_download); + gst_gl_shader_set_fragment_source(display->shader_download_AYUV, + display->text_shader_download_AYUV); + + gst_gl_shader_compile (display->shader_download_AYUV, &error); + if (error) { + GST_ERROR ("%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + display->isAlive = FALSE; + g_object_unref (G_OBJECT (display->shader_download_AYUV)); + display->shader_download_AYUV = NULL; + } else { + display->shader_download_attr_position_loc = + gst_gl_shader_get_attribute_location (display->shader_download_AYUV, + "a_position"); + display->shader_download_attr_texture_loc = + gst_gl_shader_get_attribute_location (display->shader_download_AYUV, + "a_texCoord"); + } +#endif break; default: g_assert_not_reached (); @@ -1156,6 +1593,10 @@ gst_gl_display_thread_gen_fbo (GstGLDisplay * display) void gst_gl_display_thread_use_fbo (GstGLDisplay * display) { +#ifdef OPENGL_ES2 + GLint viewport_dim[4]; +#endif + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->use_fbo); //setup a texture to render to @@ -1168,9 +1609,8 @@ gst_gl_display_thread_use_fbo (GstGLDisplay * display) if (GLEW_ARB_fragment_shader) gst_gl_shader_use (NULL); - +#ifndef OPENGL_ES2 glPushAttrib (GL_VIEWPORT_BIT); - glMatrixMode (GL_PROJECTION); glPushMatrix (); glLoadIdentity (); @@ -1192,10 +1632,16 @@ gst_gl_display_thread_use_fbo (GstGLDisplay * display) glMatrixMode (GL_MODELVIEW); glPushMatrix (); glLoadIdentity (); +#else // OPENGL_ES2 + glGetIntegerv(GL_VIEWPORT, viewport_dim); +#endif glViewport (0, 0, display->use_fbo_width, display->use_fbo_height); +#ifndef OPENGL_ES2 glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); +#endif + glClearColor (0.0, 0.0, 0.0, 0.0); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -1204,13 +1650,16 @@ gst_gl_display_thread_use_fbo (GstGLDisplay * display) display->input_texture_height, display->input_texture, display->use_fbo_stuff); +#ifndef OPENGL_ES2 glDrawBuffer (GL_NONE); - glMatrixMode (GL_PROJECTION); glPopMatrix (); glMatrixMode (GL_MODELVIEW); glPopMatrix (); glPopAttrib (); +#else + glViewport(viewport_dim[0], viewport_dim[1], viewport_dim[2], viewport_dim[3]); +#endif glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); } @@ -1319,10 +1768,12 @@ gst_gl_display_on_resize (GstGLDisplay * display, gint width, gint height) //default reshape else { glViewport (0, 0, width, height); +#ifndef OPENGL_ES2 glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluOrtho2D (0, width, 0, height); glMatrixMode (GL_MODELVIEW); +#endif } } @@ -1355,6 +1806,7 @@ gst_gl_display_on_draw (GstGLDisplay * display) //default opengl scene else { +#ifndef OPENGL_ES2 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode (GL_PROJECTION); @@ -1376,7 +1828,44 @@ gst_gl_display_on_draw (GstGLDisplay * display) glEnd (); glDisable (GL_TEXTURE_RECTANGLE_ARB); - } //end default opengl scene + +#else //OPENGL_ES2 + + const GLfloat vVertices [] = + {1.0f, 1.0f, 0.0f, + 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 0.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 1.0f}; + + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + + glClear (GL_COLOR_BUFFER_BIT); + + gst_gl_shader_use (display->redisplay_shader); + + //Load the vertex position + glVertexAttribPointer (display->redisplay_attr_position_loc, 3, GL_FLOAT, + GL_FALSE, 5 * sizeof(GLfloat), vVertices); + + //Load the texture coordinate + glVertexAttribPointer (display->redisplay_attr_texture_loc, 2, GL_FLOAT, + GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (display->redisplay_attr_position_loc); + glEnableVertexAttribArray (display->redisplay_attr_texture_loc); + + glActiveTexture (GL_TEXTURE0); + glBindTexture (GL_TEXTURE_2D, display->redisplay_texture); + gst_gl_shader_set_uniform_1i (display->redisplay_shader, "s_texture", 0); + + glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); +#endif + + }//end default opengl scene } @@ -1616,6 +2105,14 @@ gst_gl_display_redisplay (GstGLDisplay * display, GLuint texture, gint width, gst_gl_display_lock (display); isAlive = display->isAlive; if (isAlive) { + +#ifdef OPENGL_ES2 + if (!display->redisplay_shader) { + gst_gl_window_send_message (display->gl_window, + GST_GL_WINDOW_CB (gst_gl_display_thread_init_redisplay), display); + } +#endif + if (texture) { display->redisplay_texture = texture; display->redisplay_texture_width = width; @@ -2198,6 +2695,23 @@ gst_gl_display_thread_do_upload_fill (GstGLDisplay * display) void gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) { + +#ifdef OPENGL_ES2 + GLint viewport_dim[4]; + + const GLfloat vVertices [] = + {1.0f, -1.0f, 0.0f, + 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + 0.0f, .0f, + -1.0f, 1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, 0.0f, + 1.0f, 1.0f}; + + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; +#endif + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->upload_fbo); //setup a texture to render to @@ -2211,6 +2725,7 @@ gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) if (GLEW_ARB_fragment_shader) gst_gl_shader_use (NULL); +#ifndef OPENGL_ES2 glPushAttrib (GL_VIEWPORT_BIT); glMatrixMode (GL_PROJECTION); @@ -2221,10 +2736,16 @@ gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) glMatrixMode (GL_MODELVIEW); glPushMatrix (); glLoadIdentity (); +#else // OPENGL_ES2 + glGetIntegerv(GL_VIEWPORT, viewport_dim); +#endif glViewport (0, 0, display->upload_width, display->upload_height); - glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); +#ifndef OPENGL_ES2 + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); +#endif + glClearColor (0.0, 0.0, 0.0, 0.0); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -2240,9 +2761,18 @@ gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) case GST_VIDEO_FORMAT_RGB: case GST_VIDEO_FORMAT_BGR: { +#ifndef OPENGL_ES2 glMatrixMode (GL_PROJECTION); glLoadIdentity (); +#else + glVertexAttribPointer (display->shader_upload_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vVertices); + glVertexAttribPointer (display->shader_upload_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]); + glEnableVertexAttribArray (display->shader_upload_attr_position_loc); + glEnableVertexAttribArray (display->shader_upload_attr_texture_loc); +#endif glEnable (GL_TEXTURE_RECTANGLE_ARB); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex); glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, @@ -2279,8 +2809,18 @@ gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) gst_gl_shader_use (shader_upload_YUY2_UYVY); +#ifndef OPENGL_ES2 glMatrixMode (GL_PROJECTION); glLoadIdentity (); +#else + glVertexAttribPointer (display->shader_upload_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vVertices); + glVertexAttribPointer (display->shader_upload_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (display->shader_upload_attr_position_loc); + glEnableVertexAttribArray (display->shader_upload_attr_texture_loc); +#endif glActiveTextureARB (GL_TEXTURE1_ARB); gst_gl_shader_set_uniform_1i (shader_upload_YUY2_UYVY, "UVtex", 1); @@ -2309,8 +2849,11 @@ gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) break; case GST_GL_DISPLAY_CONVERSION_MESA: { + +#ifndef OPENGL_ES2 glMatrixMode (GL_PROJECTION); glLoadIdentity (); +#endif glEnable (GL_TEXTURE_RECTANGLE_ARB); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex); @@ -2336,8 +2879,18 @@ gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) { gst_gl_shader_use (display->shader_upload_I420_YV12); +#ifndef OPENGL_ES2 glMatrixMode (GL_PROJECTION); glLoadIdentity (); +#else + glVertexAttribPointer (display->shader_upload_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vVertices); + glVertexAttribPointer (display->shader_upload_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (display->shader_upload_attr_position_loc); + glEnableVertexAttribArray (display->shader_upload_attr_texture_loc); +#endif glActiveTextureARB (GL_TEXTURE1_ARB); gst_gl_shader_set_uniform_1i (display->shader_upload_I420_YV12, "Utex", @@ -2384,8 +2937,18 @@ gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) { gst_gl_shader_use (display->shader_upload_AYUV); +#ifndef OPENGL_ES2 glMatrixMode (GL_PROJECTION); glLoadIdentity (); +#else + glVertexAttribPointer (display->shader_upload_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vVertices); + glVertexAttribPointer (display->shader_upload_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (display->shader_upload_attr_position_loc); + glEnableVertexAttribArray (display->shader_upload_attr_texture_loc); +#endif glActiveTextureARB (GL_TEXTURE0_ARB); gst_gl_shader_set_uniform_1i (display->shader_upload_AYUV, "tex", 0); @@ -2406,6 +2969,7 @@ gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) } //end switch display->currentVideo_format +#ifndef OPENGL_ES2 glBegin (GL_QUADS); glTexCoord2i (display->upload_data_width, 0); glVertex2f (1.0f, -1.0f); @@ -2418,11 +2982,15 @@ gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) glEnd (); glDrawBuffer (GL_NONE); +#else //OPENGL_ES2 + glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); +#endif //we are done with the shader if (display->upload_colorspace_conversion == GST_GL_DISPLAY_CONVERSION_GLSL) glUseProgramObjectARB (0); +#ifndef OPENGL_ES2 glDisable (GL_TEXTURE_RECTANGLE_ARB); glMatrixMode (GL_PROJECTION); @@ -2430,6 +2998,9 @@ gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) glMatrixMode (GL_MODELVIEW); glPopMatrix (); glPopAttrib (); +#else + glViewport(viewport_dim[0], viewport_dim[1], viewport_dim[2], viewport_dim[3]); +#endif glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); @@ -2444,31 +3015,88 @@ gst_gl_display_thread_do_download_draw_rgb (GstGLDisplay * display) GstVideoFormat video_format = display->download_video_format; gpointer data = display->download_data; +#ifndef OPENGL_ES2 glEnable (GL_TEXTURE_RECTANGLE_ARB); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->ouput_texture); +#else + gint width = display->ouput_texture_width; + gint height = display->ouput_texture_height; + + const GLfloat vVertices [] = + {1.0f, -1.0f, 0.0f, + 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + 0.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, 0.0f, + 1.0f, 1.0f}; + + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + + glViewport (0, 0, width, height); + + glClearColor (0.0, 0.0, 0.0, 0.0); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + gst_gl_shader_use (display->shader_download_RGB); + + glVertexAttribPointer (display->shader_download_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vVertices); + glVertexAttribPointer (display->shader_download_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (display->shader_download_attr_position_loc); + glEnableVertexAttribArray (display->shader_download_attr_texture_loc); + + glActiveTextureARB (GL_TEXTURE0_ARB); + gst_gl_shader_set_uniform_1i (display->shader_download_RGB, "s_texture", 0); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->ouput_texture); + + glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); + + glUseProgramObjectARB (0); + glDisable (GL_TEXTURE_RECTANGLE_ARB); + + glReadBuffer (GL_BACK); +#endif switch (video_format) { case GST_VIDEO_FORMAT_RGBA: case GST_VIDEO_FORMAT_RGBx: case GST_VIDEO_FORMAT_xRGB: case GST_VIDEO_FORMAT_ARGB: +#ifndef OPENGL_ES2 glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); +#else + glReadPixels (0, 0, width, height, GL_RGBA, + GL_UNSIGNED_BYTE, data); +#endif break; case GST_VIDEO_FORMAT_BGRx: case GST_VIDEO_FORMAT_BGRA: case GST_VIDEO_FORMAT_xBGR: case GST_VIDEO_FORMAT_ABGR: +#ifndef OPENGL_ES2 glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); +#endif break; case GST_VIDEO_FORMAT_RGB: +#ifndef OPENGL_ES2 glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, GL_UNSIGNED_BYTE, data); +#else + glReadPixels (0, 0, width, height, GL_RGB, + GL_UNSIGNED_BYTE, data); +#endif break; case GST_VIDEO_FORMAT_BGR: +#ifndef OPENGL_ES2 glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGR, GL_UNSIGNED_BYTE, data); +#endif break; default: g_assert_not_reached (); @@ -2485,8 +3113,25 @@ gst_gl_display_thread_do_download_draw_yuv (GstGLDisplay * display) GstVideoFormat video_format = display->download_video_format; gpointer data = display->download_data; +#ifdef OPENGL_ES2 + GLint viewport_dim[4]; + + const GLfloat vVertices [] = + {1.0f, -1.0f, 0.0f, + 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + 0.0f, .0f, + -1.0f, 1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, 0.0f, + 1.0f, 1.0f}; + + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; +#endif + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->download_fbo); +#ifndef OPENGL_ES2 glPushAttrib (GL_VIEWPORT_BIT); glMatrixMode (GL_PROJECTION); @@ -2497,6 +3142,9 @@ gst_gl_display_thread_do_download_draw_yuv (GstGLDisplay * display) glMatrixMode (GL_MODELVIEW); glPushMatrix (); glLoadIdentity (); +#else // OPENGL_ES2 + glGetIntegerv(GL_VIEWPORT, viewport_dim); +#endif glViewport (0, 0, width, height); @@ -2516,16 +3164,26 @@ gst_gl_display_thread_do_download_draw_yuv (GstGLDisplay * display) default: g_assert_not_reached (); } - +#ifndef OPENGL_ES2 glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); +#endif glClearColor (0.0, 0.0, 0.0, 0.0); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gst_gl_shader_use (shader_download_YUY2_UYVY); +#ifndef OPENGL_ES2 glMatrixMode (GL_PROJECTION); - glLoadIdentity (); +#else + glVertexAttribPointer (display->shader_download_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vVertices); + glVertexAttribPointer (display->shader_download_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (display->shader_download_attr_position_loc); + glEnableVertexAttribArray (display->shader_download_attr_texture_loc); +#endif glActiveTextureARB (GL_TEXTURE0_ARB); gst_gl_shader_set_uniform_1i (shader_download_YUY2_UYVY, "tex", 0); @@ -2536,15 +3194,19 @@ gst_gl_display_thread_do_download_draw_yuv (GstGLDisplay * display) case GST_VIDEO_FORMAT_I420: case GST_VIDEO_FORMAT_YV12: { +#ifndef OPENGL_ES2 glDrawBuffers (3, display->multipleRT); +#endif glClearColor (0.0, 0.0, 0.0, 0.0); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gst_gl_shader_use (display->shader_download_I420_YV12); +#ifndef OPENGL_ES2 glMatrixMode (GL_PROJECTION); glLoadIdentity (); +#endif glActiveTextureARB (GL_TEXTURE0_ARB); gst_gl_shader_set_uniform_1i (display->shader_download_I420_YV12, "tex", @@ -2559,15 +3221,27 @@ gst_gl_display_thread_do_download_draw_yuv (GstGLDisplay * display) case GST_VIDEO_FORMAT_AYUV: { +#ifndef OPENGL_ES2 glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); +#endif glClearColor (0.0, 0.0, 0.0, 0.0); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gst_gl_shader_use (display->shader_download_AYUV); +#ifndef OPENGL_ES2 glMatrixMode (GL_PROJECTION); glLoadIdentity (); +#else + glVertexAttribPointer (display->shader_download_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vVertices); + glVertexAttribPointer (display->shader_download_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (display->shader_download_attr_position_loc); + glEnableVertexAttribArray (display->shader_download_attr_texture_loc); +#endif glActiveTextureARB (GL_TEXTURE0_ARB); gst_gl_shader_set_uniform_1i (display->shader_download_AYUV, "tex", 0); @@ -2580,6 +3254,7 @@ gst_gl_display_thread_do_download_draw_yuv (GstGLDisplay * display) } //end switch display->currentVideo_format +#ifndef OPENGL_ES2 glBegin (GL_QUADS); glTexCoord2i (0, 0); glVertex2f (-1.0f, -1.0f); @@ -2592,19 +3267,26 @@ gst_gl_display_thread_do_download_draw_yuv (GstGLDisplay * display) glEnd (); glDrawBuffer (GL_NONE); +#else //OPENGL_ES2 + glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); +#endif //dot not check if GLSL is available - //because for now download is not available - //without GLSL + //because download yuv is not available + //without GLSL (whereas rgb is) glUseProgramObjectARB (0); glDisable (GL_TEXTURE_RECTANGLE_ARB); +#ifndef OPENGL_ES2 glMatrixMode (GL_PROJECTION); glPopMatrix (); glMatrixMode (GL_MODELVIEW); glPopMatrix (); glPopAttrib (); +#else + glViewport(viewport_dim[0], viewport_dim[1], viewport_dim[2], viewport_dim[3]); +#endif glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); @@ -2646,6 +3328,8 @@ gst_gl_display_thread_do_download_draw_yuv (GstGLDisplay * display) g_assert_not_reached (); } + glReadBuffer (GL_NONE); + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); gst_gl_display_check_framebuffer_status (); } diff --git a/gst-libs/gst/gl/gstgldisplay.h b/gst-libs/gst/gl/gstgldisplay.h index 3f9eb1bfce..6ff308a97a 100644 --- a/gst-libs/gst/gl/gstgldisplay.h +++ b/gst-libs/gst/gl/gstgldisplay.h @@ -96,6 +96,13 @@ struct _GstGLDisplay { GLuint redisplay_texture; GLuint redisplay_texture_width; GLuint redisplay_texture_height; +#ifdef OPENGL_ES2 + GstGLShader* redisplay_shader; + GLbyte* redisplay_vertex_shader_str; + GLbyte* redisplay_fragment_shader_str; + GLint redisplay_attr_position_loc; + GLint redisplay_attr_texture_loc; +#endif //action gen and del texture GLuint gen_texture; @@ -183,6 +190,12 @@ struct _GstGLDisplay { gchar* text_shader_upload_AYUV; GstGLShader* shader_upload_AYUV; +#ifdef OPENGL_ES2 + GLbyte* text_vertex_shader_upload; + GLint shader_upload_attr_position_loc; + GLint shader_upload_attr_texture_loc; +#endif + //fragement shader download gchar* text_shader_download_YUY2_UYVY; GstGLShader* shader_download_YUY2; @@ -193,6 +206,15 @@ struct _GstGLDisplay { gchar* text_shader_download_AYUV; GstGLShader* shader_download_AYUV; + +#ifdef OPENGL_ES2 + GLbyte* text_vertex_shader_download; + GLint shader_download_attr_position_loc; + GLint shader_download_attr_texture_loc; + GLbyte* text_fragment_shader_download_RGB; + GstGLShader* shader_download_RGB; +#endif + }; diff --git a/gst-libs/gst/gl/gstgles2.h b/gst-libs/gst/gl/gstgles2.h new file mode 100644 index 0000000000..76ef4b1645 --- /dev/null +++ b/gst-libs/gst/gl/gstgles2.h @@ -0,0 +1,117 @@ +/* + * GStreamer + * Copyright (C) 2009 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. + */ + +/* Compatibility for OpenGL ES 2.0 */ + +#ifndef __GST_GL_ES2__ +#define __GST_GL_ES2__ + +/* GLEW */ + +#define GLEW_OK 0 +#define GLEW_NO_ERROR 0 +static const char* glewGetString (GLenum name) { return "1.5.1"; }; +static unsigned int glewInit() { return GLEW_OK;}; +static const char* glewGetErrorString (GLenum error) { return GLEW_NO_ERROR; }; + +#define GLEW_VERSION 1 +#define GLEW_VERSION_MAJOR 5 +#define GLEW_VERSION_MINOR 1 +#define GLEW_VERSION_MICRO 0 + +/* SUPPORTED */ + +//FIXME: +#define GL_RGBA8 GL_RGBA +#define GL_BGRA GL_RGBA +#define GL_UNSIGNED_INT_8_8_8_8 GL_UNSIGNED_BYTE +#define GL_UNSIGNED_INT_8_8_8_8_REV GL_UNSIGNED_BYTE +//END FIXME + +#define GL_TEXTURE_RECTANGLE_ARB GL_TEXTURE_2D +#define GL_TEXTURE0_ARB GL_TEXTURE0 +#define GL_TEXTURE1_ARB GL_TEXTURE1 +#define GL_TEXTURE2_ARB GL_TEXTURE2 + +#define GLEW_EXT_framebuffer_object 1 +#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER +#define GL_RENDERBUFFER_EXT GL_RENDERBUFFER +#define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT +#define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE +#define GL_FRAMEBUFFER_UNSUPPORTED_EXT GL_FRAMEBUFFER_UNSUPPORTED + +#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0 + +#define glFramebufferTexture2DEXT glFramebufferTexture2D +#define glFramebufferRenderbufferEXT glFramebufferRenderbuffer +#define glGenFramebuffersEXT glGenFramebuffers +#define glBindFramebufferEXT glBindFramebuffer +#define glRenderbufferStorageEXT glRenderbufferStorage +#define glDeleteRenderbuffersEXT glDeleteRenderbuffers +#define glDeleteFramebuffersEXT glDeleteFramebuffers +#define glCheckFramebufferStatusEXT glCheckFramebufferStatus +#define glGenRenderbuffersEXT glGenRenderbuffers +#define glBindRenderbufferEXT glBindRenderbuffer +#define glFramebufferTexture2DEXT glFramebufferTexture2D + +#define glActiveTextureARB glActiveTexture + +#define GLEW_ARB_fragment_shader 1 +#define GLhandleARB GLuint +#define GL_FRAGMENT_SHADER_ARB GL_FRAGMENT_SHADER +#define GL_VERTEX_SHADER_ARB GL_VERTEX_SHADER +#define GL_OBJECT_COMPILE_STATUS_ARB GL_COMPILE_STATUS + +#define glUseProgramObjectARB glUseProgram +#define glCreateProgramObjectARB glCreateProgram +#define glCreateShaderObjectARB glCreateShader +#define glCompileShaderARB glCompileShader +#define glShaderSourceARB glShaderSource +#define glGetInfoLogARB glGetProgramInfoLog +#define glAttachObjectARB glAttachShader +#define glDetachObjectARB glDetachShader +#define glDeleteObjectARB glDeleteProgram +#define glLinkProgramARB glLinkProgram +#define glGetObjectParameterivARB glGetShaderiv +#define glUniform1fARB glUniform1f +#define glUniform1fvARB glUniform1fv +#define glUniform1iARB glUniform1i +#define glUniformMatrix4fvARB glUniformMatrix4fv +#define glGetUniformLocationARB glGetUniformLocation +#define glGetAttribLocationARB glGetAttribLocation + +/* UNSUPPORTED */ + +#define GLEW_ARB_imaging 0 +#define GLEW_MESA_ycbcr_texture 0 +#define GL_BGR 0 +#define GL_YCBCR_MESA 0 +#define GL_UNSIGNED_SHORT_8_8_MESA 0 +#define GL_UNSIGNED_SHORT_8_8_MESA 0 +#define GL_UNSIGNED_SHORT_8_8_REV_MESA 0 + +#define GL_COLOR_ATTACHMENT1_EXT 0 +#define GL_COLOR_ATTACHMENT2_EXT 0 +static void glReadBuffer(GLenum name) {}; +static void glTexEnvi(GLenum name1, GLenum name2, GLenum name3) {}; +#define GL_TEXTURE_ENV 0 +#define GL_TEXTURE_ENV_MODE 0 + +#endif /* __GST_GL_ES2__ */ diff --git a/gst-libs/gst/gl/gstglshader.c b/gst-libs/gst/gl/gstglshader.c index 04cbbf4487..8ed11a8f74 100644 --- a/gst-libs/gst/gl/gstglshader.c +++ b/gst-libs/gst/gl/gstglshader.c @@ -510,6 +510,22 @@ gst_gl_shader_set_uniform_1i (GstGLShader * shader, const gchar * name, glUniform1iARB (location, value); } +void +gst_gl_shader_set_uniform_matrix_4fv (GstGLShader * shader, const gchar * name, + GLsizei count, GLboolean transpose, const GLfloat* value) +{ + GstGLShaderPrivate *priv; + GLint location = -1; + + priv = shader->priv; + + g_return_if_fail (priv->program_handle != 0); + + location = glGetUniformLocationARB (priv->program_handle, name); + + glUniformMatrix4fvARB (location, count, transpose, value); +} + GLint gst_gl_shader_get_attribute_location (GstGLShader * shader, const gchar * name) { diff --git a/gst-libs/gst/gl/gstglshader.h b/gst-libs/gst/gl/gstglshader.h index 3506997d21..6a547cb55a 100644 --- a/gst-libs/gst/gl/gstglshader.h +++ b/gst-libs/gst/gl/gstglshader.h @@ -21,7 +21,14 @@ #ifndef __GST_GL_SHADER_H__ #define __GST_GL_SHADER_H__ +/* OpenGL 2.0 for Embedded Systems */ +#ifdef OPENGL_ES2 +#include +#include "gstgles2.h" +/* OpenGL for usual systems */ +#else #include +#endif #include G_BEGIN_DECLS @@ -88,6 +95,8 @@ void gst_gl_shader_use (GstGLShader *shader); void gst_gl_shader_set_uniform_1i (GstGLShader *shader, const gchar *name, gint value); void gst_gl_shader_set_uniform_1f (GstGLShader *shader, const gchar *name, gfloat value); void gst_gl_shader_set_uniform_1fv (GstGLShader *shader, const gchar *name, guint count, gfloat * value); +void gst_gl_shader_set_uniform_matrix_4fv (GstGLShader * shader, const gchar * name, + GLsizei count, GLboolean transpose, const GLfloat* value); GLint gst_gl_shader_get_attribute_location (GstGLShader *shader, const gchar *name); diff --git a/gst-libs/gst/gl/gstglwindow.h b/gst-libs/gst/gl/gstglwindow.h index 10cdd907b0..e68333c8a7 100644 --- a/gst-libs/gst/gl/gstglwindow.h +++ b/gst-libs/gst/gl/gstglwindow.h @@ -21,6 +21,15 @@ #ifndef __GST_GL_WINDOW_H__ #define __GST_GL_WINDOW_H__ +/* OpenGL 2.0 for Embedded Systems */ +#ifdef OPENGL_ES2 +#undef UNICODE +#include +#define UNICODE +#include +#include "gstgles2.h" +/* OpenGL for usual systems */ +#else #if (!GNUSTEP && MACOS) #include #include @@ -29,6 +38,7 @@ #include #include #endif +#endif #include diff --git a/gst-libs/gst/gl/gstglwindow_winCE.c b/gst-libs/gst/gl/gstglwindow_winCE.c new file mode 100644 index 0000000000..be736f81a2 --- /dev/null +++ b/gst-libs/gst/gl/gstglwindow_winCE.c @@ -0,0 +1,610 @@ +/* + * GStreamer + * Copyright (C) 2009 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 + +#include "gstglwindow.h" + +#define WM_GST_GL_WINDOW_CUSTOM (WM_APP+1) +#define WM_GST_GL_WINDOW_QUIT (WM_APP+2) + +LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +LRESULT FAR PASCAL sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +const gchar* EGLErrorString(); + +#define GST_GL_WINDOW_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_WINDOW, GstGLWindowPrivate)) + +enum +{ + PROP_0 +}; + +struct _GstGLWindowPrivate +{ + EGLNativeWindowType internal_win_id; + EGLDisplay display; + EGLSurface surface; + EGLContext gl_context; + GstGLWindowCB draw_cb; + gpointer draw_data; + GstGLWindowCB2 resize_cb; + gpointer resize_data; + GstGLWindowCB close_cb; + gpointer close_data; + gboolean is_closed; + gboolean visible; +}; + +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; + +HHOOK hHook; + +/* 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_base_init (gpointer g_class) +{ +} + +static void +gst_gl_window_class_init (GstGLWindowClass * klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS (klass); + WNDCLASS wc; + ATOM atom = 0; + HINSTANCE hinstance = GetModuleHandle (NULL); + + g_type_class_add_private (klass, sizeof (GstGLWindowPrivate)); + + obj_class->finalize = gst_gl_window_finalize; + + atom = GetClassInfo (hinstance, "GSTGL", &wc); + + if (atom == 0) + { + ZeroMemory (&wc, sizeof(WNDCLASS)); + + wc.lpfnWndProc = window_proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hinstance; + wc.hIcon = LoadIcon (NULL, IDI_WINLOGO); + wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wc.hCursor = LoadCursor (NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = "GSTGL"; + + atom = RegisterClass (&wc); + + if (atom == 0) + g_error ("Failed to register window class %x\r\n", GetLastError()); + } +} + +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); + + HINSTANCE hinstance = GetModuleHandle (NULL); + + static gint x = 0; + static gint y = 0; + + x += 20; + y += 20; + + priv->internal_win_id = 0; + priv->display = 0; + priv->surface = 0; + priv->gl_context = 0; + priv->draw_cb = NULL; + priv->draw_data = NULL; + priv->resize_cb = NULL; + priv->resize_data = NULL; + priv->close_cb = NULL; + priv->close_data = NULL; + priv->is_closed = FALSE; + priv->visible = FALSE; + + width += 2 * GetSystemMetrics (SM_CXSIZEFRAME); + height += 2 * GetSystemMetrics (SM_CYSIZEFRAME) + GetSystemMetrics (SM_CYCAPTION); + + priv->internal_win_id = CreateWindow ( + "GSTGL", + "OpenGL renderer", + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, //WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION + x, y, width, height, + (HWND) NULL, + (HMENU) NULL, + hinstance, + window + ); + + if (!priv->internal_win_id) + { + g_debug ("failed to create gl window: %d\n", priv->internal_win_id); + return NULL; + } + + g_debug ("gl window created: %d\n", priv->internal_win_id); + + //display is set in the window_proc + if (!priv->display) { + g_object_unref (G_OBJECT (window)); + return NULL; + } + + ShowCursor (TRUE); + + 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) +{ + GstGLWindowPrivate *priv = window->priv; + WNDPROC window_parent_proc = (WNDPROC) (guint64) GetWindowLongPtr((HWND)id, GWL_WNDPROC); + RECT rect; + + SetProp (priv->internal_win_id, "gl_window_parent_id", (HWND)id); + SetProp ((HWND)id, "gl_window_id", priv->internal_win_id); + SetProp ((HWND)id, "gl_window_parent_proc", (WNDPROC) window_parent_proc); + SetWindowLongPtr ((HWND)id, GWL_WNDPROC, (DWORD) (guint64) sub_class_proc); + + SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, WS_CHILD | WS_MAXIMIZE); + SetParent (priv->internal_win_id, (HWND)id); + + //take changes into account: SWP_FRAMECHANGED + GetClientRect ((HWND)id, &rect); + SetWindowPos (priv->internal_win_id, HWND_TOP, rect.left, rect.top, rect.right, rect.bottom, + SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE); + MoveWindow (priv->internal_win_id, rect.left, rect.top, rect.right, rect.bottom, FALSE); +} + +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; +} + +void +gst_gl_window_draw_unlocked (GstGLWindow *window) +{ + gst_gl_window_draw (window); +} + +/* Thread safe */ +void +gst_gl_window_draw (GstGLWindow *window) +{ + GstGLWindowPrivate *priv = window->priv; + + if (!priv->visible) + { + ShowWindowAsync (priv->internal_win_id, SW_SHOW); + priv->visible = TRUE; + } + + RedrawWindow (priv->internal_win_id, NULL, NULL, + RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE); +} + +void +gst_gl_window_run_loop (GstGLWindow *window) +{ + GstGLWindowPrivate *priv = window->priv; + gboolean running = TRUE; + gboolean bRet = FALSE; + MSG msg; + + g_debug ("begin loop\n"); + + while (running && (bRet = GetMessage (&msg, NULL, 0, 0)) != 0) + { + if (bRet == -1) + { + g_error ("Failed to get message %x\r\n", GetLastError()); + running = FALSE; + } + else + { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + } + + g_debug ("end loop\n"); +} + +/* Thread safe */ +void +gst_gl_window_quit_loop (GstGLWindow *window, GstGLWindowCB callback, gpointer data) +{ + if (window) + { + GstGLWindowPrivate *priv = window->priv; + LRESULT res = PostMessage(priv->internal_win_id, WM_GST_GL_WINDOW_QUIT, (WPARAM) data, (LPARAM) callback); + g_assert (SUCCEEDED (res)); + g_debug ("end loop requested\n"); + } +} + +/* Thread safe */ +void +gst_gl_window_send_message (GstGLWindow *window, GstGLWindowCB callback, gpointer data) +{ + if (window) + { + GstGLWindowPrivate *priv = window->priv; + LRESULT res = SendMessage (priv->internal_win_id, WM_GST_GL_WINDOW_CUSTOM, (WPARAM) data, (LPARAM) callback); + g_assert (SUCCEEDED (res)); + } +} + +LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (uMsg == WM_CREATE) { + + GstGLWindow *window = (GstGLWindow *) (((LPCREATESTRUCT) lParam)->lpCreateParams); + + g_debug ("WM_CREATE\n"); + + g_assert (window); + + { + EGLint majorVersion; + EGLint minorVersion; + EGLint numConfigs; + EGLConfig config; + EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE }; + + EGLint attribList[] = + { + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 8, + EGL_STENCIL_SIZE, 8, + EGL_SAMPLE_BUFFERS, EGL_DONT_CARE, //1 + EGL_NONE + }; + + GstGLWindowPrivate *priv = window->priv; + + priv->display = eglGetDisplay (GetDC (hWnd)); + if (priv->display != EGL_NO_DISPLAY) + g_debug ("display retrieved: %d\n", priv->display); + else + g_debug ("failed to retrieve display %d, %s\n", hWnd, EGLErrorString()); + + if (eglInitialize (priv->display, &majorVersion, &minorVersion)) + g_debug ("egl initialized: %d.%d\n", majorVersion, minorVersion); + else + g_debug ("failed to initialize egl %d, %s\n", priv->display, EGLErrorString()); + + if (eglGetConfigs (priv->display, NULL, 0, &numConfigs)) + g_debug ("configs retrieved: %d\n", numConfigs); + else + g_debug ("failed to retrieve configs %d, %s\n", priv->display, EGLErrorString()); + + if (eglChooseConfig (priv->display, attribList, &config, 1, &numConfigs)) + g_debug ("config set: %d, %d\n", config, numConfigs); + else + g_debug ("failed to set config %d, %s\n", priv->display, EGLErrorString()); + + priv->surface = eglCreateWindowSurface (priv->display, config, (EGLNativeWindowType)hWnd, NULL); + if (priv->surface != EGL_NO_SURFACE) + g_debug ("surface created: %d\n", priv->surface); + else + g_debug ("failed to create surface %d, %d, %d, %s\n", priv->display, priv->surface, hWnd, EGLErrorString()); + + priv->gl_context = eglCreateContext (priv->display, config, EGL_NO_CONTEXT, contextAttribs); + if (priv->gl_context != EGL_NO_CONTEXT) + g_debug ("gl context created: %d\n", priv->gl_context); + else + g_debug ("failed to create glcontext %d, %d, s\n", priv->gl_context, hWnd, EGLErrorString()); + + ReleaseDC (hWnd, priv->display); + + if (!eglMakeCurrent (priv->display, priv->surface, priv->surface, priv->gl_context)) + g_debug ("failed to make opengl context current %d, %s\n", hWnd, EGLErrorString()); + } + + SetProp (hWnd, "gl_window", window); + + return 0; + } + else if (GetProp(hWnd, "gl_window")) { + + GstGLWindow *window = GetProp(hWnd, "gl_window"); + GstGLWindowPrivate *priv = NULL; + + g_assert (window); + + priv = window->priv; + + g_assert (priv); + + g_assert (priv->internal_win_id == hWnd); + + g_assert (priv->gl_context == eglGetCurrentContext()); + + switch ( uMsg ) { + + case WM_SIZE: + { + if (priv->resize_cb) + priv->resize_cb (priv->resize_data, LOWORD(lParam), HIWORD(lParam)); + break; + } + + case WM_PAINT: + { + if (priv->draw_cb) + { + priv->draw_cb (priv->draw_data); + eglSwapBuffers (priv->display, priv->surface); + ValidateRect (hWnd, NULL); + } + break; + } + + case WM_CLOSE: + { + ShowWindowAsync (priv->internal_win_id, SW_HIDE); + + if (priv->close_cb) + priv->close_cb (priv->close_data); + + priv->draw_cb = NULL; + priv->draw_data = NULL; + priv->resize_cb = NULL; + priv->resize_data = NULL; + priv->close_cb = NULL; + priv->close_data = NULL; + break; + } + + case WM_GST_GL_WINDOW_QUIT: + { + HWND parent_id = 0; + GstGLWindowCB destroy_cb = (GstGLWindowCB) lParam; + + g_debug ("WM_CLOSE\n"); + + destroy_cb ((gpointer) wParam); + + parent_id = GetProp (hWnd, "gl_window_parent_id"); + if (parent_id) + { + WNDPROC parent_proc = GetProp (parent_id, "gl_window_parent_proc"); + + g_assert (parent_proc); + + SetWindowLongPtr (parent_id, GWL_WNDPROC, (LONG) (guint64) parent_proc); + SetParent (hWnd, NULL); + + RemoveProp (parent_id, "gl_window_parent_proc"); + RemoveProp (hWnd, "gl_window_parent_id"); + } + + priv->is_closed = TRUE; + RemoveProp (hWnd, "gl_window"); + + if (!eglMakeCurrent (priv->display, priv->surface, priv->surface, EGL_NO_CONTEXT)) + g_debug ("failed to make current null context %d, %s\n", priv->display, EGLErrorString()); + + if (priv->gl_context) + { + if (!eglDestroyContext (priv->display, priv->gl_context)) + g_debug ("failed to destroy context %d, %s\n", priv->gl_context, EGLErrorString()); + priv->gl_context = NULL; + } + + if (priv->surface) + { + if (!eglDestroySurface (priv->display, priv->surface)) + g_debug ("failed to destroy surface %d, %s\n", priv->surface, EGLErrorString()); + priv->surface = NULL; + } + + if (priv->surface) + { + if (!eglTerminate (priv->display)) + g_debug ("failed to terminate display %d, %s\n", priv->display, EGLErrorString()); + priv->surface = NULL; + } + + if (priv->internal_win_id) + { + if (!DestroyWindow(priv->internal_win_id)) + g_debug ("failed to destroy window %d, 0x%x\n", hWnd, GetLastError()); + } + + PostQuitMessage (0); + break; + } + + case WM_CAPTURECHANGED: + { + g_debug ("WM_CAPTURECHANGED\n"); + if (priv->draw_cb) + priv->draw_cb (priv->draw_data); + break; + } + + case WM_GST_GL_WINDOW_CUSTOM: + { + if (!priv->is_closed) + { + GstGLWindowCB custom_cb = (GstGLWindowCB) lParam; + custom_cb ((gpointer) wParam); + } + break; + } + + case WM_ERASEBKGND: + return TRUE; + + default: + { + /* transmit messages to the parrent (ex: mouse/keyboard input) */ + HWND parent_id = GetProp (hWnd, "gl_window_parent_id"); + if (parent_id) + PostMessage (parent_id, uMsg, wParam, lParam); + return DefWindowProc (hWnd, uMsg, wParam, lParam); + } + } + + return 0; + } + else + return DefWindowProc( hWnd, uMsg, wParam, lParam ); +} + +LRESULT FAR PASCAL sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC window_parent_proc = GetProp (hWnd, "gl_window_parent_proc"); + + if (uMsg == WM_SIZE) + { + HWND gl_window_id = GetProp (hWnd, "gl_window_id"); + MoveWindow (gl_window_id, 0, 0, LOWORD(lParam), HIWORD(lParam), FALSE); + } + + return CallWindowProc (window_parent_proc, hWnd, uMsg, wParam, lParam); +} + +const gchar* EGLErrorString() +{ + EGLint nErr = eglGetError(); + switch(nErr){ + case EGL_SUCCESS: + return "EGL_SUCCESS"; + case EGL_BAD_DISPLAY: + return "EGL_BAD_DISPLAY"; + case EGL_NOT_INITIALIZED: + return "EGL_NOT_INITIALIZED"; + case EGL_BAD_ACCESS: + return "EGL_BAD_ACCESS"; + case EGL_BAD_ALLOC: + return "EGL_BAD_ALLOC"; + case EGL_BAD_ATTRIBUTE: + return "EGL_BAD_ATTRIBUTE"; + case EGL_BAD_CONFIG: + return "EGL_BAD_CONFIG"; + case EGL_BAD_CONTEXT: + return "EGL_BAD_CONTEXT"; + case EGL_BAD_CURRENT_SURFACE: + return "EGL_BAD_CURRENT_SURFACE"; + case EGL_BAD_MATCH: + return "EGL_BAD_MATCH"; + case EGL_BAD_NATIVE_PIXMAP: + return "EGL_BAD_NATIVE_PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: + return "EGL_BAD_NATIVE_WINDOW"; + case EGL_BAD_PARAMETER: + return "EGL_BAD_PARAMETER"; + case EGL_BAD_SURFACE: + return "EGL_BAD_SURFACE"; + default: + return "unknown"; + } +}