diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2015-11-22 02:46:45 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2015-11-22 02:46:45 +0000 |
commit | 0784c49c0f8fcc8b3abd4c9286d9fd8bc089dd7d (patch) | |
tree | a6394e3e264a0f80b57f4ce0f5d9526aa543d4b0 /lib/mesa/src/glx/dri_glx.c | |
parent | d91d0007eecf589ea5699e34aa4d748fce2c57b2 (diff) |
import Mesa 11.0.6
Diffstat (limited to 'lib/mesa/src/glx/dri_glx.c')
-rw-r--r-- | lib/mesa/src/glx/dri_glx.c | 942 |
1 files changed, 942 insertions, 0 deletions
diff --git a/lib/mesa/src/glx/dri_glx.c b/lib/mesa/src/glx/dri_glx.c new file mode 100644 index 000000000..d08775193 --- /dev/null +++ b/lib/mesa/src/glx/dri_glx.c @@ -0,0 +1,942 @@ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <kevin@precisioninsight.com> + * Brian Paul <brian@precisioninsight.com> + * + */ + +#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) + +#include <X11/Xlib.h> +#include <X11/extensions/Xfixes.h> +#include <X11/extensions/Xdamage.h> +#include "glxclient.h" +#include "xf86dri.h" +#include "dri2.h" +#include "dri_sarea.h" +#include <dlfcn.h> +#include <sys/types.h> +#include <sys/mman.h> +#include "xf86drm.h" +#include "dri_common.h" + +struct dri_display +{ + __GLXDRIdisplay base; + + /* + ** XFree86-DRI version information + */ + int driMajor; + int driMinor; + int driPatch; +}; + +struct dri_screen +{ + struct glx_screen base; + + __DRIscreen *driScreen; + __GLXDRIscreen vtable; + const __DRIlegacyExtension *legacy; + const __DRIcoreExtension *core; + const __DRIswapControlExtension *swapControl; + const __DRImediaStreamCounterExtension *msc; + const __DRIconfig **driver_configs; + const __DRIcopySubBufferExtension *driCopySubBuffer; + + void *driver; + int fd; +}; + +struct dri_context +{ + struct glx_context base; + __DRIcontext *driContext; + XID hwContextID; +}; + +struct dri_drawable +{ + __GLXDRIdrawable base; + + __DRIdrawable *driDrawable; +}; + +/* + * Given a display pointer and screen number, determine the name of + * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc). + * Return True for success, False for failure. + */ +static Bool +driGetDriverName(Display * dpy, int scrNum, char **driverName) +{ + int directCapable; + Bool b; + int event, error; + int driverMajor, driverMinor, driverPatch; + + *driverName = NULL; + + if (XF86DRIQueryExtension(dpy, &event, &error)) { /* DRI1 */ + if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) { + ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n"); + return False; + } + if (!directCapable) { + ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n"); + return False; + } + + b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor, + &driverPatch, driverName); + if (!b) { + ErrorMessageF("Cannot determine driver name for screen %d\n", + scrNum); + return False; + } + + InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n", + driverMajor, driverMinor, driverPatch, *driverName, + scrNum); + + return True; + } + else if (DRI2QueryExtension(dpy, &event, &error)) { /* DRI2 */ + char *dev; + Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev); + + if (ret) + free(dev); + + return ret; + } + + return False; +} + +/* + * Exported function for querying the DRI driver for a given screen. + * + * The returned char pointer points to a static array that will be + * overwritten by subsequent calls. + */ +_X_EXPORT const char * +glXGetScreenDriver(Display * dpy, int scrNum) +{ + static char ret[32]; + char *driverName; + if (driGetDriverName(dpy, scrNum, &driverName)) { + int len; + if (!driverName) + return NULL; + len = strlen(driverName); + if (len >= 31) + return NULL; + memcpy(ret, driverName, len + 1); + free(driverName); + return ret; + } + return NULL; +} + +/* + * Exported function for obtaining a driver's option list (UTF-8 encoded XML). + * + * The returned char pointer points directly into the driver. Therefore + * it should be treated as a constant. + * + * If the driver was not found or does not support configuration NULL is + * returned. + * + * Note: The driver remains opened after this function returns. + */ +_X_EXPORT const char * +glXGetDriverConfig(const char *driverName) +{ + void *handle = driOpenDriver(driverName); + const __DRIextension **extensions; + + if (!handle) + return NULL; + + extensions = driGetDriverExtensions(handle, driverName); + if (extensions) { + for (int i = 0; extensions[i]; i++) { + if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) == 0) + return ((__DRIconfigOptionsExtension *)extensions[i])->xml; + } + } + + /* Fall back to the old method */ + return dlsym(handle, "__driConfigOptions"); +} + +#ifdef XDAMAGE_1_1_INTERFACE + +static GLboolean +has_damage_post(Display * dpy) +{ + static GLboolean inited = GL_FALSE; + static GLboolean has_damage; + + if (!inited) { + int major, minor; + + if (XDamageQueryVersion(dpy, &major, &minor) && + major == 1 && minor >= 1) { + has_damage = GL_TRUE; + } + else { + has_damage = GL_FALSE; + } + inited = GL_TRUE; + } + + return has_damage; +} + +static void +__glXReportDamage(__DRIdrawable * driDraw, + int x, int y, + drm_clip_rect_t * rects, int num_rects, + GLboolean front_buffer, void *loaderPrivate) +{ + XRectangle *xrects; + XserverRegion region; + int i; + int x_off, y_off; + __GLXDRIdrawable *glxDraw = loaderPrivate; + struct glx_screen *psc = glxDraw->psc; + Display *dpy = psc->dpy; + Drawable drawable; + + if (!has_damage_post(dpy)) + return; + + if (front_buffer) { + x_off = x; + y_off = y; + drawable = RootWindow(dpy, psc->scr); + } + else { + x_off = 0; + y_off = 0; + drawable = glxDraw->xDrawable; + } + + xrects = malloc(sizeof(XRectangle) * num_rects); + if (xrects == NULL) + return; + + for (i = 0; i < num_rects; i++) { + xrects[i].x = rects[i].x1 + x_off; + xrects[i].y = rects[i].y1 + y_off; + xrects[i].width = rects[i].x2 - rects[i].x1; + xrects[i].height = rects[i].y2 - rects[i].y1; + } + region = XFixesCreateRegion(dpy, xrects, num_rects); + free(xrects); + XDamageAdd(dpy, drawable, region); + XFixesDestroyRegion(dpy, region); +} + +static const __DRIdamageExtension damageExtension = { + .base = {__DRI_DAMAGE, 1 }, + + .reportDamage = __glXReportDamage, +}; + +#endif + +static GLboolean +__glXDRIGetDrawableInfo(__DRIdrawable * drawable, + unsigned int *index, unsigned int *stamp, + int *X, int *Y, int *W, int *H, + int *numClipRects, drm_clip_rect_t ** pClipRects, + int *backX, int *backY, + int *numBackClipRects, + drm_clip_rect_t ** pBackClipRects, + void *loaderPrivate) +{ + __GLXDRIdrawable *glxDraw = loaderPrivate; + struct glx_screen *psc = glxDraw->psc; + Display *dpy = psc->dpy; + + return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable, + index, stamp, X, Y, W, H, + numClipRects, pClipRects, + backX, backY, + numBackClipRects, pBackClipRects); +} + +static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = { + .base = {__DRI_GET_DRAWABLE_INFO, 1 }, + + .getDrawableInfo = __glXDRIGetDrawableInfo +}; + +static const __DRIextension *loader_extensions[] = { + &systemTimeExtension.base, + &getDrawableInfoExtension.base, +#ifdef XDAMAGE_1_1_INTERFACE + &damageExtension.base, +#endif + NULL +}; + +/** + * Perform the required libGL-side initialization and call the client-side + * driver's \c __driCreateNewScreen function. + * + * \param dpy Display pointer. + * \param scrn Screen number on the display. + * \param psc DRI screen information. + * \param driDpy DRI display information. + * \param createNewScreen Pointer to the client-side driver's + * \c __driCreateNewScreen function. + * \returns A pointer to the \c __DRIscreen structure returned by + * the client-side driver on success, or \c NULL on failure. + */ +static void * +CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc, + struct dri_display * driDpy) +{ + void *psp = NULL; + drm_handle_t hSAREA; + drmAddress pSAREA = MAP_FAILED; + char *BusID; + __DRIversion ddx_version; + __DRIversion dri_version; + __DRIversion drm_version; + __DRIframebuffer framebuffer; + int fd = -1; + int status; + + drm_magic_t magic; + drmVersionPtr version; + int newlyopened; + char *driverName; + drm_handle_t hFB; + int junk; + const __DRIconfig **driver_configs; + struct glx_config *visual, *configs = NULL, *visuals = NULL; + + /* DRI protocol version. */ + dri_version.major = driDpy->driMajor; + dri_version.minor = driDpy->driMinor; + dri_version.patch = driDpy->driPatch; + + framebuffer.base = MAP_FAILED; + framebuffer.dev_priv = NULL; + framebuffer.size = 0; + + if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) { + ErrorMessageF("XF86DRIOpenConnection failed\n"); + goto handle_error; + } + + fd = drmOpenOnce(NULL, BusID, &newlyopened); + + free(BusID); /* No longer needed */ + + if (fd < 0) { + ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd)); + goto handle_error; + } + + if (drmGetMagic(fd, &magic)) { + ErrorMessageF("drmGetMagic failed\n"); + goto handle_error; + } + + version = drmGetVersion(fd); + if (version) { + drm_version.major = version->version_major; + drm_version.minor = version->version_minor; + drm_version.patch = version->version_patchlevel; + drmFreeVersion(version); + } + else { + drm_version.major = -1; + drm_version.minor = -1; + drm_version.patch = -1; + } + + if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) { + ErrorMessageF("XF86DRIAuthConnection failed\n"); + goto handle_error; + } + + /* Get device name (like "radeon") and the ddx version numbers. + * We'll check the version in each DRI driver's "createNewScreen" + * function. */ + if (!XF86DRIGetClientDriverName(dpy, scrn, + &ddx_version.major, + &ddx_version.minor, + &ddx_version.patch, &driverName)) { + ErrorMessageF("XF86DRIGetClientDriverName failed\n"); + goto handle_error; + } + + free(driverName); /* No longer needed. */ + + /* + * Get device-specific info. pDevPriv will point to a struct + * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that + * has information about the screen size, depth, pitch, ancilliary + * buffers, DRM mmap handles, etc. + */ + if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk, + &framebuffer.size, &framebuffer.stride, + &framebuffer.dev_priv_size, + &framebuffer.dev_priv)) { + ErrorMessageF("XF86DRIGetDeviceInfo failed\n"); + goto handle_error; + } + + framebuffer.width = DisplayWidth(dpy, scrn); + framebuffer.height = DisplayHeight(dpy, scrn); + + /* Map the framebuffer region. */ + status = drmMap(fd, hFB, framebuffer.size, + (drmAddressPtr) & framebuffer.base); + if (status != 0) { + ErrorMessageF("drmMap of framebuffer failed (%s)\n", strerror(-status)); + goto handle_error; + } + + /* Map the SAREA region. Further mmap regions may be setup in + * each DRI driver's "createNewScreen" function. + */ + status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA); + if (status != 0) { + ErrorMessageF("drmMap of SAREA failed (%s)\n", strerror(-status)); + goto handle_error; + } + + psp = (*psc->legacy->createNewScreen) (scrn, + &ddx_version, + &dri_version, + &drm_version, + &framebuffer, + pSAREA, + fd, + loader_extensions, + &driver_configs, psc); + + if (psp == NULL) { + ErrorMessageF("Calling driver entry point failed\n"); + goto handle_error; + } + + configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs); + visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs); + + if (!configs || !visuals) { + ErrorMessageF("No matching fbConfigs or visuals found\n"); + goto handle_error; + } + + glx_config_destroy_list(psc->base.configs); + psc->base.configs = configs; + glx_config_destroy_list(psc->base.visuals); + psc->base.visuals = visuals; + + psc->driver_configs = driver_configs; + + /* Visuals with depth != screen depth are subject to automatic compositing + * in the X server, so DRI1 can't render to them properly. Mark them as + * non-conformant to prevent apps from picking them up accidentally. + */ + for (visual = psc->base.visuals; visual; visual = visual->next) { + XVisualInfo template; + XVisualInfo *visuals; + int num_visuals; + long mask; + + template.visualid = visual->visualID; + mask = VisualIDMask; + visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals); + + if (visuals) { + if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn)) + visual->visualRating = GLX_NON_CONFORMANT_CONFIG; + + free(visuals); + } + } + + return psp; + + handle_error: + if (configs) + glx_config_destroy_list(configs); + if (visuals) + glx_config_destroy_list(visuals); + + if (pSAREA != MAP_FAILED) + drmUnmap(pSAREA, SAREA_MAX); + + if (framebuffer.base != MAP_FAILED) + drmUnmap((drmAddress) framebuffer.base, framebuffer.size); + + free(framebuffer.dev_priv); + + if (fd >= 0) + drmCloseOnce(fd); + + XF86DRICloseConnection(dpy, scrn); + + ErrorMessageF("reverting to software direct rendering\n"); + + return NULL; +} + +static void +dri_destroy_context(struct glx_context * context) +{ + struct dri_context *pcp = (struct dri_context *) context; + struct dri_screen *psc = (struct dri_screen *) context->psc; + + driReleaseDrawables(&pcp->base); + + free((char *) context->extensions); + + (*psc->core->destroyContext) (pcp->driContext); + + XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID); + free(pcp); +} + +static int +dri_bind_context(struct glx_context *context, struct glx_context *old, + GLXDrawable draw, GLXDrawable read) +{ + struct dri_context *pcp = (struct dri_context *) context; + struct dri_screen *psc = (struct dri_screen *) pcp->base.psc; + struct dri_drawable *pdraw, *pread; + + pdraw = (struct dri_drawable *) driFetchDrawable(context, draw); + pread = (struct dri_drawable *) driFetchDrawable(context, read); + + driReleaseDrawables(&pcp->base); + + if (pdraw == NULL || pread == NULL) + return GLXBadDrawable; + + if ((*psc->core->bindContext) (pcp->driContext, + pdraw->driDrawable, pread->driDrawable)) + return Success; + + return GLXBadContext; +} + +static void +dri_unbind_context(struct glx_context *context, struct glx_context *new) +{ + struct dri_context *pcp = (struct dri_context *) context; + struct dri_screen *psc = (struct dri_screen *) pcp->base.psc; + + (*psc->core->unbindContext) (pcp->driContext); +} + +static const struct glx_context_vtable dri_context_vtable = { + .destroy = dri_destroy_context, + .bind = dri_bind_context, + .unbind = dri_unbind_context, + .wait_gl = NULL, + .wait_x = NULL, + .use_x_font = DRI_glXUseXFont, + .bind_tex_image = NULL, + .release_tex_image = NULL, + .get_proc_address = NULL, +}; + +static struct glx_context * +dri_create_context(struct glx_screen *base, + struct glx_config *config_base, + struct glx_context *shareList, int renderType) +{ + struct dri_context *pcp, *pcp_shared; + struct dri_screen *psc = (struct dri_screen *) base; + drm_context_t hwContext; + __DRIcontext *shared = NULL; + __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; + + if (!psc->base.driScreen) + return NULL; + + /* Check the renderType value */ + if (!validate_renderType_against_config(config_base, renderType)) + return NULL; + + if (shareList) { + /* If the shareList context is not a DRI context, we cannot possibly + * create a DRI context that shares it. + */ + if (shareList->vtable->destroy != dri_destroy_context) { + return NULL; + } + + pcp_shared = (struct dri_context *) shareList; + shared = pcp_shared->driContext; + } + + pcp = calloc(1, sizeof *pcp); + if (pcp == NULL) + return NULL; + + if (!glx_context_init(&pcp->base, &psc->base, &config->base)) { + free(pcp); + return NULL; + } + + pcp->base.renderType = renderType; + + if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr, + config->base.visualID, + &pcp->hwContextID, &hwContext)) { + free(pcp); + return NULL; + } + + pcp->driContext = + (*psc->legacy->createNewContext) (psc->driScreen, + config->driConfig, + renderType, shared, hwContext, pcp); + if (pcp->driContext == NULL) { + XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID); + free(pcp); + return NULL; + } + + pcp->base.vtable = &dri_context_vtable; + + return &pcp->base; +} + +static void +driDestroyDrawable(__GLXDRIdrawable * pdraw) +{ + struct dri_screen *psc = (struct dri_screen *) pdraw->psc; + struct dri_drawable *pdp = (struct dri_drawable *) pdraw; + + (*psc->core->destroyDrawable) (pdp->driDrawable); + XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable); + free(pdraw); +} + +static __GLXDRIdrawable * +driCreateDrawable(struct glx_screen *base, + XID xDrawable, + GLXDrawable drawable, struct glx_config *config_base) +{ + drm_drawable_t hwDrawable; + void *empty_attribute_list = NULL; + __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; + struct dri_screen *psc = (struct dri_screen *) base; + struct dri_drawable *pdp; + + /* Old dri can't handle GLX 1.3+ drawable constructors. */ + if (xDrawable != drawable) + return NULL; + + pdp = calloc(1, sizeof *pdp); + if (!pdp) + return NULL; + + pdp->base.drawable = drawable; + pdp->base.psc = &psc->base; + + if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr, + drawable, &hwDrawable)) { + free(pdp); + return NULL; + } + + /* Create a new drawable */ + pdp->driDrawable = + (*psc->legacy->createNewDrawable) (psc->driScreen, + config->driConfig, + hwDrawable, + GLX_WINDOW_BIT, + empty_attribute_list, pdp); + + if (!pdp->driDrawable) { + XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable); + free(pdp); + return NULL; + } + + pdp->base.destroyDrawable = driDestroyDrawable; + + return &pdp->base; +} + +static int64_t +driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2, + int64_t unused3, Bool flush) +{ + struct dri_screen *psc = (struct dri_screen *) pdraw->psc; + struct dri_drawable *pdp = (struct dri_drawable *) pdraw; + + if (flush) { + glFlush(); + } + + (*psc->core->swapBuffers) (pdp->driDrawable); + return 0; +} + +static void +driCopySubBuffer(__GLXDRIdrawable * pdraw, + int x, int y, int width, int height, Bool flush) +{ + struct dri_drawable *pdp = (struct dri_drawable *) pdraw; + struct dri_screen *psc = (struct dri_screen *) pdp->base.psc; + + if (flush) { + glFlush(); + } + + (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable, + x, y, width, height); +} + +static void +driDestroyScreen(struct glx_screen *base) +{ + struct dri_screen *psc = (struct dri_screen *) base; + + /* Free the direct rendering per screen data */ + if (psc->driScreen) + (*psc->core->destroyScreen) (psc->driScreen); + driDestroyConfigs(psc->driver_configs); + psc->driScreen = NULL; + if (psc->driver) + dlclose(psc->driver); +} + +static int +driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval) +{ + struct dri_drawable *pdp = (struct dri_drawable *) pdraw; + + if (pdraw != NULL) { + struct dri_screen *psc = (struct dri_screen *) pdraw->psc; + + if (psc->swapControl != NULL) { + psc->swapControl->setSwapInterval(pdp->driDrawable, interval); + return 0; + } + } + return GLX_BAD_CONTEXT; +} + +static int +driGetSwapInterval(__GLXDRIdrawable *pdraw) +{ + struct dri_drawable *pdp = (struct dri_drawable *) pdraw; + + if (pdraw != NULL) { + struct dri_screen *psc = (struct dri_screen *) pdraw->psc; + + if (psc->swapControl != NULL) + return psc->swapControl->getSwapInterval(pdp->driDrawable); + } + return 0; +} + +/* Bind DRI1 specific extensions */ +static void +driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions) +{ + int i; + + for (i = 0; extensions[i]; i++) { + /* No DRI2 support for swap_control at the moment, since SwapBuffers + * is done by the X server */ + if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) { + psc->swapControl = (__DRIswapControlExtension *) extensions[i]; + __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); + __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); + } + + if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) { + psc->msc = (__DRImediaStreamCounterExtension *) extensions[i]; + __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); + } + + if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) { + psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i]; + __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); + } + + if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { + __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); + } + /* Ignore unknown extensions */ + } +} + +static const struct glx_screen_vtable dri_screen_vtable = { + .create_context = dri_create_context, + .create_context_attribs = NULL, + .query_renderer_integer = NULL, + .query_renderer_string = NULL, +}; + +static struct glx_screen * +driCreateScreen(int screen, struct glx_display *priv) +{ + struct dri_display *pdp; + __GLXDRIscreen *psp; + const __DRIextension **extensions; + struct dri_screen *psc; + char *driverName; + int i; + + psc = calloc(1, sizeof *psc); + if (psc == NULL) + return NULL; + + if (!glx_screen_init(&psc->base, screen, priv)) { + free(psc); + return NULL; + } + + if (!driGetDriverName(priv->dpy, screen, &driverName)) { + goto cleanup; + } + + psc->driver = driOpenDriver(driverName); + if (psc->driver == NULL) + goto cleanup; + + extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); + if (extensions == NULL) { + ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); + goto cleanup; + } + + for (i = 0; extensions[i]; i++) { + if (strcmp(extensions[i]->name, __DRI_CORE) == 0) + psc->core = (__DRIcoreExtension *) extensions[i]; + if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0) + psc->legacy = (__DRIlegacyExtension *) extensions[i]; + } + + if (psc->core == NULL || psc->legacy == NULL) + goto cleanup; + + pdp = (struct dri_display *) priv->driDisplay; + psc->driScreen = + CallCreateNewScreen(psc->base.dpy, screen, psc, pdp); + if (psc->driScreen == NULL) + goto cleanup; + + extensions = psc->core->getExtensions(psc->driScreen); + driBindExtensions(psc, extensions); + + psc->base.vtable = &dri_screen_vtable; + psp = &psc->vtable; + psc->base.driScreen = psp; + if (psc->driCopySubBuffer) + psp->copySubBuffer = driCopySubBuffer; + + psp->destroyScreen = driDestroyScreen; + psp->createDrawable = driCreateDrawable; + psp->swapBuffers = driSwapBuffers; + + psp->setSwapInterval = driSetSwapInterval; + psp->getSwapInterval = driGetSwapInterval; + + free(driverName); + + return &psc->base; + +cleanup: + CriticalErrorMessageF("failed to load driver: %s\n", driverName); + + free(driverName); + + if (psc->driver) + dlclose(psc->driver); + glx_screen_cleanup(&psc->base); + free(psc); + + return NULL; +} + +/* Called from __glXFreeDisplayPrivate. + */ +static void +driDestroyDisplay(__GLXDRIdisplay * dpy) +{ + free(dpy); +} + +/* + * Allocate, initialize and return a __DRIdisplayPrivate object. + * This is called from __glXInitialize() when we are given a new + * display pointer. + */ +_X_HIDDEN __GLXDRIdisplay * +driCreateDisplay(Display * dpy) +{ + struct dri_display *pdpyp; + int eventBase, errorBase; + int major, minor, patch; + + if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) { + return NULL; + } + + if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) { + return NULL; + } + + pdpyp = malloc(sizeof *pdpyp); + if (!pdpyp) { + return NULL; + } + + pdpyp->driMajor = major; + pdpyp->driMinor = minor; + pdpyp->driPatch = patch; + + pdpyp->base.destroyDisplay = driDestroyDisplay; + pdpyp->base.createScreen = driCreateScreen; + + return &pdpyp->base; +} + +#endif /* GLX_DIRECT_RENDERING */ |