mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 19:20:35 +00:00
2ce11e4bac
1. fix FBO leaks in decide_allocation 2. fix texture leaks in decide_allocation and reset 3. fix texture leaks in FBO incomplete error path
339 lines
10 KiB
C
339 lines
10 KiB
C
/*
|
|
* GStreamer
|
|
* Copyright (C) 2013 Matthew Waters <ystreet00@gmail.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "gl.h"
|
|
#include "gstglframebuffer.h"
|
|
|
|
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,
|
|
DEBUG_INIT);
|
|
|
|
#define GST_GL_FRAMEBUFFER_GET_PRIVATE(o) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE((o), GST_TYPE_GL_FRAMEBUFFER, GstGLFramebufferPrivate))
|
|
|
|
static void gst_gl_framebuffer_finalize (GObject * object);
|
|
|
|
struct _GstGLFramebufferPrivate
|
|
{
|
|
gint width;
|
|
gint height;
|
|
|
|
guint fbo;
|
|
guint depth;
|
|
};
|
|
|
|
static void
|
|
gst_gl_framebuffer_class_init (GstGLFramebufferClass * klass)
|
|
{
|
|
g_type_class_add_private (klass, sizeof (GstGLFramebufferPrivate));
|
|
|
|
G_OBJECT_CLASS (klass)->finalize = gst_gl_framebuffer_finalize;
|
|
}
|
|
|
|
static void
|
|
gst_gl_framebuffer_init (GstGLFramebuffer * fbo)
|
|
{
|
|
fbo->priv = GST_GL_FRAMEBUFFER_GET_PRIVATE (fbo);
|
|
}
|
|
|
|
static void
|
|
gst_gl_framebuffer_finalize (GObject * object)
|
|
{
|
|
GstGLFramebuffer *fbo = GST_GL_FRAMEBUFFER (object);
|
|
|
|
if (fbo->context) {
|
|
gst_object_unref (fbo->context);
|
|
fbo->context = 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;
|
|
const GstGLFuncs *gl;
|
|
|
|
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);
|
|
|
|
gl = frame->context->gl_vtable;
|
|
|
|
GST_TRACE ("creating FBO dimensions:%ux%u", width, height);
|
|
|
|
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);
|
|
|
|
if (gst_gl_context_get_gl_api (frame->context) & GST_GL_API_OPENGL) {
|
|
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
|
|
width, height);
|
|
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);
|
|
}
|
|
|
|
/* setup a texture to render to */
|
|
gl->GenTextures (1, &fake_texture);
|
|
gl->BindTexture (GL_TEXTURE_2D, fake_texture);
|
|
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
|
|
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) {
|
|
gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
|
|
GL_RENDERBUFFER, *depth);
|
|
}
|
|
|
|
if (gl->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
|
gst_gl_context_set_error (frame->context,
|
|
"GL framebuffer status incomplete");
|
|
|
|
gl->DeleteTextures (1, &fake_texture);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* unbind the FBO */
|
|
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
|
|
|
|
gl->DeleteTextures (1, &fake_texture);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gst_gl_framebuffer_use (GstGLFramebuffer * frame, gint texture_fbo_width,
|
|
gint texture_fbo_height, GLuint fbo, GLuint depth_buffer,
|
|
GLuint texture_fbo, GLCB cb, gint input_tex_width,
|
|
gint input_tex_height, GLuint input_tex, gdouble proj_param1,
|
|
gdouble proj_param2, gdouble proj_param3, gdouble proj_param4,
|
|
GstGLDisplayProjection projection, gpointer stuff)
|
|
{
|
|
const GstGLFuncs *gl;
|
|
#if GST_GL_HAVE_GLES2
|
|
GLint viewport_dim[4];
|
|
#endif
|
|
|
|
g_return_val_if_fail (GST_IS_GL_FRAMEBUFFER (frame), FALSE);
|
|
g_return_val_if_fail (input_tex_width > 0 && input_tex_height > 0, FALSE);
|
|
g_return_val_if_fail (texture_fbo_width > 0 && texture_fbo_height > 0, FALSE);
|
|
g_return_val_if_fail (input_tex != 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);
|
|
|
|
gl = frame->context->gl_vtable;
|
|
|
|
GST_TRACE ("Binding v1 FBO %u dimensions:%ux%u with texture:%u "
|
|
"dimensions:%ux%u", fbo, texture_fbo_width,
|
|
texture_fbo_height, texture_fbo, input_tex_width, input_tex_height);
|
|
|
|
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_context_clear_shader (frame->context);
|
|
|
|
#if GST_GL_HAVE_OPENGL
|
|
if (gst_gl_context_get_gl_api (frame->context) & GST_GL_API_OPENGL) {
|
|
gl->PushAttrib (GL_VIEWPORT_BIT);
|
|
gl->MatrixMode (GL_PROJECTION);
|
|
gl->PushMatrix ();
|
|
gl->LoadIdentity ();
|
|
|
|
switch (projection) {
|
|
case GST_GL_DISPLAY_PROJECTION_ORTHO2D:
|
|
gluOrtho2D (proj_param1, proj_param2, proj_param3, proj_param4);
|
|
break;
|
|
case GST_GL_DISPLAY_PROJECTION_PERSPECTIVE:
|
|
gluPerspective (proj_param1, proj_param2, proj_param3, proj_param4);
|
|
break;
|
|
default:
|
|
gst_gl_context_set_error (frame->context, "Unknow fbo projection %d",
|
|
projection);
|
|
}
|
|
|
|
gl->MatrixMode (GL_MODELVIEW);
|
|
gl->PushMatrix ();
|
|
gl->LoadIdentity ();
|
|
}
|
|
#endif
|
|
#if GST_GL_HAVE_GLES2
|
|
if (gst_gl_context_get_gl_api (frame->context) & GST_GL_API_GLES2)
|
|
gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
|
|
#endif
|
|
|
|
gl->Viewport (0, 0, texture_fbo_width, texture_fbo_height);
|
|
|
|
#if GST_GL_HAVE_OPENGL
|
|
if (gst_gl_context_get_gl_api (frame->context) & GST_GL_API_OPENGL) {
|
|
const GLenum rt[] = { GL_COLOR_ATTACHMENT0 };
|
|
gl->DrawBuffers (1, rt);
|
|
}
|
|
#endif
|
|
|
|
gl->ClearColor (0.0, 0.0, 0.0, 0.0);
|
|
gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
cb (input_tex_width, input_tex_height, input_tex, stuff);
|
|
|
|
#if GST_GL_HAVE_OPENGL
|
|
if (gst_gl_context_get_gl_api (frame->context) & GST_GL_API_OPENGL) {
|
|
const GLenum rt[] = { GL_NONE };
|
|
gl->DrawBuffers (1, rt);
|
|
gl->MatrixMode (GL_PROJECTION);
|
|
gl->PopMatrix ();
|
|
gl->MatrixMode (GL_MODELVIEW);
|
|
gl->PopMatrix ();
|
|
gl->PopAttrib ();
|
|
}
|
|
#endif
|
|
#if GST_GL_HAVE_GLES2
|
|
if (gst_gl_context_get_gl_api (frame->context) & GST_GL_API_GLES2) {
|
|
gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2],
|
|
viewport_dim[3]);
|
|
}
|
|
#endif
|
|
|
|
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
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)
|
|
{
|
|
const GstGLFuncs *gl;
|
|
GLint viewport_dim[4];
|
|
|
|
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);
|
|
|
|
gl = frame->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, 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);
|
|
|
|
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->DrawBuffer (GL_COLOR_ATTACHMENT0);
|
|
|
|
gl->ClearColor (0.0, 0.0, 0.0, 0.0);
|
|
gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
/* the opengl scene */
|
|
cb (stuff);
|
|
|
|
if (gst_gl_context_get_gl_api (frame->context) & GST_GL_API_OPENGL)
|
|
gl->DrawBuffer (GL_NONE);
|
|
|
|
gl->Viewport (viewport_dim[0], viewport_dim[1],
|
|
viewport_dim[2], viewport_dim[3]);
|
|
|
|
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
gst_gl_framebuffer_delete (GstGLFramebuffer * frame, guint fbo, guint depth)
|
|
{
|
|
const GstGLFuncs *gl;
|
|
|
|
g_return_if_fail (GST_IS_GL_FRAMEBUFFER (frame));
|
|
|
|
gl = frame->context->gl_vtable;
|
|
|
|
GST_TRACE ("Deleting FBO %u", fbo);
|
|
|
|
if (fbo) {
|
|
gl->DeleteFramebuffers (1, &fbo);
|
|
}
|
|
if (depth) {
|
|
gl->DeleteRenderbuffers (1, &depth);
|
|
}
|
|
}
|