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 | 454 ++++++++++++++++++++++++++---------- 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, 566 insertions(+), 614 deletions(-) diff --git a/ext/gl/gstglfilterapp.c b/ext/gl/gstglfilterapp.c index 07e1e55..adcf006 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; + + 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); - 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); + 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 a8978c5..d7e9a6f 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 ba8d524..717eba6 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 a0639d2..28bc485 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 f9c22a1..3fc5aa6 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 de5a3dc..309f6bb 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 701435f..41441b0 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 69c8b33..62d231f 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 1b566ad..df4abb7 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 1a8ddf2..1e80590 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 176d27e..4491823 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; + + video_mixer->out_tex = out_tex; - 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); + 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 a0776fd..f352646 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 86fff2f..465e284 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 ebddb2d..34a5818 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; - } - - GST_INFO ("Context, EXT_framebuffer_object supported: yes"); - - /* setup FBO */ - gl->GenFramebuffers (1, &convert->fbo); - gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo); + convert->fbo = + gst_gl_framebuffer_new_with_default_depth (convert->context, out_width, + out_height); - /* 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); - - /* needed? */ - gl->BindTexture (gl_target, convert->priv->out_tex[i]->tex_id); + GstGLBaseMemory *tex = (GstGLBaseMemory *) convert->priv->out_tex[i]; - 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 5980cfa..fbbbf3b 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 3f80588..f6fd439 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 71ff046..795f6ff 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 fb706f5..054c104 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,14 +56,36 @@ static void gst_gl_framebuffer_finalize (GObject * object); struct _GstGLFramebufferPrivate { - gint width; - gint height; + guint effective_width; + guint effective_height; +}; - guint fbo; - guint depth; +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) { g_type_class_add_private (klass, sizeof (GstGLFramebufferPrivate)); @@ -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 (fb->context) { + if (fb->fbo_id) + gst_gl_context_thread_add (fb->context, + (GstGLContextThreadFunc) _delete_fbo_gl, fb); - if (fbo->context) { - gst_object_unref (fbo->context); - fbo->context = NULL; + 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); + GstGLFramebuffer *fb; + const GstGLFuncs *gl; + + g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL); + g_return_val_if_fail (gst_gl_context_get_current () == context, NULL); + + gl = context->gl_vtable; + + if (!gl->GenFramebuffers) { + GST_ERROR_OBJECT (context, "Framebuffers are not supported!"); + return NULL; + } + + fb = g_object_new (GST_TYPE_GL_FRAMEBUFFER, NULL); + fb->context = gst_object_ref (context); + gl->GenFramebuffers (1, &fb->fbo_id); + + 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)) { + 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; + } - fbo->context = gst_object_ref (context); + 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); - return fbo; + renderbuffer = gst_gl_base_memory_alloc (render_alloc, params); + gst_gl_allocation_params_free (params); + gst_object_unref (render_alloc); + + 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)); + + return fb; } gboolean -gst_gl_framebuffer_generate (GstGLFramebuffer * frame, gint width, gint height, - guint * fbo, guint * depth) +gst_gl_framebuffer_draw_to_texture (GstGLFramebuffer * fb, GstGLMemory * mem, + GstGLFramebufferFunc func, gpointer user_data) { - GLuint fake_texture = 0; + GLint viewport_dim[4] = { 0 }; const GstGLFuncs *gl; - GLenum internal_format; + gboolean ret; - 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_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 ("creating FBO dimensions:%ux%u", width, height); + 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)); - if (!gl->GenFramebuffers) { - gst_gl_context_set_error (frame->context, - "Context, EXT_framebuffer_object not supported"); - return FALSE; - } - /* 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); + gst_gl_framebuffer_bind (fb); + gst_gl_framebuffer_attach (fb, GL_COLOR_ATTACHMENT0, (GstGLBaseMemory *) mem); - if (gst_gl_context_get_gl_api (frame->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); - } + gl->GetIntegerv (GL_VIEWPORT, viewport_dim); + 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); - /* 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); - - /* 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, *depth); - - 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); - } + ret = func (user_data); - if (gl->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - gst_gl_context_set_error (frame->context, - "GL framebuffer status incomplete"); + 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->DeleteTextures (1, &fake_texture); + return ret; +} - return FALSE; - } +void +gst_gl_framebuffer_bind (GstGLFramebuffer * fb) +{ + const GstGLFuncs *gl; - /* unbind the FBO */ - gl->BindFramebuffer (GL_FRAMEBUFFER, 0); + 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->DeleteTextures (1, &fake_texture); + gl = fb->context->gl_vtable; - return TRUE; + gl->BindFramebuffer (GL_FRAMEBUFFER, fb->fbo_id); } -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_context_clear_framebuffer (GstGLContext * context) { const GstGLFuncs *gl; - GLint viewport_dim[4] = { 0 }; - 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_if_fail (GST_IS_GL_CONTEXT (context)); - gl = frame->context->gl_vtable; + gl = context->gl_vtable; - GST_TRACE ("Binding v2 FBO %u dimensions:%ux%u with texture:%u ", - fbo, texture_fbo_width, texture_fbo_height, texture_fbo); + gl->BindFramebuffer (GL_FRAMEBUFFER, 0); +} - gl->BindFramebuffer (GL_FRAMEBUFFER, fbo); +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; + } - /* setup a texture to render to */ - gl->BindTexture (GL_TEXTURE_2D, texture_fbo); + fb->priv->effective_width = min_width; + fb->priv->effective_height = min_height; +} - /* attach the texture to the FBO to renderer to */ - gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, texture_fbo, 0); +static gboolean +_is_valid_attachment_point (guint attachment_point) +{ + /* all 31 possible color attachments */ + if (attachment_point >= 0x8CE0 && attachment_point <= 0x8CFF) + return TRUE; - gl->GetIntegerv (GL_VIEWPORT, viewport_dim); + /* depth-stencil attachment */ + if (attachment_point == 0x821A) + return TRUE; - gl->Viewport (0, 0, texture_fbo_width, texture_fbo_height); + /* depth attachment */ + if (attachment_point == 0x8D00) + return TRUE; - if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL | - GST_GL_API_OPENGL3)) - gl->DrawBuffer (GL_COLOR_ATTACHMENT0); + /* stencil attachment */ + if (attachment_point == 0x8D20) + return TRUE; - /* the opengl scene */ - cb (stuff); + return FALSE; +} - if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL | - GST_GL_API_OPENGL3)) - gl->DrawBuffer (GL_NONE); +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); - gl->Viewport (viewport_dim[0], viewport_dim[1], - viewport_dim[2], viewport_dim[3]); + gst_gl_framebuffer_bind (fb); - gl->BindFramebuffer (GL_FRAMEBUFFER, 0); + 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); - return TRUE; + 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_delete (GstGLFramebuffer * frame, guint fbo, guint depth) +gst_gl_framebuffer_attach (GstGLFramebuffer * fb, guint attachment_point, + GstGLBaseMemory * mem) { - const GstGLFuncs *gl; + int i; - 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 (_is_valid_attachment_point (attachment_point)); - gl = frame->context->gl_vtable; + /* remove the previous attachment */ + for (i = 0; i < fb->attachments->len; i++) { + struct fbo_attachment *attach; - GST_TRACE ("Deleting FBO %u", fbo); + attach = &g_array_index (fb->attachments, struct fbo_attachment, i); - if (fbo) { - gl->DeleteFramebuffers (1, &fbo); + if (attach->attachment_point == attachment_point) { + g_array_remove_index_fast (fb->attachments, i); + break; + } } - if (depth) { - gl->DeleteRenderbuffers (1, &depth); + + 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 4768afb..7e9e701 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); + +guint gst_gl_framebuffer_get_id (GstGLFramebuffer * fb); + +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); -gboolean gst_gl_framebuffer_generate (GstGLFramebuffer *frame, gint width, gint height, - guint * fbo, guint * depthbuffer); +void gst_gl_framebuffer_get_effective_dimensions (GstGLFramebuffer * fb, + guint * width, + guint * height); -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); +gboolean gst_gl_context_check_framebuffer_status (GstGLContext * context); -void gst_gl_framebuffer_delete (GstGLFramebuffer *frame, guint fbo, guint depth); +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 ade2f95..e4cbd91 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 4741dad..8914310 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 0697891..c50ca52 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); - } - - /* 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; - } + viewconvert->fbo = + gst_gl_framebuffer_new_with_default_depth (viewconvert->context, + out_width, out_height); - /* 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 8cfa1b2..ee1166c 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 662e3a7..25f3e00 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); -- 2.7.4