Add TFP and FBO helpers.
authorgb <gb@5584edef-b1fe-4b99-b61b-dd2bab72e969>
Tue, 30 Mar 2010 12:59:15 +0000 (12:59 +0000)
committergb <gb@5584edef-b1fe-4b99-b61b-dd2bab72e969>
Tue, 30 Mar 2010 12:59:15 +0000 (12:59 +0000)
gst-libs/gst/vaapi/gstvaapiutils_glx.c
gst-libs/gst/vaapi/gstvaapiutils_glx.h

index 5947ed7..93e8465 100644 (file)
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
+#define _GNU_SOURCE 1 /* RTLD_DEFAULT */
 #include "config.h"
+#include <string.h>
 #include <math.h>
+#include <dlfcn.h>
 #include "gstvaapiutils_glx.h"
+#include "gstvaapiutils_x11.h"
 
 #define DEBUG 1
 #include "gstvaapidebug.h"
 
+/** Lookup for substring NAME in string EXT using SEP as separators */
+static gboolean
+find_string(const char *name, const char *ext, const char *sep)
+{
+    const char *end;
+    int name_len, n;
+
+    if (!name || !ext)
+        return FALSE;
+
+    end = ext + strlen(ext);
+    name_len = strlen(name);
+    while (ext < end) {
+        n = strcspn(ext, sep);
+        if (n == name_len && strncmp(name, ext, n) == 0)
+            return TRUE;
+        ext += (n + 1);
+    }
+    return FALSE;
+}
+
 /**
  * gl_get_error_string:
  * @error: an OpenGL error enumeration
@@ -415,3 +440,594 @@ gl_create_texture(GLenum target, GLenum format, guint width, guint height)
     gl_unbind_texture(&ts);
     return texture;
 }
+
+/**
+ * get_proc_address:
+ * @name: the name of the OpenGL extension function to lookup
+ *
+ * Returns the specified OpenGL extension function
+ *
+ * Return value: the OpenGL extension matching @name, or %NULL if none
+ *   was found
+ */
+typedef void (*GLFuncPtr)(void);
+typedef GLFuncPtr (*GLXGetProcAddressProc)(const char *);
+
+static GLFuncPtr
+get_proc_address_default(const char *name)
+{
+    return NULL;
+}
+
+static GLXGetProcAddressProc
+get_proc_address_func(void)
+{
+    GLXGetProcAddressProc get_proc_func;
+
+    dlerror();
+    get_proc_func = (GLXGetProcAddressProc)
+        dlsym(RTLD_DEFAULT, "glXGetProcAddress");
+    if (!dlerror())
+        return get_proc_func;
+
+    get_proc_func = (GLXGetProcAddressProc)
+        dlsym(RTLD_DEFAULT, "glXGetProcAddressARB");
+    if (!dlerror())
+        return get_proc_func;
+
+    return get_proc_address_default;
+}
+
+static inline GLFuncPtr
+get_proc_address(const char *name)
+{
+    static GLXGetProcAddressProc get_proc_func = NULL;
+    if (!get_proc_func)
+        get_proc_func = get_proc_address_func();
+    return get_proc_func(name);
+}
+
+/**
+ * gl_init_vtable:
+ *
+ * Initializes the global #GLVTable.
+ *
+ * Return value: the #GLVTable filled in with OpenGL extensions, or
+ *   %NULL on error.
+ */
+static GLVTable gl_vtable_static;
+
+static GLVTable *
+gl_init_vtable(void)
+{
+    GLVTable * const gl_vtable = &gl_vtable_static;
+    const gchar *gl_extensions = (const gchar *)glGetString(GL_EXTENSIONS);
+    gboolean has_extension;
+
+    /* GLX_EXT_texture_from_pixmap */
+    gl_vtable->glx_bind_tex_image = (PFNGLXBINDTEXIMAGEEXTPROC)
+        get_proc_address("glXBindTexImageEXT");
+    if (!gl_vtable->glx_bind_tex_image)
+        return NULL;
+    gl_vtable->glx_release_tex_image = (PFNGLXRELEASETEXIMAGEEXTPROC)
+        get_proc_address("glXReleaseTexImageEXT");
+    if (!gl_vtable->glx_release_tex_image)
+        return NULL;
+
+    /* GL_ARB_framebuffer_object */
+    has_extension = (
+        find_string("GL_ARB_framebuffer_object", gl_extensions, " ") ||
+        find_string("GL_EXT_framebuffer_object", gl_extensions, " ")
+    );
+    if (has_extension) {
+        gl_vtable->gl_gen_framebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC)
+            get_proc_address("glGenFramebuffersEXT");
+        if (!gl_vtable->gl_gen_framebuffers)
+            return NULL;
+        gl_vtable->gl_delete_framebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
+            get_proc_address("glDeleteFramebuffersEXT");
+        if (!gl_vtable->gl_delete_framebuffers)
+            return NULL;
+        gl_vtable->gl_bind_framebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC)
+            get_proc_address("glBindFramebufferEXT");
+        if (!gl_vtable->gl_bind_framebuffer)
+            return NULL;
+        gl_vtable->gl_gen_renderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC)
+            get_proc_address("glGenRenderbuffersEXT");
+        if (!gl_vtable->gl_gen_renderbuffers)
+            return NULL;
+        gl_vtable->gl_delete_renderbuffers = (PFNGLDELETERENDERBUFFERSEXTPROC)
+            get_proc_address("glDeleteRenderbuffersEXT");
+        if (!gl_vtable->gl_delete_renderbuffers)
+            return NULL;
+        gl_vtable->gl_bind_renderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC)
+            get_proc_address("glBindRenderbufferEXT");
+        if (!gl_vtable->gl_bind_renderbuffer)
+            return NULL;
+        gl_vtable->gl_renderbuffer_storage = (PFNGLRENDERBUFFERSTORAGEEXTPROC)
+            get_proc_address("glRenderbufferStorageEXT");
+        if (!gl_vtable->gl_renderbuffer_storage)
+            return NULL;
+        gl_vtable->gl_framebuffer_renderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)
+            get_proc_address("glFramebufferRenderbufferEXT");
+        if (!gl_vtable->gl_framebuffer_renderbuffer)
+            return NULL;
+        gl_vtable->gl_framebuffer_texture_2d = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
+            get_proc_address("glFramebufferTexture2DEXT");
+        if (!gl_vtable->gl_framebuffer_texture_2d)
+            return NULL;
+        gl_vtable->gl_check_framebuffer_status = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
+            get_proc_address("glCheckFramebufferStatusEXT");
+        if (!gl_vtable->gl_check_framebuffer_status)
+            return NULL;
+        gl_vtable->has_framebuffer_object = TRUE;
+    }
+
+    /* GL_ARB_fragment_program */
+    has_extension = (
+        find_string("GL_ARB_fragment_program", gl_extensions, " ")
+    );
+    if (has_extension) {
+        gl_vtable->gl_gen_programs = (PFNGLGENPROGRAMSARBPROC)
+            get_proc_address("glGenProgramsARB");
+        if (!gl_vtable->gl_gen_programs)
+            return NULL;
+        gl_vtable->gl_delete_programs = (PFNGLDELETEPROGRAMSARBPROC)
+            get_proc_address("glDeleteProgramsARB");
+        if (!gl_vtable->gl_delete_programs)
+            return NULL;
+        gl_vtable->gl_bind_program = (PFNGLBINDPROGRAMARBPROC)
+            get_proc_address("glBindProgramARB");
+        if (!gl_vtable->gl_bind_program)
+            return NULL;
+        gl_vtable->gl_program_string = (PFNGLPROGRAMSTRINGARBPROC)
+            get_proc_address("glProgramStringARB");
+        if (!gl_vtable->gl_program_string)
+            return NULL;
+        gl_vtable->gl_get_program_iv = (PFNGLGETPROGRAMIVARBPROC)
+            get_proc_address("glGetProgramivARB");
+        if (!gl_vtable->gl_get_program_iv)
+            return NULL;
+        gl_vtable->gl_program_local_parameter_4fv = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)
+            get_proc_address("glProgramLocalParameter4fvARB");
+        if (!gl_vtable->gl_program_local_parameter_4fv)
+            return NULL;
+        gl_vtable->has_fragment_program = TRUE;
+    }
+
+    /* GL_ARB_multitexture */
+    has_extension = (
+        find_string("GL_ARB_multitexture", gl_extensions, " ")
+    );
+    if (has_extension) {
+        gl_vtable->gl_active_texture = (PFNGLACTIVETEXTUREPROC)
+            get_proc_address("glActiveTextureARB");
+        if (!gl_vtable->gl_active_texture)
+            return NULL;
+        gl_vtable->gl_multi_tex_coord_2f = (PFNGLMULTITEXCOORD2FPROC)
+            get_proc_address("glMultiTexCoord2fARB");
+        if (!gl_vtable->gl_multi_tex_coord_2f)
+            return NULL;
+        gl_vtable->has_multitexture = TRUE;
+    }
+    return gl_vtable;
+}
+
+/**
+ * gl_get_vtable:
+ *
+ * Retrieves a VTable for OpenGL extensions.
+ *
+ * Return value: VTable for OpenGL extensions
+ */
+GLVTable *
+gl_get_vtable(void)
+{
+    static GStaticMutex mutex          = G_STATIC_MUTEX_INIT;
+    static gboolean     gl_vtable_init = TRUE;
+    static GLVTable    *gl_vtable      = NULL;
+
+    g_static_mutex_lock(&mutex);
+    if (gl_vtable_init) {
+        gl_vtable_init = FALSE;
+        gl_vtable      = gl_init_vtable();
+    }
+    g_static_mutex_unlock(&mutex);
+    return gl_vtable;
+}
+
+/**
+ * gl_create_pixmap_object:
+ * @dpy: an X11 #Display
+ * @width: the request width, in pixels
+ * @height: the request height, in pixels
+ *
+ * Creates a #GLPixmapObject of the specified dimensions. This
+ * requires the GLX_EXT_texture_from_pixmap extension.
+ *
+ * Return value: the newly created #GLPixmapObject object
+ */
+GLPixmapObject *
+gl_create_pixmap_object(Display *dpy, guint width, guint height)
+{
+    GLVTable * const    gl_vtable = gl_get_vtable();
+    GLPixmapObject     *pixo;
+    GLXFBConfig        *fbconfig;
+    int                 screen;
+    Window              rootwin;
+    XWindowAttributes   wattr;
+    int                *attr;
+    int                 n_fbconfig_attrs;
+
+    int fbconfig_attrs[32] = {
+        GLX_DRAWABLE_TYPE,      GLX_PIXMAP_BIT,
+        GLX_DOUBLEBUFFER,       GL_TRUE,
+        GLX_RENDER_TYPE,        GLX_RGBA_BIT,
+        GLX_X_RENDERABLE,       GL_TRUE,
+        GLX_Y_INVERTED_EXT,     GL_TRUE,
+        GLX_RED_SIZE,           8,
+        GLX_GREEN_SIZE,         8,
+        GLX_BLUE_SIZE,          8,
+        GL_NONE,
+    };
+
+    int pixmap_attrs[10] = {
+        GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+        GLX_MIPMAP_TEXTURE_EXT, GL_FALSE,
+        GL_NONE,
+    };
+
+    if (!gl_vtable)
+        return NULL;
+
+    screen  = DefaultScreen(dpy);
+    rootwin = RootWindow(dpy, screen);
+
+    /* XXX: this won't work for different displays */
+    if (!gl_vtable->has_texture_from_pixmap) {
+        const char *glx_extensions;
+        int glx_major, glx_minor;
+        glx_extensions = glXQueryExtensionsString(dpy, screen);
+        if (!glx_extensions)
+            return NULL;
+        if (!find_string("GLX_EXT_texture_from_pixmap", glx_extensions, " "))
+            return NULL;
+        if (!glXQueryVersion(dpy, &glx_major, &glx_minor))
+            return NULL;
+        if (glx_major < 0 || (glx_major == 1 && glx_minor < 3)) /* 1.3 */
+            return NULL;
+        gl_vtable->has_texture_from_pixmap = TRUE;
+    }
+
+    pixo = calloc(1, sizeof(*pixo));
+    if (!pixo)
+        return NULL;
+
+    pixo->dpy           = dpy;
+    pixo->width         = width;
+    pixo->height        = height;
+    pixo->pixmap        = None;
+    pixo->glx_pixmap    = None;
+    pixo->is_bound      = FALSE;
+
+    XGetWindowAttributes(dpy, rootwin, &wattr);
+    pixo->pixmap  = XCreatePixmap(dpy, rootwin, width, height, wattr.depth);
+    if (!pixo->pixmap)
+        goto error;
+
+    /* Initialize FBConfig attributes */
+    for (attr = fbconfig_attrs; *attr != GL_NONE; attr += 2)
+        ;
+    *attr++ = GLX_DEPTH_SIZE;                 *attr++ = wattr.depth;
+    if (wattr.depth == 32) {
+    *attr++ = GLX_ALPHA_SIZE;                 *attr++ = 8;
+    *attr++ = GLX_BIND_TO_TEXTURE_RGBA_EXT;   *attr++ = GL_TRUE;
+    }
+    else {
+    *attr++ = GLX_BIND_TO_TEXTURE_RGB_EXT;    *attr++ = GL_TRUE;
+    }
+    *attr++ = GL_NONE;
+
+    fbconfig = glXChooseFBConfig(
+        dpy,
+        screen,
+        fbconfig_attrs, &n_fbconfig_attrs
+    );
+    if (!fbconfig)
+        goto error;
+
+    /* Initialize GLX Pixmap attrutes */
+    for (attr = pixmap_attrs; *attr != GL_NONE; attr += 2)
+        ;
+    *attr++ = GLX_TEXTURE_FORMAT_EXT;
+    if (wattr.depth == 32)
+    *attr++ = GLX_TEXTURE_FORMAT_RGBA_EXT;
+    else
+    *attr++ = GLX_TEXTURE_FORMAT_RGB_EXT;
+    *attr++ = GL_NONE;
+
+    x11_trap_errors();
+    pixo->glx_pixmap = glXCreatePixmap(dpy, fbconfig[0], pixo->pixmap, pixmap_attrs);
+    free(fbconfig);
+    if (x11_untrap_errors() != 0)
+        goto error;
+    return pixo;
+
+error:
+    gl_destroy_pixmap_object(pixo);
+    return NULL;
+}
+
+/**
+ * gl_destroy_pixmap_object:
+ * @pixo: a #GLPixmapObject
+ *
+ * Destroys the #GLPixmapObject object.
+ */
+void
+gl_destroy_pixmap_object(GLPixmapObject *pixo)
+{
+    if (!pixo)
+        return;
+
+    gl_unbind_pixmap_object(pixo);
+
+    if (pixo->glx_pixmap) {
+        glXDestroyPixmap(pixo->dpy, pixo->glx_pixmap);
+        pixo->glx_pixmap = None;
+    }
+
+    if (pixo->pixmap) {
+        XFreePixmap(pixo->dpy, pixo->pixmap);
+        pixo->pixmap = None;
+    }
+    free(pixo);
+}
+
+/**
+ * gl_bind_pixmap_object:
+ * @pixo: a #GLPixmapObject
+ *
+ * Defines a two-dimensional texture image. The texture image is taken
+ * from the @pixo pixmap and need not be copied. The texture target,
+ * format and size are derived from attributes of the @pixo pixmap.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_bind_pixmap_object(GLPixmapObject *pixo)
+{
+    GLVTable * const gl_vtable = gl_get_vtable();
+
+    if (pixo->is_bound)
+        return TRUE;
+
+    x11_trap_errors();
+    gl_vtable->glx_bind_tex_image(
+        pixo->dpy,
+        pixo->glx_pixmap,
+        GLX_FRONT_LEFT_EXT,
+        NULL
+    );
+    XSync(pixo->dpy, False);
+    if (x11_untrap_errors() != 0) {
+        GST_DEBUG("failed to bind pixmap");
+        return FALSE;
+    }
+
+    pixo->is_bound = TRUE;
+    return TRUE;
+}
+
+/**
+ * gl_unbind_pixmap_object:
+ * @pixo: a #GLPixmapObject
+ *
+ * Releases a color buffers that is being used as a texture.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_unbind_pixmap_object(GLPixmapObject *pixo)
+{
+    GLVTable * const gl_vtable = gl_get_vtable();
+
+    if (!pixo->is_bound)
+        return TRUE;
+
+    x11_trap_errors();
+    gl_vtable->glx_release_tex_image(
+        pixo->dpy,
+        pixo->glx_pixmap,
+        GLX_FRONT_LEFT_EXT
+    );
+    XSync(pixo->dpy, False);
+    if (x11_untrap_errors() != 0) {
+        GST_DEBUG("failed to release pixmap");
+        return FALSE;
+    }
+
+    pixo->is_bound = FALSE;
+    return TRUE;
+}
+
+/**
+ * gl_create_framebuffer_object:
+ * @target: the target to which the texture is bound
+ * @texture: the GL texture to hold the framebuffer
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Creates an FBO with the specified texture and size.
+ *
+ * Return value: the newly created #GLFramebufferObject, or %NULL if
+ *   an error occurred
+ */
+GLFramebufferObject *
+gl_create_framebuffer_object(
+    GLenum target,
+    GLuint texture,
+    guint  width,
+    guint  height
+)
+{
+    GLVTable * const gl_vtable = gl_get_vtable();
+    GLFramebufferObject *fbo;
+    GLTextureState ts;
+    GLenum status;
+    gboolean texture_was_bound;
+
+    if (!gl_vtable || !gl_vtable->has_framebuffer_object)
+        return NULL;
+
+    /* XXX: we only support GL_TEXTURE_2D at this time */
+    if (target != GL_TEXTURE_2D)
+        return NULL;
+
+    fbo = calloc(1, sizeof(*fbo));
+    if (!fbo)
+        return NULL;
+
+    fbo->width          = width;
+    fbo->height         = height;
+    fbo->fbo            = 0;
+    fbo->fbo_buffer     = 0;
+    fbo->fbo_target     = target;
+    fbo->fbo_texture    = 0;
+    fbo->old_fbo        = 0;
+    fbo->is_bound       = FALSE;
+
+    fbo->fbo_texture = gl_create_texture(target, GL_BGRA, width, height);
+    if (!fbo->fbo_texture)
+        goto error;
+
+    gl_get_param(GL_FRAMEBUFFER_BINDING, &fbo->old_fbo);
+    gl_vtable->gl_gen_framebuffers(1, &fbo->fbo);
+    gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo->fbo);
+    gl_vtable->gl_gen_renderbuffers(1, &fbo->fbo_buffer);
+    gl_vtable->gl_bind_renderbuffer(GL_RENDERBUFFER_EXT, fbo->fbo_buffer);
+
+    texture_was_bound = gl_bind_texture(&ts, target, texture);
+    if (texture_was_bound) {
+        gl_vtable->gl_framebuffer_texture_2d(
+            GL_FRAMEBUFFER_EXT,
+            GL_COLOR_ATTACHMENT0_EXT,
+            target, texture,
+            0
+        );
+        gl_unbind_texture(&ts);
+    }
+    status = gl_vtable->gl_check_framebuffer_status(GL_DRAW_FRAMEBUFFER_EXT);
+    gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo->old_fbo);
+    if (!texture_was_bound || status != GL_FRAMEBUFFER_COMPLETE_EXT)
+        goto error;
+    return fbo;
+
+error:
+    gl_destroy_framebuffer_object(fbo);
+    return NULL;
+}
+
+/**
+ * gl_destroy_framebuffer_object:
+ * @fbo: a #GLFramebufferObject
+ *
+ * Destroys the @fbo object.
+ */
+void
+gl_destroy_framebuffer_object(GLFramebufferObject *fbo)
+{
+    GLVTable * const gl_vtable = gl_get_vtable();
+
+    if (!fbo)
+        return;
+
+    gl_unbind_framebuffer_object(fbo);
+
+    if (fbo->fbo_texture) {
+        glDeleteTextures(1, &fbo->fbo_texture);
+        fbo->fbo_texture = 0;
+    }
+
+    if (fbo->fbo_buffer) {
+        gl_vtable->gl_delete_renderbuffers(1, &fbo->fbo_buffer);
+        fbo->fbo_buffer = 0;
+    }
+
+    if (fbo->fbo) {
+        gl_vtable->gl_delete_framebuffers(1, &fbo->fbo);
+        fbo->fbo = 0;
+    }
+    free(fbo);
+}
+
+/**
+ * gl_bind_framebuffer_object:
+ * @fbo: a #GLFramebufferObject
+ *
+ * Binds @fbo object.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_bind_framebuffer_object(GLFramebufferObject *fbo)
+{
+    GLVTable * const gl_vtable = gl_get_vtable();
+    const guint width  = fbo->width;
+    const guint height = fbo->height;
+
+    const guint attribs = (GL_VIEWPORT_BIT|
+                           GL_CURRENT_BIT|
+                           GL_ENABLE_BIT|
+                           GL_TEXTURE_BIT|
+                           GL_COLOR_BUFFER_BIT);
+
+    if (fbo->is_bound)
+        return TRUE;
+
+    gl_get_param(GL_FRAMEBUFFER_BINDING, &fbo->old_fbo);
+    gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo->fbo);
+    glPushAttrib(attribs);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+    glViewport(0, 0, width, height);
+    glTranslatef(-1.0f, -1.0f, 0.0f);
+    glScalef(2.0f / width, 2.0f / height, 1.0f);
+
+    if (!gl_bind_texture(&fbo->old_texture, fbo->fbo_target, fbo->fbo_texture))
+        return FALSE;
+
+    fbo->is_bound = TRUE;
+    return TRUE;
+}
+
+/**
+ * gl_unbind_framebuffer_object:
+ * @fbo: a #GLFramebufferObject
+ *
+ * Releases @fbo object.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_unbind_framebuffer_object(GLFramebufferObject *fbo)
+{
+    GLVTable * const gl_vtable = gl_get_vtable();
+
+    if (!fbo->is_bound)
+        return TRUE;
+
+    glPopAttrib();
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+    gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo->old_fbo);
+
+    fbo->is_bound = FALSE;
+    return TRUE;
+}
index 69d0048..3c83da2 100644 (file)
 
 #include "config.h"
 #include <GL/gl.h>
+#include <GL/glext.h>
 #include <GL/glx.h>
+#include <GL/glxext.h>
 #include <glib/gtypes.h>
 
+#if GLX_GLXEXT_VERSION < 18
+typedef void (*PFNGLXBINDTEXIMAGEEXTPROC)(Display *, GLXDrawable, int, const int *);
+typedef void (*PFNGLXRELEASETEXIMAGEEXTPROC)(Display *, GLXDrawable, int);
+#endif
+
+#ifndef GL_FRAMEBUFFER_BINDING
+#define GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_EXT
+#endif
+
 const char *
 gl_get_error_string(GLenum error)
     attribute_hidden;
@@ -88,4 +99,95 @@ GLuint
 gl_create_texture(GLenum target, GLenum format, guint width, guint height)
     attribute_hidden;
 
+typedef struct _GLVTable GLVTable;
+struct _GLVTable {
+    PFNGLXBINDTEXIMAGEEXTPROC           glx_bind_tex_image;
+    PFNGLXRELEASETEXIMAGEEXTPROC        glx_release_tex_image;
+    PFNGLGENFRAMEBUFFERSEXTPROC         gl_gen_framebuffers;
+    PFNGLDELETEFRAMEBUFFERSEXTPROC      gl_delete_framebuffers;
+    PFNGLBINDFRAMEBUFFEREXTPROC         gl_bind_framebuffer;
+    PFNGLGENRENDERBUFFERSEXTPROC        gl_gen_renderbuffers;
+    PFNGLDELETERENDERBUFFERSEXTPROC     gl_delete_renderbuffers;
+    PFNGLBINDRENDERBUFFEREXTPROC        gl_bind_renderbuffer;
+    PFNGLRENDERBUFFERSTORAGEEXTPROC     gl_renderbuffer_storage;
+    PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC gl_framebuffer_renderbuffer;
+    PFNGLFRAMEBUFFERTEXTURE2DEXTPROC    gl_framebuffer_texture_2d;
+    PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC  gl_check_framebuffer_status;
+    PFNGLGENPROGRAMSARBPROC             gl_gen_programs;
+    PFNGLDELETEPROGRAMSARBPROC          gl_delete_programs;
+    PFNGLBINDPROGRAMARBPROC             gl_bind_program;
+    PFNGLPROGRAMSTRINGARBPROC           gl_program_string;
+    PFNGLGETPROGRAMIVARBPROC            gl_get_program_iv;
+    PFNGLPROGRAMLOCALPARAMETER4FVARBPROC gl_program_local_parameter_4fv;
+    PFNGLACTIVETEXTUREPROC              gl_active_texture;
+    PFNGLMULTITEXCOORD2FPROC            gl_multi_tex_coord_2f;
+    guint                               has_texture_from_pixmap : 1;
+    guint                               has_framebuffer_object  : 1;
+    guint                               has_fragment_program    : 1;
+    guint                               has_multitexture        : 1;
+};
+
+GLVTable *
+gl_get_vtable(void)
+    attribute_hidden;
+
+typedef struct _GLPixmapObject GLPixmapObject;
+struct _GLPixmapObject {
+    Display    *dpy;
+    guint       width;
+    guint       height;
+    Pixmap      pixmap;
+    GLXPixmap   glx_pixmap;
+    guint       is_bound        : 1;
+};
+
+GLPixmapObject *
+gl_create_pixmap_object(Display *dpy, guint width, guint height)
+    attribute_hidden;
+
+void
+gl_destroy_pixmap_object(GLPixmapObject *pixo)
+    attribute_hidden;
+
+gboolean
+gl_bind_pixmap_object(GLPixmapObject *pixo)
+    attribute_hidden;
+
+gboolean
+gl_unbind_pixmap_object(GLPixmapObject *pixo)
+    attribute_hidden;
+
+typedef struct _GLFramebufferObject GLFramebufferObject;
+struct _GLFramebufferObject {
+    guint           width;
+    guint           height;
+    GLuint          fbo;
+    GLuint          fbo_buffer;
+    GLenum          fbo_target;
+    GLuint          fbo_texture;
+    GLuint          old_fbo;
+    GLTextureState  old_texture;
+    guint           is_bound    : 1;
+};
+
+GLFramebufferObject *
+gl_create_framebuffer_object(
+    GLenum target,
+    GLuint texture,
+    guint  width,
+    guint  height
+) attribute_hidden;
+
+void
+gl_destroy_framebuffer_object(GLFramebufferObject *fbo)
+    attribute_hidden;
+
+gboolean
+gl_bind_framebuffer_object(GLFramebufferObject *fbo)
+    attribute_hidden;
+
+gboolean
+gl_unbind_framebuffer_object(GLFramebufferObject *fbo)
+    attribute_hidden;
+
 #endif /* GST_VAAPI_UTILS_GLX_H */