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 committed by Tim-Philipp Müller
parent 7f10822de4
commit 4bbda2b626
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;
}
static void
_emit_draw_signal (guint tex, gint width, gint height, gpointer data)
{
GstGLFilterApp *app_filter = GST_GL_FILTER_APP (data);
gboolean drawn;
g_signal_emit (app_filter, gst_gl_filter_app_signals[CLIENT_DRAW_SIGNAL], 0,
tex, width, height, &drawn);
app_filter->default_draw = !drawn;
}
struct glcb2
{
GLCB func;
gpointer data;
GstGLFilterApp *app;
GstGLMemory *in_tex;
GstGLMemory *out_tex;
};
/* convenience functions to simplify filter development */
static void
_glcb2 (gpointer data)
static gboolean
_emit_draw_signal (gpointer data)
{
struct glcb2 *cb = data;
gboolean drawn;
cb->func (gst_gl_memory_get_texture_width (cb->in_tex),
gst_gl_memory_get_texture_height (cb->in_tex), cb->in_tex->tex_id,
cb->data);
g_signal_emit (cb->app, gst_gl_filter_app_signals[CLIENT_DRAW_SIGNAL], 0,
cb->in_tex->tex_id, gst_gl_memory_get_texture_width (cb->out_tex),
gst_gl_memory_get_texture_height (cb->out_tex), &drawn);
return !drawn;
}
static gboolean
@ -220,20 +209,18 @@ gst_gl_filter_app_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLFilterApp *app_filter = GST_GL_FILTER_APP (filter);
gboolean default_draw;
struct glcb2 cb;
cb.func = (GLCB) _emit_draw_signal;
cb.data = filter;
cb.app = app_filter;
cb.in_tex = in_tex;
cb.out_tex = out_tex;
//blocking call, use a FBO
gst_gl_context_use_fbo_v2 (GST_GL_BASE_FILTER (filter)->context,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
filter->fbo, filter->depthbuffer, out_tex->tex_id, _glcb2, &cb);
default_draw =
gst_gl_framebuffer_draw_to_texture (filter->fbo,
out_tex, _emit_draw_signal, &cb);
if (app_filter->default_draw) {
if (default_draw) {
gst_gl_filter_render_to_target_with_shader (filter, TRUE, in_tex, out_tex,
filter->default_shader);
}

View file

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

View file

@ -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;
}

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,
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;
}

View file

@ -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);

View file

@ -84,8 +84,7 @@ struct _GstGLMixer
{
GstGLBaseMixer vaggregator;
GLuint fbo;
GLuint depthbuffer;
GstGLFramebuffer *fbo;
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,
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;
}

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,
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

View file

@ -62,8 +62,8 @@ struct _GstGLTestSrc {
/* video state */
GstVideoInfo out_info;
GLuint fbo;
GLuint depthbuffer;
GstGLFramebuffer *fbo;
GstGLMemory *out_tex;
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 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;
}

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

View file

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

View file

@ -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;

View file

@ -549,11 +549,9 @@ gst_gl_color_convert_reset (GstGLColorConvert * convert)
{
guint i;
if (convert->fbo || convert->depth_buffer) {
gst_gl_context_del_fbo (convert->context, convert->fbo,
convert->depth_buffer);
convert->fbo = 0;
convert->depth_buffer = 0;
if (convert->fbo) {
gst_object_unref (convert->fbo);
convert->fbo = NULL;
}
for (i = 0; i < convert->priv->convert_info.out_n_textures; i++) {
@ -2027,7 +2025,7 @@ _init_convert (GstGLColorConvert * convert)
gst_gl_context_clear_shader (convert->context);
if (convert->fbo == 0 && !_init_convert_fbo (convert)) {
if (convert->fbo == NULL && !_init_convert_fbo (convert)) {
goto error;
}
@ -2088,82 +2086,16 @@ incompatible_api:
static gboolean
_init_convert_fbo (GstGLColorConvert * convert)
{
GstGLFuncs *gl;
guint out_width, out_height;
GLuint fake_texture = 0; /* a FBO must hava texture to init */
GLenum internal_format;
gl = convert->context->gl_vtable;
out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
if (!gl->GenFramebuffers) {
/* turn off the pipeline because Frame buffer object is a not present */
gst_gl_context_set_error (convert->context,
"Context, EXT_framebuffer_object supported: no");
return FALSE;
}
convert->fbo =
gst_gl_framebuffer_new_with_default_depth (convert->context, out_width,
out_height);
GST_INFO ("Context, EXT_framebuffer_object supported: yes");
/* setup FBO */
gl->GenFramebuffers (1, &convert->fbo);
gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo);
/* setup the render buffer for depth */
gl->GenRenderbuffers (1, &convert->depth_buffer);
gl->BindRenderbuffer (GL_RENDERBUFFER, convert->depth_buffer);
if (USING_OPENGL (convert->context) || USING_OPENGL3 (convert->context)) {
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
out_width, out_height);
}
if (USING_GLES2 (convert->context)) {
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
out_width, out_height);
}
/* a fake texture is attached to the convert FBO (cannot init without it) */
gl->GenTextures (1, &fake_texture);
gl->BindTexture (GL_TEXTURE_2D, fake_texture);
internal_format =
gst_gl_sized_gl_format_from_gl_format_type (convert->context, GL_RGBA,
GL_UNSIGNED_BYTE);
gl->TexImage2D (GL_TEXTURE_2D, 0, internal_format, out_width, out_height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
/* attach the texture to the FBO to renderer to */
gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, fake_texture, 0);
/* attach the depth render buffer to the FBO */
gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, convert->depth_buffer);
if (USING_OPENGL (convert->context)) {
gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, convert->depth_buffer);
}
if (!gst_gl_context_check_framebuffer_status (convert->context)) {
gst_gl_context_set_error (convert->context,
"GL framebuffer status incomplete");
gl->DeleteTextures (1, &fake_texture);
return FALSE;
}
/* unbind the FBO */
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
gl->DeleteTextures (1, &fake_texture);
return TRUE;
return convert->fbo != NULL;
}
static gboolean
@ -2487,21 +2419,13 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
gl = context->gl_vtable;
out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo);
gst_gl_framebuffer_bind (convert->fbo);
/* attach the texture to the FBO to renderer to */
for (i = 0; i < c_info->out_n_textures; i++) {
guint gl_target =
gst_gl_texture_target_to_gl (convert->priv->to_texture_target);
GstGLBaseMemory *tex = (GstGLBaseMemory *) convert->priv->out_tex[i];
/* needed? */
gl->BindTexture (gl_target, convert->priv->out_tex[i]->tex_id);
gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
gl_target, convert->priv->out_tex[i]->tex_id, 0);
gst_gl_framebuffer_attach (convert->fbo, GL_COLOR_ATTACHMENT0 + i, tex);
}
if (gl->DrawBuffers)
@ -2511,6 +2435,8 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
gst_gl_framebuffer_get_effective_dimensions (convert->fbo, &out_width,
&out_height);
gl->Viewport (0, 0, out_width, out_height);
gst_gl_shader_use (convert->shader);
@ -2556,7 +2482,7 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
gst_gl_context_check_framebuffer_status (context);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
gst_gl_context_clear_framebuffer (context);
return TRUE;
}

View file

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

View file

@ -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

View file

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

View file

@ -24,13 +24,29 @@
#include "gl.h"
#include "gstglframebuffer.h"
#ifndef GL_FRAMEBUFFER_UNDEFINED
#define GL_FRAMEBUFFER_UNDEFINED 0x8219
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
#endif
#ifndef GL_FRAMEBUFFER_UNSUPPORTED
#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
#endif
GST_DEBUG_CATEGORY_STATIC (gst_gl_framebuffer_debug);
#define GST_CAT_DEFAULT gst_gl_framebuffer_debug
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_framebuffer_debug, "glframebuffer", 0, "GL Framebuffer");
G_DEFINE_TYPE_WITH_CODE (GstGLFramebuffer, gst_gl_framebuffer, G_TYPE_OBJECT,
G_DEFINE_TYPE_WITH_CODE (GstGLFramebuffer, gst_gl_framebuffer, GST_TYPE_OBJECT,
DEBUG_INIT);
#define GST_GL_FRAMEBUFFER_GET_PRIVATE(o) \
@ -40,13 +56,35 @@ static void gst_gl_framebuffer_finalize (GObject * object);
struct _GstGLFramebufferPrivate
{
gint width;
gint height;
guint fbo;
guint depth;
guint effective_width;
guint effective_height;
};
struct fbo_attachment
{
guint attachment_point;
GstGLBaseMemory *mem;
};
static void
_fbo_attachment_init (struct fbo_attachment *attach, guint point,
GstGLBaseMemory * mem)
{
attach->attachment_point = point;
attach->mem = (GstGLBaseMemory *) gst_memory_ref (GST_MEMORY_CAST (mem));
}
static void
_fbo_attachment_unset (struct fbo_attachment *attach)
{
if (!attach)
return;
if (attach->mem)
gst_memory_unref (GST_MEMORY_CAST (attach->mem));
attach->mem = NULL;
}
static void
gst_gl_framebuffer_class_init (GstGLFramebufferClass * klass)
{
@ -56,183 +94,355 @@ gst_gl_framebuffer_class_init (GstGLFramebufferClass * klass)
}
static void
gst_gl_framebuffer_init (GstGLFramebuffer * fbo)
gst_gl_framebuffer_init (GstGLFramebuffer * fb)
{
fbo->priv = GST_GL_FRAMEBUFFER_GET_PRIVATE (fbo);
fb->priv = GST_GL_FRAMEBUFFER_GET_PRIVATE (fb);
fb->attachments =
g_array_new (FALSE, FALSE, (sizeof (struct fbo_attachment)));
g_array_set_clear_func (fb->attachments,
(GDestroyNotify) _fbo_attachment_unset);
}
static void
_delete_fbo_gl (GstGLContext * context, GstGLFramebuffer * fb)
{
const GstGLFuncs *gl = context->gl_vtable;
if (fb->fbo_id)
gl->DeleteFramebuffers (1, &fb->fbo_id);
fb->fbo_id = 0;
}
static void
gst_gl_framebuffer_finalize (GObject * object)
{
GstGLFramebuffer *fbo = GST_GL_FRAMEBUFFER (object);
GstGLFramebuffer *fb = GST_GL_FRAMEBUFFER (object);
if (fbo->context) {
gst_object_unref (fbo->context);
fbo->context = NULL;
if (fb->context) {
if (fb->fbo_id)
gst_gl_context_thread_add (fb->context,
(GstGLContextThreadFunc) _delete_fbo_gl, fb);
gst_object_unref (fb->context);
fb->context = NULL;
}
if (fb->attachments)
g_array_free (fb->attachments, TRUE);
fb->attachments = NULL;
G_OBJECT_CLASS (gst_gl_framebuffer_parent_class)->finalize (object);
}
GstGLFramebuffer *
gst_gl_framebuffer_new (GstGLContext * context)
{
GstGLFramebuffer *fbo = g_object_new (GST_TYPE_GL_FRAMEBUFFER, NULL);
fbo->context = gst_object_ref (context);
return fbo;
}
gboolean
gst_gl_framebuffer_generate (GstGLFramebuffer * frame, gint width, gint height,
guint * fbo, guint * depth)
{
GLuint fake_texture = 0;
GstGLFramebuffer *fb;
const GstGLFuncs *gl;
GLenum internal_format;
g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (frame), FALSE);
g_return_val_if_fail (fbo != NULL && depth != NULL, FALSE);
g_return_val_if_fail (width > 0 && height > 0, FALSE);
g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
g_return_val_if_fail (gst_gl_context_get_current () == context, NULL);
gl = frame->context->gl_vtable;
GST_TRACE ("creating FBO dimensions:%ux%u", width, height);
gl = context->gl_vtable;
if (!gl->GenFramebuffers) {
gst_gl_context_set_error (frame->context,
"Context, EXT_framebuffer_object not supported");
return FALSE;
GST_ERROR_OBJECT (context, "Framebuffers are not supported!");
return NULL;
}
/* setup FBO */
gl->GenFramebuffers (1, fbo);
gl->BindFramebuffer (GL_FRAMEBUFFER, *fbo);
/* setup the render buffer for depth */
gl->GenRenderbuffers (1, depth);
gl->BindRenderbuffer (GL_RENDERBUFFER, *depth);
fb = g_object_new (GST_TYPE_GL_FRAMEBUFFER, NULL);
fb->context = gst_object_ref (context);
gl->GenFramebuffers (1, &fb->fbo_id);
if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL |
return fb;
}
GstGLFramebuffer *
gst_gl_framebuffer_new_with_default_depth (GstGLContext * context, guint width,
guint height)
{
GstGLFramebuffer *fb = gst_gl_framebuffer_new (context);
GstGLBaseMemoryAllocator *render_alloc;
GstGLAllocationParams *params;
GstGLBaseMemory *renderbuffer;
guint attach_point, attach_type;
if (!fb)
return NULL;
if (gst_gl_context_get_gl_api (fb->context) & (GST_GL_API_OPENGL |
GST_GL_API_OPENGL3)) {
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width,
height);
}
if (gst_gl_context_get_gl_api (frame->context) & GST_GL_API_GLES2) {
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
width, height);
attach_point = GL_DEPTH_STENCIL_ATTACHMENT;
attach_type = GST_GL_DEPTH24_STENCIL8;
} else if (gst_gl_context_get_gl_api (fb->context) & GST_GL_API_GLES2) {
attach_point = GL_DEPTH_ATTACHMENT;
attach_type = GST_GL_DEPTH_COMPONENT16;
} else {
g_assert_not_reached ();
return NULL;
}
/* setup a texture to render to */
gl->GenTextures (1, &fake_texture);
gl->BindTexture (GL_TEXTURE_2D, fake_texture);
internal_format =
gst_gl_sized_gl_format_from_gl_format_type (frame->context, GL_RGBA,
GL_UNSIGNED_BYTE);
gl->TexImage2D (GL_TEXTURE_2D, 0, internal_format, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, NULL);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
render_alloc = (GstGLBaseMemoryAllocator *)
gst_allocator_find (GST_GL_RENDERBUFFER_ALLOCATOR_NAME);
params = (GstGLAllocationParams *)
gst_gl_renderbuffer_allocation_params_new (context, NULL, attach_type,
width, height);
/* attach the texture to the FBO to renderer to */
gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, fake_texture, 0);
renderbuffer = gst_gl_base_memory_alloc (render_alloc, params);
gst_gl_allocation_params_free (params);
gst_object_unref (render_alloc);
/* attach the depth render buffer to the FBO */
gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, *depth);
gst_gl_framebuffer_bind (fb);
gst_gl_framebuffer_attach (fb, attach_point, renderbuffer);
gst_gl_context_clear_framebuffer (fb->context);
gst_memory_unref (GST_MEMORY_CAST (renderbuffer));
if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL |
GST_GL_API_OPENGL3)) {
gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, *depth);
}
if (gl->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
gst_gl_context_set_error (frame->context,
"GL framebuffer status incomplete");
gl->DeleteTextures (1, &fake_texture);
return FALSE;
}
/* unbind the FBO */
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
gl->DeleteTextures (1, &fake_texture);
return TRUE;
return fb;
}
gboolean
gst_gl_framebuffer_use_v2 (GstGLFramebuffer * frame, gint texture_fbo_width,
gint texture_fbo_height, GLuint fbo, GLuint depth_buffer,
GLuint texture_fbo, GLCB_V2 cb, gpointer stuff)
gst_gl_framebuffer_draw_to_texture (GstGLFramebuffer * fb, GstGLMemory * mem,
GstGLFramebufferFunc func, gpointer user_data)
{
const GstGLFuncs *gl;
GLint viewport_dim[4] = { 0 };
const GstGLFuncs *gl;
gboolean ret;
g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (frame), FALSE);
g_return_val_if_fail (texture_fbo_width > 0 && texture_fbo_height > 0, FALSE);
g_return_val_if_fail (fbo != 0, FALSE);
g_return_val_if_fail (texture_fbo != 0, FALSE);
g_return_val_if_fail (cb != NULL, FALSE);
g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (fb), FALSE);
g_return_val_if_fail (gst_is_gl_memory (GST_MEMORY_CAST (mem)), FALSE);
gl = frame->context->gl_vtable;
gl = fb->context->gl_vtable;
GST_TRACE ("Binding v2 FBO %u dimensions:%ux%u with texture:%u ",
fbo, texture_fbo_width, texture_fbo_height, texture_fbo);
GST_TRACE_OBJECT (fb, "drawing to texture %u, dimensions %ix%i", mem->tex_id,
gst_gl_memory_get_texture_width (mem),
gst_gl_memory_get_texture_height (mem));
gl->BindFramebuffer (GL_FRAMEBUFFER, fbo);
/* setup a texture to render to */
gl->BindTexture (GL_TEXTURE_2D, texture_fbo);
/* attach the texture to the FBO to renderer to */
gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, texture_fbo, 0);
gst_gl_framebuffer_bind (fb);
gst_gl_framebuffer_attach (fb, GL_COLOR_ATTACHMENT0, (GstGLBaseMemory *) mem);
gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
gl->Viewport (0, 0, texture_fbo_width, texture_fbo_height);
if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL |
gl->Viewport (0, 0, fb->priv->effective_width, fb->priv->effective_height);
if (gst_gl_context_get_gl_api (fb->context) & (GST_GL_API_OPENGL |
GST_GL_API_OPENGL3))
gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
/* the opengl scene */
cb (stuff);
ret = func (user_data);
if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL |
if (gst_gl_context_get_gl_api (fb->context) & (GST_GL_API_OPENGL |
GST_GL_API_OPENGL3))
gl->DrawBuffer (GL_NONE);
gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2],
viewport_dim[3]);
gst_gl_context_clear_framebuffer (fb->context);
gl->Viewport (viewport_dim[0], viewport_dim[1],
viewport_dim[2], viewport_dim[3]);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
return TRUE;
return ret;
}
void
gst_gl_framebuffer_delete (GstGLFramebuffer * frame, guint fbo, guint depth)
gst_gl_framebuffer_bind (GstGLFramebuffer * fb)
{
const GstGLFuncs *gl;
g_return_if_fail (GST_IS_GL_FRAMEBUFFER (frame));
g_return_if_fail (GST_IS_GL_FRAMEBUFFER (fb));
g_return_if_fail (gst_gl_context_get_current () == fb->context);
g_return_if_fail (fb->fbo_id != 0);
gl = frame->context->gl_vtable;
gl = fb->context->gl_vtable;
GST_TRACE ("Deleting FBO %u", fbo);
if (fbo) {
gl->DeleteFramebuffers (1, &fbo);
}
if (depth) {
gl->DeleteRenderbuffers (1, &depth);
}
gl->BindFramebuffer (GL_FRAMEBUFFER, fb->fbo_id);
}
void
gst_gl_context_clear_framebuffer (GstGLContext * context)
{
const GstGLFuncs *gl;
g_return_if_fail (GST_IS_GL_CONTEXT (context));
gl = context->gl_vtable;
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
}
static void
_update_effective_dimensions (GstGLFramebuffer * fb)
{
int i;
guint min_width = -1, min_height = -1;
/* remove the previous attachment */
for (i = 0; i < fb->attachments->len; i++) {
struct fbo_attachment *attach;
int width, height;
attach = &g_array_index (fb->attachments, struct fbo_attachment, i);
if (gst_is_gl_memory (GST_MEMORY_CAST (attach->mem))) {
GstGLMemory *mem = (GstGLMemory *) attach->mem;
width = gst_gl_memory_get_texture_width (mem);
height = gst_gl_memory_get_texture_height (mem);
} else if (gst_is_gl_renderbuffer (GST_MEMORY_CAST (attach->mem))) {
GstGLRenderbuffer *mem = (GstGLRenderbuffer *) attach->mem;
width = mem->width;
height = mem->height;
} else {
g_assert_not_reached ();
}
if (width < min_width)
min_width = width;
if (height < min_height)
min_height = height;
}
fb->priv->effective_width = min_width;
fb->priv->effective_height = min_height;
}
static gboolean
_is_valid_attachment_point (guint attachment_point)
{
/* all 31 possible color attachments */
if (attachment_point >= 0x8CE0 && attachment_point <= 0x8CFF)
return TRUE;
/* depth-stencil attachment */
if (attachment_point == 0x821A)
return TRUE;
/* depth attachment */
if (attachment_point == 0x8D00)
return TRUE;
/* stencil attachment */
if (attachment_point == 0x8D20)
return TRUE;
return FALSE;
}
static void
_attach_gl_memory (GstGLFramebuffer * fb, guint attachment_point,
GstGLMemory * mem)
{
struct fbo_attachment attach;
const GstGLFuncs *gl = fb->context->gl_vtable;
guint gl_target = gst_gl_texture_target_to_gl (mem->tex_target);
gst_gl_framebuffer_bind (fb);
gl->FramebufferTexture2D (GL_FRAMEBUFFER, attachment_point, gl_target,
mem->tex_id, 0);
_fbo_attachment_init (&attach, attachment_point, (GstGLBaseMemory *) mem);
fb->attachments = g_array_append_val (fb->attachments, attach);
}
static void
_attach_renderbuffer (GstGLFramebuffer * fb, guint attachment_point,
GstGLRenderbuffer * rb)
{
struct fbo_attachment attach;
const GstGLFuncs *gl = fb->context->gl_vtable;
gst_gl_framebuffer_bind (fb);
gl->BindRenderbuffer (GL_RENDERBUFFER, rb->renderbuffer_id);
gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, attachment_point,
GL_RENDERBUFFER, rb->renderbuffer_id);
_fbo_attachment_init (&attach, attachment_point, (GstGLBaseMemory *) rb);
fb->attachments = g_array_append_val (fb->attachments, attach);
}
void
gst_gl_framebuffer_attach (GstGLFramebuffer * fb, guint attachment_point,
GstGLBaseMemory * mem)
{
int i;
g_return_if_fail (GST_IS_GL_FRAMEBUFFER (fb));
g_return_if_fail (gst_gl_context_get_current () == fb->context);
g_return_if_fail (_is_valid_attachment_point (attachment_point));
/* remove the previous attachment */
for (i = 0; i < fb->attachments->len; i++) {
struct fbo_attachment *attach;
attach = &g_array_index (fb->attachments, struct fbo_attachment, i);
if (attach->attachment_point == attachment_point) {
g_array_remove_index_fast (fb->attachments, i);
break;
}
}
if (gst_is_gl_memory (GST_MEMORY_CAST (mem))) {
_attach_gl_memory (fb, attachment_point, (GstGLMemory *) mem);
} else if (gst_is_gl_renderbuffer (GST_MEMORY_CAST (mem))) {
_attach_renderbuffer (fb, attachment_point, (GstGLRenderbuffer *) mem);
} else {
g_assert_not_reached ();
return;
}
_update_effective_dimensions (fb);
}
void
gst_gl_framebuffer_get_effective_dimensions (GstGLFramebuffer * fb,
guint * width, guint * height)
{
g_return_if_fail (GST_IS_GL_FRAMEBUFFER (fb));
if (width)
*width = fb->priv->effective_width;
if (height)
*height = fb->priv->effective_height;
}
gboolean
gst_gl_context_check_framebuffer_status (GstGLContext * context)
{
g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
switch (context->gl_vtable->CheckFramebufferStatus (GL_FRAMEBUFFER)) {
case GL_FRAMEBUFFER_COMPLETE:
return TRUE;
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_UNSUPPORTED");
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
GST_WARNING_OBJECT (context,
"GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
break;
#if GST_GL_HAVE_OPENGL
case GL_FRAMEBUFFER_UNDEFINED:
GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_UNDEFINED");
break;
#endif
default:
GST_WARNING_OBJECT (context, "Unknown FBO error");
break;
}
return FALSE;
}
guint
gst_gl_framebuffer_get_id (GstGLFramebuffer * fb)
{
g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (fb), 0);
return fb->fbo_id;
}

View file

@ -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;
/* <private> */
GstGLContext *context;
guint fbo_id;
GArray *attachments;
GstGLFramebufferPrivate *priv;
};
struct _GstGLFramebufferClass
{
GObjectClass object_class;
GstObjectClass object_class;
};
GstGLFramebuffer *gst_gl_framebuffer_new (GstGLContext *context);
GstGLFramebuffer * gst_gl_framebuffer_new (GstGLContext *context);
GstGLFramebuffer * gst_gl_framebuffer_new_with_default_depth (GstGLContext *context,
guint width,
guint height);
gboolean gst_gl_framebuffer_generate (GstGLFramebuffer *frame, gint width, gint height,
guint * fbo, guint * depthbuffer);
guint gst_gl_framebuffer_get_id (GstGLFramebuffer * fb);
gboolean gst_gl_framebuffer_use_v2 (GstGLFramebuffer * frame, gint texture_fbo_width,
gint texture_fbo_height, GLuint fbo, GLuint depth_buffer,
GLuint texture_fbo, GLCB_V2 cb, gpointer stuff);
void gst_gl_framebuffer_attach (GstGLFramebuffer * fb,
guint attachment_point,
GstGLBaseMemory * mem);
void gst_gl_framebuffer_bind (GstGLFramebuffer * fb);
void gst_gl_context_clear_framebuffer (GstGLContext * context);
void gst_gl_framebuffer_delete (GstGLFramebuffer *frame, guint fbo, guint depth);
void gst_gl_framebuffer_get_effective_dimensions (GstGLFramebuffer * fb,
guint * width,
guint * height);
gboolean gst_gl_context_check_framebuffer_status (GstGLContext * context);
gboolean gst_gl_framebuffer_draw_to_texture (GstGLFramebuffer * fb,
GstGLMemory * mem,
GstGLFramebufferFunc cb,
gpointer user_data);
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstGLFramebuffer, gst_object_unref)

View file

@ -36,22 +36,6 @@
#include <gst/gl/wayland/gstgldisplay_wayland.h>
#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;

View file

@ -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);

View file

@ -1304,6 +1304,11 @@ gst_gl_view_convert_reset (GstGLViewConvert * viewconvert)
if (viewconvert->shader)
gst_gl_context_del_shader (viewconvert->context, viewconvert->shader);
viewconvert->shader = NULL;
if (viewconvert->fbo)
gst_object_unref (viewconvert->fbo);
viewconvert->fbo = NULL;
viewconvert->initted = FALSE;
viewconvert->reconfigure = FALSE;
}
@ -1383,74 +1388,16 @@ gst_gl_view_convert_perform (GstGLViewConvert * viewconvert, GstBuffer * inbuf)
static gboolean
_init_view_convert_fbo (GstGLViewConvert * viewconvert)
{
GstGLFuncs *gl;
guint out_width, out_height;
GLuint fake_texture = 0; /* a FBO must hava texture to init */
GLenum internal_format;
gboolean ret = TRUE;
gl = viewconvert->context->gl_vtable;
out_width = GST_VIDEO_INFO_WIDTH (&viewconvert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&viewconvert->out_info);
if (!gl->GenFramebuffers) {
/* turn off the pipeline because Frame buffer object is a not present */
gst_gl_context_set_error (viewconvert->context,
"Frambuffer objects unsupported");
return FALSE;
}
/* setup FBO */
gl->GenFramebuffers (1, &viewconvert->fbo);
gl->BindFramebuffer (GL_FRAMEBUFFER, viewconvert->fbo);
/* setup the render buffer for depth */
gl->GenRenderbuffers (1, &viewconvert->depth_buffer);
gl->BindRenderbuffer (GL_RENDERBUFFER, viewconvert->depth_buffer);
if (USING_OPENGL (viewconvert->context)
|| USING_OPENGL3 (viewconvert->context)) {
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, out_width,
out_height);
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
out_width, out_height);
}
if (USING_GLES2 (viewconvert->context)) {
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
out_width, out_height);
}
viewconvert->fbo =
gst_gl_framebuffer_new_with_default_depth (viewconvert->context,
out_width, out_height);
/* a fake texture is attached to the convert FBO (cannot init without it) */
gl->GenTextures (1, &fake_texture);
gl->BindTexture (GL_TEXTURE_2D, fake_texture);
internal_format =
gst_gl_sized_gl_format_from_gl_format_type (viewconvert->context, GL_RGBA,
GL_UNSIGNED_BYTE);
gl->TexImage2D (GL_TEXTURE_2D, 0, internal_format, out_width, out_height,
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
/* attach the texture to the FBO to renderer to */
gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, fake_texture, 0);
/* attach the depth render buffer to the FBO */
gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, viewconvert->depth_buffer);
if (USING_OPENGL (viewconvert->context)) {
gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, viewconvert->depth_buffer);
}
if (!gst_gl_context_check_framebuffer_status (viewconvert->context)) {
gst_gl_context_set_error (viewconvert->context,
"GL framebuffer status incomplete");
ret = FALSE;
}
/* unbind the FBO */
gl->BindTexture (GL_TEXTURE_2D, 0);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
gl->DeleteTextures (1, &fake_texture);
return ret;
return viewconvert->fbo != NULL;
}
/* free after use */
@ -1865,9 +1812,9 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert)
gst_gl_texture_target_to_gl (viewconvert->from_texture_target);
gl = context->gl_vtable;
out_width = GST_VIDEO_INFO_WIDTH (&viewconvert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&viewconvert->out_info);
gl->BindFramebuffer (GL_FRAMEBUFFER, viewconvert->fbo);
gst_gl_framebuffer_bind (viewconvert->fbo);
if (out_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED ||
out_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
out_views = viewconvert->out_info.views;
@ -1877,19 +1824,18 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert)
/* attach the texture to the FBO to renderer to */
for (i = 0; i < out_views; i++) {
guint gl_target =
gst_gl_texture_target_to_gl (viewconvert->to_texture_target);
GstGLBaseMemory *tex = (GstGLBaseMemory *) priv->out_tex[i];
/* needed? */
gl->BindTexture (gl_target, priv->out_tex[i]->tex_id);
gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
gl_target, priv->out_tex[i]->tex_id, 0);
gst_gl_framebuffer_attach (viewconvert->fbo, GL_COLOR_ATTACHMENT0 + i, tex);
}
if (gl->DrawBuffers)
gl->DrawBuffers (out_views, multipleRT);
else if (gl->DrawBuffer)
gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
gst_gl_framebuffer_get_effective_dimensions (viewconvert->fbo, &out_width,
&out_height);
gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
gl->Viewport (0, 0, out_width, out_height);
@ -1911,6 +1857,7 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert)
gl->BindVertexArray (priv->vao);
else
_bind_buffer (viewconvert);
if (in_mode == GST_VIDEO_MULTIVIEW_MODE_SEPARATED ||
in_mode == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
if (priv->in_tex[1] == NULL) {
@ -1924,7 +1871,9 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert)
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (from_gl_target, priv->in_tex[0]->tex_id);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
if (gl->BindVertexArray)
gl->BindVertexArray (0);
else
@ -1935,8 +1884,8 @@ _do_view_convert_draw (GstGLContext * context, GstGLViewConvert * viewconvert)
gst_gl_context_clear_shader (context);
gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2],
viewport_dim[3]);
gst_gl_context_check_framebuffer_status (context);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
gst_gl_context_clear_framebuffer (context);
return TRUE;
}

View file

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

View file

@ -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);