Blame va/glx/va_glx_impl.c

Packit 38d9dc
/*
Packit 38d9dc
 * Copyright (C) 2009 Splitted-Desktop Systems. All Rights Reserved.
Packit 38d9dc
 *
Packit 38d9dc
 * Permission is hereby granted, free of charge, to any person obtaining a
Packit 38d9dc
 * copy of this software and associated documentation files (the
Packit 38d9dc
 * "Software"), to deal in the Software without restriction, including
Packit 38d9dc
 * without limitation the rights to use, copy, modify, merge, publish,
Packit 38d9dc
 * distribute, sub license, and/or sell copies of the Software, and to
Packit 38d9dc
 * permit persons to whom the Software is furnished to do so, subject to
Packit 38d9dc
 * the following conditions:
Packit 38d9dc
 * 
Packit 38d9dc
 * The above copyright notice and this permission notice (including the
Packit 38d9dc
 * next paragraph) shall be included in all copies or substantial portions
Packit 38d9dc
 * of the Software.
Packit 38d9dc
 * 
Packit 38d9dc
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
Packit 38d9dc
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 38d9dc
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
Packit 38d9dc
 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
Packit 38d9dc
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
Packit 38d9dc
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
Packit 38d9dc
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit 38d9dc
 */
Packit 38d9dc
Packit 38d9dc
#define _GNU_SOURCE 1
Packit 38d9dc
#include "sysdeps.h"
Packit 38d9dc
#include "va_glx_private.h"
Packit 38d9dc
#include "va_glx_impl.h"
Packit 38d9dc
#include <stdio.h>
Packit 38d9dc
#include <stdlib.h>
Packit 38d9dc
#include <stdarg.h>
Packit 38d9dc
#include <string.h>
Packit 38d9dc
#include <assert.h>
Packit 38d9dc
#include <dlfcn.h>
Packit 38d9dc
Packit 38d9dc
static void va_glx_error_message(const char *format, ...)
Packit 38d9dc
{
Packit 38d9dc
    va_list args;
Packit 38d9dc
    va_start(args, format);
Packit 38d9dc
    fprintf(stderr, "libva-glx error: ");
Packit 38d9dc
    vfprintf(stderr, format, args);
Packit 38d9dc
    va_end(args);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// X error trap
Packit 38d9dc
static int x11_error_code = 0;
Packit 38d9dc
static int (*old_error_handler)(Display *, XErrorEvent *);
Packit 38d9dc
Packit 38d9dc
static int error_handler(Display *dpy, XErrorEvent *error)
Packit 38d9dc
{
Packit 38d9dc
    x11_error_code = error->error_code;
Packit 38d9dc
    return 0;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static void x11_trap_errors(void)
Packit 38d9dc
{
Packit 38d9dc
    x11_error_code    = 0;
Packit 38d9dc
    old_error_handler = XSetErrorHandler(error_handler);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static int x11_untrap_errors(void)
Packit 38d9dc
{
Packit 38d9dc
    XSetErrorHandler(old_error_handler);
Packit 38d9dc
    return x11_error_code;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Returns a string representation of an OpenGL error
Packit 38d9dc
static const char *gl_get_error_string(GLenum error)
Packit 38d9dc
{
Packit 38d9dc
    static const struct {
Packit 38d9dc
        GLenum val;
Packit 38d9dc
        const char *str;
Packit 38d9dc
    }
Packit 38d9dc
    gl_errors[] = {
Packit 38d9dc
        { GL_NO_ERROR,          "no error" },
Packit 38d9dc
        { GL_INVALID_ENUM,      "invalid enumerant" },
Packit 38d9dc
        { GL_INVALID_VALUE,     "invalid value" },
Packit 38d9dc
        { GL_INVALID_OPERATION, "invalid operation" },
Packit 38d9dc
        { GL_STACK_OVERFLOW,    "stack overflow" },
Packit 38d9dc
        { GL_STACK_UNDERFLOW,   "stack underflow" },
Packit 38d9dc
        { GL_OUT_OF_MEMORY,     "out of memory" },
Packit 38d9dc
#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
Packit 38d9dc
        { GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "invalid framebuffer operation" },
Packit 38d9dc
#endif
Packit 38d9dc
        { ~0, NULL }
Packit 38d9dc
    };
Packit 38d9dc
Packit 38d9dc
    int i;
Packit 38d9dc
    for (i = 0; gl_errors[i].str; i++) {
Packit 38d9dc
        if (gl_errors[i].val == error)
Packit 38d9dc
            return gl_errors[i].str;
Packit 38d9dc
    }
Packit 38d9dc
    return "unknown";
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static inline int gl_do_check_error(int report)
Packit 38d9dc
{
Packit 38d9dc
    GLenum error;
Packit 38d9dc
    int is_error = 0;
Packit 38d9dc
    while ((error = glGetError()) != GL_NO_ERROR) {
Packit 38d9dc
        if (report)
Packit 38d9dc
            va_glx_error_message("glError: %s caught\n",
Packit 38d9dc
                                 gl_get_error_string(error));
Packit 38d9dc
        is_error = 1;
Packit 38d9dc
    }
Packit 38d9dc
    return is_error;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static inline void gl_purge_errors(void)
Packit 38d9dc
{
Packit 38d9dc
    gl_do_check_error(0);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static inline int gl_check_error(void)
Packit 38d9dc
{
Packit 38d9dc
    return gl_do_check_error(1);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// glGetTexLevelParameteriv() wrapper
Packit 38d9dc
static int gl_get_texture_param(GLenum param, unsigned int *pval)
Packit 38d9dc
{
Packit 38d9dc
    GLint val;
Packit 38d9dc
Packit 38d9dc
    gl_purge_errors();
Packit 38d9dc
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, param, &val;;
Packit 38d9dc
    if (gl_check_error())
Packit 38d9dc
        return 0;
Packit 38d9dc
    if (pval)
Packit 38d9dc
        *pval = val;
Packit 38d9dc
    return 1;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Returns the OpenGL VTable
Packit 38d9dc
static inline VAOpenGLVTableP gl_get_vtable(VADriverContextP ctx)
Packit 38d9dc
{
Packit 38d9dc
    return &VA_DRIVER_CONTEXT_GLX(ctx)->gl_vtable;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Lookup for a GLX function
Packit 38d9dc
typedef void (*GLFuncPtr)(void);
Packit 38d9dc
typedef GLFuncPtr (*GLXGetProcAddressProc)(const char *);
Packit 38d9dc
Packit 38d9dc
static GLFuncPtr get_proc_address_default(const char *name)
Packit 38d9dc
{
Packit 38d9dc
    return NULL;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static GLXGetProcAddressProc get_proc_address_func(void)
Packit 38d9dc
{
Packit 38d9dc
    GLXGetProcAddressProc get_proc_func;
Packit 38d9dc
Packit 38d9dc
    dlerror();
Packit 38d9dc
    get_proc_func = (GLXGetProcAddressProc)
Packit 38d9dc
        dlsym(RTLD_DEFAULT, "glXGetProcAddress");
Packit 38d9dc
    if (!dlerror())
Packit 38d9dc
        return get_proc_func;
Packit 38d9dc
Packit 38d9dc
    get_proc_func = (GLXGetProcAddressProc)
Packit 38d9dc
        dlsym(RTLD_DEFAULT, "glXGetProcAddressARB");
Packit 38d9dc
    if (!dlerror())
Packit 38d9dc
        return get_proc_func;
Packit 38d9dc
Packit 38d9dc
    return get_proc_address_default;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static inline GLFuncPtr get_proc_address(const char *name)
Packit 38d9dc
{
Packit 38d9dc
    static GLXGetProcAddressProc get_proc_func = NULL;
Packit 38d9dc
    if (!get_proc_func)
Packit 38d9dc
        get_proc_func = get_proc_address_func();
Packit 38d9dc
    return get_proc_func(name);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Check for GLX extensions (TFP, FBO)
Packit 38d9dc
static int check_extension(const char *name, const char *ext)
Packit 38d9dc
{
Packit 38d9dc
    const char *end;
Packit 38d9dc
    int name_len, n;
Packit 38d9dc
Packit 38d9dc
    if (!name || !ext)
Packit 38d9dc
        return 0;
Packit 38d9dc
Packit 38d9dc
    end = ext + strlen(ext);
Packit 38d9dc
    name_len = strlen(name);
Packit 38d9dc
    while (ext < end) {
Packit 38d9dc
        n = strcspn(ext, " ");
Packit 38d9dc
        if (n == name_len && strncmp(name, ext, n) == 0)
Packit 38d9dc
            return 1;
Packit 38d9dc
        ext += (n + 1);
Packit 38d9dc
    }
Packit 38d9dc
    return 0;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static int check_extension3(const char *name)
Packit 38d9dc
{
Packit 38d9dc
    int nbExtensions, i;
Packit 38d9dc
    PFNGLGETSTRINGIPROC glGetStringi = 0;
Packit 38d9dc
Packit 38d9dc
    glGetStringi = (PFNGLGETSTRINGIPROC) get_proc_address("glGetStringi");
Packit 38d9dc
    if(!glGetStringi)
Packit 38d9dc
        return 0;
Packit 38d9dc
Packit 38d9dc
Packit 38d9dc
    glGetIntegerv(GL_NUM_EXTENSIONS, &nbExtensions);
Packit 38d9dc
    for(i = 0; i < nbExtensions; i++)
Packit 38d9dc
    {
Packit 38d9dc
        const GLubyte *strExtension = glGetStringi(GL_EXTENSIONS, i);
Packit 38d9dc
        if(strcmp((const char *) strExtension, name) == 0)
Packit 38d9dc
            return 1;
Packit 38d9dc
    }
Packit 38d9dc
Packit 38d9dc
    return 0;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static int check_tfp_extensions(VADriverContextP ctx)
Packit 38d9dc
{
Packit 38d9dc
    const char *gl_extensions;
Packit 38d9dc
    const char *glx_extensions;
Packit 38d9dc
Packit 38d9dc
    gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
Packit 38d9dc
    if (!check_extension("GL_ARB_texture_non_power_of_two", gl_extensions) && !check_extension3("GL_ARB_texture_non_power_of_two"))
Packit 38d9dc
        return 0;
Packit 38d9dc
Packit 38d9dc
    glx_extensions = glXQueryExtensionsString(ctx->native_dpy, ctx->x11_screen);
Packit 38d9dc
    if (!check_extension("GLX_EXT_texture_from_pixmap", glx_extensions))
Packit 38d9dc
        return 0;
Packit 38d9dc
Packit 38d9dc
    return 1;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static int check_fbo_extensions(VADriverContextP ctx)
Packit 38d9dc
{
Packit 38d9dc
    const char *gl_extensions;
Packit 38d9dc
Packit 38d9dc
    gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
Packit 38d9dc
    if (check_extension("GL_ARB_framebuffer_object", gl_extensions) || check_extension3("GL_ARB_framebuffer_object"))
Packit 38d9dc
        return 1;
Packit 38d9dc
    if (check_extension("GL_EXT_framebuffer_object", gl_extensions) || check_extension3("GL_EXT_framebuffer_object"))
Packit 38d9dc
        return 1;
Packit 38d9dc
Packit 38d9dc
    return 0;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Load GLX extensions
Packit 38d9dc
static int load_tfp_extensions(VADriverContextP ctx)
Packit 38d9dc
{
Packit 38d9dc
    VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
Packit 38d9dc
Packit 38d9dc
    pOpenGLVTable->glx_create_pixmap = (PFNGLXCREATEPIXMAPPROC)
Packit 38d9dc
        get_proc_address("glXCreatePixmap");
Packit 38d9dc
    if (!pOpenGLVTable->glx_create_pixmap)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->glx_destroy_pixmap = (PFNGLXDESTROYPIXMAPPROC)
Packit 38d9dc
        get_proc_address("glXDestroyPixmap");
Packit 38d9dc
    if (!pOpenGLVTable->glx_destroy_pixmap)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->glx_bind_tex_image = (PFNGLXBINDTEXIMAGEEXTPROC)
Packit 38d9dc
        get_proc_address("glXBindTexImageEXT");
Packit 38d9dc
    if (!pOpenGLVTable->glx_bind_tex_image)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->glx_release_tex_image = (PFNGLXRELEASETEXIMAGEEXTPROC)
Packit 38d9dc
        get_proc_address("glXReleaseTexImageEXT");
Packit 38d9dc
    if (!pOpenGLVTable->glx_release_tex_image)
Packit 38d9dc
        return 0;
Packit 38d9dc
    return 1;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static int load_fbo_extensions(VADriverContextP ctx)
Packit 38d9dc
{
Packit 38d9dc
    VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
Packit 38d9dc
Packit 38d9dc
    pOpenGLVTable->gl_gen_framebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC)
Packit 38d9dc
        get_proc_address("glGenFramebuffersEXT");
Packit 38d9dc
    if (!pOpenGLVTable->gl_gen_framebuffers)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->gl_delete_framebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
Packit 38d9dc
        get_proc_address("glDeleteFramebuffersEXT");
Packit 38d9dc
    if (!pOpenGLVTable->gl_delete_framebuffers)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->gl_bind_framebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC)
Packit 38d9dc
        get_proc_address("glBindFramebufferEXT");
Packit 38d9dc
    if (!pOpenGLVTable->gl_bind_framebuffer)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->gl_gen_renderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC)
Packit 38d9dc
        get_proc_address("glGenRenderbuffersEXT");
Packit 38d9dc
    if (!pOpenGLVTable->gl_gen_renderbuffers)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->gl_delete_renderbuffers = (PFNGLDELETERENDERBUFFERSEXTPROC)
Packit 38d9dc
        get_proc_address("glDeleteRenderbuffersEXT");
Packit 38d9dc
    if (!pOpenGLVTable->gl_delete_renderbuffers)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->gl_bind_renderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC)
Packit 38d9dc
        get_proc_address("glBindRenderbufferEXT");
Packit 38d9dc
    if (!pOpenGLVTable->gl_bind_renderbuffer)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->gl_renderbuffer_storage = (PFNGLRENDERBUFFERSTORAGEEXTPROC)
Packit 38d9dc
        get_proc_address("glRenderbufferStorageEXT");
Packit 38d9dc
    if (!pOpenGLVTable->gl_renderbuffer_storage)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->gl_framebuffer_renderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)
Packit 38d9dc
        get_proc_address("glFramebufferRenderbufferEXT");
Packit 38d9dc
    if (!pOpenGLVTable->gl_framebuffer_renderbuffer)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->gl_framebuffer_texture_2d = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
Packit 38d9dc
        get_proc_address("glFramebufferTexture2DEXT");
Packit 38d9dc
    if (!pOpenGLVTable->gl_framebuffer_texture_2d)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pOpenGLVTable->gl_check_framebuffer_status = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
Packit 38d9dc
        get_proc_address("glCheckFramebufferStatusEXT");
Packit 38d9dc
    if (!pOpenGLVTable->gl_check_framebuffer_status)
Packit 38d9dc
        return 0;
Packit 38d9dc
    return 1;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
Packit 38d9dc
/* ========================================================================= */
Packit 38d9dc
/* === VA/GLX helpers                                                    === */
Packit 38d9dc
/* ========================================================================= */
Packit 38d9dc
Packit 38d9dc
// OpenGL context state
Packit 38d9dc
typedef struct OpenGLContextState *OpenGLContextStateP;
Packit 38d9dc
Packit 38d9dc
struct OpenGLContextState {
Packit 38d9dc
    Display     *display;
Packit 38d9dc
    Window       window;
Packit 38d9dc
    GLXContext   context;
Packit 38d9dc
};
Packit 38d9dc
Packit 38d9dc
static void
Packit 38d9dc
gl_destroy_context(OpenGLContextStateP cs)
Packit 38d9dc
{
Packit 38d9dc
    if (!cs)
Packit 38d9dc
        return;
Packit 38d9dc
Packit 38d9dc
    if (cs->display && cs->context) {
Packit 38d9dc
        if (glXGetCurrentContext() == cs->context)
Packit 38d9dc
            glXMakeCurrent(cs->display, None, NULL);
Packit 38d9dc
        glXDestroyContext(cs->display, cs->context);
Packit 38d9dc
        cs->display = NULL;
Packit 38d9dc
        cs->context = NULL;
Packit 38d9dc
    }
Packit 38d9dc
    free(cs);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static OpenGLContextStateP
Packit 38d9dc
gl_create_context(VADriverContextP ctx, OpenGLContextStateP parent)
Packit 38d9dc
{
Packit 38d9dc
    OpenGLContextStateP cs;
Packit 38d9dc
    GLXFBConfig *fbconfigs = NULL;
Packit 38d9dc
    int fbconfig_id, val, n, n_fbconfigs;
Packit 38d9dc
    Status status;
Packit 38d9dc
Packit 38d9dc
    static GLint fbconfig_attrs[] = {
Packit 38d9dc
        GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
Packit 38d9dc
        GLX_RENDER_TYPE,   GLX_RGBA_BIT,
Packit 38d9dc
        GLX_DOUBLEBUFFER,  True,
Packit 38d9dc
        GLX_RED_SIZE,      8,
Packit 38d9dc
        GLX_GREEN_SIZE,    8, 
Packit 38d9dc
        GLX_BLUE_SIZE,     8,
Packit 38d9dc
        None
Packit 38d9dc
    };
Packit 38d9dc
Packit 38d9dc
    cs = malloc(sizeof(*cs));
Packit 38d9dc
    if (!cs)
Packit 38d9dc
        goto error;
Packit 38d9dc
Packit 38d9dc
    if (parent) {
Packit 38d9dc
        cs->display = parent->display;
Packit 38d9dc
        cs->window  = parent->window;
Packit 38d9dc
    }
Packit 38d9dc
    else {
Packit 38d9dc
        cs->display = ctx->native_dpy;
Packit 38d9dc
        cs->window  = None;
Packit 38d9dc
    }
Packit 38d9dc
    cs->context = NULL;
Packit 38d9dc
Packit 38d9dc
    if (parent && parent->context) {
Packit 38d9dc
        status = glXQueryContext(
Packit 38d9dc
            parent->display,
Packit 38d9dc
            parent->context,
Packit 38d9dc
            GLX_FBCONFIG_ID, &fbconfig_id
Packit 38d9dc
        );
Packit 38d9dc
        if (status != Success)
Packit 38d9dc
            goto error;
Packit 38d9dc
Packit 38d9dc
        if (fbconfig_id == GLX_DONT_CARE)
Packit 38d9dc
            goto choose_fbconfig;
Packit 38d9dc
Packit 38d9dc
        fbconfigs = glXGetFBConfigs(
Packit 38d9dc
            parent->display,
Packit 38d9dc
            DefaultScreen(parent->display),
Packit 38d9dc
            &n_fbconfigs
Packit 38d9dc
        );
Packit 38d9dc
        if (!fbconfigs)
Packit 38d9dc
            goto error;
Packit 38d9dc
Packit 38d9dc
        /* Find out a GLXFBConfig compatible with the parent context */
Packit 38d9dc
        for (n = 0; n < n_fbconfigs; n++) {
Packit 38d9dc
            status = glXGetFBConfigAttrib(
Packit 38d9dc
                cs->display,
Packit 38d9dc
                fbconfigs[n],
Packit 38d9dc
                GLX_FBCONFIG_ID, &val
Packit 38d9dc
            );
Packit 38d9dc
            if (status == Success && val == fbconfig_id)
Packit 38d9dc
                break;
Packit 38d9dc
        }
Packit 38d9dc
        if (n == n_fbconfigs)
Packit 38d9dc
            goto error;
Packit 38d9dc
    }
Packit 38d9dc
    else {
Packit 38d9dc
    choose_fbconfig:
Packit 38d9dc
        fbconfigs = glXChooseFBConfig(
Packit 38d9dc
            ctx->native_dpy,
Packit 38d9dc
            ctx->x11_screen,
Packit 38d9dc
            fbconfig_attrs, &n_fbconfigs
Packit 38d9dc
        );
Packit 38d9dc
        if (!fbconfigs)
Packit 38d9dc
            goto error;
Packit 38d9dc
Packit 38d9dc
        /* Select the first one */
Packit 38d9dc
        n = 0;
Packit 38d9dc
    }
Packit 38d9dc
Packit 38d9dc
    cs->context = glXCreateNewContext(
Packit 38d9dc
        cs->display,
Packit 38d9dc
        fbconfigs[n],
Packit 38d9dc
        GLX_RGBA_TYPE,
Packit 38d9dc
        parent ? parent->context : NULL,
Packit 38d9dc
        True
Packit 38d9dc
    );
Packit 38d9dc
    if (cs->context)
Packit 38d9dc
        goto end;
Packit 38d9dc
Packit 38d9dc
error:
Packit 38d9dc
    gl_destroy_context(cs);
Packit 38d9dc
    cs = NULL;
Packit 38d9dc
end:
Packit 38d9dc
    if (fbconfigs)
Packit 38d9dc
        XFree(fbconfigs);
Packit 38d9dc
    return cs;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static void gl_get_current_context(OpenGLContextStateP cs)
Packit 38d9dc
{
Packit 38d9dc
    cs->display = glXGetCurrentDisplay();
Packit 38d9dc
    cs->window  = glXGetCurrentDrawable();
Packit 38d9dc
    cs->context = glXGetCurrentContext();
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static int
Packit 38d9dc
gl_set_current_context(OpenGLContextStateP new_cs, OpenGLContextStateP old_cs)
Packit 38d9dc
{
Packit 38d9dc
    /* If display is NULL, this could be that new_cs was retrieved from
Packit 38d9dc
       gl_get_current_context() with none set previously. If that case,
Packit 38d9dc
       the other fields are also NULL and we don't return an error */
Packit 38d9dc
    if (!new_cs->display)
Packit 38d9dc
        return !new_cs->window && !new_cs->context;
Packit 38d9dc
Packit 38d9dc
    if (old_cs) {
Packit 38d9dc
        if (old_cs == new_cs)
Packit 38d9dc
            return 1;
Packit 38d9dc
        gl_get_current_context(old_cs);
Packit 38d9dc
        if (old_cs->display == new_cs->display &&
Packit 38d9dc
            old_cs->window  == new_cs->window  &&
Packit 38d9dc
            old_cs->context == new_cs->context)
Packit 38d9dc
            return 1;
Packit 38d9dc
    }
Packit 38d9dc
    return glXMakeCurrent(new_cs->display, new_cs->window, new_cs->context);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
/** Unique VASurfaceGLX identifier */
Packit 38d9dc
#define VA_SURFACE_GLX_MAGIC VA_FOURCC('V','A','G','L')
Packit 38d9dc
Packit 38d9dc
struct VASurfaceGLX {
Packit 38d9dc
    uint32_t            magic;      ///< Magic number identifying a VASurfaceGLX
Packit 38d9dc
    GLenum              target;     ///< GL target to which the texture is bound
Packit 38d9dc
    GLuint              texture;    ///< GL texture
Packit 38d9dc
    VASurfaceID         surface;    ///< Associated VA surface
Packit 38d9dc
    unsigned int        width;
Packit 38d9dc
    unsigned int        height;
Packit 38d9dc
    OpenGLContextStateP gl_context;
Packit 38d9dc
    int                 is_bound;
Packit 38d9dc
    Pixmap              pixmap;
Packit 38d9dc
    GLuint              pix_texture;
Packit 38d9dc
    GLXPixmap           glx_pixmap;
Packit 38d9dc
    GLuint              fbo;
Packit 38d9dc
};
Packit 38d9dc
Packit 38d9dc
// Create Pixmaps for GLX texture-from-pixmap extension
Packit 38d9dc
static int create_tfp_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    VAOpenGLVTableP const pOpenGLVTable = gl_get_vtable(ctx);
Packit 38d9dc
    const unsigned int    width         = pSurfaceGLX->width;
Packit 38d9dc
    const unsigned int    height        = pSurfaceGLX->height;
Packit 38d9dc
    Pixmap                pixmap        = None;
Packit 38d9dc
    GLXFBConfig          *fbconfig      = NULL;
Packit 38d9dc
    GLXPixmap             glx_pixmap    = None;
Packit 38d9dc
    Window                root_window;
Packit 38d9dc
    XWindowAttributes     wattr;
Packit 38d9dc
    int                  *attrib;
Packit 38d9dc
    int                   n_fbconfig_attrs;
Packit 38d9dc
Packit 38d9dc
    root_window = RootWindow(ctx->native_dpy, ctx->x11_screen);
Packit 38d9dc
    XGetWindowAttributes(ctx->native_dpy, root_window, &wattr);
Packit 38d9dc
    if (wattr.depth != 24 && wattr.depth != 32)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pixmap = XCreatePixmap(
Packit 38d9dc
        ctx->native_dpy,
Packit 38d9dc
        root_window,
Packit 38d9dc
        width,
Packit 38d9dc
        height,
Packit 38d9dc
        wattr.depth
Packit 38d9dc
    );
Packit 38d9dc
    if (!pixmap)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pSurfaceGLX->pixmap = pixmap;
Packit 38d9dc
Packit 38d9dc
    int fbconfig_attrs[32] = {
Packit 38d9dc
        GLX_DRAWABLE_TYPE,      GLX_PIXMAP_BIT,
Packit 38d9dc
        GLX_DOUBLEBUFFER,       GL_TRUE,
Packit 38d9dc
        GLX_RENDER_TYPE,        GLX_RGBA_BIT,
Packit 38d9dc
        GLX_X_RENDERABLE,       GL_TRUE,
Packit 38d9dc
        GLX_Y_INVERTED_EXT,     GL_TRUE,
Packit 38d9dc
        GLX_RED_SIZE,           8,
Packit 38d9dc
        GLX_GREEN_SIZE,         8,
Packit 38d9dc
        GLX_BLUE_SIZE,          8,
Packit 38d9dc
        /*
Packit 38d9dc
         * depth test isn't enabled in the implementaion of VA GLX,
Packit 38d9dc
         * so depth buffer is unnecessary. However to workaround a
Packit 38d9dc
         * bug in older verson of xorg-server, always require a depth
Packit 38d9dc
         * buffer.
Packit 38d9dc
         *
Packit 38d9dc
         * See https://bugs.freedesktop.org/show_bug.cgi?id=76755
Packit 38d9dc
         */
Packit 38d9dc
        GLX_DEPTH_SIZE,         1,
Packit 38d9dc
        GL_NONE,
Packit 38d9dc
    };
Packit 38d9dc
    for (attrib = fbconfig_attrs; *attrib != GL_NONE; attrib += 2)
Packit 38d9dc
        ;
Packit 38d9dc
    if (wattr.depth == 32) {
Packit 38d9dc
    *attrib++ = GLX_ALPHA_SIZE;                 *attrib++ = 8;
Packit 38d9dc
    *attrib++ = GLX_BIND_TO_TEXTURE_RGBA_EXT;   *attrib++ = GL_TRUE;
Packit 38d9dc
    }
Packit 38d9dc
    else {
Packit 38d9dc
    *attrib++ = GLX_BIND_TO_TEXTURE_RGB_EXT;    *attrib++ = GL_TRUE;
Packit 38d9dc
    }
Packit 38d9dc
    *attrib++ = GL_NONE;
Packit 38d9dc
Packit 38d9dc
    fbconfig = glXChooseFBConfig(
Packit 38d9dc
        ctx->native_dpy,
Packit 38d9dc
        ctx->x11_screen,
Packit 38d9dc
        fbconfig_attrs,
Packit 38d9dc
        &n_fbconfig_attrs
Packit 38d9dc
    );
Packit 38d9dc
    if (!fbconfig)
Packit 38d9dc
        return 0;
Packit 38d9dc
Packit 38d9dc
    int pixmap_attrs[10] = {
Packit 38d9dc
        GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
Packit 38d9dc
        GLX_MIPMAP_TEXTURE_EXT, GL_FALSE,
Packit 38d9dc
        GL_NONE,
Packit 38d9dc
    };
Packit 38d9dc
    for (attrib = pixmap_attrs; *attrib != GL_NONE; attrib += 2)
Packit 38d9dc
        ;
Packit 38d9dc
    *attrib++ = GLX_TEXTURE_FORMAT_EXT;
Packit 38d9dc
    if (wattr.depth == 32)
Packit 38d9dc
    *attrib++ = GLX_TEXTURE_FORMAT_RGBA_EXT;
Packit 38d9dc
    else
Packit 38d9dc
    *attrib++ = GLX_TEXTURE_FORMAT_RGB_EXT;
Packit 38d9dc
    *attrib++ = GL_NONE;
Packit 38d9dc
Packit 38d9dc
    x11_trap_errors();
Packit 38d9dc
    glx_pixmap = pOpenGLVTable->glx_create_pixmap(
Packit 38d9dc
        ctx->native_dpy,
Packit 38d9dc
        fbconfig[0],
Packit 38d9dc
        pixmap,
Packit 38d9dc
        pixmap_attrs
Packit 38d9dc
    );
Packit 38d9dc
    free(fbconfig);
Packit 38d9dc
    if (x11_untrap_errors() != 0)
Packit 38d9dc
        return 0;
Packit 38d9dc
    pSurfaceGLX->glx_pixmap = glx_pixmap;
Packit 38d9dc
Packit 38d9dc
    glGenTextures(1, &pSurfaceGLX->pix_texture);
Packit 38d9dc
    glBindTexture(GL_TEXTURE_2D, pSurfaceGLX->pix_texture);
Packit 38d9dc
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
Packit 38d9dc
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Packit 38d9dc
    return 1;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Destroy Pixmaps used for TFP
Packit 38d9dc
static void destroy_tfp_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    VAOpenGLVTableP const pOpenGLVTable = gl_get_vtable(ctx);
Packit 38d9dc
Packit 38d9dc
    if (pSurfaceGLX->pix_texture) {
Packit 38d9dc
        glDeleteTextures(1, &pSurfaceGLX->pix_texture);
Packit 38d9dc
        pSurfaceGLX->pix_texture = 0;
Packit 38d9dc
    }
Packit 38d9dc
Packit 38d9dc
    if (pSurfaceGLX->glx_pixmap) {
Packit 38d9dc
        pOpenGLVTable->glx_destroy_pixmap(ctx->native_dpy, pSurfaceGLX->glx_pixmap);
Packit 38d9dc
        pSurfaceGLX->glx_pixmap = None;
Packit 38d9dc
    }
Packit 38d9dc
Packit 38d9dc
    if (pSurfaceGLX->pixmap) {
Packit 38d9dc
        XFreePixmap(ctx->native_dpy, pSurfaceGLX->pixmap);
Packit 38d9dc
        pSurfaceGLX->pixmap = None;
Packit 38d9dc
    }
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Bind GLX Pixmap to texture
Packit 38d9dc
static int bind_pixmap(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
Packit 38d9dc
Packit 38d9dc
    if (pSurfaceGLX->is_bound)
Packit 38d9dc
        return 1;
Packit 38d9dc
Packit 38d9dc
    glBindTexture(GL_TEXTURE_2D, pSurfaceGLX->pix_texture);
Packit 38d9dc
Packit 38d9dc
    x11_trap_errors();
Packit 38d9dc
    pOpenGLVTable->glx_bind_tex_image(
Packit 38d9dc
        ctx->native_dpy,
Packit 38d9dc
        pSurfaceGLX->glx_pixmap,
Packit 38d9dc
        GLX_FRONT_LEFT_EXT,
Packit 38d9dc
        NULL
Packit 38d9dc
    );
Packit 38d9dc
    XSync(ctx->native_dpy, False);
Packit 38d9dc
    if (x11_untrap_errors() != 0) {
Packit 38d9dc
        va_glx_error_message("failed to bind pixmap\n");
Packit 38d9dc
        return 0;
Packit 38d9dc
    }
Packit 38d9dc
Packit 38d9dc
    pSurfaceGLX->is_bound = 1;
Packit 38d9dc
    return 1;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Release GLX Pixmap from texture
Packit 38d9dc
static int unbind_pixmap(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
Packit 38d9dc
Packit 38d9dc
    if (!pSurfaceGLX->is_bound)
Packit 38d9dc
        return 1;
Packit 38d9dc
Packit 38d9dc
    x11_trap_errors();
Packit 38d9dc
    pOpenGLVTable->glx_release_tex_image(
Packit 38d9dc
        ctx->native_dpy,
Packit 38d9dc
        pSurfaceGLX->glx_pixmap,
Packit 38d9dc
        GLX_FRONT_LEFT_EXT
Packit 38d9dc
    );
Packit 38d9dc
    XSync(ctx->native_dpy, False);
Packit 38d9dc
    if (x11_untrap_errors() != 0) {
Packit 38d9dc
        va_glx_error_message("failed to release pixmap\n");
Packit 38d9dc
        return 0;
Packit 38d9dc
    }
Packit 38d9dc
Packit 38d9dc
    glBindTexture(GL_TEXTURE_2D, 0);
Packit 38d9dc
Packit 38d9dc
    pSurfaceGLX->is_bound = 0;
Packit 38d9dc
    return 1;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Render GLX Pixmap to texture
Packit 38d9dc
static void render_pixmap(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    const unsigned int w = pSurfaceGLX->width;
Packit 38d9dc
    const unsigned int h = pSurfaceGLX->height;
Packit 38d9dc
Packit 38d9dc
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
Packit 38d9dc
    glBegin(GL_QUADS);
Packit 38d9dc
    {
Packit 38d9dc
        glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0);
Packit 38d9dc
        glTexCoord2f(0.0f, 1.0f); glVertex2i(0, h);
Packit 38d9dc
        glTexCoord2f(1.0f, 1.0f); glVertex2i(w, h);
Packit 38d9dc
        glTexCoord2f(1.0f, 0.0f); glVertex2i(w, 0);
Packit 38d9dc
    }
Packit 38d9dc
    glEnd();
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Create offscreen surface
Packit 38d9dc
static int create_fbo_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
Packit 38d9dc
    GLuint fbo;
Packit 38d9dc
    GLenum status;
Packit 38d9dc
Packit 38d9dc
    pOpenGLVTable->gl_gen_framebuffers(1, &fbo);
Packit 38d9dc
    pOpenGLVTable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo);
Packit 38d9dc
    pOpenGLVTable->gl_framebuffer_texture_2d(
Packit 38d9dc
        GL_FRAMEBUFFER_EXT,
Packit 38d9dc
        GL_COLOR_ATTACHMENT0_EXT,
Packit 38d9dc
        GL_TEXTURE_2D,
Packit 38d9dc
        pSurfaceGLX->texture,
Packit 38d9dc
        0
Packit 38d9dc
    );
Packit 38d9dc
Packit 38d9dc
    status = pOpenGLVTable->gl_check_framebuffer_status(GL_DRAW_FRAMEBUFFER_EXT);
Packit 38d9dc
    pOpenGLVTable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, 0);
Packit 38d9dc
    if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
Packit 38d9dc
        return 0;
Packit 38d9dc
Packit 38d9dc
    pSurfaceGLX->fbo = fbo;
Packit 38d9dc
    return 1;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Destroy offscreen surface
Packit 38d9dc
static void destroy_fbo_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
Packit 38d9dc
Packit 38d9dc
    if (pSurfaceGLX->fbo) {
Packit 38d9dc
        pOpenGLVTable->gl_delete_framebuffers(1, &pSurfaceGLX->fbo);
Packit 38d9dc
        pSurfaceGLX->fbo = 0;
Packit 38d9dc
    }
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Setup matrices to match the FBO texture dimensions
Packit 38d9dc
static void fbo_enter(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
Packit 38d9dc
    const unsigned int width  = pSurfaceGLX->width;
Packit 38d9dc
    const unsigned int height = pSurfaceGLX->height;
Packit 38d9dc
Packit 38d9dc
    pOpenGLVTable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, pSurfaceGLX->fbo);
Packit 38d9dc
    glPushAttrib(GL_VIEWPORT_BIT);
Packit 38d9dc
    glMatrixMode(GL_PROJECTION);
Packit 38d9dc
    glPushMatrix();
Packit 38d9dc
    glLoadIdentity();
Packit 38d9dc
    glMatrixMode(GL_MODELVIEW);
Packit 38d9dc
    glPushMatrix();
Packit 38d9dc
    glLoadIdentity();
Packit 38d9dc
    glViewport(0, 0, width, height);
Packit 38d9dc
    glTranslatef(-1.0f, -1.0f, 0.0f);
Packit 38d9dc
    glScalef(2.0f / width, 2.0f / height, 1.0f);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Restore original OpenGL matrices
Packit 38d9dc
static void fbo_leave(VADriverContextP ctx)
Packit 38d9dc
{
Packit 38d9dc
    VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
Packit 38d9dc
Packit 38d9dc
    glPopAttrib();
Packit 38d9dc
    glMatrixMode(GL_PROJECTION);
Packit 38d9dc
    glPopMatrix();
Packit 38d9dc
    glMatrixMode(GL_MODELVIEW);
Packit 38d9dc
    glPopMatrix();
Packit 38d9dc
    pOpenGLVTable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, 0);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Check internal texture format is supported
Packit 38d9dc
static int is_supported_internal_format(GLenum format)
Packit 38d9dc
{
Packit 38d9dc
    /* XXX: we don't support other textures than RGBA */
Packit 38d9dc
    switch (format) {
Packit 38d9dc
    case 4:
Packit 38d9dc
    case GL_RGBA:
Packit 38d9dc
    case GL_RGBA8:
Packit 38d9dc
        return 1;
Packit 38d9dc
    }
Packit 38d9dc
    return 0;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Destroy VA/GLX surface
Packit 38d9dc
static void
Packit 38d9dc
destroy_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    unbind_pixmap(ctx, pSurfaceGLX);
Packit 38d9dc
    destroy_fbo_surface(ctx, pSurfaceGLX);
Packit 38d9dc
    destroy_tfp_surface(ctx, pSurfaceGLX);
Packit 38d9dc
    free(pSurfaceGLX);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
// Create VA/GLX surface
Packit 38d9dc
static VASurfaceGLXP
Packit 38d9dc
create_surface(VADriverContextP ctx, GLenum target, GLuint texture)
Packit 38d9dc
{
Packit 38d9dc
    VASurfaceGLXP pSurfaceGLX = NULL;
Packit 38d9dc
    unsigned int internal_format, border_width, width, height;
Packit 38d9dc
    int is_error = 1;
Packit 38d9dc
Packit 38d9dc
    pSurfaceGLX = malloc(sizeof(*pSurfaceGLX));
Packit 38d9dc
    if (!pSurfaceGLX)
Packit 38d9dc
        goto end;
Packit 38d9dc
Packit 38d9dc
    pSurfaceGLX->magic          = VA_SURFACE_GLX_MAGIC;
Packit 38d9dc
    pSurfaceGLX->target         = target;
Packit 38d9dc
    pSurfaceGLX->texture        = texture;
Packit 38d9dc
    pSurfaceGLX->surface        = VA_INVALID_SURFACE;
Packit 38d9dc
    pSurfaceGLX->gl_context     = NULL;
Packit 38d9dc
    pSurfaceGLX->is_bound       = 0;
Packit 38d9dc
    pSurfaceGLX->pixmap         = None;
Packit 38d9dc
    pSurfaceGLX->pix_texture    = 0;
Packit 38d9dc
    pSurfaceGLX->glx_pixmap     = None;
Packit 38d9dc
    pSurfaceGLX->fbo            = 0;
Packit 38d9dc
Packit 38d9dc
    glEnable(target);
Packit 38d9dc
    glBindTexture(target, texture);
Packit 38d9dc
    if (!gl_get_texture_param(GL_TEXTURE_INTERNAL_FORMAT, &internal_format))
Packit 38d9dc
        goto end;
Packit 38d9dc
    if (!is_supported_internal_format(internal_format))
Packit 38d9dc
        goto end;
Packit 38d9dc
Packit 38d9dc
    /* Check texture dimensions */
Packit 38d9dc
    if (!gl_get_texture_param(GL_TEXTURE_BORDER, &border_width))
Packit 38d9dc
        goto end;
Packit 38d9dc
    if (!gl_get_texture_param(GL_TEXTURE_WIDTH, &width))
Packit 38d9dc
        goto end;
Packit 38d9dc
    if (!gl_get_texture_param(GL_TEXTURE_HEIGHT, &height))
Packit 38d9dc
        goto end;
Packit 38d9dc
Packit 38d9dc
    width  -= 2 * border_width;
Packit 38d9dc
    height -= 2 * border_width;
Packit 38d9dc
    if (width == 0 || height == 0)
Packit 38d9dc
        goto end;
Packit 38d9dc
Packit 38d9dc
    pSurfaceGLX->width  = width;
Packit 38d9dc
    pSurfaceGLX->height = height;
Packit 38d9dc
Packit 38d9dc
    /* Create TFP objects */
Packit 38d9dc
    if (!create_tfp_surface(ctx, pSurfaceGLX))
Packit 38d9dc
        goto end;
Packit 38d9dc
Packit 38d9dc
    /* Create FBO objects */
Packit 38d9dc
    if (!create_fbo_surface(ctx, pSurfaceGLX))
Packit 38d9dc
        goto end;
Packit 38d9dc
Packit 38d9dc
    is_error = 0;
Packit 38d9dc
end:
Packit 38d9dc
    if (is_error && pSurfaceGLX) {
Packit 38d9dc
        destroy_surface(ctx, pSurfaceGLX);
Packit 38d9dc
        pSurfaceGLX = NULL;
Packit 38d9dc
    }
Packit 38d9dc
    return pSurfaceGLX;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
Packit 38d9dc
/* ========================================================================= */
Packit 38d9dc
/* === VA/GLX implementation from the driver (fordward calls)            === */
Packit 38d9dc
/* ========================================================================= */
Packit 38d9dc
Packit 38d9dc
#define INVOKE(ctx, func, args) do {                    \
Packit 38d9dc
        VADriverVTableGLXP vtable = (ctx)->vtable_glx;  \
Packit 38d9dc
        if (!vtable->va##func##GLX)                     \
Packit 38d9dc
            return VA_STATUS_ERROR_UNIMPLEMENTED;       \
Packit 38d9dc
                                                        \
Packit 38d9dc
        VAStatus status = vtable->va##func##GLX args;   \
Packit 38d9dc
        if (status != VA_STATUS_SUCCESS)                \
Packit 38d9dc
            return status;                              \
Packit 38d9dc
    } while (0)
Packit 38d9dc
Packit 38d9dc
static VAStatus
Packit 38d9dc
vaCreateSurfaceGLX_impl_driver(
Packit 38d9dc
    VADriverContextP    ctx,
Packit 38d9dc
    GLenum              target,
Packit 38d9dc
    GLuint              texture,
Packit 38d9dc
    void              **gl_surface
Packit 38d9dc
)
Packit 38d9dc
{
Packit 38d9dc
    INVOKE(ctx, CreateSurface, (ctx, target, texture, gl_surface));
Packit 38d9dc
    return VA_STATUS_SUCCESS;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static VAStatus
Packit 38d9dc
vaDestroySurfaceGLX_impl_driver(VADriverContextP ctx, void *gl_surface)
Packit 38d9dc
{
Packit 38d9dc
    INVOKE(ctx, DestroySurface, (ctx, gl_surface));
Packit 38d9dc
    return VA_STATUS_SUCCESS;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static VAStatus
Packit 38d9dc
vaCopySurfaceGLX_impl_driver(
Packit 38d9dc
    VADriverContextP    ctx,
Packit 38d9dc
    void               *gl_surface,
Packit 38d9dc
    VASurfaceID         surface,
Packit 38d9dc
    unsigned int        flags
Packit 38d9dc
)
Packit 38d9dc
{
Packit 38d9dc
    INVOKE(ctx, CopySurface, (ctx, gl_surface, surface, flags));
Packit 38d9dc
    return VA_STATUS_SUCCESS;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
#undef INVOKE
Packit 38d9dc
Packit 38d9dc
Packit 38d9dc
/* ========================================================================= */
Packit 38d9dc
/* === VA/GLX implementation from libVA (generic and suboptimal path)    === */
Packit 38d9dc
/* ========================================================================= */
Packit 38d9dc
Packit 38d9dc
#define INIT_SURFACE(surface, surface_arg) do {         \
Packit 38d9dc
        surface = (VASurfaceGLXP)(surface_arg);         \
Packit 38d9dc
        if (!check_surface(surface))                    \
Packit 38d9dc
            return VA_STATUS_ERROR_INVALID_SURFACE;     \
Packit 38d9dc
    } while (0)
Packit 38d9dc
Packit 38d9dc
// Check VASurfaceGLX is valid
Packit 38d9dc
static inline int check_surface(VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    return pSurfaceGLX && pSurfaceGLX->magic == VA_SURFACE_GLX_MAGIC;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static VAStatus
Packit 38d9dc
vaCreateSurfaceGLX_impl_libva(
Packit 38d9dc
    VADriverContextP    ctx,
Packit 38d9dc
    GLenum              target,
Packit 38d9dc
    GLuint              texture,
Packit 38d9dc
    void              **gl_surface
Packit 38d9dc
)
Packit 38d9dc
{
Packit 38d9dc
    VASurfaceGLXP pSurfaceGLX;
Packit 38d9dc
    struct OpenGLContextState old_cs, *new_cs;
Packit 38d9dc
Packit 38d9dc
    gl_get_current_context(&old_cs);
Packit 38d9dc
    new_cs = gl_create_context(ctx, &old_cs);
Packit 38d9dc
    if (!new_cs)
Packit 38d9dc
        goto error;
Packit 38d9dc
    if (!gl_set_current_context(new_cs, NULL))
Packit 38d9dc
        goto error;
Packit 38d9dc
Packit 38d9dc
    pSurfaceGLX = create_surface(ctx, target, texture);
Packit 38d9dc
    if (!pSurfaceGLX)
Packit 38d9dc
        goto error;
Packit 38d9dc
Packit 38d9dc
    pSurfaceGLX->gl_context = new_cs;
Packit 38d9dc
    *gl_surface = pSurfaceGLX;
Packit 38d9dc
Packit 38d9dc
    gl_set_current_context(&old_cs, NULL);
Packit 38d9dc
    return VA_STATUS_SUCCESS;
Packit 38d9dc
Packit 38d9dc
error:
Packit 38d9dc
    if (new_cs)
Packit 38d9dc
        gl_destroy_context(new_cs);
Packit 38d9dc
Packit 38d9dc
    return VA_STATUS_ERROR_ALLOCATION_FAILED;    
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static VAStatus
Packit 38d9dc
vaDestroySurfaceGLX_impl_libva(VADriverContextP ctx, void *gl_surface)
Packit 38d9dc
{
Packit 38d9dc
    VASurfaceGLXP pSurfaceGLX;
Packit Service 32d048
    struct OpenGLContextState old_cs = {0}, *new_cs;
Packit 38d9dc
Packit 38d9dc
    INIT_SURFACE(pSurfaceGLX, gl_surface);
Packit 38d9dc
Packit 38d9dc
    new_cs = pSurfaceGLX->gl_context;
Packit 38d9dc
    if (!gl_set_current_context(new_cs, &old_cs))
Packit 38d9dc
        return VA_STATUS_ERROR_OPERATION_FAILED;
Packit 38d9dc
Packit 38d9dc
    destroy_surface(ctx, pSurfaceGLX);
Packit 38d9dc
Packit 38d9dc
    gl_destroy_context(new_cs);
Packit 38d9dc
    gl_set_current_context(&old_cs, NULL);
Packit 38d9dc
    return VA_STATUS_SUCCESS;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static inline VAStatus
Packit 38d9dc
deassociate_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    if (!unbind_pixmap(ctx, pSurfaceGLX))
Packit 38d9dc
        return VA_STATUS_ERROR_OPERATION_FAILED;
Packit 38d9dc
Packit 38d9dc
    pSurfaceGLX->surface = VA_INVALID_SURFACE;
Packit 38d9dc
    return VA_STATUS_SUCCESS;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static VAStatus
Packit 38d9dc
associate_surface(
Packit 38d9dc
    VADriverContextP    ctx,
Packit 38d9dc
    VASurfaceGLXP       pSurfaceGLX,
Packit 38d9dc
    VASurfaceID         surface,
Packit 38d9dc
    unsigned int        flags
Packit 38d9dc
)
Packit 38d9dc
{
Packit 38d9dc
    VAStatus status;
Packit 38d9dc
Packit 38d9dc
    /* XXX: optimise case where we are associating the same VA surface
Packit 38d9dc
       as before an no changed occurred to it */
Packit 38d9dc
    status = deassociate_surface(ctx, pSurfaceGLX);
Packit 38d9dc
    if (status != VA_STATUS_SUCCESS)
Packit 38d9dc
        return status;
Packit 38d9dc
Packit 38d9dc
    x11_trap_errors();
Packit 38d9dc
    status = ctx->vtable->vaPutSurface(
Packit 38d9dc
        ctx,
Packit 38d9dc
        surface,
Packit 38d9dc
        (void *)pSurfaceGLX->pixmap,
Packit 38d9dc
        0, 0, pSurfaceGLX->width, pSurfaceGLX->height,
Packit 38d9dc
        0, 0, pSurfaceGLX->width, pSurfaceGLX->height,
Packit 38d9dc
        NULL, 0,
Packit 38d9dc
        flags
Packit 38d9dc
    );
Packit 38d9dc
    XSync(ctx->native_dpy, False);
Packit 38d9dc
    if (x11_untrap_errors() != 0)
Packit 38d9dc
        return VA_STATUS_ERROR_OPERATION_FAILED;
Packit 38d9dc
    if (status != VA_STATUS_SUCCESS)
Packit 38d9dc
        return status;
Packit 38d9dc
Packit 38d9dc
    pSurfaceGLX->surface = surface;
Packit 38d9dc
    return VA_STATUS_SUCCESS;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static inline VAStatus
Packit 38d9dc
sync_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    if (pSurfaceGLX->surface == VA_INVALID_SURFACE)
Packit 38d9dc
        return VA_STATUS_ERROR_INVALID_SURFACE;
Packit 38d9dc
Packit 38d9dc
    return ctx->vtable->vaSyncSurface(ctx, pSurfaceGLX->surface);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static inline VAStatus
Packit 38d9dc
begin_render_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    VAStatus status;
Packit 38d9dc
Packit 38d9dc
    status = sync_surface(ctx, pSurfaceGLX);
Packit 38d9dc
    if (status != VA_STATUS_SUCCESS)
Packit 38d9dc
        return status;
Packit 38d9dc
Packit 38d9dc
    if (!bind_pixmap(ctx, pSurfaceGLX))
Packit 38d9dc
        return VA_STATUS_ERROR_OPERATION_FAILED;
Packit 38d9dc
Packit 38d9dc
    return VA_STATUS_SUCCESS;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static inline VAStatus
Packit 38d9dc
end_render_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
Packit 38d9dc
{
Packit 38d9dc
    if (!unbind_pixmap(ctx, pSurfaceGLX))
Packit 38d9dc
        return VA_STATUS_ERROR_OPERATION_FAILED;
Packit 38d9dc
Packit 38d9dc
    return VA_STATUS_SUCCESS;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static VAStatus
Packit 38d9dc
copy_surface(
Packit 38d9dc
    VADriverContextP    ctx,
Packit 38d9dc
    VASurfaceGLXP       pSurfaceGLX,
Packit 38d9dc
    VASurfaceID         surface,
Packit 38d9dc
    unsigned int        flags
Packit 38d9dc
)
Packit 38d9dc
{
Packit 38d9dc
    VAStatus status;
Packit 38d9dc
Packit 38d9dc
    /* Associate VA surface */
Packit 38d9dc
    status = associate_surface(ctx, pSurfaceGLX, surface, flags);
Packit 38d9dc
    if (status != VA_STATUS_SUCCESS)
Packit 38d9dc
        return status;
Packit 38d9dc
Packit 38d9dc
    /* Render to FBO */
Packit 38d9dc
    fbo_enter(ctx, pSurfaceGLX);
Packit 38d9dc
    status = begin_render_surface(ctx, pSurfaceGLX);
Packit 38d9dc
    if (status == VA_STATUS_SUCCESS) {
Packit 38d9dc
        render_pixmap(ctx, pSurfaceGLX);
Packit 38d9dc
        status = end_render_surface(ctx, pSurfaceGLX);
Packit 38d9dc
    }
Packit 38d9dc
    fbo_leave(ctx);
Packit 38d9dc
    if (status != VA_STATUS_SUCCESS)
Packit 38d9dc
        return status;
Packit 38d9dc
Packit 38d9dc
    return deassociate_surface(ctx, pSurfaceGLX);
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
static VAStatus
Packit 38d9dc
vaCopySurfaceGLX_impl_libva(
Packit 38d9dc
    VADriverContextP    ctx,
Packit 38d9dc
    void               *gl_surface,
Packit 38d9dc
    VASurfaceID         surface,
Packit 38d9dc
    unsigned int        flags
Packit 38d9dc
)
Packit 38d9dc
{
Packit 38d9dc
    VASurfaceGLXP pSurfaceGLX;
Packit 38d9dc
    VAStatus status;
Packit Service 32d048
    struct OpenGLContextState old_cs = {0};
Packit 38d9dc
Packit 38d9dc
    INIT_SURFACE(pSurfaceGLX, gl_surface);
Packit 38d9dc
Packit 38d9dc
    if (!gl_set_current_context(pSurfaceGLX->gl_context, &old_cs))
Packit 38d9dc
        return VA_STATUS_ERROR_OPERATION_FAILED;
Packit 38d9dc
Packit 38d9dc
    status = copy_surface(ctx, pSurfaceGLX, surface, flags);
Packit 38d9dc
Packit 38d9dc
    gl_set_current_context(&old_cs, NULL);
Packit 38d9dc
    return status;
Packit 38d9dc
}
Packit 38d9dc
Packit 38d9dc
#undef INIT_SURFACE
Packit 38d9dc
Packit 38d9dc
Packit 38d9dc
/* ========================================================================= */
Packit 38d9dc
/* === Private VA/GLX vtable initialization                              === */
Packit 38d9dc
/* ========================================================================= */
Packit 38d9dc
Packit 38d9dc
// Initialize GLX driver context
Packit 38d9dc
VAStatus va_glx_init_context(VADriverContextP ctx)
Packit 38d9dc
{
Packit 38d9dc
    VADriverContextGLXP glx_ctx = VA_DRIVER_CONTEXT_GLX(ctx);
Packit 38d9dc
    VADriverVTableGLXP  vtable  = &glx_ctx->vtable;
Packit 38d9dc
    int glx_major, glx_minor;
Packit 38d9dc
Packit 38d9dc
    if (glx_ctx->is_initialized)
Packit 38d9dc
        return VA_STATUS_SUCCESS;
Packit 38d9dc
Packit 38d9dc
    if (ctx->vtable_glx && ctx->vtable_glx->vaCopySurfaceGLX) {
Packit 38d9dc
        vtable->vaCreateSurfaceGLX      = vaCreateSurfaceGLX_impl_driver;
Packit 38d9dc
        vtable->vaDestroySurfaceGLX     = vaDestroySurfaceGLX_impl_driver;
Packit 38d9dc
        vtable->vaCopySurfaceGLX        = vaCopySurfaceGLX_impl_driver;
Packit 38d9dc
    }
Packit 38d9dc
    else {
Packit 38d9dc
        vtable->vaCreateSurfaceGLX      = vaCreateSurfaceGLX_impl_libva;
Packit 38d9dc
        vtable->vaDestroySurfaceGLX     = vaDestroySurfaceGLX_impl_libva;
Packit 38d9dc
        vtable->vaCopySurfaceGLX        = vaCopySurfaceGLX_impl_libva;
Packit 38d9dc
Packit 38d9dc
        if (!glXQueryVersion(ctx->native_dpy, &glx_major, &glx_minor))
Packit 38d9dc
            return VA_STATUS_ERROR_UNIMPLEMENTED;
Packit 38d9dc
Packit 38d9dc
        if (!check_tfp_extensions(ctx) || !load_tfp_extensions(ctx))
Packit 38d9dc
            return VA_STATUS_ERROR_UNIMPLEMENTED;
Packit 38d9dc
Packit 38d9dc
        if (!check_fbo_extensions(ctx) || !load_fbo_extensions(ctx))
Packit 38d9dc
            return VA_STATUS_ERROR_UNIMPLEMENTED;
Packit 38d9dc
    }
Packit 38d9dc
Packit 38d9dc
    glx_ctx->is_initialized = 1;
Packit 38d9dc
    return VA_STATUS_SUCCESS;
Packit 38d9dc
}