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().
This commit is contained in:
Matthew Waters 2016-07-12 12:59:57 +10:00
parent aa109016a3
commit 518e8a3fd2
24 changed files with 574 additions and 622 deletions

View File

@ -184,35 +184,24 @@ gst_gl_filter_app_set_caps (GstGLFilter * filter, GstCaps * incaps,
return TRUE; 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 struct glcb2
{ {
GLCB func; GstGLFilterApp *app;
gpointer data;
GstGLMemory *in_tex; GstGLMemory *in_tex;
GstGLMemory *out_tex; GstGLMemory *out_tex;
}; };
/* convenience functions to simplify filter development */ static gboolean
static void _emit_draw_signal (gpointer data)
_glcb2 (gpointer data)
{ {
struct glcb2 *cb = data; struct glcb2 *cb = data;
gboolean drawn;
cb->func (gst_gl_memory_get_texture_width (cb->in_tex), g_signal_emit (cb->app, gst_gl_filter_app_signals[CLIENT_DRAW_SIGNAL], 0,
gst_gl_memory_get_texture_height (cb->in_tex), cb->in_tex->tex_id, cb->in_tex->tex_id, gst_gl_memory_get_texture_width (cb->out_tex),
cb->data); gst_gl_memory_get_texture_height (cb->out_tex), &drawn);
return !drawn;
} }
static gboolean static gboolean
@ -220,20 +209,18 @@ gst_gl_filter_app_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex) GstGLMemory * out_tex)
{ {
GstGLFilterApp *app_filter = GST_GL_FILTER_APP (filter); GstGLFilterApp *app_filter = GST_GL_FILTER_APP (filter);
gboolean default_draw;
struct glcb2 cb; struct glcb2 cb;
cb.func = (GLCB) _emit_draw_signal; cb.app = app_filter;
cb.data = filter;
cb.in_tex = in_tex; cb.in_tex = in_tex;
cb.out_tex = out_tex; cb.out_tex = out_tex;
//blocking call, use a FBO default_draw =
gst_gl_context_use_fbo_v2 (GST_GL_BASE_FILTER (filter)->context, gst_gl_framebuffer_draw_to_texture (filter->fbo,
GST_VIDEO_INFO_WIDTH (&filter->out_info), out_tex, _emit_draw_signal, &cb);
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
filter->fbo, filter->depthbuffer, out_tex->tex_id, _glcb2, &cb);
if (app_filter->default_draw) { if (default_draw) {
gst_gl_filter_render_to_target_with_shader (filter, TRUE, in_tex, out_tex, gst_gl_filter_render_to_target_with_shader (filter, TRUE, in_tex, out_tex,
filter->default_shader); filter->default_shader);
} }

View File

@ -37,8 +37,6 @@ typedef struct _GstGLFilterAppClass GstGLFilterAppClass;
struct _GstGLFilterApp struct _GstGLFilterApp
{ {
GstGLFilter filter; GstGLFilter filter;
gboolean default_draw;
}; };
struct _GstGLFilterAppClass struct _GstGLFilterAppClass

View File

@ -79,7 +79,7 @@ static gboolean gst_gl_filter_cube_set_caps (GstGLFilter * filter,
GstCaps * incaps, GstCaps * outcaps); GstCaps * incaps, GstCaps * outcaps);
static void gst_gl_filter_cube_reset_gl (GstGLFilter * filter); static void gst_gl_filter_cube_reset_gl (GstGLFilter * filter);
static gboolean gst_gl_filter_cube_init_shader (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, static gboolean gst_gl_filter_cube_filter_texture (GstGLFilter * filter,
GstGLMemory * in_tex, GstGLMemory * out_tex); 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; cube_filter->in_tex = in_tex;
/* blocking call, use a FBO */ return gst_gl_framebuffer_draw_to_texture (filter->fbo, out_tex, _callback,
gst_gl_context_use_fbo_v2 (GST_GL_BASE_FILTER (filter)->context, cube_filter);
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;
} }
/* *INDENT-OFF* */ /* *INDENT-OFF* */
@ -440,7 +435,7 @@ _unbind_buffer (GstGLFilterCube * cube_filter)
gl->DisableVertexAttribArray (cube_filter->attr_texture); gl->DisableVertexAttribArray (cube_filter->attr_texture);
} }
static void static gboolean
_callback (gpointer stuff) _callback (gpointer stuff)
{ {
GstGLFilter *filter = GST_GL_FILTER (stuff); GstGLFilter *filter = GST_GL_FILTER (stuff);
@ -516,4 +511,6 @@ _callback (gpointer stuff)
xrot += 0.3f; xrot += 0.3f;
yrot += 0.2f; yrot += 0.2f;
zrot += 0.4f; zrot += 0.4f;
return TRUE;
} }

View File

@ -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, gint width, gint height, guint texture, gfloat center_x, gfloat center_y,
gfloat start_alpha, gfloat stop_alpha, gboolean reversed, gfloat rotation); 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* */ /* *INDENT-OFF* */
static const gchar *glass_fragment_source = 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; glass_filter->in_tex = in_tex;
//blocking call, use a FBO gst_gl_framebuffer_draw_to_texture (filter->fbo, out_tex,
gst_gl_context_use_fbo_v2 (GST_GL_BASE_FILTER (filter)->context, gst_gl_filter_glass_callback, glass_filter);
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);
return TRUE; return TRUE;
} }
@ -353,8 +349,7 @@ gst_gl_filter_glass_draw_video_plane (GstGLFilter * filter,
gl->DisableClientState (GL_COLOR_ARRAY); gl->DisableClientState (GL_COLOR_ARRAY);
} }
//opengl scene, params: input texture (not the output filter->texture) static gboolean
static void
gst_gl_filter_glass_callback (gpointer stuff) gst_gl_filter_glass_callback (gpointer stuff)
{ {
static gint64 start_time = 0; static gint64 start_time = 0;
@ -376,7 +371,7 @@ gst_gl_filter_glass_callback (gpointer stuff)
time_left -= 1000000 / 25; time_left -= 1000000 / 25;
if (time_left > 2000) { if (time_left > 2000) {
GST_LOG ("escape"); 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); gst_gl_context_clear_shader (GST_GL_BASE_FILTER (filter)->context);
gl->Disable (GL_BLEND); gl->Disable (GL_BLEND);
return TRUE;
} }

View File

@ -410,8 +410,6 @@ static void
gst_gl_mixer_init (GstGLMixer * mix) gst_gl_mixer_init (GstGLMixer * mix)
{ {
mix->priv = GST_GL_MIXER_GET_PRIVATE (mix); mix->priv = GST_GL_MIXER_GET_PRIVATE (mix);
mix->fbo = 0;
mix->depthbuffer = 0;
mix->priv->gl_resource_ready = FALSE; mix->priv->gl_resource_ready = FALSE;
g_mutex_init (&mix->priv->gl_resource_lock); g_mutex_init (&mix->priv->gl_resource_lock);
@ -512,33 +510,38 @@ gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator,
return ret; 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 static gboolean
gst_gl_mixer_decide_allocation (GstGLBaseMixer * base_mix, GstQuery * query) gst_gl_mixer_decide_allocation (GstGLBaseMixer * base_mix, GstQuery * query)
{ {
GstGLMixer *mix = GST_GL_MIXER (base_mix); GstGLMixer *mix = GST_GL_MIXER (base_mix);
GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix); GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
GstGLContext *context = base_mix->context; GstGLContext *context = base_mix->context;
GstBufferPool *pool = NULL; GstBufferPool *pool = NULL;
GstStructure *config; GstStructure *config;
GstCaps *caps; GstCaps *caps;
guint min, max, size; guint min, max, size;
gboolean update_pool; 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); g_mutex_lock (&mix->priv->gl_resource_lock);
mix->priv->gl_resource_ready = FALSE; mix->priv->gl_resource_ready = FALSE;
if (mix->fbo) { if (mix->fbo)
gst_gl_context_del_fbo (context, mix->fbo, mix->depthbuffer); gst_object_unref (mix->fbo);
mix->fbo = 0;
mix->depthbuffer = 0;
}
if (!gst_gl_context_gen_fbo (context, out_width, out_height, gst_gl_context_thread_add (context,
&mix->fbo, &mix->depthbuffer)) { (GstGLContextThreadFunc) _mixer_create_fbo, mix);
if (!mix->fbo) {
g_cond_signal (&mix->priv->gl_resource_cond); g_cond_signal (&mix->priv->gl_resource_cond);
g_mutex_unlock (&mix->priv->gl_resource_lock); g_mutex_unlock (&mix->priv->gl_resource_lock);
goto context_error; goto context_error;
@ -735,14 +738,13 @@ gst_gl_mixer_stop (GstAggregator * agg)
{ {
GstGLMixer *mix = GST_GL_MIXER (agg); GstGLMixer *mix = GST_GL_MIXER (agg);
GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix); GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
GstGLContext *context = GST_GL_BASE_MIXER (mix)->context;
if (mixer_class->reset) if (mixer_class->reset)
mixer_class->reset (mix); mixer_class->reset (mix);
if (mix->fbo) { if (mix->fbo) {
gst_gl_context_del_fbo (context, mix->fbo, mix->depthbuffer); gst_object_unref (mix->fbo);
mix->fbo = 0; mix->fbo = NULL;
mix->depthbuffer = 0;
} }
gst_gl_mixer_reset (mix); gst_gl_mixer_reset (mix);

View File

@ -84,8 +84,7 @@ struct _GstGLMixer
{ {
GstGLBaseMixer vaggregator; GstGLBaseMixer vaggregator;
GLuint fbo; GstGLFramebuffer *fbo;
GLuint depthbuffer;
GstCaps *out_caps; GstCaps *out_caps;

View File

@ -71,7 +71,7 @@ static gboolean gst_gl_mosaic_init_shader (GstGLMixer * mixer,
static gboolean gst_gl_mosaic_process_textures (GstGLMixer * mixer, static gboolean gst_gl_mosaic_process_textures (GstGLMixer * mixer,
GstGLMemory * out_tex); GstGLMemory * out_tex);
static void gst_gl_mosaic_callback (gpointer stuff); static gboolean gst_gl_mosaic_callback (gpointer stuff);
//vertex source //vertex source
static const gchar *mosaic_v_src = 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); 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 static gboolean
gst_gl_mosaic_process_textures (GstGLMixer * mix, GstGLMemory * out_tex) gst_gl_mosaic_process_textures (GstGLMixer * mix, GstGLMemory * out_tex)
{ {
GstGLMosaic *mosaic = GST_GL_MOSAIC (mix); GstGLMosaic *mosaic = GST_GL_MOSAIC (mix);
GstGLContext *context = GST_GL_BASE_MIXER (mix)->context;
//blocking call, use a FBO mosaic->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_gl_context_thread_add (context, (GstGLContextThreadFunc) _mosaic_render,
GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR (mix)->info), mix->fbo, mosaic);
mix->depthbuffer, out_tex->tex_id, gst_gl_mosaic_callback,
(gpointer) mosaic);
return TRUE; return TRUE;
} }
/* opengl scene, params: input texture (not the output mixer->texture) */ /* opengl scene, params: input texture (not the output mixer->texture) */
static void static gboolean
gst_gl_mosaic_callback (gpointer stuff) gst_gl_mosaic_callback (gpointer stuff)
{ {
GstGLMosaic *mosaic = GST_GL_MOSAIC (stuff); GstGLMosaic *mosaic = GST_GL_MOSAIC (stuff);
@ -345,4 +353,6 @@ gst_gl_mosaic_callback (gpointer stuff)
xrot += 0.6f; xrot += 0.6f;
yrot += 0.4f; yrot += 0.4f;
zrot += 0.8f; zrot += 0.8f;
return TRUE;
} }

View File

@ -107,7 +107,7 @@ static gboolean gst_gl_test_src_stop (GstBaseSrc * basesrc);
static gboolean gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc, static gboolean gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc,
GstQuery * query); 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); static gboolean gst_gl_test_src_init_shader (GstGLTestSrc * gltestsrc);
@ -454,22 +454,24 @@ gst_gl_test_src_init_shader (GstGLTestSrc * gltestsrc)
return TRUE; 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 static GstFlowReturn
gst_gl_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer) gst_gl_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
{ {
GstGLTestSrc *src = GST_GL_TEST_SRC (psrc); GstGLTestSrc *src = GST_GL_TEST_SRC (psrc);
GstClockTime next_time; GstClockTime next_time;
gint width, height;
GstVideoFrame out_frame; GstVideoFrame out_frame;
GstGLSyncMeta *sync_meta; GstGLSyncMeta *sync_meta;
guint out_tex;
if (G_UNLIKELY (!src->negotiated || !src->context)) if (G_UNLIKELY (!src->negotiated || !src->context))
goto not_negotiated; 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 */ /* 0 framerate and we are at the second frame, eos */
if (G_UNLIKELY (GST_VIDEO_INFO_FPS_N (&src->out_info) == 0 if (G_UNLIKELY (GST_VIDEO_INFO_FPS_N (&src->out_info) == 0
&& src->n_frames == 1)) && src->n_frames == 1))
@ -480,11 +482,11 @@ gst_gl_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
return GST_FLOW_NOT_NEGOTIATED; 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, gst_gl_context_thread_add (src->context, (GstGLContextThreadFunc) _fill_gl,
src->depthbuffer, out_tex, gst_gl_test_src_callback, src);
(gpointer) src)) { if (!src->gl_result) {
gst_video_frame_unmap (&out_frame); gst_video_frame_unmap (&out_frame);
goto gl_error; goto gl_error;
} }
@ -562,8 +564,11 @@ gst_gl_test_src_stop (GstBaseSrc * basesrc)
gst_object_unref (src->shader); gst_object_unref (src->shader);
src->shader = NULL; 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); gst_object_unref (src->context);
src->context = NULL; src->context = NULL;
} }
@ -615,6 +620,14 @@ _find_local_gl_context (GstGLTestSrc * src)
return FALSE; 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 static gboolean
gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query) 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; guint min, max, size;
gboolean update_pool; gboolean update_pool;
GError *error = NULL; GError *error = NULL;
guint out_width, out_height;
if (!gst_gl_ensure_element_data (src, &src->display, &src->other_context)) if (!gst_gl_ensure_element_data (src, &src->display, &src->other_context))
return FALSE; 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) if ((gst_gl_context_get_gl_api (src->context) & SUPPORTED_GL_APIS) == 0)
goto unsupported_gl_api; goto unsupported_gl_api;
out_width = GST_VIDEO_INFO_WIDTH (&src->out_info); gst_gl_context_thread_add (src->context,
out_height = GST_VIDEO_INFO_HEIGHT (&src->out_info); (GstGLContextThreadFunc) _src_generate_fbo_gl, src);
if (!src->fbo)
if (!gst_gl_context_gen_fbo (src->context, out_width, out_height,
&src->fbo, &src->depthbuffer))
goto context_error; goto context_error;
gst_query_parse_allocation (query, &caps, NULL); gst_query_parse_allocation (query, &caps, NULL);
@ -735,8 +745,7 @@ context_error:
} }
} }
//opengl scene static gboolean
static void
gst_gl_test_src_callback (gpointer stuff) gst_gl_test_src_callback (gpointer stuff)
{ {
GstGLTestSrc *src = GST_GL_TEST_SRC (stuff); GstGLTestSrc *src = GST_GL_TEST_SRC (stuff);
@ -752,21 +761,18 @@ gst_gl_test_src_callback (gpointer stuff)
if (funcs == NULL) { if (funcs == NULL) {
GST_ERROR_OBJECT (src, "Could not find an implementation of the " GST_ERROR_OBJECT (src, "Could not find an implementation of the "
"requested pattern"); "requested pattern");
src->gl_result = FALSE; return FALSE;
return;
} }
src->src_impl = funcs->new (src); src->src_impl = funcs->new (src);
if (!(src->gl_result = if (!(src->gl_result =
funcs->init (src->src_impl, src->context, &src->out_info))) { funcs->init (src->src_impl, src->context, &src->out_info))) {
GST_ERROR_OBJECT (src, "Failed to initialize pattern"); GST_ERROR_OBJECT (src, "Failed to initialize pattern");
return; return FALSE;
} }
src->active_pattern = src->set_pattern; src->active_pattern = src->set_pattern;
} }
src->gl_result = funcs->fill_bound_fbo (src->src_impl); return funcs->fill_bound_fbo (src->src_impl);
if (!src->gl_result)
GST_ERROR_OBJECT (src, "Failed to render the pattern");
} }
static GstStateChangeReturn static GstStateChangeReturn

View File

@ -62,8 +62,8 @@ struct _GstGLTestSrc {
/* video state */ /* video state */
GstVideoInfo out_info; GstVideoInfo out_info;
GLuint fbo; GstGLFramebuffer *fbo;
GLuint depthbuffer; GstGLMemory *out_tex;
GstGLShader *shader; GstGLShader *shader;

View File

@ -97,7 +97,7 @@ static gboolean gst_gl_transformation_decide_allocation (GstBaseTransform *
static void gst_gl_transformation_reset_gl (GstGLFilter * filter); static void gst_gl_transformation_reset_gl (GstGLFilter * filter);
static gboolean gst_gl_transformation_stop (GstBaseTransform * trans); static gboolean gst_gl_transformation_stop (GstBaseTransform * trans);
static gboolean gst_gl_transformation_init_shader (GstGLFilter * filter); 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 * static void gst_gl_transformation_build_mvp (GstGLTransformation *
transformation); transformation);
@ -789,13 +789,8 @@ gst_gl_transformation_filter_texture (GstGLFilter * filter,
transformation->in_tex = in_tex; transformation->in_tex = in_tex;
/* blocking call, use a FBO */ gst_gl_framebuffer_draw_to_texture (filter->fbo, out_tex,
gst_gl_context_use_fbo_v2 (GST_GL_BASE_FILTER (filter)->context, (GstGLFramebufferFunc) gst_gl_transformation_callback, transformation);
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);
return TRUE; return TRUE;
} }
@ -857,7 +852,7 @@ _unbind_buffer (GstGLTransformation * transformation)
gl->DisableVertexAttribArray (transformation->attr_texture); gl->DisableVertexAttribArray (transformation->attr_texture);
} }
static void static gboolean
gst_gl_transformation_callback (gpointer stuff) gst_gl_transformation_callback (gpointer stuff)
{ {
GstGLFilter *filter = GST_GL_FILTER (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); gst_gl_context_clear_shader (GST_GL_BASE_FILTER (filter)->context);
transformation->caps_change = FALSE; transformation->caps_change = FALSE;
return TRUE;
} }

View File

@ -475,7 +475,7 @@ static gboolean gst_gl_video_mixer_init_shader (GstGLMixer * mixer,
static gboolean gst_gl_video_mixer_process_textures (GstGLMixer * mixer, static gboolean gst_gl_video_mixer_process_textures (GstGLMixer * mixer,
GstGLMemory * out_tex); GstGLMemory * out_tex);
static void gst_gl_video_mixer_callback (gpointer stuff); static gboolean gst_gl_video_mixer_callback (gpointer stuff);
/* *INDENT-OFF* */ /* *INDENT-OFF* */
@ -1155,16 +1155,25 @@ gst_gl_video_mixer_init_shader (GstGLMixer * mixer, GstCaps * outcaps)
video_mixer_f_src, &video_mixer->shader); 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 static gboolean
gst_gl_video_mixer_process_textures (GstGLMixer * mix, GstGLMemory * out_tex) gst_gl_video_mixer_process_textures (GstGLMixer * mix, GstGLMemory * out_tex)
{ {
GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mix); 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, video_mixer->out_tex = out_tex;
GST_VIDEO_INFO_WIDTH (&GST_VIDEO_AGGREGATOR (mix)->info),
GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR (mix)->info), gst_gl_context_thread_add (context,
mix->fbo, mix->depthbuffer, (GstGLContextThreadFunc) _video_mixer_process_gl, video_mixer);
out_tex->tex_id, gst_gl_video_mixer_callback, (gpointer) video_mixer);
return TRUE; 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) */ /* opengl scene, params: input texture (not the output mixer->texture) */
static void static gboolean
gst_gl_video_mixer_callback (gpointer stuff) gst_gl_video_mixer_callback (gpointer stuff)
{ {
GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (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)) if (!_draw_background (video_mixer))
return; return FALSE;
gst_gl_shader_use (video_mixer->shader); gst_gl_shader_use (video_mixer->shader);
@ -1546,4 +1555,6 @@ gst_gl_video_mixer_callback (gpointer stuff)
gl->Disable (GL_BLEND); gl->Disable (GL_BLEND);
gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context); gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context);
return TRUE;
} }

View File

@ -125,6 +125,7 @@ struct _GstGLVideoMixer
GLuint vao; GLuint vao;
GLuint vbo_indices; GLuint vbo_indices;
GLuint checker_vbo; GLuint checker_vbo;
GstGLMemory *out_tex;
}; };
struct _GstGLVideoMixerClass struct _GstGLVideoMixerClass

View File

@ -63,6 +63,10 @@ typedef struct _GstGLRenderbuffer GstGLRenderbuffer;
typedef struct _GstGLRenderbufferAllocator GstGLRenderbufferAllocator; typedef struct _GstGLRenderbufferAllocator GstGLRenderbufferAllocator;
typedef struct _GstGLRenderbufferAllocatorClass GstGLRenderbufferAllocatorClass; typedef struct _GstGLRenderbufferAllocatorClass GstGLRenderbufferAllocatorClass;
typedef struct _GstGLFramebuffer GstGLFramebuffer;
typedef struct _GstGLFramebufferAllocator GstGLFramebufferAllocator;
typedef struct _GstGLFramebufferAllocatorClass GstGLFramebufferAllocatorClass;
typedef struct _GstGLSLStage GstGLSLStage; typedef struct _GstGLSLStage GstGLSLStage;
typedef struct _GstGLSLStagePrivate GstGLSLStagePrivate; typedef struct _GstGLSLStagePrivate GstGLSLStagePrivate;
typedef struct _GstGLSLStageClass GstGLSLStageClass; typedef struct _GstGLSLStageClass GstGLSLStageClass;

View File

@ -549,11 +549,9 @@ gst_gl_color_convert_reset (GstGLColorConvert * convert)
{ {
guint i; guint i;
if (convert->fbo || convert->depth_buffer) { if (convert->fbo) {
gst_gl_context_del_fbo (convert->context, convert->fbo, gst_object_unref (convert->fbo);
convert->depth_buffer); convert->fbo = NULL;
convert->fbo = 0;
convert->depth_buffer = 0;
} }
for (i = 0; i < convert->priv->convert_info.out_n_textures; i++) { 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); 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; goto error;
} }
@ -2088,82 +2086,16 @@ incompatible_api:
static gboolean static gboolean
_init_convert_fbo (GstGLColorConvert * convert) _init_convert_fbo (GstGLColorConvert * convert)
{ {
GstGLFuncs *gl;
guint out_width, out_height; 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_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info); out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
if (!gl->GenFramebuffers) { convert->fbo =
/* turn off the pipeline because Frame buffer object is a not present */ gst_gl_framebuffer_new_with_default_depth (convert->context, out_width,
gst_gl_context_set_error (convert->context, out_height);
"Context, EXT_framebuffer_object supported: no");
return FALSE;
}
GST_INFO ("Context, EXT_framebuffer_object supported: yes"); return convert->fbo != NULL;
/* 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;
} }
static gboolean static gboolean
@ -2487,21 +2419,13 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
gl = context->gl_vtable; gl = context->gl_vtable;
out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info); gst_gl_framebuffer_bind (convert->fbo);
out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo);
/* attach the texture to the FBO to renderer to */ /* attach the texture to the FBO to renderer to */
for (i = 0; i < c_info->out_n_textures; i++) { for (i = 0; i < c_info->out_n_textures; i++) {
guint gl_target = GstGLBaseMemory *tex = (GstGLBaseMemory *) convert->priv->out_tex[i];
gst_gl_texture_target_to_gl (convert->priv->to_texture_target);
/* needed? */ gst_gl_framebuffer_attach (convert->fbo, GL_COLOR_ATTACHMENT0 + i, tex);
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);
} }
if (gl->DrawBuffers) if (gl->DrawBuffers)
@ -2511,6 +2435,8 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
gl->GetIntegerv (GL_VIEWPORT, viewport_dim); 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); gl->Viewport (0, 0, out_width, out_height);
gst_gl_shader_use (convert->shader); gst_gl_shader_use (convert->shader);
@ -2556,7 +2482,7 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
gst_gl_context_check_framebuffer_status (context); gst_gl_context_check_framebuffer_status (context);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0); gst_gl_context_clear_framebuffer (context);
return TRUE; return TRUE;
} }

View File

@ -59,8 +59,7 @@ struct _GstGLColorConvert
GstBuffer * outbuf; GstBuffer * outbuf;
/* used for the conversion */ /* used for the conversion */
GLuint fbo; GstGLFramebuffer *fbo;
GLuint depth_buffer;
GstGLShader *shader; GstGLShader *shader;
/* <private> */ /* <private> */

View File

@ -228,12 +228,11 @@ gst_gl_filter_gl_stop (GstGLBaseFilter * base_filter)
filter->vbo_indices = 0; filter->vbo_indices = 0;
} }
if (filter->fbo != 0) { if (filter->fbo != NULL) {
gst_gl_context_del_fbo (context, filter->fbo, filter->depthbuffer); gst_object_unref (filter->fbo);
filter->fbo = NULL;
} }
filter->fbo = 0;
filter->depthbuffer = 0;
filter->default_shader = NULL; filter->default_shader = NULL;
filter->draw_attr_position_loc = -1; filter->draw_attr_position_loc = -1;
filter->draw_attr_texture_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_width = GST_VIDEO_INFO_WIDTH (&filter->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&filter->out_info); out_height = GST_VIDEO_INFO_HEIGHT (&filter->out_info);
if (filter->fbo) { if (filter->fbo)
gst_gl_context_del_fbo (context, filter->fbo, filter->depthbuffer); gst_object_unref (filter->fbo);
filter->fbo = 0;
filter->depthbuffer = 0; if (!(filter->fbo =
} gst_gl_framebuffer_new_with_default_depth (context, out_width,
//blocking call, generate a FBO out_height)))
if (!gst_gl_context_gen_fbo (context, out_width, out_height,
&filter->fbo, &filter->depthbuffer))
goto context_error; goto context_error;
if (filter_class->init_fbo) { if (filter_class->init_fbo) {
@ -1009,12 +1006,14 @@ struct glcb2
}; };
/* convenience functions to simplify filter development */ /* convenience functions to simplify filter development */
static void static gboolean
_glcb2 (gpointer data) _glcb2 (gpointer data)
{ {
struct glcb2 *cb = data; struct glcb2 *cb = data;
cb->func (cb->width, cb->height, cb->texture, 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, gst_gl_filter_render_to_target (GstGLFilter * filter, gboolean resize,
GstGLMemory * input, GstGLMemory * output, GLCB func, gpointer data) 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; guint in_width, in_height, out_width, out_height;
struct glcb2 cb; struct glcb2 cb;
@ -1057,8 +1055,7 @@ gst_gl_filter_render_to_target (GstGLFilter * filter, gboolean resize,
cb.width = in_width; cb.width = in_width;
cb.height = in_height; cb.height = in_height;
gst_gl_context_use_fbo_v2 (context, out_width, out_height, gst_gl_framebuffer_draw_to_texture (filter->fbo, output, _glcb2, &cb);
filter->fbo, filter->depthbuffer, output->tex_id, _glcb2, &cb);
} }
static void static void

View File

@ -63,9 +63,10 @@ struct _GstGLFilter
GstCaps *out_caps; GstCaps *out_caps;
/* <protected> */
GstGLFramebuffer *fbo;
/* <private> */ /* <private> */
GLuint fbo;
GLuint depthbuffer;
gboolean gl_result; gboolean gl_result;
GstBuffer *inbuf; GstBuffer *inbuf;
GstBuffer *outbuf; GstBuffer *outbuf;

View File

@ -24,13 +24,29 @@
#include "gl.h" #include "gl.h"
#include "gstglframebuffer.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); GST_DEBUG_CATEGORY_STATIC (gst_gl_framebuffer_debug);
#define GST_CAT_DEFAULT gst_gl_framebuffer_debug #define GST_CAT_DEFAULT gst_gl_framebuffer_debug
#define DEBUG_INIT \ #define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_framebuffer_debug, "glframebuffer", 0, "GL Framebuffer"); 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); DEBUG_INIT);
#define GST_GL_FRAMEBUFFER_GET_PRIVATE(o) \ #define GST_GL_FRAMEBUFFER_GET_PRIVATE(o) \
@ -40,13 +56,35 @@ static void gst_gl_framebuffer_finalize (GObject * object);
struct _GstGLFramebufferPrivate struct _GstGLFramebufferPrivate
{ {
gint width; guint effective_width;
gint height; 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 static void
gst_gl_framebuffer_class_init (GstGLFramebufferClass * klass) gst_gl_framebuffer_class_init (GstGLFramebufferClass * klass)
{ {
@ -56,183 +94,355 @@ gst_gl_framebuffer_class_init (GstGLFramebufferClass * klass)
} }
static void 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 static void
gst_gl_framebuffer_finalize (GObject * object) gst_gl_framebuffer_finalize (GObject * object)
{ {
GstGLFramebuffer *fbo = GST_GL_FRAMEBUFFER (object); GstGLFramebuffer *fb = GST_GL_FRAMEBUFFER (object);
if (fbo->context) { if (fb->context) {
gst_object_unref (fbo->context); if (fb->fbo_id)
fbo->context = NULL; 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); G_OBJECT_CLASS (gst_gl_framebuffer_parent_class)->finalize (object);
} }
GstGLFramebuffer * GstGLFramebuffer *
gst_gl_framebuffer_new (GstGLContext * context) gst_gl_framebuffer_new (GstGLContext * context)
{ {
GstGLFramebuffer *fbo = g_object_new (GST_TYPE_GL_FRAMEBUFFER, NULL); GstGLFramebuffer *fb;
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;
const GstGLFuncs *gl; const GstGLFuncs *gl;
GLenum internal_format;
g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (frame), FALSE); g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
g_return_val_if_fail (fbo != NULL && depth != NULL, FALSE); g_return_val_if_fail (gst_gl_context_get_current () == context, NULL);
g_return_val_if_fail (width > 0 && height > 0, FALSE);
gl = frame->context->gl_vtable; gl = context->gl_vtable;
GST_TRACE ("creating FBO dimensions:%ux%u", width, height);
if (!gl->GenFramebuffers) { if (!gl->GenFramebuffers) {
gst_gl_context_set_error (frame->context, GST_ERROR_OBJECT (context, "Framebuffers are not supported!");
"Context, EXT_framebuffer_object not supported"); return NULL;
return FALSE;
} }
/* setup FBO */
gl->GenFramebuffers (1, fbo);
gl->BindFramebuffer (GL_FRAMEBUFFER, *fbo);
/* setup the render buffer for depth */ fb = g_object_new (GST_TYPE_GL_FRAMEBUFFER, NULL);
gl->GenRenderbuffers (1, depth); fb->context = gst_object_ref (context);
gl->BindRenderbuffer (GL_RENDERBUFFER, *depth); 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)) { GST_GL_API_OPENGL3)) {
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, attach_point = GL_DEPTH_STENCIL_ATTACHMENT;
height); attach_type = GST_GL_DEPTH24_STENCIL8;
} } else if (gst_gl_context_get_gl_api (fb->context) & GST_GL_API_GLES2) {
if (gst_gl_context_get_gl_api (frame->context) & GST_GL_API_GLES2) { attach_point = GL_DEPTH_ATTACHMENT;
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, attach_type = GST_GL_DEPTH_COMPONENT16;
width, height); } else {
g_assert_not_reached ();
return NULL;
} }
/* setup a texture to render to */ render_alloc = (GstGLBaseMemoryAllocator *)
gl->GenTextures (1, &fake_texture); gst_allocator_find (GST_GL_RENDERBUFFER_ALLOCATOR_NAME);
gl->BindTexture (GL_TEXTURE_2D, fake_texture); params = (GstGLAllocationParams *)
internal_format = gst_gl_renderbuffer_allocation_params_new (context, NULL, attach_type,
gst_gl_sized_gl_format_from_gl_format_type (frame->context, GL_RGBA, width, height);
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 */ renderbuffer = gst_gl_base_memory_alloc (render_alloc, params);
gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gst_gl_allocation_params_free (params);
GL_TEXTURE_2D, fake_texture, 0); gst_object_unref (render_alloc);
/* attach the depth render buffer to the FBO */ gst_gl_framebuffer_bind (fb);
gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, gst_gl_framebuffer_attach (fb, attach_point, renderbuffer);
GL_RENDERBUFFER, *depth); 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 | return fb;
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;
} }
gboolean gboolean
gst_gl_framebuffer_use_v2 (GstGLFramebuffer * frame, gint texture_fbo_width, gst_gl_framebuffer_draw_to_texture (GstGLFramebuffer * fb, GstGLMemory * mem,
gint texture_fbo_height, GLuint fbo, GLuint depth_buffer, GstGLFramebufferFunc func, gpointer user_data)
GLuint texture_fbo, GLCB_V2 cb, gpointer stuff)
{ {
const GstGLFuncs *gl;
GLint viewport_dim[4] = { 0 }; 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 (GST_IS_GL_FRAMEBUFFER (fb), FALSE);
g_return_val_if_fail (texture_fbo_width > 0 && texture_fbo_height > 0, FALSE); g_return_val_if_fail (gst_is_gl_memory (GST_MEMORY_CAST (mem)), 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);
gl = frame->context->gl_vtable; gl = fb->context->gl_vtable;
GST_TRACE ("Binding v2 FBO %u dimensions:%ux%u with texture:%u ", GST_TRACE_OBJECT (fb, "drawing to texture %u, dimensions %ix%i", mem->tex_id,
fbo, texture_fbo_width, texture_fbo_height, texture_fbo); gst_gl_memory_get_texture_width (mem),
gst_gl_memory_get_texture_height (mem));
gl->BindFramebuffer (GL_FRAMEBUFFER, fbo); gst_gl_framebuffer_bind (fb);
gst_gl_framebuffer_attach (fb, GL_COLOR_ATTACHMENT0, (GstGLBaseMemory *) mem);
/* 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);
gl->GetIntegerv (GL_VIEWPORT, viewport_dim); gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
gl->Viewport (0, 0, fb->priv->effective_width, fb->priv->effective_height);
gl->Viewport (0, 0, texture_fbo_width, texture_fbo_height); if (gst_gl_context_get_gl_api (fb->context) & (GST_GL_API_OPENGL |
if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL |
GST_GL_API_OPENGL3)) GST_GL_API_OPENGL3))
gl->DrawBuffer (GL_COLOR_ATTACHMENT0); gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
/* the opengl scene */ ret = func (user_data);
cb (stuff);
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)) GST_GL_API_OPENGL3))
gl->DrawBuffer (GL_NONE); 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], return ret;
viewport_dim[2], viewport_dim[3]);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
return TRUE;
} }
void void
gst_gl_framebuffer_delete (GstGLFramebuffer * frame, guint fbo, guint depth) gst_gl_framebuffer_bind (GstGLFramebuffer * fb)
{ {
const GstGLFuncs *gl; 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); gl->BindFramebuffer (GL_FRAMEBUFFER, fb->fbo_id);
}
if (fbo) {
gl->DeleteFramebuffers (1, &fbo); void
} gst_gl_context_clear_framebuffer (GstGLContext * context)
if (depth) { {
gl->DeleteRenderbuffers (1, &depth); 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;
} }

View File

@ -38,31 +38,55 @@ typedef struct _GstGLFramebuffer GstGLFramebuffer;
typedef struct _GstGLFramebufferClass GstGLFramebufferClass; typedef struct _GstGLFramebufferClass GstGLFramebufferClass;
typedef struct _GstGLFramebufferPrivate GstGLFramebufferPrivate; typedef struct _GstGLFramebufferPrivate GstGLFramebufferPrivate;
/**
* GstGLFramebufferFunc:
* @data: user data
*
* callback definition for operating through a Framebuffer object
*/
typedef gboolean (*GstGLFramebufferFunc) (gpointer stuff);
struct _GstGLFramebuffer struct _GstGLFramebuffer
{ {
GObject object; GstObject object;
/* <private> */ /* <private> */
GstGLContext *context; GstGLContext *context;
guint fbo_id;
GArray *attachments;
GstGLFramebufferPrivate *priv; GstGLFramebufferPrivate *priv;
}; };
struct _GstGLFramebufferClass 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 gst_gl_framebuffer_get_id (GstGLFramebuffer * fb);
guint * fbo, guint * depthbuffer);
gboolean gst_gl_framebuffer_use_v2 (GstGLFramebuffer * frame, gint texture_fbo_width, void gst_gl_framebuffer_attach (GstGLFramebuffer * fb,
gint texture_fbo_height, GLuint fbo, GLuint depth_buffer, guint attachment_point,
GLuint texture_fbo, GLCB_V2 cb, gpointer stuff); 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 #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstGLFramebuffer, gst_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstGLFramebuffer, gst_object_unref)

View File

@ -36,22 +36,6 @@
#include <gst/gl/wayland/gstgldisplay_wayland.h> #include <gst/gl/wayland/gstgldisplay_wayland.h>
#endif #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_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_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)) #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; 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 struct _compile_shader
{ {
GstGLShader **shader; GstGLShader **shader;

View File

@ -60,29 +60,12 @@ typedef gboolean (*CDCB) (GLuint texture, GLuint width, GLuint height, gpointer
* callback definition for operating on textures * callback definition for operating on textures
*/ */
typedef void (*GLCB) (gint, gint, guint, gpointer stuff); 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, gboolean gst_gl_context_gen_shader (GstGLContext * context,
const gchar * shader_vertex_source, const gchar * shader_vertex_source,
const gchar * shader_fragment_source, GstGLShader ** shader); const gchar * shader_fragment_source, GstGLShader ** shader);
void gst_gl_context_del_shader (GstGLContext * context, 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, ...); void gst_gl_context_set_error (GstGLContext * context, const char * format, ...);
gchar *gst_gl_context_get_error (void); gchar *gst_gl_context_get_error (void);

View File

@ -1304,6 +1304,11 @@ gst_gl_view_convert_reset (GstGLViewConvert * viewconvert)
if (viewconvert->shader) if (viewconvert->shader)
gst_gl_context_del_shader (viewconvert->context, viewconvert->shader); gst_gl_context_del_shader (viewconvert->context, viewconvert->shader);
viewconvert->shader = NULL; viewconvert->shader = NULL;
if (viewconvert->fbo)
gst_object_unref (viewconvert->fbo);
viewconvert->fbo = NULL;
viewconvert->initted = FALSE; viewconvert->initted = FALSE;
viewconvert->reconfigure = FALSE; viewconvert->reconfigure = FALSE;
} }
@ -1383,74 +1388,16 @@ gst_gl_view_convert_perform (GstGLViewConvert * viewconvert, GstBuffer * inbuf)
static gboolean static gboolean
_init_view_convert_fbo (GstGLViewConvert * viewconvert) _init_view_convert_fbo (GstGLViewConvert * viewconvert)
{ {
GstGLFuncs *gl;
guint out_width, out_height; 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_width = GST_VIDEO_INFO_WIDTH (&viewconvert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&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 */ viewconvert->fbo =
gl->GenFramebuffers (1, &viewconvert->fbo); gst_gl_framebuffer_new_with_default_depth (viewconvert->context,
gl->BindFramebuffer (GL_FRAMEBUFFER, viewconvert->fbo); out_width, out_height);
/* 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) */ return viewconvert->fbo != NULL;
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;
} }
/* free after use */ /* 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); gst_gl_texture_target_to_gl (viewconvert->from_texture_target);
gl = context->gl_vtable; gl = context->gl_vtable;
out_width = GST_VIDEO_INFO_WIDTH (&viewconvert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&viewconvert->out_info); gst_gl_framebuffer_bind (viewconvert->fbo);
gl->BindFramebuffer (GL_FRAMEBUFFER, viewconvert->fbo);
if (out_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED || if (out_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED ||
out_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) { out_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
out_views = viewconvert->out_info.views; 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 */ /* attach the texture to the FBO to renderer to */
for (i = 0; i < out_views; i++) { for (i = 0; i < out_views; i++) {
guint gl_target = GstGLBaseMemory *tex = (GstGLBaseMemory *) priv->out_tex[i];
gst_gl_texture_target_to_gl (viewconvert->to_texture_target);
/* needed? */ gst_gl_framebuffer_attach (viewconvert->fbo, GL_COLOR_ATTACHMENT0 + i, tex);
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);
} }
if (gl->DrawBuffers) if (gl->DrawBuffers)
gl->DrawBuffers (out_views, multipleRT); gl->DrawBuffers (out_views, multipleRT);
else if (gl->DrawBuffer) else if (gl->DrawBuffer)
gl->DrawBuffer (GL_COLOR_ATTACHMENT0); gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
gst_gl_framebuffer_get_effective_dimensions (viewconvert->fbo, &out_width,
&out_height);
gl->GetIntegerv (GL_VIEWPORT, viewport_dim); gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
gl->Viewport (0, 0, out_width, out_height); gl->Viewport (0, 0, out_width, out_height);
@ -1911,6 +1857,7 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert)
gl->BindVertexArray (priv->vao); gl->BindVertexArray (priv->vao);
else else
_bind_buffer (viewconvert); _bind_buffer (viewconvert);
if (in_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED || if (in_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED ||
in_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) { in_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
if (priv->in_tex[1] == NULL) { if (priv->in_tex[1] == NULL) {
@ -1924,7 +1871,9 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert)
gl->ActiveTexture (GL_TEXTURE0); gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (from_gl_target, priv->in_tex[0]->tex_id); gl->BindTexture (from_gl_target, priv->in_tex[0]->tex_id);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL); gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
if (gl->BindVertexArray) if (gl->BindVertexArray)
gl->BindVertexArray (0); gl->BindVertexArray (0);
else else
@ -1935,8 +1884,8 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert)
gst_gl_context_clear_shader (context); gst_gl_context_clear_shader (context);
gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2], gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2],
viewport_dim[3]); viewport_dim[3]);
gst_gl_context_check_framebuffer_status (context); gst_gl_context_clear_framebuffer (context);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
return TRUE; return TRUE;
} }

View File

@ -68,8 +68,7 @@ struct _GstGLViewConvert
gboolean initted; gboolean initted;
gboolean reconfigure; gboolean reconfigure;
GLuint fbo; GstGLFramebuffer *fbo;
GLuint depth_buffer;
GstGLViewConvertPrivate *priv; GstGLViewConvertPrivate *priv;
}; };

View File

@ -43,7 +43,7 @@ teardown (void)
} }
static GstGLMemory *gl_tex; static GstGLMemory *gl_tex;
static GLuint vbo, vbo_indices, vao, fbo_id, rbo; static GLuint vbo, vbo_indices, vao;
static GstGLFramebuffer *fbo; static GstGLFramebuffer *fbo;
static GstGLShader *shader; static GstGLShader *shader;
static GLint shader_attr_position_loc; static GLint shader_attr_position_loc;
@ -75,10 +75,9 @@ init (gpointer data)
GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA); 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 */ /* 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, "failed to create framebuffer object");
fail_if (fbo == NULL || fbo_id == 0, "failed to create framebuffer object");
gl_tex = gl_tex =
(GstGLMemory *) gst_gl_base_memory_alloc ((GstGLBaseMemoryAllocator *) (GstGLMemory *) gst_gl_base_memory_alloc ((GstGLBaseMemoryAllocator *)
@ -109,7 +108,7 @@ deinit (gpointer data)
gst_memory_unref (GST_MEMORY_CAST (gl_tex)); gst_memory_unref (GST_MEMORY_CAST (gl_tex));
} }
static void static gboolean
clear_tex (gpointer data) clear_tex (gpointer data)
{ {
GstGLContext *context = data; GstGLContext *context = data;
@ -122,13 +121,15 @@ clear_tex (gpointer data)
r = r > 1.0 ? 0.0 : r + 0.03; r = r > 1.0 ? 0.0 : r + 0.03;
g = g > 1.0 ? 0.0 : g + 0.01; g = g > 1.0 ? 0.0 : g + 0.01;
b = b > 1.0 ? 0.0 : b + 0.015; b = b > 1.0 ? 0.0 : b + 0.015;
return TRUE;
} }
static void static void
draw_tex (gpointer data) draw_tex (gpointer data)
{ {
gst_gl_framebuffer_use_v2 (fbo, 320, 240, fbo_id, rbo, gst_gl_framebuffer_draw_to_texture (fbo, gl_tex,
gst_gl_memory_get_texture_id (gl_tex), (GLCB_V2) clear_tex, data); (GstGLFramebufferFunc) clear_tex, data);
} }
static void static void
@ -275,7 +276,8 @@ GST_START_TEST (test_share)
gst_gl_window_set_preferred_size (window, 320, 240); gst_gl_window_set_preferred_size (window, 320, 240);
gst_gl_window_draw (window); 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); gst_gl_window_send_message (window, GST_GL_WINDOW_CB (init_blit), context);
while (i < 10) { while (i < 10) {
@ -286,7 +288,8 @@ GST_START_TEST (test_share)
i++; 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_gl_window_send_message (window, GST_GL_WINDOW_CB (deinit_blit), context);
gst_object_unref (window); 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_set_preferred_size (window, 320, 240);
gst_gl_window_draw (window); 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); gst_gl_window_send_message (window, GST_GL_WINDOW_CB (init_blit), context);
while (i < 10) { 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), gst_gl_window_send_message (window, GST_GL_WINDOW_CB (check_wrapped),
wrapped_context); 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_gl_window_send_message (window, GST_GL_WINDOW_CB (deinit_blit), context);
gst_object_unref (other_context); gst_object_unref (other_context);