From 4bbda2b6268a5bc4749190a16decc2520a120f64 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 12 Jul 2016 12:59:57 +1000 Subject: [PATCH] glframebuffer: rewrite for a more consistent API Facilities are given to create fbo's and attach GL memory (renderbuffers or textures). It also keeps track of the renderable size for use with effective use with glViewport(). --- ext/gl/gstglfilterapp.c | 43 +-- ext/gl/gstglfilterapp.h | 2 - ext/gl/gstglfiltercube.c | 15 +- ext/gl/gstglfilterglass.c | 17 +- ext/gl/gstglmixer.c | 38 +-- ext/gl/gstglmixer.h | 3 +- ext/gl/gstglmosaic.c | 26 +- ext/gl/gstgltestsrc.c | 58 ++-- ext/gl/gstgltestsrc.h | 4 +- ext/gl/gstgltransformation.c | 15 +- ext/gl/gstglvideomixer.c | 27 +- ext/gl/gstglvideomixer.h | 1 + gst-libs/gst/gl/gstgl_fwd.h | 4 + gst-libs/gst/gl/gstglcolorconvert.c | 102 +----- gst-libs/gst/gl/gstglcolorconvert.h | 3 +- gst-libs/gst/gl/gstglfilter.c | 29 +- gst-libs/gst/gl/gstglfilter.h | 5 +- gst-libs/gst/gl/gstglframebuffer.c | 470 ++++++++++++++++++++-------- gst-libs/gst/gl/gstglframebuffer.h | 42 ++- gst-libs/gst/gl/gstglutils.c | 150 --------- gst-libs/gst/gl/gstglutils.h | 17 - gst-libs/gst/gl/gstglviewconvert.c | 95 ++---- gst-libs/gst/gl/gstglviewconvert.h | 3 +- tests/check/libs/gstglcontext.c | 27 +- 24 files changed, 574 insertions(+), 622 deletions(-) diff --git a/ext/gl/gstglfilterapp.c b/ext/gl/gstglfilterapp.c index 07e1e5597e..adcf006bb9 100644 --- a/ext/gl/gstglfilterapp.c +++ b/ext/gl/gstglfilterapp.c @@ -184,35 +184,24 @@ gst_gl_filter_app_set_caps (GstGLFilter * filter, GstCaps * incaps, return TRUE; } -static void -_emit_draw_signal (guint tex, gint width, gint height, gpointer data) -{ - GstGLFilterApp *app_filter = GST_GL_FILTER_APP (data); - gboolean drawn; - - g_signal_emit (app_filter, gst_gl_filter_app_signals[CLIENT_DRAW_SIGNAL], 0, - tex, width, height, &drawn); - - app_filter->default_draw = !drawn; -} - struct glcb2 { - GLCB func; - gpointer data; + GstGLFilterApp *app; GstGLMemory *in_tex; GstGLMemory *out_tex; }; -/* convenience functions to simplify filter development */ -static void -_glcb2 (gpointer data) +static gboolean +_emit_draw_signal (gpointer data) { struct glcb2 *cb = data; + gboolean drawn; - cb->func (gst_gl_memory_get_texture_width (cb->in_tex), - gst_gl_memory_get_texture_height (cb->in_tex), cb->in_tex->tex_id, - cb->data); + g_signal_emit (cb->app, gst_gl_filter_app_signals[CLIENT_DRAW_SIGNAL], 0, + cb->in_tex->tex_id, gst_gl_memory_get_texture_width (cb->out_tex), + gst_gl_memory_get_texture_height (cb->out_tex), &drawn); + + return !drawn; } static gboolean @@ -220,20 +209,18 @@ gst_gl_filter_app_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex, GstGLMemory * out_tex) { GstGLFilterApp *app_filter = GST_GL_FILTER_APP (filter); + gboolean default_draw; struct glcb2 cb; - cb.func = (GLCB) _emit_draw_signal; - cb.data = filter; + cb.app = app_filter; cb.in_tex = in_tex; cb.out_tex = out_tex; - //blocking call, use a FBO - gst_gl_context_use_fbo_v2 (GST_GL_BASE_FILTER (filter)->context, - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info), - filter->fbo, filter->depthbuffer, out_tex->tex_id, _glcb2, &cb); + default_draw = + gst_gl_framebuffer_draw_to_texture (filter->fbo, + out_tex, _emit_draw_signal, &cb); - if (app_filter->default_draw) { + if (default_draw) { gst_gl_filter_render_to_target_with_shader (filter, TRUE, in_tex, out_tex, filter->default_shader); } diff --git a/ext/gl/gstglfilterapp.h b/ext/gl/gstglfilterapp.h index a8978c519a..d7e9a6f2ab 100644 --- a/ext/gl/gstglfilterapp.h +++ b/ext/gl/gstglfilterapp.h @@ -37,8 +37,6 @@ typedef struct _GstGLFilterAppClass GstGLFilterAppClass; struct _GstGLFilterApp { GstGLFilter filter; - - gboolean default_draw; }; struct _GstGLFilterAppClass diff --git a/ext/gl/gstglfiltercube.c b/ext/gl/gstglfiltercube.c index ba8d5243e0..717eba6938 100644 --- a/ext/gl/gstglfiltercube.c +++ b/ext/gl/gstglfiltercube.c @@ -79,7 +79,7 @@ static gboolean gst_gl_filter_cube_set_caps (GstGLFilter * filter, GstCaps * incaps, GstCaps * outcaps); static void gst_gl_filter_cube_reset_gl (GstGLFilter * filter); static gboolean gst_gl_filter_cube_init_shader (GstGLFilter * filter); -static void _callback (gpointer stuff); +static gboolean _callback (gpointer stuff); static gboolean gst_gl_filter_cube_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex, GstGLMemory * out_tex); @@ -342,13 +342,8 @@ gst_gl_filter_cube_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex, cube_filter->in_tex = in_tex; - /* blocking call, use a FBO */ - gst_gl_context_use_fbo_v2 (GST_GL_BASE_FILTER (filter)->context, - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info), filter->fbo, - filter->depthbuffer, out_tex->tex_id, _callback, (gpointer) cube_filter); - - return TRUE; + return gst_gl_framebuffer_draw_to_texture (filter->fbo, out_tex, _callback, + cube_filter); } /* *INDENT-OFF* */ @@ -440,7 +435,7 @@ _unbind_buffer (GstGLFilterCube * cube_filter) gl->DisableVertexAttribArray (cube_filter->attr_texture); } -static void +static gboolean _callback (gpointer stuff) { GstGLFilter *filter = GST_GL_FILTER (stuff); @@ -516,4 +511,6 @@ _callback (gpointer stuff) xrot += 0.3f; yrot += 0.2f; zrot += 0.4f; + + return TRUE; } diff --git a/ext/gl/gstglfilterglass.c b/ext/gl/gstglfilterglass.c index a0639d2d02..28bc48585e 100644 --- a/ext/gl/gstglfilterglass.c +++ b/ext/gl/gstglfilterglass.c @@ -73,7 +73,7 @@ static void gst_gl_filter_glass_draw_video_plane (GstGLFilter * filter, gint width, gint height, guint texture, gfloat center_x, gfloat center_y, gfloat start_alpha, gfloat stop_alpha, gboolean reversed, gfloat rotation); -static void gst_gl_filter_glass_callback (gpointer stuff); +static gboolean gst_gl_filter_glass_callback (gpointer stuff); /* *INDENT-OFF* */ static const gchar *glass_fragment_source = @@ -245,12 +245,8 @@ gst_gl_filter_glass_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex, glass_filter->in_tex = in_tex; - //blocking call, use a FBO - gst_gl_context_use_fbo_v2 (GST_GL_BASE_FILTER (filter)->context, - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info), - filter->fbo, filter->depthbuffer, out_tex->tex_id, - gst_gl_filter_glass_callback, (gpointer) glass_filter); + gst_gl_framebuffer_draw_to_texture (filter->fbo, out_tex, + gst_gl_filter_glass_callback, glass_filter); return TRUE; } @@ -353,8 +349,7 @@ gst_gl_filter_glass_draw_video_plane (GstGLFilter * filter, gl->DisableClientState (GL_COLOR_ARRAY); } -//opengl scene, params: input texture (not the output filter->texture) -static void +static gboolean gst_gl_filter_glass_callback (gpointer stuff) { static gint64 start_time = 0; @@ -376,7 +371,7 @@ gst_gl_filter_glass_callback (gpointer stuff) time_left -= 1000000 / 25; if (time_left > 2000) { GST_LOG ("escape"); - return; + return FALSE; } } @@ -408,4 +403,6 @@ gst_gl_filter_glass_callback (gpointer stuff) gst_gl_context_clear_shader (GST_GL_BASE_FILTER (filter)->context); gl->Disable (GL_BLEND); + + return TRUE; } diff --git a/ext/gl/gstglmixer.c b/ext/gl/gstglmixer.c index f9c22a1d2e..3fc5aa6f50 100644 --- a/ext/gl/gstglmixer.c +++ b/ext/gl/gstglmixer.c @@ -410,8 +410,6 @@ static void gst_gl_mixer_init (GstGLMixer * mix) { mix->priv = GST_GL_MIXER_GET_PRIVATE (mix); - mix->fbo = 0; - mix->depthbuffer = 0; mix->priv->gl_resource_ready = FALSE; g_mutex_init (&mix->priv->gl_resource_lock); @@ -512,33 +510,38 @@ gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator, return ret; } +static void +_mixer_create_fbo (GstGLContext * context, GstGLMixer * mix) +{ + GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix); + guint out_width = GST_VIDEO_INFO_WIDTH (&vagg->info); + guint out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info); + + mix->fbo = + gst_gl_framebuffer_new_with_default_depth (context, out_width, + out_height); +} + static gboolean gst_gl_mixer_decide_allocation (GstGLBaseMixer * base_mix, GstQuery * query) { GstGLMixer *mix = GST_GL_MIXER (base_mix); GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix); - GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix); GstGLContext *context = base_mix->context; GstBufferPool *pool = NULL; GstStructure *config; GstCaps *caps; guint min, max, size; gboolean update_pool; - guint out_width, out_height; - - out_width = GST_VIDEO_INFO_WIDTH (&vagg->info); - out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info); g_mutex_lock (&mix->priv->gl_resource_lock); mix->priv->gl_resource_ready = FALSE; - if (mix->fbo) { - gst_gl_context_del_fbo (context, mix->fbo, mix->depthbuffer); - mix->fbo = 0; - mix->depthbuffer = 0; - } + if (mix->fbo) + gst_object_unref (mix->fbo); - if (!gst_gl_context_gen_fbo (context, out_width, out_height, - &mix->fbo, &mix->depthbuffer)) { + gst_gl_context_thread_add (context, + (GstGLContextThreadFunc) _mixer_create_fbo, mix); + if (!mix->fbo) { g_cond_signal (&mix->priv->gl_resource_cond); g_mutex_unlock (&mix->priv->gl_resource_lock); goto context_error; @@ -735,14 +738,13 @@ gst_gl_mixer_stop (GstAggregator * agg) { GstGLMixer *mix = GST_GL_MIXER (agg); GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix); - GstGLContext *context = GST_GL_BASE_MIXER (mix)->context; if (mixer_class->reset) mixer_class->reset (mix); + if (mix->fbo) { - gst_gl_context_del_fbo (context, mix->fbo, mix->depthbuffer); - mix->fbo = 0; - mix->depthbuffer = 0; + gst_object_unref (mix->fbo); + mix->fbo = NULL; } gst_gl_mixer_reset (mix); diff --git a/ext/gl/gstglmixer.h b/ext/gl/gstglmixer.h index de5a3dc4ef..309f6bbf0c 100644 --- a/ext/gl/gstglmixer.h +++ b/ext/gl/gstglmixer.h @@ -84,8 +84,7 @@ struct _GstGLMixer { GstGLBaseMixer vaggregator; - GLuint fbo; - GLuint depthbuffer; + GstGLFramebuffer *fbo; GstCaps *out_caps; diff --git a/ext/gl/gstglmosaic.c b/ext/gl/gstglmosaic.c index 701435f804..41441b0649 100644 --- a/ext/gl/gstglmosaic.c +++ b/ext/gl/gstglmosaic.c @@ -71,7 +71,7 @@ static gboolean gst_gl_mosaic_init_shader (GstGLMixer * mixer, static gboolean gst_gl_mosaic_process_textures (GstGLMixer * mixer, GstGLMemory * out_tex); -static void gst_gl_mosaic_callback (gpointer stuff); +static gboolean gst_gl_mosaic_callback (gpointer stuff); //vertex source static const gchar *mosaic_v_src = @@ -193,23 +193,31 @@ gst_gl_mosaic_init_shader (GstGLMixer * mixer, GstCaps * outcaps) mosaic_v_src, mosaic_f_src, &mosaic->shader); } +static void +_mosaic_render (GstGLContext * context, GstGLMosaic * mosaic) +{ + GstGLMixer *mixer = GST_GL_MIXER (mosaic); + + gst_gl_framebuffer_draw_to_texture (mixer->fbo, mosaic->out_tex, + gst_gl_mosaic_callback, mosaic); +} + static gboolean gst_gl_mosaic_process_textures (GstGLMixer * mix, GstGLMemory * out_tex) { GstGLMosaic *mosaic = GST_GL_MOSAIC (mix); + GstGLContext *context = GST_GL_BASE_MIXER (mix)->context; - //blocking call, use a FBO - gst_gl_context_use_fbo_v2 (GST_GL_BASE_MIXER (mix)->context, - GST_VIDEO_INFO_WIDTH (&GST_VIDEO_AGGREGATOR (mix)->info), - GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR (mix)->info), mix->fbo, - mix->depthbuffer, out_tex->tex_id, gst_gl_mosaic_callback, - (gpointer) mosaic); + mosaic->out_tex = out_tex; + + gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _mosaic_render, + mosaic); return TRUE; } /* opengl scene, params: input texture (not the output mixer->texture) */ -static void +static gboolean gst_gl_mosaic_callback (gpointer stuff) { GstGLMosaic *mosaic = GST_GL_MOSAIC (stuff); @@ -345,4 +353,6 @@ gst_gl_mosaic_callback (gpointer stuff) xrot += 0.6f; yrot += 0.4f; zrot += 0.8f; + + return TRUE; } diff --git a/ext/gl/gstgltestsrc.c b/ext/gl/gstgltestsrc.c index 69c8b33b63..62d231ff8f 100644 --- a/ext/gl/gstgltestsrc.c +++ b/ext/gl/gstgltestsrc.c @@ -107,7 +107,7 @@ static gboolean gst_gl_test_src_stop (GstBaseSrc * basesrc); static gboolean gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query); -static void gst_gl_test_src_callback (gpointer stuff); +static gboolean gst_gl_test_src_callback (gpointer stuff); static gboolean gst_gl_test_src_init_shader (GstGLTestSrc * gltestsrc); @@ -454,22 +454,24 @@ gst_gl_test_src_init_shader (GstGLTestSrc * gltestsrc) return TRUE; } +static void +_fill_gl (GstGLContext * context, GstGLTestSrc * src) +{ + src->gl_result = gst_gl_framebuffer_draw_to_texture (src->fbo, src->out_tex, + gst_gl_test_src_callback, src); +} + static GstFlowReturn gst_gl_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer) { GstGLTestSrc *src = GST_GL_TEST_SRC (psrc); GstClockTime next_time; - gint width, height; GstVideoFrame out_frame; GstGLSyncMeta *sync_meta; - guint out_tex; if (G_UNLIKELY (!src->negotiated || !src->context)) goto not_negotiated; - width = GST_VIDEO_INFO_WIDTH (&src->out_info); - height = GST_VIDEO_INFO_HEIGHT (&src->out_info); - /* 0 framerate and we are at the second frame, eos */ if (G_UNLIKELY (GST_VIDEO_INFO_FPS_N (&src->out_info) == 0 && src->n_frames == 1)) @@ -480,11 +482,11 @@ gst_gl_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer) return GST_FLOW_NOT_NEGOTIATED; } - out_tex = *(guint *) out_frame.data[0]; + src->out_tex = (GstGLMemory *) out_frame.map[0].memory; - if (!gst_gl_context_use_fbo_v2 (src->context, width, height, src->fbo, - src->depthbuffer, out_tex, gst_gl_test_src_callback, - (gpointer) src)) { + gst_gl_context_thread_add (src->context, (GstGLContextThreadFunc) _fill_gl, + src); + if (!src->gl_result) { gst_video_frame_unmap (&out_frame); goto gl_error; } @@ -562,8 +564,11 @@ gst_gl_test_src_stop (GstBaseSrc * basesrc) gst_object_unref (src->shader); src->shader = NULL; } - //blocking call, delete the FBO - gst_gl_context_del_fbo (src->context, src->fbo, src->depthbuffer); + + if (src->fbo) + gst_object_unref (src->fbo); + src->fbo = NULL; + gst_object_unref (src->context); src->context = NULL; } @@ -615,6 +620,14 @@ _find_local_gl_context (GstGLTestSrc * src) return FALSE; } +static void +_src_generate_fbo_gl (GstGLContext * context, GstGLTestSrc * src) +{ + src->fbo = gst_gl_framebuffer_new_with_default_depth (src->context, + GST_VIDEO_INFO_WIDTH (&src->out_info), + GST_VIDEO_INFO_HEIGHT (&src->out_info)); +} + static gboolean gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query) { @@ -625,7 +638,6 @@ gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query) guint min, max, size; gboolean update_pool; GError *error = NULL; - guint out_width, out_height; if (!gst_gl_ensure_element_data (src, &src->display, &src->other_context)) return FALSE; @@ -658,11 +670,9 @@ gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query) if ((gst_gl_context_get_gl_api (src->context) & SUPPORTED_GL_APIS) == 0) goto unsupported_gl_api; - out_width = GST_VIDEO_INFO_WIDTH (&src->out_info); - out_height = GST_VIDEO_INFO_HEIGHT (&src->out_info); - - if (!gst_gl_context_gen_fbo (src->context, out_width, out_height, - &src->fbo, &src->depthbuffer)) + gst_gl_context_thread_add (src->context, + (GstGLContextThreadFunc) _src_generate_fbo_gl, src); + if (!src->fbo) goto context_error; gst_query_parse_allocation (query, &caps, NULL); @@ -735,8 +745,7 @@ context_error: } } -//opengl scene -static void +static gboolean gst_gl_test_src_callback (gpointer stuff) { GstGLTestSrc *src = GST_GL_TEST_SRC (stuff); @@ -752,21 +761,18 @@ gst_gl_test_src_callback (gpointer stuff) if (funcs == NULL) { GST_ERROR_OBJECT (src, "Could not find an implementation of the " "requested pattern"); - src->gl_result = FALSE; - return; + return FALSE; } src->src_impl = funcs->new (src); if (!(src->gl_result = funcs->init (src->src_impl, src->context, &src->out_info))) { GST_ERROR_OBJECT (src, "Failed to initialize pattern"); - return; + return FALSE; } src->active_pattern = src->set_pattern; } - src->gl_result = funcs->fill_bound_fbo (src->src_impl); - if (!src->gl_result) - GST_ERROR_OBJECT (src, "Failed to render the pattern"); + return funcs->fill_bound_fbo (src->src_impl); } static GstStateChangeReturn diff --git a/ext/gl/gstgltestsrc.h b/ext/gl/gstgltestsrc.h index 1b566ad060..df4abb74a0 100644 --- a/ext/gl/gstgltestsrc.h +++ b/ext/gl/gstgltestsrc.h @@ -62,8 +62,8 @@ struct _GstGLTestSrc { /* video state */ GstVideoInfo out_info; - GLuint fbo; - GLuint depthbuffer; + GstGLFramebuffer *fbo; + GstGLMemory *out_tex; GstGLShader *shader; diff --git a/ext/gl/gstgltransformation.c b/ext/gl/gstgltransformation.c index 1a8ddf28cb..1e805901e3 100644 --- a/ext/gl/gstgltransformation.c +++ b/ext/gl/gstgltransformation.c @@ -97,7 +97,7 @@ static gboolean gst_gl_transformation_decide_allocation (GstBaseTransform * static void gst_gl_transformation_reset_gl (GstGLFilter * filter); static gboolean gst_gl_transformation_stop (GstBaseTransform * trans); static gboolean gst_gl_transformation_init_shader (GstGLFilter * filter); -static void gst_gl_transformation_callback (gpointer stuff); +static gboolean gst_gl_transformation_callback (gpointer stuff); static void gst_gl_transformation_build_mvp (GstGLTransformation * transformation); @@ -789,13 +789,8 @@ gst_gl_transformation_filter_texture (GstGLFilter * filter, transformation->in_tex = in_tex; - /* blocking call, use a FBO */ - gst_gl_context_use_fbo_v2 (GST_GL_BASE_FILTER (filter)->context, - GST_VIDEO_INFO_WIDTH (&filter->out_info), - GST_VIDEO_INFO_HEIGHT (&filter->out_info), - filter->fbo, filter->depthbuffer, - out_tex->tex_id, gst_gl_transformation_callback, - (gpointer) transformation); + gst_gl_framebuffer_draw_to_texture (filter->fbo, out_tex, + (GstGLFramebufferFunc) gst_gl_transformation_callback, transformation); return TRUE; } @@ -857,7 +852,7 @@ _unbind_buffer (GstGLTransformation * transformation) gl->DisableVertexAttribArray (transformation->attr_texture); } -static void +static gboolean gst_gl_transformation_callback (gpointer stuff) { GstGLFilter *filter = GST_GL_FILTER (stuff); @@ -925,4 +920,6 @@ gst_gl_transformation_callback (gpointer stuff) gst_gl_context_clear_shader (GST_GL_BASE_FILTER (filter)->context); transformation->caps_change = FALSE; + + return TRUE; } diff --git a/ext/gl/gstglvideomixer.c b/ext/gl/gstglvideomixer.c index 176d27e547..4491823d13 100644 --- a/ext/gl/gstglvideomixer.c +++ b/ext/gl/gstglvideomixer.c @@ -475,7 +475,7 @@ static gboolean gst_gl_video_mixer_init_shader (GstGLMixer * mixer, static gboolean gst_gl_video_mixer_process_textures (GstGLMixer * mixer, GstGLMemory * out_tex); -static void gst_gl_video_mixer_callback (gpointer stuff); +static gboolean gst_gl_video_mixer_callback (gpointer stuff); /* *INDENT-OFF* */ @@ -1155,16 +1155,25 @@ gst_gl_video_mixer_init_shader (GstGLMixer * mixer, GstCaps * outcaps) video_mixer_f_src, &video_mixer->shader); } +static void +_video_mixer_process_gl (GstGLContext * context, GstGLVideoMixer * video_mixer) +{ + GstGLMixer *mixer = GST_GL_MIXER (video_mixer); + + gst_gl_framebuffer_draw_to_texture (mixer->fbo, video_mixer->out_tex, + gst_gl_video_mixer_callback, video_mixer); +} + static gboolean gst_gl_video_mixer_process_textures (GstGLMixer * mix, GstGLMemory * out_tex) { GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mix); + GstGLContext *context = GST_GL_BASE_MIXER (mix)->context; - gst_gl_context_use_fbo_v2 (GST_GL_BASE_MIXER (mix)->context, - GST_VIDEO_INFO_WIDTH (&GST_VIDEO_AGGREGATOR (mix)->info), - GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR (mix)->info), - mix->fbo, mix->depthbuffer, - out_tex->tex_id, gst_gl_video_mixer_callback, (gpointer) video_mixer); + video_mixer->out_tex = out_tex; + + gst_gl_context_thread_add (context, + (GstGLContextThreadFunc) _video_mixer_process_gl, video_mixer); return TRUE; } @@ -1383,7 +1392,7 @@ _set_blend_state (GstGLVideoMixer * video_mixer, GstGLVideoMixerPad * mix_pad) } /* opengl scene, params: input texture (not the output mixer->texture) */ -static void +static gboolean gst_gl_video_mixer_callback (gpointer stuff) { GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (stuff); @@ -1411,7 +1420,7 @@ gst_gl_video_mixer_callback (gpointer stuff) } if (!_draw_background (video_mixer)) - return; + return FALSE; gst_gl_shader_use (video_mixer->shader); @@ -1546,4 +1555,6 @@ gst_gl_video_mixer_callback (gpointer stuff) gl->Disable (GL_BLEND); gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context); + + return TRUE; } diff --git a/ext/gl/gstglvideomixer.h b/ext/gl/gstglvideomixer.h index a0776fd9fc..f3526465eb 100644 --- a/ext/gl/gstglvideomixer.h +++ b/ext/gl/gstglvideomixer.h @@ -125,6 +125,7 @@ struct _GstGLVideoMixer GLuint vao; GLuint vbo_indices; GLuint checker_vbo; + GstGLMemory *out_tex; }; struct _GstGLVideoMixerClass diff --git a/gst-libs/gst/gl/gstgl_fwd.h b/gst-libs/gst/gl/gstgl_fwd.h index 86fff2f573..465e284537 100644 --- a/gst-libs/gst/gl/gstgl_fwd.h +++ b/gst-libs/gst/gl/gstgl_fwd.h @@ -63,6 +63,10 @@ typedef struct _GstGLRenderbuffer GstGLRenderbuffer; typedef struct _GstGLRenderbufferAllocator GstGLRenderbufferAllocator; typedef struct _GstGLRenderbufferAllocatorClass GstGLRenderbufferAllocatorClass; +typedef struct _GstGLFramebuffer GstGLFramebuffer; +typedef struct _GstGLFramebufferAllocator GstGLFramebufferAllocator; +typedef struct _GstGLFramebufferAllocatorClass GstGLFramebufferAllocatorClass; + typedef struct _GstGLSLStage GstGLSLStage; typedef struct _GstGLSLStagePrivate GstGLSLStagePrivate; typedef struct _GstGLSLStageClass GstGLSLStageClass; diff --git a/gst-libs/gst/gl/gstglcolorconvert.c b/gst-libs/gst/gl/gstglcolorconvert.c index ebddb2d2ba..34a5818975 100644 --- a/gst-libs/gst/gl/gstglcolorconvert.c +++ b/gst-libs/gst/gl/gstglcolorconvert.c @@ -549,11 +549,9 @@ gst_gl_color_convert_reset (GstGLColorConvert * convert) { guint i; - if (convert->fbo || convert->depth_buffer) { - gst_gl_context_del_fbo (convert->context, convert->fbo, - convert->depth_buffer); - convert->fbo = 0; - convert->depth_buffer = 0; + if (convert->fbo) { + gst_object_unref (convert->fbo); + convert->fbo = NULL; } for (i = 0; i < convert->priv->convert_info.out_n_textures; i++) { @@ -2027,7 +2025,7 @@ _init_convert (GstGLColorConvert * convert) gst_gl_context_clear_shader (convert->context); - if (convert->fbo == 0 && !_init_convert_fbo (convert)) { + if (convert->fbo == NULL && !_init_convert_fbo (convert)) { goto error; } @@ -2088,82 +2086,16 @@ incompatible_api: static gboolean _init_convert_fbo (GstGLColorConvert * convert) { - GstGLFuncs *gl; guint out_width, out_height; - GLuint fake_texture = 0; /* a FBO must hava texture to init */ - GLenum internal_format; - - gl = convert->context->gl_vtable; out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info); out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info); - if (!gl->GenFramebuffers) { - /* turn off the pipeline because Frame buffer object is a not present */ - gst_gl_context_set_error (convert->context, - "Context, EXT_framebuffer_object supported: no"); - return FALSE; - } + convert->fbo = + gst_gl_framebuffer_new_with_default_depth (convert->context, out_width, + out_height); - GST_INFO ("Context, EXT_framebuffer_object supported: yes"); - - /* setup FBO */ - gl->GenFramebuffers (1, &convert->fbo); - gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo); - - /* setup the render buffer for depth */ - gl->GenRenderbuffers (1, &convert->depth_buffer); - gl->BindRenderbuffer (GL_RENDERBUFFER, convert->depth_buffer); - if (USING_OPENGL (convert->context) || USING_OPENGL3 (convert->context)) { - gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, - out_width, out_height); - } - if (USING_GLES2 (convert->context)) { - gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, - out_width, out_height); - } - - /* a fake texture is attached to the convert FBO (cannot init without it) */ - gl->GenTextures (1, &fake_texture); - gl->BindTexture (GL_TEXTURE_2D, fake_texture); - internal_format = - gst_gl_sized_gl_format_from_gl_format_type (convert->context, GL_RGBA, - GL_UNSIGNED_BYTE); - gl->TexImage2D (GL_TEXTURE_2D, 0, internal_format, out_width, out_height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - /* attach the texture to the FBO to renderer to */ - gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, fake_texture, 0); - - /* attach the depth render buffer to the FBO */ - gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, convert->depth_buffer); - - if (USING_OPENGL (convert->context)) { - gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, convert->depth_buffer); - } - - if (!gst_gl_context_check_framebuffer_status (convert->context)) { - gst_gl_context_set_error (convert->context, - "GL framebuffer status incomplete"); - - gl->DeleteTextures (1, &fake_texture); - - return FALSE; - } - - /* unbind the FBO */ - gl->BindFramebuffer (GL_FRAMEBUFFER, 0); - - gl->DeleteTextures (1, &fake_texture); - - return TRUE; + return convert->fbo != NULL; } static gboolean @@ -2487,21 +2419,13 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert) gl = context->gl_vtable; - out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info); - out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info); - - gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo); + gst_gl_framebuffer_bind (convert->fbo); /* attach the texture to the FBO to renderer to */ for (i = 0; i < c_info->out_n_textures; i++) { - guint gl_target = - gst_gl_texture_target_to_gl (convert->priv->to_texture_target); + GstGLBaseMemory *tex = (GstGLBaseMemory *) convert->priv->out_tex[i]; - /* needed? */ - gl->BindTexture (gl_target, convert->priv->out_tex[i]->tex_id); - - gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, - gl_target, convert->priv->out_tex[i]->tex_id, 0); + gst_gl_framebuffer_attach (convert->fbo, GL_COLOR_ATTACHMENT0 + i, tex); } if (gl->DrawBuffers) @@ -2511,6 +2435,8 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert) gl->GetIntegerv (GL_VIEWPORT, viewport_dim); + gst_gl_framebuffer_get_effective_dimensions (convert->fbo, &out_width, + &out_height); gl->Viewport (0, 0, out_width, out_height); gst_gl_shader_use (convert->shader); @@ -2556,7 +2482,7 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert) gst_gl_context_check_framebuffer_status (context); - gl->BindFramebuffer (GL_FRAMEBUFFER, 0); + gst_gl_context_clear_framebuffer (context); return TRUE; } diff --git a/gst-libs/gst/gl/gstglcolorconvert.h b/gst-libs/gst/gl/gstglcolorconvert.h index 5980cfa182..fbbbf3b0d7 100644 --- a/gst-libs/gst/gl/gstglcolorconvert.h +++ b/gst-libs/gst/gl/gstglcolorconvert.h @@ -59,8 +59,7 @@ struct _GstGLColorConvert GstBuffer * outbuf; /* used for the conversion */ - GLuint fbo; - GLuint depth_buffer; + GstGLFramebuffer *fbo; GstGLShader *shader; /* */ diff --git a/gst-libs/gst/gl/gstglfilter.c b/gst-libs/gst/gl/gstglfilter.c index 3f80588623..f6fd4392c0 100644 --- a/gst-libs/gst/gl/gstglfilter.c +++ b/gst-libs/gst/gl/gstglfilter.c @@ -228,12 +228,11 @@ gst_gl_filter_gl_stop (GstGLBaseFilter * base_filter) filter->vbo_indices = 0; } - if (filter->fbo != 0) { - gst_gl_context_del_fbo (context, filter->fbo, filter->depthbuffer); + if (filter->fbo != NULL) { + gst_object_unref (filter->fbo); + filter->fbo = NULL; } - filter->fbo = 0; - filter->depthbuffer = 0; filter->default_shader = NULL; filter->draw_attr_position_loc = -1; filter->draw_attr_texture_loc = -1; @@ -691,14 +690,12 @@ gst_gl_filter_gl_set_caps (GstGLBaseFilter * bt, GstCaps * incaps, out_width = GST_VIDEO_INFO_WIDTH (&filter->out_info); out_height = GST_VIDEO_INFO_HEIGHT (&filter->out_info); - if (filter->fbo) { - gst_gl_context_del_fbo (context, filter->fbo, filter->depthbuffer); - filter->fbo = 0; - filter->depthbuffer = 0; - } - //blocking call, generate a FBO - if (!gst_gl_context_gen_fbo (context, out_width, out_height, - &filter->fbo, &filter->depthbuffer)) + if (filter->fbo) + gst_object_unref (filter->fbo); + + if (!(filter->fbo = + gst_gl_framebuffer_new_with_default_depth (context, out_width, + out_height))) goto context_error; if (filter_class->init_fbo) { @@ -1009,12 +1006,14 @@ struct glcb2 }; /* convenience functions to simplify filter development */ -static void +static gboolean _glcb2 (gpointer data) { struct glcb2 *cb = data; cb->func (cb->width, cb->height, cb->texture, cb->data); + + return TRUE; } /** @@ -1034,7 +1033,6 @@ void gst_gl_filter_render_to_target (GstGLFilter * filter, gboolean resize, GstGLMemory * input, GstGLMemory * output, GLCB func, gpointer data) { - GstGLContext *context = GST_GL_BASE_FILTER (filter)->context; guint in_width, in_height, out_width, out_height; struct glcb2 cb; @@ -1057,8 +1055,7 @@ gst_gl_filter_render_to_target (GstGLFilter * filter, gboolean resize, cb.width = in_width; cb.height = in_height; - gst_gl_context_use_fbo_v2 (context, out_width, out_height, - filter->fbo, filter->depthbuffer, output->tex_id, _glcb2, &cb); + gst_gl_framebuffer_draw_to_texture (filter->fbo, output, _glcb2, &cb); } static void diff --git a/gst-libs/gst/gl/gstglfilter.h b/gst-libs/gst/gl/gstglfilter.h index 71ff0467db..795f6fffce 100644 --- a/gst-libs/gst/gl/gstglfilter.h +++ b/gst-libs/gst/gl/gstglfilter.h @@ -63,9 +63,10 @@ struct _GstGLFilter GstCaps *out_caps; + /* */ + GstGLFramebuffer *fbo; + /* */ - GLuint fbo; - GLuint depthbuffer; gboolean gl_result; GstBuffer *inbuf; GstBuffer *outbuf; diff --git a/gst-libs/gst/gl/gstglframebuffer.c b/gst-libs/gst/gl/gstglframebuffer.c index fb706f50db..054c104960 100644 --- a/gst-libs/gst/gl/gstglframebuffer.c +++ b/gst-libs/gst/gl/gstglframebuffer.c @@ -24,13 +24,29 @@ #include "gl.h" #include "gstglframebuffer.h" +#ifndef GL_FRAMEBUFFER_UNDEFINED +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#endif +#ifndef GL_FRAMEBUFFER_UNSUPPORTED +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#endif + GST_DEBUG_CATEGORY_STATIC (gst_gl_framebuffer_debug); #define GST_CAT_DEFAULT gst_gl_framebuffer_debug #define DEBUG_INIT \ GST_DEBUG_CATEGORY_INIT (gst_gl_framebuffer_debug, "glframebuffer", 0, "GL Framebuffer"); -G_DEFINE_TYPE_WITH_CODE (GstGLFramebuffer, gst_gl_framebuffer, G_TYPE_OBJECT, +G_DEFINE_TYPE_WITH_CODE (GstGLFramebuffer, gst_gl_framebuffer, GST_TYPE_OBJECT, DEBUG_INIT); #define GST_GL_FRAMEBUFFER_GET_PRIVATE(o) \ @@ -40,13 +56,35 @@ static void gst_gl_framebuffer_finalize (GObject * object); struct _GstGLFramebufferPrivate { - gint width; - gint height; - - guint fbo; - guint depth; + guint effective_width; + guint effective_height; }; +struct fbo_attachment +{ + guint attachment_point; + GstGLBaseMemory *mem; +}; + +static void +_fbo_attachment_init (struct fbo_attachment *attach, guint point, + GstGLBaseMemory * mem) +{ + attach->attachment_point = point; + attach->mem = (GstGLBaseMemory *) gst_memory_ref (GST_MEMORY_CAST (mem)); +} + +static void +_fbo_attachment_unset (struct fbo_attachment *attach) +{ + if (!attach) + return; + + if (attach->mem) + gst_memory_unref (GST_MEMORY_CAST (attach->mem)); + attach->mem = NULL; +} + static void gst_gl_framebuffer_class_init (GstGLFramebufferClass * klass) { @@ -56,183 +94,355 @@ gst_gl_framebuffer_class_init (GstGLFramebufferClass * klass) } static void -gst_gl_framebuffer_init (GstGLFramebuffer * fbo) +gst_gl_framebuffer_init (GstGLFramebuffer * fb) { - fbo->priv = GST_GL_FRAMEBUFFER_GET_PRIVATE (fbo); + fb->priv = GST_GL_FRAMEBUFFER_GET_PRIVATE (fb); + + fb->attachments = + g_array_new (FALSE, FALSE, (sizeof (struct fbo_attachment))); + g_array_set_clear_func (fb->attachments, + (GDestroyNotify) _fbo_attachment_unset); +} + +static void +_delete_fbo_gl (GstGLContext * context, GstGLFramebuffer * fb) +{ + const GstGLFuncs *gl = context->gl_vtable; + + if (fb->fbo_id) + gl->DeleteFramebuffers (1, &fb->fbo_id); + fb->fbo_id = 0; } static void gst_gl_framebuffer_finalize (GObject * object) { - GstGLFramebuffer *fbo = GST_GL_FRAMEBUFFER (object); + GstGLFramebuffer *fb = GST_GL_FRAMEBUFFER (object); - if (fbo->context) { - gst_object_unref (fbo->context); - fbo->context = NULL; + if (fb->context) { + if (fb->fbo_id) + gst_gl_context_thread_add (fb->context, + (GstGLContextThreadFunc) _delete_fbo_gl, fb); + + gst_object_unref (fb->context); + fb->context = NULL; } + if (fb->attachments) + g_array_free (fb->attachments, TRUE); + fb->attachments = NULL; + G_OBJECT_CLASS (gst_gl_framebuffer_parent_class)->finalize (object); } GstGLFramebuffer * gst_gl_framebuffer_new (GstGLContext * context) { - GstGLFramebuffer *fbo = g_object_new (GST_TYPE_GL_FRAMEBUFFER, NULL); - - fbo->context = gst_object_ref (context); - - return fbo; -} - -gboolean -gst_gl_framebuffer_generate (GstGLFramebuffer * frame, gint width, gint height, - guint * fbo, guint * depth) -{ - GLuint fake_texture = 0; + GstGLFramebuffer *fb; const GstGLFuncs *gl; - GLenum internal_format; - g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (frame), FALSE); - g_return_val_if_fail (fbo != NULL && depth != NULL, FALSE); - g_return_val_if_fail (width > 0 && height > 0, FALSE); + g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL); + g_return_val_if_fail (gst_gl_context_get_current () == context, NULL); - gl = frame->context->gl_vtable; - - GST_TRACE ("creating FBO dimensions:%ux%u", width, height); + gl = context->gl_vtable; if (!gl->GenFramebuffers) { - gst_gl_context_set_error (frame->context, - "Context, EXT_framebuffer_object not supported"); - return FALSE; + GST_ERROR_OBJECT (context, "Framebuffers are not supported!"); + return NULL; } - /* setup FBO */ - gl->GenFramebuffers (1, fbo); - gl->BindFramebuffer (GL_FRAMEBUFFER, *fbo); - /* setup the render buffer for depth */ - gl->GenRenderbuffers (1, depth); - gl->BindRenderbuffer (GL_RENDERBUFFER, *depth); + fb = g_object_new (GST_TYPE_GL_FRAMEBUFFER, NULL); + fb->context = gst_object_ref (context); + gl->GenFramebuffers (1, &fb->fbo_id); - if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL | + return fb; +} + +GstGLFramebuffer * +gst_gl_framebuffer_new_with_default_depth (GstGLContext * context, guint width, + guint height) +{ + GstGLFramebuffer *fb = gst_gl_framebuffer_new (context); + GstGLBaseMemoryAllocator *render_alloc; + GstGLAllocationParams *params; + GstGLBaseMemory *renderbuffer; + guint attach_point, attach_type; + + if (!fb) + return NULL; + + if (gst_gl_context_get_gl_api (fb->context) & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3)) { - gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, - height); - } - if (gst_gl_context_get_gl_api (frame->context) & GST_GL_API_GLES2) { - gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, - width, height); + attach_point = GL_DEPTH_STENCIL_ATTACHMENT; + attach_type = GST_GL_DEPTH24_STENCIL8; + } else if (gst_gl_context_get_gl_api (fb->context) & GST_GL_API_GLES2) { + attach_point = GL_DEPTH_ATTACHMENT; + attach_type = GST_GL_DEPTH_COMPONENT16; + } else { + g_assert_not_reached (); + return NULL; } - /* setup a texture to render to */ - gl->GenTextures (1, &fake_texture); - gl->BindTexture (GL_TEXTURE_2D, fake_texture); - internal_format = - gst_gl_sized_gl_format_from_gl_format_type (frame->context, GL_RGBA, - GL_UNSIGNED_BYTE); - gl->TexImage2D (GL_TEXTURE_2D, 0, internal_format, width, height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, NULL); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + render_alloc = (GstGLBaseMemoryAllocator *) + gst_allocator_find (GST_GL_RENDERBUFFER_ALLOCATOR_NAME); + params = (GstGLAllocationParams *) + gst_gl_renderbuffer_allocation_params_new (context, NULL, attach_type, + width, height); - /* attach the texture to the FBO to renderer to */ - gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, fake_texture, 0); + renderbuffer = gst_gl_base_memory_alloc (render_alloc, params); + gst_gl_allocation_params_free (params); + gst_object_unref (render_alloc); - /* attach the depth render buffer to the FBO */ - gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, *depth); + gst_gl_framebuffer_bind (fb); + gst_gl_framebuffer_attach (fb, attach_point, renderbuffer); + gst_gl_context_clear_framebuffer (fb->context); + gst_memory_unref (GST_MEMORY_CAST (renderbuffer)); - if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL | - GST_GL_API_OPENGL3)) { - gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, *depth); - } - - if (gl->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - gst_gl_context_set_error (frame->context, - "GL framebuffer status incomplete"); - - gl->DeleteTextures (1, &fake_texture); - - return FALSE; - } - - /* unbind the FBO */ - gl->BindFramebuffer (GL_FRAMEBUFFER, 0); - - gl->DeleteTextures (1, &fake_texture); - - return TRUE; + return fb; } gboolean -gst_gl_framebuffer_use_v2 (GstGLFramebuffer * frame, gint texture_fbo_width, - gint texture_fbo_height, GLuint fbo, GLuint depth_buffer, - GLuint texture_fbo, GLCB_V2 cb, gpointer stuff) +gst_gl_framebuffer_draw_to_texture (GstGLFramebuffer * fb, GstGLMemory * mem, + GstGLFramebufferFunc func, gpointer user_data) { - const GstGLFuncs *gl; GLint viewport_dim[4] = { 0 }; + const GstGLFuncs *gl; + gboolean ret; - g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (frame), FALSE); - g_return_val_if_fail (texture_fbo_width > 0 && texture_fbo_height > 0, FALSE); - g_return_val_if_fail (fbo != 0, FALSE); - g_return_val_if_fail (texture_fbo != 0, FALSE); - g_return_val_if_fail (cb != NULL, FALSE); + g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (fb), FALSE); + g_return_val_if_fail (gst_is_gl_memory (GST_MEMORY_CAST (mem)), FALSE); - gl = frame->context->gl_vtable; + gl = fb->context->gl_vtable; - GST_TRACE ("Binding v2 FBO %u dimensions:%ux%u with texture:%u ", - fbo, texture_fbo_width, texture_fbo_height, texture_fbo); + GST_TRACE_OBJECT (fb, "drawing to texture %u, dimensions %ix%i", mem->tex_id, + gst_gl_memory_get_texture_width (mem), + gst_gl_memory_get_texture_height (mem)); - gl->BindFramebuffer (GL_FRAMEBUFFER, fbo); - - /* setup a texture to render to */ - gl->BindTexture (GL_TEXTURE_2D, texture_fbo); - - /* attach the texture to the FBO to renderer to */ - gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, texture_fbo, 0); + gst_gl_framebuffer_bind (fb); + gst_gl_framebuffer_attach (fb, GL_COLOR_ATTACHMENT0, (GstGLBaseMemory *) mem); gl->GetIntegerv (GL_VIEWPORT, viewport_dim); - - gl->Viewport (0, 0, texture_fbo_width, texture_fbo_height); - - if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL | + gl->Viewport (0, 0, fb->priv->effective_width, fb->priv->effective_height); + if (gst_gl_context_get_gl_api (fb->context) & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3)) gl->DrawBuffer (GL_COLOR_ATTACHMENT0); - /* the opengl scene */ - cb (stuff); + ret = func (user_data); - if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL | + if (gst_gl_context_get_gl_api (fb->context) & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3)) gl->DrawBuffer (GL_NONE); + gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2], + viewport_dim[3]); + gst_gl_context_clear_framebuffer (fb->context); - gl->Viewport (viewport_dim[0], viewport_dim[1], - viewport_dim[2], viewport_dim[3]); - - gl->BindFramebuffer (GL_FRAMEBUFFER, 0); - - return TRUE; + return ret; } void -gst_gl_framebuffer_delete (GstGLFramebuffer * frame, guint fbo, guint depth) +gst_gl_framebuffer_bind (GstGLFramebuffer * fb) { const GstGLFuncs *gl; - g_return_if_fail (GST_IS_GL_FRAMEBUFFER (frame)); + g_return_if_fail (GST_IS_GL_FRAMEBUFFER (fb)); + g_return_if_fail (gst_gl_context_get_current () == fb->context); + g_return_if_fail (fb->fbo_id != 0); - gl = frame->context->gl_vtable; + gl = fb->context->gl_vtable; - GST_TRACE ("Deleting FBO %u", fbo); - - if (fbo) { - gl->DeleteFramebuffers (1, &fbo); - } - if (depth) { - gl->DeleteRenderbuffers (1, &depth); - } + gl->BindFramebuffer (GL_FRAMEBUFFER, fb->fbo_id); +} + +void +gst_gl_context_clear_framebuffer (GstGLContext * context) +{ + const GstGLFuncs *gl; + + g_return_if_fail (GST_IS_GL_CONTEXT (context)); + + gl = context->gl_vtable; + + gl->BindFramebuffer (GL_FRAMEBUFFER, 0); +} + +static void +_update_effective_dimensions (GstGLFramebuffer * fb) +{ + int i; + guint min_width = -1, min_height = -1; + + /* remove the previous attachment */ + for (i = 0; i < fb->attachments->len; i++) { + struct fbo_attachment *attach; + int width, height; + + attach = &g_array_index (fb->attachments, struct fbo_attachment, i); + + if (gst_is_gl_memory (GST_MEMORY_CAST (attach->mem))) { + GstGLMemory *mem = (GstGLMemory *) attach->mem; + + width = gst_gl_memory_get_texture_width (mem); + height = gst_gl_memory_get_texture_height (mem); + } else if (gst_is_gl_renderbuffer (GST_MEMORY_CAST (attach->mem))) { + GstGLRenderbuffer *mem = (GstGLRenderbuffer *) attach->mem; + + width = mem->width; + height = mem->height; + } else { + g_assert_not_reached (); + } + + if (width < min_width) + min_width = width; + if (height < min_height) + min_height = height; + } + + fb->priv->effective_width = min_width; + fb->priv->effective_height = min_height; +} + +static gboolean +_is_valid_attachment_point (guint attachment_point) +{ + /* all 31 possible color attachments */ + if (attachment_point >= 0x8CE0 && attachment_point <= 0x8CFF) + return TRUE; + + /* depth-stencil attachment */ + if (attachment_point == 0x821A) + return TRUE; + + /* depth attachment */ + if (attachment_point == 0x8D00) + return TRUE; + + /* stencil attachment */ + if (attachment_point == 0x8D20) + return TRUE; + + return FALSE; +} + +static void +_attach_gl_memory (GstGLFramebuffer * fb, guint attachment_point, + GstGLMemory * mem) +{ + struct fbo_attachment attach; + const GstGLFuncs *gl = fb->context->gl_vtable; + guint gl_target = gst_gl_texture_target_to_gl (mem->tex_target); + + gst_gl_framebuffer_bind (fb); + + gl->FramebufferTexture2D (GL_FRAMEBUFFER, attachment_point, gl_target, + mem->tex_id, 0); + + _fbo_attachment_init (&attach, attachment_point, (GstGLBaseMemory *) mem); + fb->attachments = g_array_append_val (fb->attachments, attach); +} + +static void +_attach_renderbuffer (GstGLFramebuffer * fb, guint attachment_point, + GstGLRenderbuffer * rb) +{ + struct fbo_attachment attach; + const GstGLFuncs *gl = fb->context->gl_vtable; + + gst_gl_framebuffer_bind (fb); + gl->BindRenderbuffer (GL_RENDERBUFFER, rb->renderbuffer_id); + + gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, attachment_point, + GL_RENDERBUFFER, rb->renderbuffer_id); + + _fbo_attachment_init (&attach, attachment_point, (GstGLBaseMemory *) rb); + fb->attachments = g_array_append_val (fb->attachments, attach); +} + +void +gst_gl_framebuffer_attach (GstGLFramebuffer * fb, guint attachment_point, + GstGLBaseMemory * mem) +{ + int i; + + g_return_if_fail (GST_IS_GL_FRAMEBUFFER (fb)); + g_return_if_fail (gst_gl_context_get_current () == fb->context); + g_return_if_fail (_is_valid_attachment_point (attachment_point)); + + /* remove the previous attachment */ + for (i = 0; i < fb->attachments->len; i++) { + struct fbo_attachment *attach; + + attach = &g_array_index (fb->attachments, struct fbo_attachment, i); + + if (attach->attachment_point == attachment_point) { + g_array_remove_index_fast (fb->attachments, i); + break; + } + } + + if (gst_is_gl_memory (GST_MEMORY_CAST (mem))) { + _attach_gl_memory (fb, attachment_point, (GstGLMemory *) mem); + } else if (gst_is_gl_renderbuffer (GST_MEMORY_CAST (mem))) { + _attach_renderbuffer (fb, attachment_point, (GstGLRenderbuffer *) mem); + } else { + g_assert_not_reached (); + return; + } + + _update_effective_dimensions (fb); +} + +void +gst_gl_framebuffer_get_effective_dimensions (GstGLFramebuffer * fb, + guint * width, guint * height) +{ + g_return_if_fail (GST_IS_GL_FRAMEBUFFER (fb)); + + if (width) + *width = fb->priv->effective_width; + if (height) + *height = fb->priv->effective_height; +} + +gboolean +gst_gl_context_check_framebuffer_status (GstGLContext * context) +{ + g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE); + + switch (context->gl_vtable->CheckFramebufferStatus (GL_FRAMEBUFFER)) { + case GL_FRAMEBUFFER_COMPLETE: + return TRUE; + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_UNSUPPORTED"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + GST_WARNING_OBJECT (context, + "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + break; +#if GST_GL_HAVE_OPENGL + case GL_FRAMEBUFFER_UNDEFINED: + GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_UNDEFINED"); + break; +#endif + default: + GST_WARNING_OBJECT (context, "Unknown FBO error"); + break; + } + + return FALSE; +} + +guint +gst_gl_framebuffer_get_id (GstGLFramebuffer * fb) +{ + g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (fb), 0); + + return fb->fbo_id; } diff --git a/gst-libs/gst/gl/gstglframebuffer.h b/gst-libs/gst/gl/gstglframebuffer.h index 4768afb0cd..7e9e701247 100644 --- a/gst-libs/gst/gl/gstglframebuffer.h +++ b/gst-libs/gst/gl/gstglframebuffer.h @@ -38,31 +38,55 @@ typedef struct _GstGLFramebuffer GstGLFramebuffer; typedef struct _GstGLFramebufferClass GstGLFramebufferClass; typedef struct _GstGLFramebufferPrivate GstGLFramebufferPrivate; +/** + * GstGLFramebufferFunc: + * @data: user data + * + * callback definition for operating through a Framebuffer object + */ +typedef gboolean (*GstGLFramebufferFunc) (gpointer stuff); + struct _GstGLFramebuffer { - GObject object; + GstObject object; /* */ GstGLContext *context; + guint fbo_id; + GArray *attachments; + GstGLFramebufferPrivate *priv; }; struct _GstGLFramebufferClass { - GObjectClass object_class; + GstObjectClass object_class; }; -GstGLFramebuffer *gst_gl_framebuffer_new (GstGLContext *context); +GstGLFramebuffer * gst_gl_framebuffer_new (GstGLContext *context); +GstGLFramebuffer * gst_gl_framebuffer_new_with_default_depth (GstGLContext *context, + guint width, + guint height); -gboolean gst_gl_framebuffer_generate (GstGLFramebuffer *frame, gint width, gint height, - guint * fbo, guint * depthbuffer); +guint gst_gl_framebuffer_get_id (GstGLFramebuffer * fb); -gboolean gst_gl_framebuffer_use_v2 (GstGLFramebuffer * frame, gint texture_fbo_width, - gint texture_fbo_height, GLuint fbo, GLuint depth_buffer, - GLuint texture_fbo, GLCB_V2 cb, gpointer stuff); +void gst_gl_framebuffer_attach (GstGLFramebuffer * fb, + guint attachment_point, + GstGLBaseMemory * mem); +void gst_gl_framebuffer_bind (GstGLFramebuffer * fb); +void gst_gl_context_clear_framebuffer (GstGLContext * context); -void gst_gl_framebuffer_delete (GstGLFramebuffer *frame, guint fbo, guint depth); +void gst_gl_framebuffer_get_effective_dimensions (GstGLFramebuffer * fb, + guint * width, + guint * height); + +gboolean gst_gl_context_check_framebuffer_status (GstGLContext * context); + +gboolean gst_gl_framebuffer_draw_to_texture (GstGLFramebuffer * fb, + GstGLMemory * mem, + GstGLFramebufferFunc cb, + gpointer user_data); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstGLFramebuffer, gst_object_unref) diff --git a/gst-libs/gst/gl/gstglutils.c b/gst-libs/gst/gl/gstglutils.c index ade2f95620..e4cbd91e91 100644 --- a/gst-libs/gst/gl/gstglutils.c +++ b/gst-libs/gst/gl/gstglutils.c @@ -36,22 +36,6 @@ #include #endif -#ifndef GL_FRAMEBUFFER_UNDEFINED -#define GL_FRAMEBUFFER_UNDEFINED 0x8219 -#endif -#ifndef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 -#endif -#ifndef GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 -#endif -#ifndef GL_FRAMEBUFFER_UNSUPPORTED -#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#endif -#ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS -#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 -#endif - #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0)) #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1)) #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0)) @@ -60,140 +44,6 @@ static gchar *error_message; -/* called in the gl thread */ -gboolean -gst_gl_context_check_framebuffer_status (GstGLContext * context) -{ - GLenum status = 0; - status = context->gl_vtable->CheckFramebufferStatus (GL_FRAMEBUFFER); - - switch (status) { - case GL_FRAMEBUFFER_COMPLETE: - return TRUE; - break; - - case GL_FRAMEBUFFER_UNSUPPORTED: - GST_ERROR ("GL_FRAMEBUFFER_UNSUPPORTED"); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - GST_ERROR ("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - GST_ERROR ("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - GST_ERROR ("GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); - break; -#if GST_GL_HAVE_OPENGL - case GL_FRAMEBUFFER_UNDEFINED: - GST_ERROR ("GL_FRAMEBUFFER_UNDEFINED"); - break; -#endif - default: - GST_ERROR ("General FBO error"); - } - - return FALSE; -} - -typedef struct _GenFBO -{ - GstGLFramebuffer *frame; - gint width, height; - GLuint *fbo, *depth; -} GenFBO; - -static void -_gen_fbo (GstGLContext * context, GenFBO * data) -{ - gst_gl_framebuffer_generate (data->frame, data->width, data->height, - data->fbo, data->depth); -} - -gboolean -gst_gl_context_gen_fbo (GstGLContext * context, gint width, gint height, - GLuint * fbo, GLuint * depthbuffer) -{ - GstGLFramebuffer *frame = gst_gl_framebuffer_new (context); - - GenFBO data = { frame, width, height, fbo, depthbuffer }; - - gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _gen_fbo, &data); - - gst_object_unref (frame); - - return TRUE; -} - -typedef struct _UseFBO2 -{ - GstGLFramebuffer *frame; - gint texture_fbo_width; - gint texture_fbo_height; - GLuint fbo; - GLuint depth_buffer; - GLuint texture_fbo; - GLCB_V2 cb; - gpointer stuff; -} UseFBO2; - -static void -_use_fbo_v2 (GstGLContext * context, UseFBO2 * data) -{ - gst_gl_framebuffer_use_v2 (data->frame, data->texture_fbo_width, - data->texture_fbo_height, data->fbo, data->depth_buffer, - data->texture_fbo, data->cb, data->stuff); -} - -gboolean -gst_gl_context_use_fbo_v2 (GstGLContext * context, gint texture_fbo_width, - gint texture_fbo_height, GLuint fbo, GLuint depth_buffer, - GLuint texture_fbo, GLCB_V2 cb, gpointer stuff) -{ - GstGLFramebuffer *frame = gst_gl_framebuffer_new (context); - - UseFBO2 data = - { frame, texture_fbo_width, texture_fbo_height, fbo, depth_buffer, - texture_fbo, cb, stuff - }; - - gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _use_fbo_v2, - &data); - - gst_object_unref (frame); - - return TRUE; -} - -typedef struct _DelFBO -{ - GstGLFramebuffer *frame; - GLuint fbo; - GLuint depth; -} DelFBO; - -/* Called in the gl thread */ -static void -_del_fbo (GstGLContext * context, DelFBO * data) -{ - gst_gl_framebuffer_delete (data->frame, data->fbo, data->depth); -} - -/* Called by gltestsrc and glfilter */ -void -gst_gl_context_del_fbo (GstGLContext * context, GLuint fbo, GLuint depth_buffer) -{ - GstGLFramebuffer *frame = gst_gl_framebuffer_new (context); - - DelFBO data = { frame, fbo, depth_buffer }; - - gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _del_fbo, &data); - - gst_object_unref (frame); -} - struct _compile_shader { GstGLShader **shader; diff --git a/gst-libs/gst/gl/gstglutils.h b/gst-libs/gst/gl/gstglutils.h index 4741dadc17..8914310fa5 100644 --- a/gst-libs/gst/gl/gstglutils.h +++ b/gst-libs/gst/gl/gstglutils.h @@ -60,29 +60,12 @@ typedef gboolean (*CDCB) (GLuint texture, GLuint width, GLuint height, gpointer * callback definition for operating on textures */ typedef void (*GLCB) (gint, gint, guint, gpointer stuff); -/** - * GLCB_V2: - * @stuff: user data - * - * callback definition for operating through a Framebuffer object - */ -typedef void (*GLCB_V2) (gpointer stuff); - -gboolean gst_gl_context_gen_fbo (GstGLContext * context, gint width, gint height, - GLuint * fbo, GLuint * depthbuffer); -gboolean gst_gl_context_use_fbo_v2 (GstGLContext * context, gint texture_fbo_width, - gint texture_fbo_height, GLuint fbo, GLuint depth_buffer, - GLuint texture_fbo, GLCB_V2 cb, gpointer stuff); -void gst_gl_context_del_fbo (GstGLContext * context, GLuint fbo, - GLuint depth_buffer); gboolean gst_gl_context_gen_shader (GstGLContext * context, const gchar * shader_vertex_source, const gchar * shader_fragment_source, GstGLShader ** shader); void gst_gl_context_del_shader (GstGLContext * context, GstGLShader * shader); -gboolean gst_gl_context_check_framebuffer_status (GstGLContext * context); - void gst_gl_context_set_error (GstGLContext * context, const char * format, ...); gchar *gst_gl_context_get_error (void); diff --git a/gst-libs/gst/gl/gstglviewconvert.c b/gst-libs/gst/gl/gstglviewconvert.c index 06978914c4..c50ca5213a 100644 --- a/gst-libs/gst/gl/gstglviewconvert.c +++ b/gst-libs/gst/gl/gstglviewconvert.c @@ -1304,6 +1304,11 @@ gst_gl_view_convert_reset (GstGLViewConvert * viewconvert) if (viewconvert->shader) gst_gl_context_del_shader (viewconvert->context, viewconvert->shader); viewconvert->shader = NULL; + + if (viewconvert->fbo) + gst_object_unref (viewconvert->fbo); + viewconvert->fbo = NULL; + viewconvert->initted = FALSE; viewconvert->reconfigure = FALSE; } @@ -1383,74 +1388,16 @@ gst_gl_view_convert_perform (GstGLViewConvert * viewconvert, GstBuffer * inbuf) static gboolean _init_view_convert_fbo (GstGLViewConvert * viewconvert) { - GstGLFuncs *gl; guint out_width, out_height; - GLuint fake_texture = 0; /* a FBO must hava texture to init */ - GLenum internal_format; - gboolean ret = TRUE; - gl = viewconvert->context->gl_vtable; out_width = GST_VIDEO_INFO_WIDTH (&viewconvert->out_info); out_height = GST_VIDEO_INFO_HEIGHT (&viewconvert->out_info); - if (!gl->GenFramebuffers) { - /* turn off the pipeline because Frame buffer object is a not present */ - gst_gl_context_set_error (viewconvert->context, - "Frambuffer objects unsupported"); - return FALSE; - } - /* setup FBO */ - gl->GenFramebuffers (1, &viewconvert->fbo); - gl->BindFramebuffer (GL_FRAMEBUFFER, viewconvert->fbo); - /* setup the render buffer for depth */ - gl->GenRenderbuffers (1, &viewconvert->depth_buffer); - gl->BindRenderbuffer (GL_RENDERBUFFER, viewconvert->depth_buffer); - if (USING_OPENGL (viewconvert->context) - || USING_OPENGL3 (viewconvert->context)) { - gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, out_width, - out_height); - gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, - out_width, out_height); - } - if (USING_GLES2 (viewconvert->context)) { - gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, - out_width, out_height); - } + viewconvert->fbo = + gst_gl_framebuffer_new_with_default_depth (viewconvert->context, + out_width, out_height); - /* a fake texture is attached to the convert FBO (cannot init without it) */ - gl->GenTextures (1, &fake_texture); - gl->BindTexture (GL_TEXTURE_2D, fake_texture); - internal_format = - gst_gl_sized_gl_format_from_gl_format_type (viewconvert->context, GL_RGBA, - GL_UNSIGNED_BYTE); - gl->TexImage2D (GL_TEXTURE_2D, 0, internal_format, out_width, out_height, - 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - /* attach the texture to the FBO to renderer to */ - gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, fake_texture, 0); - /* attach the depth render buffer to the FBO */ - gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, viewconvert->depth_buffer); - if (USING_OPENGL (viewconvert->context)) { - gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, viewconvert->depth_buffer); - } - - if (!gst_gl_context_check_framebuffer_status (viewconvert->context)) { - gst_gl_context_set_error (viewconvert->context, - "GL framebuffer status incomplete"); - ret = FALSE; - } - - /* unbind the FBO */ - gl->BindTexture (GL_TEXTURE_2D, 0); - gl->BindFramebuffer (GL_FRAMEBUFFER, 0); - gl->DeleteTextures (1, &fake_texture); - return ret; + return viewconvert->fbo != NULL; } /* free after use */ @@ -1865,9 +1812,9 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert) gst_gl_texture_target_to_gl (viewconvert->from_texture_target); gl = context->gl_vtable; - out_width = GST_VIDEO_INFO_WIDTH (&viewconvert->out_info); - out_height = GST_VIDEO_INFO_HEIGHT (&viewconvert->out_info); - gl->BindFramebuffer (GL_FRAMEBUFFER, viewconvert->fbo); + + gst_gl_framebuffer_bind (viewconvert->fbo); + if (out_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED || out_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) { out_views = viewconvert->out_info.views; @@ -1877,19 +1824,18 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert) /* attach the texture to the FBO to renderer to */ for (i = 0; i < out_views; i++) { - guint gl_target = - gst_gl_texture_target_to_gl (viewconvert->to_texture_target); + GstGLBaseMemory *tex = (GstGLBaseMemory *) priv->out_tex[i]; - /* needed? */ - gl->BindTexture (gl_target, priv->out_tex[i]->tex_id); - gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, - gl_target, priv->out_tex[i]->tex_id, 0); + gst_gl_framebuffer_attach (viewconvert->fbo, GL_COLOR_ATTACHMENT0 + i, tex); } if (gl->DrawBuffers) gl->DrawBuffers (out_views, multipleRT); else if (gl->DrawBuffer) gl->DrawBuffer (GL_COLOR_ATTACHMENT0); + + gst_gl_framebuffer_get_effective_dimensions (viewconvert->fbo, &out_width, + &out_height); gl->GetIntegerv (GL_VIEWPORT, viewport_dim); gl->Viewport (0, 0, out_width, out_height); @@ -1911,6 +1857,7 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert) gl->BindVertexArray (priv->vao); else _bind_buffer (viewconvert); + if (in_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED || in_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) { if (priv->in_tex[1] == NULL) { @@ -1924,7 +1871,9 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert) gl->ActiveTexture (GL_TEXTURE0); gl->BindTexture (from_gl_target, priv->in_tex[0]->tex_id); + gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL); + if (gl->BindVertexArray) gl->BindVertexArray (0); else @@ -1935,8 +1884,8 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert) gst_gl_context_clear_shader (context); gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2], viewport_dim[3]); - gst_gl_context_check_framebuffer_status (context); - gl->BindFramebuffer (GL_FRAMEBUFFER, 0); + gst_gl_context_clear_framebuffer (context); + return TRUE; } diff --git a/gst-libs/gst/gl/gstglviewconvert.h b/gst-libs/gst/gl/gstglviewconvert.h index 8cfa1b2700..ee1166cc90 100644 --- a/gst-libs/gst/gl/gstglviewconvert.h +++ b/gst-libs/gst/gl/gstglviewconvert.h @@ -68,8 +68,7 @@ struct _GstGLViewConvert gboolean initted; gboolean reconfigure; - GLuint fbo; - GLuint depth_buffer; + GstGLFramebuffer *fbo; GstGLViewConvertPrivate *priv; }; diff --git a/tests/check/libs/gstglcontext.c b/tests/check/libs/gstglcontext.c index 662e3a765a..25f3e00cf7 100644 --- a/tests/check/libs/gstglcontext.c +++ b/tests/check/libs/gstglcontext.c @@ -43,7 +43,7 @@ teardown (void) } static GstGLMemory *gl_tex; -static GLuint vbo, vbo_indices, vao, fbo_id, rbo; +static GLuint vbo, vbo_indices, vao; static GstGLFramebuffer *fbo; static GstGLShader *shader; static GLint shader_attr_position_loc; @@ -75,10 +75,9 @@ init (gpointer data) GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA); /* has to be called in the thread that is going to use the framebuffer */ - fbo = gst_gl_framebuffer_new (context); + fbo = gst_gl_framebuffer_new_with_default_depth (context, 320, 240); - gst_gl_framebuffer_generate (fbo, 320, 240, &fbo_id, &rbo); - fail_if (fbo == NULL || fbo_id == 0, "failed to create framebuffer object"); + fail_if (fbo == NULL, "failed to create framebuffer object"); gl_tex = (GstGLMemory *) gst_gl_base_memory_alloc ((GstGLBaseMemoryAllocator *) @@ -109,7 +108,7 @@ deinit (gpointer data) gst_memory_unref (GST_MEMORY_CAST (gl_tex)); } -static void +static gboolean clear_tex (gpointer data) { GstGLContext *context = data; @@ -122,13 +121,15 @@ clear_tex (gpointer data) r = r > 1.0 ? 0.0 : r + 0.03; g = g > 1.0 ? 0.0 : g + 0.01; b = b > 1.0 ? 0.0 : b + 0.015; + + return TRUE; } static void draw_tex (gpointer data) { - gst_gl_framebuffer_use_v2 (fbo, 320, 240, fbo_id, rbo, - gst_gl_memory_get_texture_id (gl_tex), (GLCB_V2) clear_tex, data); + gst_gl_framebuffer_draw_to_texture (fbo, gl_tex, + (GstGLFramebufferFunc) clear_tex, data); } static void @@ -275,7 +276,8 @@ GST_START_TEST (test_share) gst_gl_window_set_preferred_size (window, 320, 240); gst_gl_window_draw (window); - gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (init), context); + gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (init), + other_context); gst_gl_window_send_message (window, GST_GL_WINDOW_CB (init_blit), context); while (i < 10) { @@ -286,7 +288,8 @@ GST_START_TEST (test_share) i++; } - gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (deinit), context); + gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (deinit), + other_context); gst_gl_window_send_message (window, GST_GL_WINDOW_CB (deinit_blit), context); gst_object_unref (window); @@ -380,7 +383,8 @@ GST_START_TEST (test_wrapped_context) gst_gl_window_set_preferred_size (window, 320, 240); gst_gl_window_draw (window); - gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (init), context); + gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (init), + other_context); gst_gl_window_send_message (window, GST_GL_WINDOW_CB (init_blit), context); while (i < 10) { @@ -394,7 +398,8 @@ GST_START_TEST (test_wrapped_context) gst_gl_window_send_message (window, GST_GL_WINDOW_CB (check_wrapped), wrapped_context); - gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (deinit), context); + gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (deinit), + other_context); gst_gl_window_send_message (window, GST_GL_WINDOW_CB (deinit_blit), context); gst_object_unref (other_context);