return TRUE;
}
-static void
-_emit_draw_signal (guint tex, gint width, gint height, gpointer data)
-{
- GstGLFilterApp *app_filter = GST_GL_FILTER_APP (data);
- gboolean drawn;
-
- g_signal_emit (app_filter, gst_gl_filter_app_signals[CLIENT_DRAW_SIGNAL], 0,
- tex, width, height, &drawn);
-
- app_filter->default_draw = !drawn;
-}
-
struct glcb2
{
- GLCB func;
- gpointer data;
+ GstGLFilterApp *app;
GstGLMemory *in_tex;
GstGLMemory *out_tex;
};
-/* convenience functions to simplify filter development */
-static void
-_glcb2 (gpointer data)
+static gboolean
+_emit_draw_signal (gpointer data)
{
struct glcb2 *cb = data;
+ gboolean drawn;
+
+ g_signal_emit (cb->app, gst_gl_filter_app_signals[CLIENT_DRAW_SIGNAL], 0,
+ cb->in_tex->tex_id, gst_gl_memory_get_texture_width (cb->out_tex),
+ gst_gl_memory_get_texture_height (cb->out_tex), &drawn);
- cb->func (gst_gl_memory_get_texture_width (cb->in_tex),
- gst_gl_memory_get_texture_height (cb->in_tex), cb->in_tex->tex_id,
- cb->data);
+ return !drawn;
}
static gboolean
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);
}
struct _GstGLFilterApp
{
GstGLFilter filter;
-
- gboolean default_draw;
};
struct _GstGLFilterAppClass
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);
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* */
gl->DisableVertexAttribArray (cube_filter->attr_texture);
}
-static void
+static gboolean
_callback (gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
xrot += 0.3f;
yrot += 0.2f;
zrot += 0.4f;
+
+ return TRUE;
}
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 =
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;
}
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;
time_left -= 1000000 / 25;
if (time_left > 2000) {
GST_LOG ("escape");
- return;
+ return FALSE;
}
}
gst_gl_context_clear_shader (GST_GL_BASE_FILTER (filter)->context);
gl->Disable (GL_BLEND);
+
+ return TRUE;
}
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);
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;
{
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);
{
GstGLBaseMixer vaggregator;
- GLuint fbo;
- GLuint depthbuffer;
+ GstGLFramebuffer *fbo;
GstCaps *out_caps;
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 =
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);
xrot += 0.6f;
yrot += 0.4f;
zrot += 0.8f;
+
+ return TRUE;
}
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);
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))
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;
}
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;
}
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)
{
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;
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);
}
}
-//opengl scene
-static void
+static gboolean
gst_gl_test_src_callback (gpointer stuff)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (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
/* video state */
GstVideoInfo out_info;
- GLuint fbo;
- GLuint depthbuffer;
+ GstGLFramebuffer *fbo;
+ GstGLMemory *out_tex;
GstGLShader *shader;
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);
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;
}
gl->DisableVertexAttribArray (transformation->attr_texture);
}
-static void
+static gboolean
gst_gl_transformation_callback (gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
gst_gl_context_clear_shader (GST_GL_BASE_FILTER (filter)->context);
transformation->caps_change = FALSE;
+
+ return TRUE;
}
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* */
video_mixer_f_src, &video_mixer->shader);
}
+static void
+_video_mixer_process_gl (GstGLContext * context, GstGLVideoMixer * video_mixer)
+{
+ GstGLMixer *mixer = GST_GL_MIXER (video_mixer);
+
+ gst_gl_framebuffer_draw_to_texture (mixer->fbo, video_mixer->out_tex,
+ gst_gl_video_mixer_callback, video_mixer);
+}
+
static gboolean
gst_gl_video_mixer_process_textures (GstGLMixer * mix, GstGLMemory * out_tex)
{
GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mix);
+ GstGLContext *context = GST_GL_BASE_MIXER (mix)->context;
+
+ video_mixer->out_tex = out_tex;
- gst_gl_context_use_fbo_v2 (GST_GL_BASE_MIXER (mix)->context,
- GST_VIDEO_INFO_WIDTH (&GST_VIDEO_AGGREGATOR (mix)->info),
- GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR (mix)->info),
- mix->fbo, mix->depthbuffer,
- out_tex->tex_id, gst_gl_video_mixer_callback, (gpointer) video_mixer);
+ gst_gl_context_thread_add (context,
+ (GstGLContextThreadFunc) _video_mixer_process_gl, video_mixer);
return TRUE;
}
}
/* 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);
}
if (!_draw_background (video_mixer))
- return;
+ return FALSE;
gst_gl_shader_use (video_mixer->shader);
gl->Disable (GL_BLEND);
gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context);
+
+ return TRUE;
}
GLuint vao;
GLuint vbo_indices;
GLuint checker_vbo;
+ GstGLMemory *out_tex;
};
struct _GstGLVideoMixerClass
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;
{
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++) {
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;
}
static gboolean
_init_convert_fbo (GstGLColorConvert * convert)
{
- GstGLFuncs *gl;
guint out_width, out_height;
- GLuint fake_texture = 0; /* a FBO must hava texture to init */
- GLenum internal_format;
-
- gl = convert->context->gl_vtable;
out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
- if (!gl->GenFramebuffers) {
- /* turn off the pipeline because Frame buffer object is a not present */
- gst_gl_context_set_error (convert->context,
- "Context, EXT_framebuffer_object supported: no");
- return FALSE;
- }
-
- GST_INFO ("Context, EXT_framebuffer_object supported: yes");
-
- /* setup FBO */
- gl->GenFramebuffers (1, &convert->fbo);
- gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo);
+ convert->fbo =
+ gst_gl_framebuffer_new_with_default_depth (convert->context, out_width,
+ out_height);
- /* setup the render buffer for depth */
- gl->GenRenderbuffers (1, &convert->depth_buffer);
- gl->BindRenderbuffer (GL_RENDERBUFFER, convert->depth_buffer);
- if (USING_OPENGL (convert->context) || USING_OPENGL3 (convert->context)) {
- gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
- out_width, out_height);
- }
- if (USING_GLES2 (convert->context)) {
- gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
- out_width, out_height);
- }
-
- /* a fake texture is attached to the convert FBO (cannot init without it) */
- gl->GenTextures (1, &fake_texture);
- gl->BindTexture (GL_TEXTURE_2D, fake_texture);
- internal_format =
- gst_gl_sized_gl_format_from_gl_format_type (convert->context, GL_RGBA,
- GL_UNSIGNED_BYTE);
- gl->TexImage2D (GL_TEXTURE_2D, 0, internal_format, out_width, out_height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- /* attach the texture to the FBO to renderer to */
- gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, fake_texture, 0);
-
- /* attach the depth render buffer to the FBO */
- gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, convert->depth_buffer);
-
- if (USING_OPENGL (convert->context)) {
- gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, convert->depth_buffer);
- }
-
- if (!gst_gl_context_check_framebuffer_status (convert->context)) {
- gst_gl_context_set_error (convert->context,
- "GL framebuffer status incomplete");
-
- gl->DeleteTextures (1, &fake_texture);
-
- return FALSE;
- }
-
- /* unbind the FBO */
- gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
-
- gl->DeleteTextures (1, &fake_texture);
-
- return TRUE;
+ return convert->fbo != NULL;
}
static gboolean
gl = context->gl_vtable;
- out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
- out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
-
- gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo);
+ gst_gl_framebuffer_bind (convert->fbo);
/* attach the texture to the FBO to renderer to */
for (i = 0; i < c_info->out_n_textures; i++) {
- guint gl_target =
- gst_gl_texture_target_to_gl (convert->priv->to_texture_target);
-
- /* needed? */
- gl->BindTexture (gl_target, convert->priv->out_tex[i]->tex_id);
+ GstGLBaseMemory *tex = (GstGLBaseMemory *) convert->priv->out_tex[i];
- gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
- gl_target, convert->priv->out_tex[i]->tex_id, 0);
+ gst_gl_framebuffer_attach (convert->fbo, GL_COLOR_ATTACHMENT0 + i, tex);
}
if (gl->DrawBuffers)
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);
gst_gl_context_check_framebuffer_status (context);
- gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
+ gst_gl_context_clear_framebuffer (context);
return TRUE;
}
GstBuffer * outbuf;
/* used for the conversion */
- GLuint fbo;
- GLuint depth_buffer;
+ GstGLFramebuffer *fbo;
GstGLShader *shader;
/* <private> */
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;
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) {
};
/* 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;
}
/**
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;
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
GstCaps *out_caps;
+ /* <protected> */
+ GstGLFramebuffer *fbo;
+
/* <private> */
- GLuint fbo;
- GLuint depthbuffer;
gboolean gl_result;
GstBuffer *inbuf;
GstBuffer *outbuf;
#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) \
struct _GstGLFramebufferPrivate
{
- gint width;
- gint height;
+ guint effective_width;
+ guint effective_height;
+};
- guint fbo;
- guint depth;
+struct fbo_attachment
+{
+ guint attachment_point;
+ GstGLBaseMemory *mem;
};
+static void
+_fbo_attachment_init (struct fbo_attachment *attach, guint point,
+ GstGLBaseMemory * mem)
+{
+ attach->attachment_point = point;
+ attach->mem = (GstGLBaseMemory *) gst_memory_ref (GST_MEMORY_CAST (mem));
+}
+
+static void
+_fbo_attachment_unset (struct fbo_attachment *attach)
+{
+ if (!attach)
+ return;
+
+ if (attach->mem)
+ gst_memory_unref (GST_MEMORY_CAST (attach->mem));
+ attach->mem = NULL;
+}
+
static void
gst_gl_framebuffer_class_init (GstGLFramebufferClass * klass)
{
}
static void
-gst_gl_framebuffer_init (GstGLFramebuffer * fbo)
+gst_gl_framebuffer_init (GstGLFramebuffer * fb)
{
- fbo->priv = GST_GL_FRAMEBUFFER_GET_PRIVATE (fbo);
+ fb->priv = GST_GL_FRAMEBUFFER_GET_PRIVATE (fb);
+
+ fb->attachments =
+ g_array_new (FALSE, FALSE, (sizeof (struct fbo_attachment)));
+ g_array_set_clear_func (fb->attachments,
+ (GDestroyNotify) _fbo_attachment_unset);
+}
+
+static void
+_delete_fbo_gl (GstGLContext * context, GstGLFramebuffer * fb)
+{
+ const GstGLFuncs *gl = context->gl_vtable;
+
+ if (fb->fbo_id)
+ gl->DeleteFramebuffers (1, &fb->fbo_id);
+ fb->fbo_id = 0;
}
static void
gst_gl_framebuffer_finalize (GObject * object)
{
- GstGLFramebuffer *fbo = GST_GL_FRAMEBUFFER (object);
+ GstGLFramebuffer *fb = GST_GL_FRAMEBUFFER (object);
+
+ if (fb->context) {
+ if (fb->fbo_id)
+ gst_gl_context_thread_add (fb->context,
+ (GstGLContextThreadFunc) _delete_fbo_gl, fb);
- if (fbo->context) {
- gst_object_unref (fbo->context);
- fbo->context = NULL;
+ gst_object_unref (fb->context);
+ fb->context = NULL;
}
+ if (fb->attachments)
+ g_array_free (fb->attachments, TRUE);
+ fb->attachments = NULL;
+
G_OBJECT_CLASS (gst_gl_framebuffer_parent_class)->finalize (object);
}
GstGLFramebuffer *
gst_gl_framebuffer_new (GstGLContext * context)
{
- GstGLFramebuffer *fbo = g_object_new (GST_TYPE_GL_FRAMEBUFFER, NULL);
+ GstGLFramebuffer *fb;
+ const GstGLFuncs *gl;
+
+ g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
+ g_return_val_if_fail (gst_gl_context_get_current () == context, NULL);
+
+ gl = context->gl_vtable;
+
+ if (!gl->GenFramebuffers) {
+ GST_ERROR_OBJECT (context, "Framebuffers are not supported!");
+ return NULL;
+ }
+
+ fb = g_object_new (GST_TYPE_GL_FRAMEBUFFER, NULL);
+ fb->context = gst_object_ref (context);
+ gl->GenFramebuffers (1, &fb->fbo_id);
+
+ return fb;
+}
+
+GstGLFramebuffer *
+gst_gl_framebuffer_new_with_default_depth (GstGLContext * context, guint width,
+ guint height)
+{
+ GstGLFramebuffer *fb = gst_gl_framebuffer_new (context);
+ GstGLBaseMemoryAllocator *render_alloc;
+ GstGLAllocationParams *params;
+ GstGLBaseMemory *renderbuffer;
+ guint attach_point, attach_type;
+
+ if (!fb)
+ return NULL;
+
+ if (gst_gl_context_get_gl_api (fb->context) & (GST_GL_API_OPENGL |
+ GST_GL_API_OPENGL3)) {
+ attach_point = GL_DEPTH_STENCIL_ATTACHMENT;
+ attach_type = GST_GL_DEPTH24_STENCIL8;
+ } else if (gst_gl_context_get_gl_api (fb->context) & GST_GL_API_GLES2) {
+ attach_point = GL_DEPTH_ATTACHMENT;
+ attach_type = GST_GL_DEPTH_COMPONENT16;
+ } else {
+ g_assert_not_reached ();
+ return NULL;
+ }
- fbo->context = gst_object_ref (context);
+ render_alloc = (GstGLBaseMemoryAllocator *)
+ gst_allocator_find (GST_GL_RENDERBUFFER_ALLOCATOR_NAME);
+ params = (GstGLAllocationParams *)
+ gst_gl_renderbuffer_allocation_params_new (context, NULL, attach_type,
+ width, height);
- return fbo;
+ renderbuffer = gst_gl_base_memory_alloc (render_alloc, params);
+ gst_gl_allocation_params_free (params);
+ gst_object_unref (render_alloc);
+
+ gst_gl_framebuffer_bind (fb);
+ gst_gl_framebuffer_attach (fb, attach_point, renderbuffer);
+ gst_gl_context_clear_framebuffer (fb->context);
+ gst_memory_unref (GST_MEMORY_CAST (renderbuffer));
+
+ return fb;
}
gboolean
-gst_gl_framebuffer_generate (GstGLFramebuffer * frame, gint width, gint height,
- guint * fbo, guint * depth)
+gst_gl_framebuffer_draw_to_texture (GstGLFramebuffer * fb, GstGLMemory * mem,
+ GstGLFramebufferFunc func, gpointer user_data)
{
- GLuint fake_texture = 0;
+ GLint viewport_dim[4] = { 0 };
const GstGLFuncs *gl;
- GLenum internal_format;
+ gboolean ret;
- g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (frame), FALSE);
- g_return_val_if_fail (fbo != NULL && depth != NULL, FALSE);
- g_return_val_if_fail (width > 0 && height > 0, FALSE);
+ g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (fb), FALSE);
+ g_return_val_if_fail (gst_is_gl_memory (GST_MEMORY_CAST (mem)), FALSE);
- gl = frame->context->gl_vtable;
+ gl = fb->context->gl_vtable;
- GST_TRACE ("creating FBO dimensions:%ux%u", width, height);
+ GST_TRACE_OBJECT (fb, "drawing to texture %u, dimensions %ix%i", mem->tex_id,
+ gst_gl_memory_get_texture_width (mem),
+ gst_gl_memory_get_texture_height (mem));
- if (!gl->GenFramebuffers) {
- gst_gl_context_set_error (frame->context,
- "Context, EXT_framebuffer_object not supported");
- return FALSE;
- }
- /* setup FBO */
- gl->GenFramebuffers (1, fbo);
- gl->BindFramebuffer (GL_FRAMEBUFFER, *fbo);
-
- /* setup the render buffer for depth */
- gl->GenRenderbuffers (1, depth);
- gl->BindRenderbuffer (GL_RENDERBUFFER, *depth);
+ gst_gl_framebuffer_bind (fb);
+ gst_gl_framebuffer_attach (fb, GL_COLOR_ATTACHMENT0, (GstGLBaseMemory *) mem);
- if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL |
- GST_GL_API_OPENGL3)) {
- gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width,
- height);
- }
- if (gst_gl_context_get_gl_api (frame->context) & GST_GL_API_GLES2) {
- gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
- width, height);
- }
+ gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
+ gl->Viewport (0, 0, fb->priv->effective_width, fb->priv->effective_height);
+ if (gst_gl_context_get_gl_api (fb->context) & (GST_GL_API_OPENGL |
+ GST_GL_API_OPENGL3))
+ gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
- /* setup a texture to render to */
- gl->GenTextures (1, &fake_texture);
- gl->BindTexture (GL_TEXTURE_2D, fake_texture);
- internal_format =
- gst_gl_sized_gl_format_from_gl_format_type (frame->context, GL_RGBA,
- GL_UNSIGNED_BYTE);
- gl->TexImage2D (GL_TEXTURE_2D, 0, internal_format, width, height, 0, GL_RGBA,
- GL_UNSIGNED_BYTE, NULL);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- /* attach the texture to the FBO to renderer to */
- gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, fake_texture, 0);
-
- /* attach the depth render buffer to the FBO */
- gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, *depth);
-
- if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL |
- GST_GL_API_OPENGL3)) {
- gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, *depth);
- }
+ ret = func (user_data);
- if (gl->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- gst_gl_context_set_error (frame->context,
- "GL framebuffer status incomplete");
+ if (gst_gl_context_get_gl_api (fb->context) & (GST_GL_API_OPENGL |
+ GST_GL_API_OPENGL3))
+ gl->DrawBuffer (GL_NONE);
+ gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2],
+ viewport_dim[3]);
+ gst_gl_context_clear_framebuffer (fb->context);
- gl->DeleteTextures (1, &fake_texture);
+ return ret;
+}
- return FALSE;
- }
+void
+gst_gl_framebuffer_bind (GstGLFramebuffer * fb)
+{
+ const GstGLFuncs *gl;
- /* unbind the FBO */
- gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
+ g_return_if_fail (GST_IS_GL_FRAMEBUFFER (fb));
+ g_return_if_fail (gst_gl_context_get_current () == fb->context);
+ g_return_if_fail (fb->fbo_id != 0);
- gl->DeleteTextures (1, &fake_texture);
+ gl = fb->context->gl_vtable;
- return TRUE;
+ gl->BindFramebuffer (GL_FRAMEBUFFER, fb->fbo_id);
}
-gboolean
-gst_gl_framebuffer_use_v2 (GstGLFramebuffer * frame, gint texture_fbo_width,
- gint texture_fbo_height, GLuint fbo, GLuint depth_buffer,
- GLuint texture_fbo, GLCB_V2 cb, gpointer stuff)
+void
+gst_gl_context_clear_framebuffer (GstGLContext * context)
{
const GstGLFuncs *gl;
- GLint viewport_dim[4] = { 0 };
- g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (frame), FALSE);
- g_return_val_if_fail (texture_fbo_width > 0 && texture_fbo_height > 0, FALSE);
- g_return_val_if_fail (fbo != 0, FALSE);
- g_return_val_if_fail (texture_fbo != 0, FALSE);
- g_return_val_if_fail (cb != NULL, FALSE);
+ g_return_if_fail (GST_IS_GL_CONTEXT (context));
- gl = frame->context->gl_vtable;
+ gl = context->gl_vtable;
- GST_TRACE ("Binding v2 FBO %u dimensions:%ux%u with texture:%u ",
- fbo, texture_fbo_width, texture_fbo_height, texture_fbo);
+ gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
+}
- gl->BindFramebuffer (GL_FRAMEBUFFER, fbo);
+static void
+_update_effective_dimensions (GstGLFramebuffer * fb)
+{
+ int i;
+ guint min_width = -1, min_height = -1;
+
+ /* remove the previous attachment */
+ for (i = 0; i < fb->attachments->len; i++) {
+ struct fbo_attachment *attach;
+ int width, height;
+
+ attach = &g_array_index (fb->attachments, struct fbo_attachment, i);
+
+ if (gst_is_gl_memory (GST_MEMORY_CAST (attach->mem))) {
+ GstGLMemory *mem = (GstGLMemory *) attach->mem;
+
+ width = gst_gl_memory_get_texture_width (mem);
+ height = gst_gl_memory_get_texture_height (mem);
+ } else if (gst_is_gl_renderbuffer (GST_MEMORY_CAST (attach->mem))) {
+ GstGLRenderbuffer *mem = (GstGLRenderbuffer *) attach->mem;
+
+ width = mem->width;
+ height = mem->height;
+ } else {
+ g_assert_not_reached ();
+ }
+
+ if (width < min_width)
+ min_width = width;
+ if (height < min_height)
+ min_height = height;
+ }
- /* setup a texture to render to */
- gl->BindTexture (GL_TEXTURE_2D, texture_fbo);
+ fb->priv->effective_width = min_width;
+ fb->priv->effective_height = min_height;
+}
- /* attach the texture to the FBO to renderer to */
- gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, texture_fbo, 0);
+static gboolean
+_is_valid_attachment_point (guint attachment_point)
+{
+ /* all 31 possible color attachments */
+ if (attachment_point >= 0x8CE0 && attachment_point <= 0x8CFF)
+ return TRUE;
- gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
+ /* depth-stencil attachment */
+ if (attachment_point == 0x821A)
+ return TRUE;
- gl->Viewport (0, 0, texture_fbo_width, texture_fbo_height);
+ /* depth attachment */
+ if (attachment_point == 0x8D00)
+ return TRUE;
- if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL |
- GST_GL_API_OPENGL3))
- gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
+ /* stencil attachment */
+ if (attachment_point == 0x8D20)
+ return TRUE;
- /* the opengl scene */
- cb (stuff);
+ return FALSE;
+}
- if (gst_gl_context_get_gl_api (frame->context) & (GST_GL_API_OPENGL |
- GST_GL_API_OPENGL3))
- gl->DrawBuffer (GL_NONE);
+static void
+_attach_gl_memory (GstGLFramebuffer * fb, guint attachment_point,
+ GstGLMemory * mem)
+{
+ struct fbo_attachment attach;
+ const GstGLFuncs *gl = fb->context->gl_vtable;
+ guint gl_target = gst_gl_texture_target_to_gl (mem->tex_target);
- gl->Viewport (viewport_dim[0], viewport_dim[1],
- viewport_dim[2], viewport_dim[3]);
+ gst_gl_framebuffer_bind (fb);
- gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
+ gl->FramebufferTexture2D (GL_FRAMEBUFFER, attachment_point, gl_target,
+ mem->tex_id, 0);
+
+ _fbo_attachment_init (&attach, attachment_point, (GstGLBaseMemory *) mem);
+ fb->attachments = g_array_append_val (fb->attachments, attach);
+}
+
+static void
+_attach_renderbuffer (GstGLFramebuffer * fb, guint attachment_point,
+ GstGLRenderbuffer * rb)
+{
+ struct fbo_attachment attach;
+ const GstGLFuncs *gl = fb->context->gl_vtable;
+
+ gst_gl_framebuffer_bind (fb);
+ gl->BindRenderbuffer (GL_RENDERBUFFER, rb->renderbuffer_id);
- return TRUE;
+ gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, attachment_point,
+ GL_RENDERBUFFER, rb->renderbuffer_id);
+
+ _fbo_attachment_init (&attach, attachment_point, (GstGLBaseMemory *) rb);
+ fb->attachments = g_array_append_val (fb->attachments, attach);
}
void
-gst_gl_framebuffer_delete (GstGLFramebuffer * frame, guint fbo, guint depth)
+gst_gl_framebuffer_attach (GstGLFramebuffer * fb, guint attachment_point,
+ GstGLBaseMemory * mem)
{
- const GstGLFuncs *gl;
+ int i;
- g_return_if_fail (GST_IS_GL_FRAMEBUFFER (frame));
+ g_return_if_fail (GST_IS_GL_FRAMEBUFFER (fb));
+ g_return_if_fail (gst_gl_context_get_current () == fb->context);
+ g_return_if_fail (_is_valid_attachment_point (attachment_point));
- gl = frame->context->gl_vtable;
+ /* remove the previous attachment */
+ for (i = 0; i < fb->attachments->len; i++) {
+ struct fbo_attachment *attach;
- GST_TRACE ("Deleting FBO %u", fbo);
+ attach = &g_array_index (fb->attachments, struct fbo_attachment, i);
- if (fbo) {
- gl->DeleteFramebuffers (1, &fbo);
+ if (attach->attachment_point == attachment_point) {
+ g_array_remove_index_fast (fb->attachments, i);
+ break;
+ }
}
- if (depth) {
- gl->DeleteRenderbuffers (1, &depth);
+
+ if (gst_is_gl_memory (GST_MEMORY_CAST (mem))) {
+ _attach_gl_memory (fb, attachment_point, (GstGLMemory *) mem);
+ } else if (gst_is_gl_renderbuffer (GST_MEMORY_CAST (mem))) {
+ _attach_renderbuffer (fb, attachment_point, (GstGLRenderbuffer *) mem);
+ } else {
+ g_assert_not_reached ();
+ return;
}
+
+ _update_effective_dimensions (fb);
+}
+
+void
+gst_gl_framebuffer_get_effective_dimensions (GstGLFramebuffer * fb,
+ guint * width, guint * height)
+{
+ g_return_if_fail (GST_IS_GL_FRAMEBUFFER (fb));
+
+ if (width)
+ *width = fb->priv->effective_width;
+ if (height)
+ *height = fb->priv->effective_height;
+}
+
+gboolean
+gst_gl_context_check_framebuffer_status (GstGLContext * context)
+{
+ g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
+
+ switch (context->gl_vtable->CheckFramebufferStatus (GL_FRAMEBUFFER)) {
+ case GL_FRAMEBUFFER_COMPLETE:
+ return TRUE;
+ break;
+ case GL_FRAMEBUFFER_UNSUPPORTED:
+ GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_UNSUPPORTED");
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+ GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+ GST_WARNING_OBJECT (context,
+ "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+ GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
+ break;
+#if GST_GL_HAVE_OPENGL
+ case GL_FRAMEBUFFER_UNDEFINED:
+ GST_WARNING_OBJECT (context, "GL_FRAMEBUFFER_UNDEFINED");
+ break;
+#endif
+ default:
+ GST_WARNING_OBJECT (context, "Unknown FBO error");
+ break;
+ }
+
+ return FALSE;
+}
+
+guint
+gst_gl_framebuffer_get_id (GstGLFramebuffer * fb)
+{
+ g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (fb), 0);
+
+ return fb->fbo_id;
}
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);
+
+guint gst_gl_framebuffer_get_id (GstGLFramebuffer * fb);
+
+void gst_gl_framebuffer_attach (GstGLFramebuffer * fb,
+ guint attachment_point,
+ GstGLBaseMemory * mem);
+void gst_gl_framebuffer_bind (GstGLFramebuffer * fb);
+void gst_gl_context_clear_framebuffer (GstGLContext * context);
-gboolean gst_gl_framebuffer_generate (GstGLFramebuffer *frame, gint width, gint height,
- guint * fbo, guint * depthbuffer);
+void gst_gl_framebuffer_get_effective_dimensions (GstGLFramebuffer * fb,
+ guint * width,
+ guint * height);
-gboolean gst_gl_framebuffer_use_v2 (GstGLFramebuffer * frame, gint texture_fbo_width,
- gint texture_fbo_height, GLuint fbo, GLuint depth_buffer,
- GLuint texture_fbo, GLCB_V2 cb, gpointer stuff);
+gboolean gst_gl_context_check_framebuffer_status (GstGLContext * context);
-void gst_gl_framebuffer_delete (GstGLFramebuffer *frame, guint fbo, guint depth);
+gboolean gst_gl_framebuffer_draw_to_texture (GstGLFramebuffer * fb,
+ GstGLMemory * mem,
+ GstGLFramebufferFunc cb,
+ gpointer user_data);
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstGLFramebuffer, gst_object_unref)
#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))
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;
* 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);
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;
}
static gboolean
_init_view_convert_fbo (GstGLViewConvert * viewconvert)
{
- GstGLFuncs *gl;
guint out_width, out_height;
- GLuint fake_texture = 0; /* a FBO must hava texture to init */
- GLenum internal_format;
- gboolean ret = TRUE;
- gl = viewconvert->context->gl_vtable;
out_width = GST_VIDEO_INFO_WIDTH (&viewconvert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&viewconvert->out_info);
- if (!gl->GenFramebuffers) {
- /* turn off the pipeline because Frame buffer object is a not present */
- gst_gl_context_set_error (viewconvert->context,
- "Frambuffer objects unsupported");
- return FALSE;
- }
- /* setup FBO */
- gl->GenFramebuffers (1, &viewconvert->fbo);
- gl->BindFramebuffer (GL_FRAMEBUFFER, viewconvert->fbo);
- /* setup the render buffer for depth */
- gl->GenRenderbuffers (1, &viewconvert->depth_buffer);
- gl->BindRenderbuffer (GL_RENDERBUFFER, viewconvert->depth_buffer);
- if (USING_OPENGL (viewconvert->context)
- || USING_OPENGL3 (viewconvert->context)) {
- gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, out_width,
- out_height);
- gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
- out_width, out_height);
- }
- if (USING_GLES2 (viewconvert->context)) {
- gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
- out_width, out_height);
- }
-
- /* a fake texture is attached to the convert FBO (cannot init without it) */
- gl->GenTextures (1, &fake_texture);
- gl->BindTexture (GL_TEXTURE_2D, fake_texture);
- internal_format =
- gst_gl_sized_gl_format_from_gl_format_type (viewconvert->context, GL_RGBA,
- GL_UNSIGNED_BYTE);
- gl->TexImage2D (GL_TEXTURE_2D, 0, internal_format, out_width, out_height,
- 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- /* attach the texture to the FBO to renderer to */
- gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, fake_texture, 0);
- /* attach the depth render buffer to the FBO */
- gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, viewconvert->depth_buffer);
- if (USING_OPENGL (viewconvert->context)) {
- gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, viewconvert->depth_buffer);
- }
-
- if (!gst_gl_context_check_framebuffer_status (viewconvert->context)) {
- gst_gl_context_set_error (viewconvert->context,
- "GL framebuffer status incomplete");
- ret = FALSE;
- }
+ viewconvert->fbo =
+ gst_gl_framebuffer_new_with_default_depth (viewconvert->context,
+ out_width, out_height);
- /* unbind the FBO */
- gl->BindTexture (GL_TEXTURE_2D, 0);
- gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
- gl->DeleteTextures (1, &fake_texture);
- return ret;
+ return viewconvert->fbo != NULL;
}
/* free after use */
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;
/* 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);
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) {
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
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;
}
gboolean initted;
gboolean reconfigure;
- GLuint fbo;
- GLuint depth_buffer;
+ GstGLFramebuffer *fbo;
GstGLViewConvertPrivate *priv;
};
}
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;
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 *)
gst_memory_unref (GST_MEMORY_CAST (gl_tex));
}
-static void
+static gboolean
clear_tex (gpointer data)
{
GstGLContext *context = 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
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) {
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);
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) {
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);