commit fb6ccda5984eda96bcb394b23255143dcbc21f18 Author: Gwenole Beauchesne Date: Thu Sep 10 12:22:17 2009 +0000 Don't link against libdrm to workaround XvBA / fglrx >= 8.66-RC1 bugs. commit ab3c0f65182462b54729d2d82d4d645c8be5b2d1 Author: Gwenole Beauchesne Date: Wed Sep 9 13:24:46 2009 +0000 Fix DRM device opening with fglrx >= 8.66-RC1. diff --git a/src/x11/Makefile.am b/src/x11/Makefile.am index c70380d..b6916f2 100644 --- a/src/x11/Makefile.am +++ b/src/x11/Makefile.am @@ -25,6 +25,6 @@ noinst_LTLIBRARIES = libva_x11.la libva_x11includedir = ${includedir}/va libva_x11include_HEADERS = va_x11.h va_dri.h va_dri2.h va_dricommon.h -libva_x11_la_SOURCES = va_x11.c va_dri.c va_dri2.c va_dricommon.c dri2_util.c dri1_util.c va_nvctrl.c +libva_x11_la_SOURCES = va_x11.c va_dri.c va_dri2.c va_dricommon.c dri2_util.c dri1_util.c va_nvctrl.c libdrm_glue.c -EXTRA_DIST = va_dristr.h va_dri2str.h va_dri2tokens.h va_nvctrl.h +EXTRA_DIST = va_dristr.h va_dri2str.h va_dri2tokens.h va_nvctrl.h libdrm_glue.h diff --git a/src/x11/dri1_util.c b/src/x11/dri1_util.c index b3db5b4..3bd490f 100644 --- a/src/x11/dri1_util.c +++ b/src/x11/dri1_util.c @@ -1,10 +1,12 @@ +#include "config.h" +#include #include #include #include #include #include -#include +#include "libdrm_glue.h" #include "X11/Xlib.h" #include "va.h" @@ -21,6 +23,75 @@ struct dri1_drawable int height; }; +static int +firegl_drmOpenMinor(int minor) +{ + char buf[64]; + int fd; + + sprintf(buf, "/dev/ati/card%d", minor); + if ((fd = open(buf, O_RDWR, 0)) >= 0) + return fd; + return -1; +} + +static int +firegl_drmOpenByBusID(const char *busid) +{ + int i, fd; + drmSetVersion sv; + const char *buf; + + for (i = 0; i < DRM_MAX_MINOR; i++) { + if ((fd = firegl_drmOpenMinor(i)) < 0) + continue; + sv.drm_di_major = 1; + sv.drm_di_minor = 1; + sv.drm_dd_major = -1; + sv.drm_dd_minor = -1; + libdrm_drmSetInterfaceVersion(fd, &sv); + buf = libdrm_drmGetBusid(fd); + if (buf && strcasecmp(buf, busid) == 0) { /* XXX: drmMatchBusID() */ + libdrm_drmFreeBusid(buf); + return fd; + } + if (buf) + libdrm_drmFreeBusid(buf); + close(fd); + } + return -1; +} + +static int +drm_open_once(struct dri_state *dri_state, const char *BusID, int *newlyopened) +{ + dri_state->driConnectedFlag = VA_NONE; + dri_state->fd = libdrm_drmOpenOnce(NULL, BusID, newlyopened); + if (dri_state->fd < 0) { + dri_state->fd = firegl_drmOpenByBusID(BusID); + if (dri_state->fd >= 0) { + *newlyopened = 1; + dri_state->driConnectedFlag |= VA_DRI_AMD; + } + } + return dri_state->fd; +} + +static void +drm_close_once(struct dri_state *dri_state) +{ + /* XXX: dri_state->close() doesn't seem to be called, thus this + function is never called either */ + if (dri_state->fd < 0) + return; + if (dri_state->driConnectedFlag & VA_DRI_AMD) + close(dri_state->fd); + else + libdrm_drmCloseOnce(dri_state->fd); + dri_state->fd = -1; + dri_state->driConnectedFlag = VA_NONE; +} + static struct dri_drawable * dri1CreateDrawable(VADriverContextP ctx, XID x_drawable) { @@ -64,9 +135,9 @@ dri1Close(VADriverContextP ctx) free_drawable_hashtable(ctx); VA_DRIDestroyContext(ctx->x11_dpy, ctx->x11_screen, dri_state->hwContextID); assert(dri_state->pSAREA != MAP_FAILED); - drmUnmap(dri_state->pSAREA, SAREA_MAX); + libdrm_drmUnmap(dri_state->pSAREA, SAREA_MAX); assert(dri_state->fd >= 0); - drmCloseOnce(dri_state->fd); + drm_close_once(dri_state); VA_DRICloseConnection(ctx->x11_dpy, ctx->x11_screen); } @@ -104,21 +175,20 @@ isDRI1Connected(VADriverContextP ctx, char **driver_name) &dri_state->hSAREA, &BusID)) goto err_out0; - - dri_state->fd = drmOpenOnce(NULL, BusID, &newlyopened); + drm_open_once(dri_state, BusID, &newlyopened); XFree(BusID); if (dri_state->fd < 0) goto err_out1; - if (drmGetMagic(dri_state->fd, &magic)) + if (libdrm_drmGetMagic(dri_state->fd, &magic)) goto err_out1; if (newlyopened && !VA_DRIAuthConnection(ctx->x11_dpy, ctx->x11_screen, magic)) goto err_out1; - if (drmMap(dri_state->fd, dri_state->hSAREA, SAREA_MAX, &dri_state->pSAREA)) + if (libdrm_drmMap(dri_state->fd, dri_state->hSAREA, SAREA_MAX, &dri_state->pSAREA)) goto err_out1; if (!VA_DRICreateContext(ctx->x11_dpy, ctx->x11_screen, @@ -127,7 +196,8 @@ isDRI1Connected(VADriverContextP ctx, char **driver_name) &dri_state->hwContextID, &dri_state->hwContext)) goto err_out1; - dri_state->driConnectedFlag = VA_DRI1; + dri_state->driConnectedFlag &= VA_DRI_AMD; /* clear flags but AMD bit */ + dri_state->driConnectedFlag |= VA_DRI1; dri_state->createDrawable = dri1CreateDrawable; dri_state->destroyDrawable = dri1DestroyDrawable; dri_state->swapBuffer = dri1SwapBuffer; @@ -138,10 +208,10 @@ isDRI1Connected(VADriverContextP ctx, char **driver_name) err_out1: if (dri_state->pSAREA != MAP_FAILED) - drmUnmap(dri_state->pSAREA, SAREA_MAX); + libdrm_drmUnmap(dri_state->pSAREA, SAREA_MAX); if (dri_state->fd >= 0) - drmCloseOnce(dri_state->fd); + drm_close_once(dri_state); VA_DRICloseConnection(ctx->x11_dpy, ctx->x11_screen); diff --git a/src/x11/dri2_util.c b/src/x11/dri2_util.c index ebe7a2c..b727e97 100644 --- a/src/x11/dri2_util.c +++ b/src/x11/dri2_util.c @@ -3,7 +3,7 @@ #include #include -#include +#include "libdrm_glue.h" #include #include @@ -166,7 +166,7 @@ isDRI2Connected(VADriverContextP ctx, char **driver_name) if (dri_state->fd < 0) goto err_out; - if (drmGetMagic(dri_state->fd, &magic)) + if (libdrm_drmGetMagic(dri_state->fd, &magic)) goto err_out; if (!VA_DRI2Authenticate(ctx->x11_dpy, RootWindow(ctx->x11_dpy, ctx->x11_screen), diff --git a/src/x11/libdrm_glue.c b/src/x11/libdrm_glue.c new file mode 100644 index 0000000..b72a2d1 --- /dev/null +++ b/src/x11/libdrm_glue.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2009 Splitted-Desktop Systems. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#define _GNU_SOURCE 1 +#include "libdrm_glue.h" +#include +#include +#include +#include + +#define LOAD_FUNC_(NAME, RET, ARGS, FALLBACK) \ + static RET (*lib_##NAME) ARGS; \ + if (lib_##NAME == NULL) { \ + lib_##NAME = libdrm_symbol(#NAME); \ + if (!lib_##NAME) \ + lib_##NAME = FALLBACK; \ + } \ + assert(lib_##NAME != NULL) + +#define LOAD_FUNC(NAME, RET, ARGS) \ + LOAD_FUNC_(NAME, RET, ARGS, NULL) + +static void *libdrm_handle; +static int libdrm_handle_ok = -1; + +static inline void *libdrm_symbol(const char *name) +{ + if (!libdrm_open()) + return NULL; + return dlsym(libdrm_handle, name); +} + +int libdrm_open(void) +{ + if (libdrm_handle_ok < 0) { + libdrm_handle = dlopen("libdrm.so.2", RTLD_LOCAL|RTLD_LAZY); + libdrm_handle_ok = libdrm_handle != NULL; + } + assert(libdrm_handle); + return libdrm_handle_ok; +} + +void libdrm_close(void) +{ + if (libdrm_handle) + dlclose(libdrm_handle); +} + +// Default drmOpenOnce() and drmCloseOnce() implementations based on current GIT +#define DRM_MAX_FDS 16 +static struct { + char *BusID; + int fd; + int refcount; +} connection[DRM_MAX_FDS]; + +static int nr_fds = 0; + +// Default implementation for drmOpenOnce() if none exists in the library +static int +libdrm_default_drmOpenOnce(void *unused, const char *BusID, int *newlyopened) +{ + int i; + int fd; + + for (i = 0; i < nr_fds; i++) + if (strcmp(BusID, connection[i].BusID) == 0) { + connection[i].refcount++; + *newlyopened = 0; + return connection[i].fd; + } + + fd = libdrm_drmOpen(unused, BusID); + if (fd <= 0 || nr_fds == DRM_MAX_FDS) + return fd; + + connection[nr_fds].BusID = strdup(BusID); + connection[nr_fds].fd = fd; + connection[nr_fds].refcount = 1; + *newlyopened = 1; + + if (0) + fprintf(stderr, "saved connection %d for %s %d\n", + nr_fds, connection[nr_fds].BusID, + strcmp(BusID, connection[nr_fds].BusID)); + nr_fds++; + return fd; +} + +// Default implementation for drmCloseOnce() if none exists in the library +static void libdrm_default_drmCloseOnce(int fd) +{ + int i; + + for (i = 0; i < nr_fds; i++) { + if (fd == connection[i].fd) { + if (--connection[i].refcount == 0) { + libdrm_drmClose(connection[i].fd); + free(connection[i].BusID); + if (i < --nr_fds) + connection[i] = connection[nr_fds]; + return; + } + } + } +} + +// Determine whether the DRM kernel driver has been loaded +int libdrm_drmAvailable(void) +{ + LOAD_FUNC(drmAvailable, int, (void)); + return lib_drmAvailable(); +} + +// Open the DRM device +int libdrm_drmOpen(const char *name, const char *busid) +{ + LOAD_FUNC(drmOpen, int, (const char *, const char *)); + return lib_drmOpen(name, busid); +} + +// Close the device +int libdrm_drmClose(int fd) +{ + LOAD_FUNC(drmClose, int, (int)); + return lib_drmClose(fd); +} + +// Open the DRM device (re-use an existing connection) +int libdrm_drmOpenOnce(void *unused, const char *BusID, int *newlyopened) +{ + LOAD_FUNC_(drmOpenOnce, int, (void *, const char *, int *), + libdrm_default_drmOpenOnce); + return lib_drmOpenOnce(unused, BusID, newlyopened); +} + +// Close the device (unref an existing connection prior to actually closing it) +void libdrm_drmCloseOnce(int fd) +{ + LOAD_FUNC_(drmCloseOnce, void, (int), libdrm_default_drmCloseOnce); + lib_drmCloseOnce(fd); +} + +// DRM connection cookie +int libdrm_drmGetMagic(int fd, drm_magic_t * magic) +{ + LOAD_FUNC(drmGetMagic, int, (int, drm_magic_t *)); + return lib_drmGetMagic(fd, magic); +} + +// Issue a set-version ioctl +int libdrm_drmSetInterfaceVersion(int fd, drmSetVersion *version) +{ + LOAD_FUNC(drmSetInterfaceVersion, int, (int, drmSetVersion *)); + return lib_drmSetInterfaceVersion(fd, version); +} + +// Get the bus ID of the device +char *libdrm_drmGetBusid(int fd) +{ + LOAD_FUNC(drmGetBusid, char *, (int)); + return lib_drmGetBusid(fd); +} + +// Free the bus ID information +void libdrm_drmFreeBusid(const char *busid) +{ + LOAD_FUNC(drmFreeBusid, void, (const char *)); + lib_drmFreeBusid(busid); +} + +// Map a region of memory +int libdrm_drmMap(int fd, + drm_handle_t handle, + drmSize size, + drmAddressPtr address) +{ + LOAD_FUNC(drmMap, int, (int, drm_handle_t, drmSize, drmAddressPtr)); + return lib_drmMap(fd, handle, size, address); +} + +// Unmap mappings obtained with drmMap() +int libdrm_drmUnmap(drmAddress address, drmSize size) +{ + LOAD_FUNC(drmUnmap, int, (drmAddress, drmSize)); + return lib_drmUnmap(address, size); +} diff --git a/src/x11/libdrm_glue.h b/src/x11/libdrm_glue.h new file mode 100644 index 0000000..878470b --- /dev/null +++ b/src/x11/libdrm_glue.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2009 Splitted-Desktop Systems. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef LIBDRM_GLUE_H +#define LIBDRM_GLUE_H + +#include "config.h" +#include + +int libdrm_open(void) + ATTRIBUTE_HIDDEN; + +void libdrm_close(void) + ATTRIBUTE_HIDDEN; + +int libdrm_drmAvailable(void) + ATTRIBUTE_HIDDEN; + +int libdrm_drmOpen(const char *name, const char *busid) + ATTRIBUTE_HIDDEN; + +int libdrm_drmClose(int fd) + ATTRIBUTE_HIDDEN; + +int libdrm_drmOpenOnce(void *unused, const char *BusID, int *newlyopened) + ATTRIBUTE_HIDDEN; + +void libdrm_drmCloseOnce(int fd) + ATTRIBUTE_HIDDEN; + +int libdrm_drmGetMagic(int fd, drm_magic_t * magic) + ATTRIBUTE_HIDDEN; + +int libdrm_drmSetInterfaceVersion(int fd, drmSetVersion *version) + ATTRIBUTE_HIDDEN; + +char *libdrm_drmGetBusid(int fd) + ATTRIBUTE_HIDDEN; + +void libdrm_drmFreeBusid(const char *busid) + ATTRIBUTE_HIDDEN; + +int libdrm_drmMap(int fd, + drm_handle_t handle, + drmSize size, + drmAddressPtr address) + ATTRIBUTE_HIDDEN; + +int libdrm_drmUnmap(drmAddress address, drmSize size) + ATTRIBUTE_HIDDEN; + +#endif /* LIBDRM_GLUE_H */ diff --git a/src/x11/va_dricommon.h b/src/x11/va_dricommon.h index a2a51a6..0da35fe 100644 --- a/src/x11/va_dricommon.h +++ b/src/x11/va_dricommon.h @@ -13,7 +13,8 @@ enum { VA_NONE = 0, VA_DRI1 = 1, - VA_DRI2 = 2 + VA_DRI2 = 2, + VA_DRI_AMD = 4 /* AMD DRI implementation */ }; union dri_buffer diff --git a/src/x11/va_x11.c b/src/x11/va_x11.c index b8c60fa..414c261 100644 --- a/src/x11/va_x11.c +++ b/src/x11/va_x11.c @@ -31,6 +31,7 @@ #include "va_dri2.h" #include "va_dricommon.h" #include "va_nvctrl.h" +#include "libdrm_glue.h" #include #include #include @@ -94,6 +75,8 @@ static void va_DisplayContextDestroy ( } ctx = &((*ctx)->pNext); } + + libdrm_close(); free(pDisplayContext->pDriverContext->dri_state); free(pDisplayContext->pDriverContext); free(pDisplayContext); diff --git a/src/Makefile.am b/src/Makefile.am index e50a15f..d1f8f70 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,7 +45,7 @@ libva_la_LDFLAGS = $(LDADD) -no-undefined libva_la_LIBADD = $(LIBVA_LIBS) -ldl libva_x11_la_SOURCES = -libva_x11_la_LIBADD = $(libvacorelib) x11/libva_x11.la $(LIBVA_LIBS) $(X11_LIBS) $(XEXT_LIBS) $(DRM_LIBS) $(XFIXES_LIBS) +libva_x11_la_LIBADD = $(libvacorelib) x11/libva_x11.la $(LIBVA_LIBS) $(X11_LIBS) $(XEXT_LIBS) $(XFIXES_LIBS) -ldl libva_x11_la_LDFLAGS = $(LDADD) libva_x11_la_DEPENDENCIES = $(libvacorelib) x11/libva_x11.la