2 * Copyright (C) 2009 Splitted-Desktop Systems. All Rights Reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sub license, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include "va_glx_private.h"
28 #include "va_glx_impl.h"
36 static void va_glx_error_message(const char *format, ...)
39 va_start(args, format);
40 fprintf(stderr, "libva-glx error: ");
41 vfprintf(stderr, format, args);
46 static int x11_error_code = 0;
47 static int (*old_error_handler)(Display *, XErrorEvent *);
49 static int error_handler(Display *dpy, XErrorEvent *error)
51 x11_error_code = error->error_code;
55 static void x11_trap_errors(void)
58 old_error_handler = XSetErrorHandler(error_handler);
61 static int x11_untrap_errors(void)
63 XSetErrorHandler(old_error_handler);
64 return x11_error_code;
67 // Returns a string representation of an OpenGL error
68 static const char *gl_get_error_string(GLenum error)
75 { GL_NO_ERROR, "no error" },
76 { GL_INVALID_ENUM, "invalid enumerant" },
77 { GL_INVALID_VALUE, "invalid value" },
78 { GL_INVALID_OPERATION, "invalid operation" },
79 { GL_STACK_OVERFLOW, "stack overflow" },
80 { GL_STACK_UNDERFLOW, "stack underflow" },
81 { GL_OUT_OF_MEMORY, "out of memory" },
82 #ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
83 { GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "invalid framebuffer operation" },
89 for (i = 0; gl_errors[i].str; i++) {
90 if (gl_errors[i].val == error)
91 return gl_errors[i].str;
96 static inline int gl_do_check_error(int report)
100 while ((error = glGetError()) != GL_NO_ERROR) {
102 va_glx_error_message("glError: %s caught\n",
103 gl_get_error_string(error));
109 static inline void gl_purge_errors(void)
111 gl_do_check_error(0);
114 static inline int gl_check_error(void)
116 return gl_do_check_error(1);
119 // glGetTexLevelParameteriv() wrapper
120 static int gl_get_texture_param(GLenum param, unsigned int *pval)
125 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, param, &val);
126 if (gl_check_error())
133 // Returns the OpenGL VTable
134 static inline VAOpenGLVTableP gl_get_vtable(VADriverContextP ctx)
136 return &VA_DRIVER_CONTEXT_GLX(ctx)->gl_vtable;
139 // Lookup for a GLX function
140 typedef void (*GLFuncPtr)(void);
141 typedef GLFuncPtr (*GLXGetProcAddressProc)(const char *);
143 static GLFuncPtr get_proc_address_default(const char *name)
148 static GLXGetProcAddressProc get_proc_address_func(void)
150 GLXGetProcAddressProc get_proc_func;
153 get_proc_func = (GLXGetProcAddressProc)
154 dlsym(RTLD_DEFAULT, "glXGetProcAddress");
156 return get_proc_func;
158 get_proc_func = (GLXGetProcAddressProc)
159 dlsym(RTLD_DEFAULT, "glXGetProcAddressARB");
161 return get_proc_func;
163 return get_proc_address_default;
166 static inline GLFuncPtr get_proc_address(const char *name)
168 static GLXGetProcAddressProc get_proc_func = NULL;
170 get_proc_func = get_proc_address_func();
171 return get_proc_func(name);
174 // Check for GLX extensions (TFP, FBO)
175 static int check_extension(const char *name, const char *ext)
183 end = ext + strlen(ext);
184 name_len = strlen(name);
186 n = strcspn(ext, " ");
187 if (n == name_len && strncmp(name, ext, n) == 0)
194 static int check_extension3(const char *name)
197 PFNGLGETSTRINGIPROC glGetStringi = 0;
199 glGetStringi = (PFNGLGETSTRINGIPROC) get_proc_address("glGetStringi");
204 glGetIntegerv(GL_NUM_EXTENSIONS, &nbExtensions);
205 for(i = 0; i < nbExtensions; i++)
207 const GLubyte *strExtension = glGetStringi(GL_EXTENSIONS, i);
208 if(strcmp(strExtension, (const GLubyte *)name) == 0)
215 static int check_tfp_extensions(VADriverContextP ctx)
217 const char *gl_extensions;
218 const char *glx_extensions;
220 gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
221 if (!check_extension("GL_ARB_texture_non_power_of_two", gl_extensions) && !check_extension3("GL_ARB_texture_non_power_of_two"))
224 glx_extensions = glXQueryExtensionsString(ctx->native_dpy, ctx->x11_screen);
225 if (!check_extension("GLX_EXT_texture_from_pixmap", glx_extensions))
231 static int check_fbo_extensions(VADriverContextP ctx)
233 const char *gl_extensions;
235 gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
236 if (check_extension("GL_ARB_framebuffer_object", gl_extensions) || check_extension3("GL_ARB_framebuffer_object"))
238 if (check_extension("GL_EXT_framebuffer_object", gl_extensions) || check_extension3("GL_EXT_framebuffer_object"))
244 // Load GLX extensions
245 static int load_tfp_extensions(VADriverContextP ctx)
247 VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
249 pOpenGLVTable->glx_create_pixmap = (PFNGLXCREATEPIXMAPPROC)
250 get_proc_address("glXCreatePixmap");
251 if (!pOpenGLVTable->glx_create_pixmap)
253 pOpenGLVTable->glx_destroy_pixmap = (PFNGLXDESTROYPIXMAPPROC)
254 get_proc_address("glXDestroyPixmap");
255 if (!pOpenGLVTable->glx_destroy_pixmap)
257 pOpenGLVTable->glx_bind_tex_image = (PFNGLXBINDTEXIMAGEEXTPROC)
258 get_proc_address("glXBindTexImageEXT");
259 if (!pOpenGLVTable->glx_bind_tex_image)
261 pOpenGLVTable->glx_release_tex_image = (PFNGLXRELEASETEXIMAGEEXTPROC)
262 get_proc_address("glXReleaseTexImageEXT");
263 if (!pOpenGLVTable->glx_release_tex_image)
268 static int load_fbo_extensions(VADriverContextP ctx)
270 VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
272 pOpenGLVTable->gl_gen_framebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC)
273 get_proc_address("glGenFramebuffersEXT");
274 if (!pOpenGLVTable->gl_gen_framebuffers)
276 pOpenGLVTable->gl_delete_framebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
277 get_proc_address("glDeleteFramebuffersEXT");
278 if (!pOpenGLVTable->gl_delete_framebuffers)
280 pOpenGLVTable->gl_bind_framebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC)
281 get_proc_address("glBindFramebufferEXT");
282 if (!pOpenGLVTable->gl_bind_framebuffer)
284 pOpenGLVTable->gl_gen_renderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC)
285 get_proc_address("glGenRenderbuffersEXT");
286 if (!pOpenGLVTable->gl_gen_renderbuffers)
288 pOpenGLVTable->gl_delete_renderbuffers = (PFNGLDELETERENDERBUFFERSEXTPROC)
289 get_proc_address("glDeleteRenderbuffersEXT");
290 if (!pOpenGLVTable->gl_delete_renderbuffers)
292 pOpenGLVTable->gl_bind_renderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC)
293 get_proc_address("glBindRenderbufferEXT");
294 if (!pOpenGLVTable->gl_bind_renderbuffer)
296 pOpenGLVTable->gl_renderbuffer_storage = (PFNGLRENDERBUFFERSTORAGEEXTPROC)
297 get_proc_address("glRenderbufferStorageEXT");
298 if (!pOpenGLVTable->gl_renderbuffer_storage)
300 pOpenGLVTable->gl_framebuffer_renderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)
301 get_proc_address("glFramebufferRenderbufferEXT");
302 if (!pOpenGLVTable->gl_framebuffer_renderbuffer)
304 pOpenGLVTable->gl_framebuffer_texture_2d = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
305 get_proc_address("glFramebufferTexture2DEXT");
306 if (!pOpenGLVTable->gl_framebuffer_texture_2d)
308 pOpenGLVTable->gl_check_framebuffer_status = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
309 get_proc_address("glCheckFramebufferStatusEXT");
310 if (!pOpenGLVTable->gl_check_framebuffer_status)
316 /* ========================================================================= */
317 /* === VA/GLX helpers === */
318 /* ========================================================================= */
320 // OpenGL context state
321 typedef struct OpenGLContextState *OpenGLContextStateP;
323 struct OpenGLContextState {
330 gl_destroy_context(OpenGLContextStateP cs)
335 if (cs->display && cs->context) {
336 if (glXGetCurrentContext() == cs->context)
337 glXMakeCurrent(cs->display, None, NULL);
338 glXDestroyContext(cs->display, cs->context);
345 static OpenGLContextStateP
346 gl_create_context(VADriverContextP ctx, OpenGLContextStateP parent)
348 OpenGLContextStateP cs;
349 GLXFBConfig *fbconfigs = NULL;
350 int fbconfig_id, val, n, n_fbconfigs;
353 static GLint fbconfig_attrs[] = {
354 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
355 GLX_RENDER_TYPE, GLX_RGBA_BIT,
356 GLX_DOUBLEBUFFER, True,
363 cs = malloc(sizeof(*cs));
368 cs->display = parent->display;
369 cs->window = parent->window;
372 cs->display = ctx->native_dpy;
377 if (parent && parent->context) {
378 status = glXQueryContext(
381 GLX_FBCONFIG_ID, &fbconfig_id
383 if (status != Success)
386 if (fbconfig_id == GLX_DONT_CARE)
387 goto choose_fbconfig;
389 fbconfigs = glXGetFBConfigs(
391 DefaultScreen(parent->display),
397 /* Find out a GLXFBConfig compatible with the parent context */
398 for (n = 0; n < n_fbconfigs; n++) {
399 status = glXGetFBConfigAttrib(
402 GLX_FBCONFIG_ID, &val
404 if (status == Success && val == fbconfig_id)
407 if (n == n_fbconfigs)
412 fbconfigs = glXChooseFBConfig(
415 fbconfig_attrs, &n_fbconfigs
420 /* Select the first one */
424 cs->context = glXCreateNewContext(
428 parent ? parent->context : NULL,
435 gl_destroy_context(cs);
443 static void gl_get_current_context(OpenGLContextStateP cs)
445 cs->display = glXGetCurrentDisplay();
446 cs->window = glXGetCurrentDrawable();
447 cs->context = glXGetCurrentContext();
451 gl_set_current_context(OpenGLContextStateP new_cs, OpenGLContextStateP old_cs)
453 /* If display is NULL, this could be that new_cs was retrieved from
454 gl_get_current_context() with none set previously. If that case,
455 the other fields are also NULL and we don't return an error */
456 if (!new_cs->display)
457 return !new_cs->window && !new_cs->context;
460 if (old_cs == new_cs)
462 gl_get_current_context(old_cs);
463 if (old_cs->display == new_cs->display &&
464 old_cs->window == new_cs->window &&
465 old_cs->context == new_cs->context)
468 return glXMakeCurrent(new_cs->display, new_cs->window, new_cs->context);
471 /** Unique VASurfaceGLX identifier */
472 #define VA_SURFACE_GLX_MAGIC VA_FOURCC('V','A','G','L')
474 struct VASurfaceGLX {
475 uint32_t magic; ///< Magic number identifying a VASurfaceGLX
476 GLenum target; ///< GL target to which the texture is bound
477 GLuint texture; ///< GL texture
478 VASurfaceID surface; ///< Associated VA surface
481 OpenGLContextStateP gl_context;
485 GLXPixmap glx_pixmap;
489 // Create Pixmaps for GLX texture-from-pixmap extension
490 static int create_tfp_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
492 VAOpenGLVTableP const pOpenGLVTable = gl_get_vtable(ctx);
493 const unsigned int width = pSurfaceGLX->width;
494 const unsigned int height = pSurfaceGLX->height;
495 Pixmap pixmap = None;
496 GLXFBConfig *fbconfig = NULL;
497 GLXPixmap glx_pixmap = None;
499 XWindowAttributes wattr;
501 int n_fbconfig_attrs;
503 root_window = RootWindow(ctx->native_dpy, ctx->x11_screen);
504 XGetWindowAttributes(ctx->native_dpy, root_window, &wattr);
505 if (wattr.depth != 24 && wattr.depth != 32)
507 pixmap = XCreatePixmap(
516 pSurfaceGLX->pixmap = pixmap;
518 int fbconfig_attrs[32] = {
519 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
520 GLX_DOUBLEBUFFER, GL_TRUE,
521 GLX_RENDER_TYPE, GLX_RGBA_BIT,
522 GLX_X_RENDERABLE, GL_TRUE,
523 GLX_Y_INVERTED_EXT, GL_TRUE,
528 * depth test isn't enabled in the implementaion of VA GLX,
529 * so depth buffer is unnecessary. However to workaround a
530 * bug in older verson of xorg-server, always require a depth
533 * See https://bugs.freedesktop.org/show_bug.cgi?id=76755
538 for (attrib = fbconfig_attrs; *attrib != GL_NONE; attrib += 2)
540 if (wattr.depth == 32) {
541 *attrib++ = GLX_ALPHA_SIZE; *attrib++ = 8;
542 *attrib++ = GLX_BIND_TO_TEXTURE_RGBA_EXT; *attrib++ = GL_TRUE;
545 *attrib++ = GLX_BIND_TO_TEXTURE_RGB_EXT; *attrib++ = GL_TRUE;
549 fbconfig = glXChooseFBConfig(
558 int pixmap_attrs[10] = {
559 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
560 GLX_MIPMAP_TEXTURE_EXT, GL_FALSE,
563 for (attrib = pixmap_attrs; *attrib != GL_NONE; attrib += 2)
565 *attrib++ = GLX_TEXTURE_FORMAT_EXT;
566 if (wattr.depth == 32)
567 *attrib++ = GLX_TEXTURE_FORMAT_RGBA_EXT;
569 *attrib++ = GLX_TEXTURE_FORMAT_RGB_EXT;
573 glx_pixmap = pOpenGLVTable->glx_create_pixmap(
580 if (x11_untrap_errors() != 0)
582 pSurfaceGLX->glx_pixmap = glx_pixmap;
584 glGenTextures(1, &pSurfaceGLX->pix_texture);
585 glBindTexture(GL_TEXTURE_2D, pSurfaceGLX->pix_texture);
586 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
587 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
591 // Destroy Pixmaps used for TFP
592 static void destroy_tfp_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
594 VAOpenGLVTableP const pOpenGLVTable = gl_get_vtable(ctx);
596 if (pSurfaceGLX->pix_texture) {
597 glDeleteTextures(1, &pSurfaceGLX->pix_texture);
598 pSurfaceGLX->pix_texture = 0;
601 if (pSurfaceGLX->glx_pixmap) {
602 pOpenGLVTable->glx_destroy_pixmap(ctx->native_dpy, pSurfaceGLX->glx_pixmap);
603 pSurfaceGLX->glx_pixmap = None;
606 if (pSurfaceGLX->pixmap) {
607 XFreePixmap(ctx->native_dpy, pSurfaceGLX->pixmap);
608 pSurfaceGLX->pixmap = None;
612 // Bind GLX Pixmap to texture
613 static int bind_pixmap(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
615 VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
617 if (pSurfaceGLX->is_bound)
620 glBindTexture(GL_TEXTURE_2D, pSurfaceGLX->pix_texture);
623 pOpenGLVTable->glx_bind_tex_image(
625 pSurfaceGLX->glx_pixmap,
629 XSync(ctx->native_dpy, False);
630 if (x11_untrap_errors() != 0) {
631 va_glx_error_message("failed to bind pixmap\n");
635 pSurfaceGLX->is_bound = 1;
639 // Release GLX Pixmap from texture
640 static int unbind_pixmap(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
642 VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
644 if (!pSurfaceGLX->is_bound)
648 pOpenGLVTable->glx_release_tex_image(
650 pSurfaceGLX->glx_pixmap,
653 XSync(ctx->native_dpy, False);
654 if (x11_untrap_errors() != 0) {
655 va_glx_error_message("failed to release pixmap\n");
659 glBindTexture(GL_TEXTURE_2D, 0);
661 pSurfaceGLX->is_bound = 0;
665 // Render GLX Pixmap to texture
666 static void render_pixmap(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
668 const unsigned int w = pSurfaceGLX->width;
669 const unsigned int h = pSurfaceGLX->height;
671 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
674 glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0);
675 glTexCoord2f(0.0f, 1.0f); glVertex2i(0, h);
676 glTexCoord2f(1.0f, 1.0f); glVertex2i(w, h);
677 glTexCoord2f(1.0f, 0.0f); glVertex2i(w, 0);
682 // Create offscreen surface
683 static int create_fbo_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
685 VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
689 pOpenGLVTable->gl_gen_framebuffers(1, &fbo);
690 pOpenGLVTable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo);
691 pOpenGLVTable->gl_framebuffer_texture_2d(
693 GL_COLOR_ATTACHMENT0_EXT,
695 pSurfaceGLX->texture,
699 status = pOpenGLVTable->gl_check_framebuffer_status(GL_DRAW_FRAMEBUFFER_EXT);
700 pOpenGLVTable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, 0);
701 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
704 pSurfaceGLX->fbo = fbo;
708 // Destroy offscreen surface
709 static void destroy_fbo_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
711 VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
713 if (pSurfaceGLX->fbo) {
714 pOpenGLVTable->gl_delete_framebuffers(1, &pSurfaceGLX->fbo);
715 pSurfaceGLX->fbo = 0;
719 // Setup matrices to match the FBO texture dimensions
720 static void fbo_enter(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
722 VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
723 const unsigned int width = pSurfaceGLX->width;
724 const unsigned int height = pSurfaceGLX->height;
726 pOpenGLVTable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, pSurfaceGLX->fbo);
727 glPushAttrib(GL_VIEWPORT_BIT);
728 glMatrixMode(GL_PROJECTION);
731 glMatrixMode(GL_MODELVIEW);
734 glViewport(0, 0, width, height);
735 glTranslatef(-1.0f, -1.0f, 0.0f);
736 glScalef(2.0f / width, 2.0f / height, 1.0f);
739 // Restore original OpenGL matrices
740 static void fbo_leave(VADriverContextP ctx)
742 VAOpenGLVTableP pOpenGLVTable = gl_get_vtable(ctx);
745 glMatrixMode(GL_PROJECTION);
747 glMatrixMode(GL_MODELVIEW);
749 pOpenGLVTable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, 0);
752 // Check internal texture format is supported
753 static int is_supported_internal_format(GLenum format)
755 /* XXX: we don't support other textures than RGBA */
765 // Destroy VA/GLX surface
767 destroy_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
769 unbind_pixmap(ctx, pSurfaceGLX);
770 destroy_fbo_surface(ctx, pSurfaceGLX);
771 destroy_tfp_surface(ctx, pSurfaceGLX);
775 // Create VA/GLX surface
777 create_surface(VADriverContextP ctx, GLenum target, GLuint texture)
779 VASurfaceGLXP pSurfaceGLX = NULL;
780 unsigned int internal_format, border_width, width, height;
783 pSurfaceGLX = malloc(sizeof(*pSurfaceGLX));
787 pSurfaceGLX->magic = VA_SURFACE_GLX_MAGIC;
788 pSurfaceGLX->target = target;
789 pSurfaceGLX->texture = texture;
790 pSurfaceGLX->surface = VA_INVALID_SURFACE;
791 pSurfaceGLX->gl_context = NULL;
792 pSurfaceGLX->is_bound = 0;
793 pSurfaceGLX->pixmap = None;
794 pSurfaceGLX->pix_texture = 0;
795 pSurfaceGLX->glx_pixmap = None;
796 pSurfaceGLX->fbo = 0;
799 glBindTexture(target, texture);
800 if (!gl_get_texture_param(GL_TEXTURE_INTERNAL_FORMAT, &internal_format))
802 if (!is_supported_internal_format(internal_format))
805 /* Check texture dimensions */
806 if (!gl_get_texture_param(GL_TEXTURE_BORDER, &border_width))
808 if (!gl_get_texture_param(GL_TEXTURE_WIDTH, &width))
810 if (!gl_get_texture_param(GL_TEXTURE_HEIGHT, &height))
813 width -= 2 * border_width;
814 height -= 2 * border_width;
815 if (width == 0 || height == 0)
818 pSurfaceGLX->width = width;
819 pSurfaceGLX->height = height;
821 /* Create TFP objects */
822 if (!create_tfp_surface(ctx, pSurfaceGLX))
825 /* Create FBO objects */
826 if (!create_fbo_surface(ctx, pSurfaceGLX))
831 if (is_error && pSurfaceGLX) {
832 destroy_surface(ctx, pSurfaceGLX);
839 /* ========================================================================= */
840 /* === VA/GLX implementation from the driver (fordward calls) === */
841 /* ========================================================================= */
843 #define INVOKE(ctx, func, args) do { \
844 VADriverVTableGLXP vtable = (ctx)->vtable_glx; \
845 if (!vtable->va##func##GLX) \
846 return VA_STATUS_ERROR_UNIMPLEMENTED; \
848 VAStatus status = vtable->va##func##GLX args; \
849 if (status != VA_STATUS_SUCCESS) \
854 vaCreateSurfaceGLX_impl_driver(
855 VADriverContextP ctx,
861 INVOKE(ctx, CreateSurface, (ctx, target, texture, gl_surface));
862 return VA_STATUS_SUCCESS;
866 vaDestroySurfaceGLX_impl_driver(VADriverContextP ctx, void *gl_surface)
868 INVOKE(ctx, DestroySurface, (ctx, gl_surface));
869 return VA_STATUS_SUCCESS;
873 vaCopySurfaceGLX_impl_driver(
874 VADriverContextP ctx,
880 INVOKE(ctx, CopySurface, (ctx, gl_surface, surface, flags));
881 return VA_STATUS_SUCCESS;
887 /* ========================================================================= */
888 /* === VA/GLX implementation from libVA (generic and suboptimal path) === */
889 /* ========================================================================= */
891 #define INIT_SURFACE(surface, surface_arg) do { \
892 surface = (VASurfaceGLXP)(surface_arg); \
893 if (!check_surface(surface)) \
894 return VA_STATUS_ERROR_INVALID_SURFACE; \
897 // Check VASurfaceGLX is valid
898 static inline int check_surface(VASurfaceGLXP pSurfaceGLX)
900 return pSurfaceGLX && pSurfaceGLX->magic == VA_SURFACE_GLX_MAGIC;
904 vaCreateSurfaceGLX_impl_libva(
905 VADriverContextP ctx,
911 VASurfaceGLXP pSurfaceGLX;
912 struct OpenGLContextState old_cs, *new_cs;
914 gl_get_current_context(&old_cs);
915 new_cs = gl_create_context(ctx, &old_cs);
918 if (!gl_set_current_context(new_cs, NULL))
921 pSurfaceGLX = create_surface(ctx, target, texture);
925 pSurfaceGLX->gl_context = new_cs;
926 *gl_surface = pSurfaceGLX;
928 gl_set_current_context(&old_cs, NULL);
929 return VA_STATUS_SUCCESS;
933 gl_destroy_context(new_cs);
935 return VA_STATUS_ERROR_ALLOCATION_FAILED;
939 vaDestroySurfaceGLX_impl_libva(VADriverContextP ctx, void *gl_surface)
941 VASurfaceGLXP pSurfaceGLX;
942 struct OpenGLContextState old_cs, *new_cs;
944 INIT_SURFACE(pSurfaceGLX, gl_surface);
946 new_cs = pSurfaceGLX->gl_context;
947 if (!gl_set_current_context(new_cs, &old_cs))
948 return VA_STATUS_ERROR_OPERATION_FAILED;
950 destroy_surface(ctx, pSurfaceGLX);
952 gl_destroy_context(new_cs);
953 gl_set_current_context(&old_cs, NULL);
954 return VA_STATUS_SUCCESS;
957 static inline VAStatus
958 deassociate_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
960 if (!unbind_pixmap(ctx, pSurfaceGLX))
961 return VA_STATUS_ERROR_OPERATION_FAILED;
963 pSurfaceGLX->surface = VA_INVALID_SURFACE;
964 return VA_STATUS_SUCCESS;
969 VADriverContextP ctx,
970 VASurfaceGLXP pSurfaceGLX,
977 /* XXX: optimise case where we are associating the same VA surface
978 as before an no changed occurred to it */
979 status = deassociate_surface(ctx, pSurfaceGLX);
980 if (status != VA_STATUS_SUCCESS)
984 status = ctx->vtable->vaPutSurface(
987 (void *)pSurfaceGLX->pixmap,
988 0, 0, pSurfaceGLX->width, pSurfaceGLX->height,
989 0, 0, pSurfaceGLX->width, pSurfaceGLX->height,
993 XSync(ctx->native_dpy, False);
994 if (x11_untrap_errors() != 0)
995 return VA_STATUS_ERROR_OPERATION_FAILED;
996 if (status != VA_STATUS_SUCCESS)
999 pSurfaceGLX->surface = surface;
1000 return VA_STATUS_SUCCESS;
1003 static inline VAStatus
1004 sync_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
1006 if (pSurfaceGLX->surface == VA_INVALID_SURFACE)
1007 return VA_STATUS_ERROR_INVALID_SURFACE;
1009 return ctx->vtable->vaSyncSurface(ctx, pSurfaceGLX->surface);
1012 static inline VAStatus
1013 begin_render_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
1017 status = sync_surface(ctx, pSurfaceGLX);
1018 if (status != VA_STATUS_SUCCESS)
1021 if (!bind_pixmap(ctx, pSurfaceGLX))
1022 return VA_STATUS_ERROR_OPERATION_FAILED;
1024 return VA_STATUS_SUCCESS;
1027 static inline VAStatus
1028 end_render_surface(VADriverContextP ctx, VASurfaceGLXP pSurfaceGLX)
1030 if (!unbind_pixmap(ctx, pSurfaceGLX))
1031 return VA_STATUS_ERROR_OPERATION_FAILED;
1033 return VA_STATUS_SUCCESS;
1038 VADriverContextP ctx,
1039 VASurfaceGLXP pSurfaceGLX,
1040 VASurfaceID surface,
1046 /* Associate VA surface */
1047 status = associate_surface(ctx, pSurfaceGLX, surface, flags);
1048 if (status != VA_STATUS_SUCCESS)
1052 fbo_enter(ctx, pSurfaceGLX);
1053 status = begin_render_surface(ctx, pSurfaceGLX);
1054 if (status == VA_STATUS_SUCCESS) {
1055 render_pixmap(ctx, pSurfaceGLX);
1056 status = end_render_surface(ctx, pSurfaceGLX);
1059 if (status != VA_STATUS_SUCCESS)
1062 return deassociate_surface(ctx, pSurfaceGLX);
1066 vaCopySurfaceGLX_impl_libva(
1067 VADriverContextP ctx,
1069 VASurfaceID surface,
1073 VASurfaceGLXP pSurfaceGLX;
1075 struct OpenGLContextState old_cs;
1077 INIT_SURFACE(pSurfaceGLX, gl_surface);
1079 if (!gl_set_current_context(pSurfaceGLX->gl_context, &old_cs))
1080 return VA_STATUS_ERROR_OPERATION_FAILED;
1082 status = copy_surface(ctx, pSurfaceGLX, surface, flags);
1084 gl_set_current_context(&old_cs, NULL);
1091 /* ========================================================================= */
1092 /* === Private VA/GLX vtable initialization === */
1093 /* ========================================================================= */
1095 // Initialize GLX driver context
1096 VAStatus va_glx_init_context(VADriverContextP ctx)
1098 VADriverContextGLXP glx_ctx = VA_DRIVER_CONTEXT_GLX(ctx);
1099 VADriverVTableGLXP vtable = &glx_ctx->vtable;
1100 int glx_major, glx_minor;
1102 if (glx_ctx->is_initialized)
1103 return VA_STATUS_SUCCESS;
1105 if (ctx->vtable_glx && ctx->vtable_glx->vaCopySurfaceGLX) {
1106 vtable->vaCreateSurfaceGLX = vaCreateSurfaceGLX_impl_driver;
1107 vtable->vaDestroySurfaceGLX = vaDestroySurfaceGLX_impl_driver;
1108 vtable->vaCopySurfaceGLX = vaCopySurfaceGLX_impl_driver;
1111 vtable->vaCreateSurfaceGLX = vaCreateSurfaceGLX_impl_libva;
1112 vtable->vaDestroySurfaceGLX = vaDestroySurfaceGLX_impl_libva;
1113 vtable->vaCopySurfaceGLX = vaCopySurfaceGLX_impl_libva;
1115 if (!glXQueryVersion(ctx->native_dpy, &glx_major, &glx_minor))
1116 return VA_STATUS_ERROR_UNIMPLEMENTED;
1118 if (!check_tfp_extensions(ctx) || !load_tfp_extensions(ctx))
1119 return VA_STATUS_ERROR_UNIMPLEMENTED;
1121 if (!check_fbo_extensions(ctx) || !load_fbo_extensions(ctx))
1122 return VA_STATUS_ERROR_UNIMPLEMENTED;
1125 glx_ctx->is_initialized = 1;
1126 return VA_STATUS_SUCCESS;