| /************************************************************************** |
| |
| 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> |
| * |
| */ |
| |
| #ifdef GLX_DIRECT_RENDERING |
| |
| #include <X11/Xlib.h> |
| #include <X11/extensions/Xfixes.h> |
| #include <X11/extensions/Xdamage.h> |
| #include "glxclient.h" |
| #include "xf86dri.h" |
| #include "dri2.h" |
| #include "sarea.h" |
| #include <dlfcn.h> |
| #include <sys/types.h> |
| #include <sys/mman.h> |
| #include "xf86drm.h" |
| #include "dri_common.h" |
| |
| typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate; |
| typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate; |
| |
| struct __GLXDRIdisplayPrivateRec |
| { |
| __GLXDRIdisplay base; |
| |
| /* |
| ** XFree86-DRI version information |
| */ |
| int driMajor; |
| int driMinor; |
| int driPatch; |
| }; |
| |
| struct __GLXDRIcontextPrivateRec |
| { |
| __GLXDRIcontext base; |
| __DRIcontext *driContext; |
| XID hwContextID; |
| __GLXscreenConfigs *psc; |
| }; |
| |
| /* |
| * Given a display pointer and screen number, determine the name of |
| * the DRI driver for the screen. (I.e. "r128", "tdfx", 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) |
| Xfree(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. |
| */ |
| PUBLIC 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); |
| Xfree(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. |
| */ |
| PUBLIC const char * |
| glXGetDriverConfig(const char *driverName) |
| { |
| void *handle = driOpenDriver(driverName); |
| if (handle) |
| return dlsym(handle, "__driConfigOptions"); |
| else |
| return NULL; |
| } |
| |
| #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; |
| __GLXscreenConfigs *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 = { |
| {__DRI_DAMAGE, __DRI_DAMAGE_VERSION}, |
| __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; |
| __GLXscreenConfigs *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 = { |
| {__DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION}, |
| __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, __GLXscreenConfigs * psc, |
| __GLXDRIdisplayPrivate * 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; |
| __GLcontextModes *visual; |
| |
| /* 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); |
| |
| Xfree(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 "tdfx") 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; |
| } |
| |
| Xfree(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"); |
| 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)", 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)", 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"); |
| goto handle_error; |
| } |
| |
| psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs); |
| psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs); |
| |
| 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->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; |
| |
| XFree(visuals); |
| } |
| } |
| |
| return psp; |
| |
| handle_error: |
| if (pSAREA != MAP_FAILED) |
| drmUnmap(pSAREA, SAREA_MAX); |
| |
| if (framebuffer.base != MAP_FAILED) |
| drmUnmap((drmAddress) framebuffer.base, framebuffer.size); |
| |
| if (framebuffer.dev_priv != NULL) |
| Xfree(framebuffer.dev_priv); |
| |
| if (fd >= 0) |
| drmCloseOnce(fd); |
| |
| XF86DRICloseConnection(dpy, scrn); |
| |
| ErrorMessageF("reverting to software direct rendering\n"); |
| |
| return NULL; |
| } |
| |
| static void |
| driDestroyContext(__GLXDRIcontext * context, |
| __GLXscreenConfigs * psc, Display * dpy) |
| { |
| __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; |
| |
| (*psc->core->destroyContext) (pcp->driContext); |
| |
| XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID); |
| Xfree(pcp); |
| } |
| |
| static Bool |
| driBindContext(__GLXDRIcontext * context, |
| __GLXDRIdrawable * draw, __GLXDRIdrawable * read) |
| { |
| __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; |
| const __DRIcoreExtension *core = pcp->psc->core; |
| |
| return (*core->bindContext) (pcp->driContext, |
| draw->driDrawable, read->driDrawable); |
| } |
| |
| static void |
| driUnbindContext(__GLXDRIcontext * context) |
| { |
| __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; |
| const __DRIcoreExtension *core = pcp->psc->core; |
| |
| (*core->unbindContext) (pcp->driContext); |
| } |
| |
| static __GLXDRIcontext * |
| driCreateContext(__GLXscreenConfigs * psc, |
| const __GLcontextModes * mode, |
| GLXContext gc, GLXContext shareList, int renderType) |
| { |
| __GLXDRIcontextPrivate *pcp, *pcp_shared; |
| drm_context_t hwContext; |
| __DRIcontext *shared = NULL; |
| __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode; |
| |
| if (!psc || !psc->driScreen) |
| return NULL; |
| |
| if (shareList) { |
| pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext; |
| shared = pcp_shared->driContext; |
| } |
| |
| pcp = Xmalloc(sizeof *pcp); |
| if (pcp == NULL) |
| return NULL; |
| |
| pcp->psc = psc; |
| if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr, |
| mode->visualID, |
| &pcp->hwContextID, &hwContext)) { |
| Xfree(pcp); |
| return NULL; |
| } |
| |
| pcp->driContext = |
| (*psc->legacy->createNewContext) (psc->__driScreen, |
| config->driConfig, |
| renderType, shared, hwContext, pcp); |
| if (pcp->driContext == NULL) { |
| XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID); |
| Xfree(pcp); |
| return NULL; |
| } |
| |
| pcp->base.destroyContext = driDestroyContext; |
| pcp->base.bindContext = driBindContext; |
| pcp->base.unbindContext = driUnbindContext; |
| |
| return &pcp->base; |
| } |
| |
| static void |
| driDestroyDrawable(__GLXDRIdrawable * pdraw) |
| { |
| __GLXscreenConfigs *psc = pdraw->psc; |
| |
| (*psc->core->destroyDrawable) (pdraw->driDrawable); |
| XF86DRIDestroyDrawable(psc->dpy, psc->scr, pdraw->drawable); |
| Xfree(pdraw); |
| } |
| |
| static __GLXDRIdrawable * |
| driCreateDrawable(__GLXscreenConfigs * psc, |
| XID xDrawable, |
| GLXDrawable drawable, const __GLcontextModes * modes) |
| { |
| __GLXDRIdrawable *pdraw; |
| drm_drawable_t hwDrawable; |
| void *empty_attribute_list = NULL; |
| __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes; |
| |
| /* Old dri can't handle GLX 1.3+ drawable constructors. */ |
| if (xDrawable != drawable) |
| return NULL; |
| |
| pdraw = Xmalloc(sizeof(*pdraw)); |
| if (!pdraw) |
| return NULL; |
| |
| pdraw->drawable = drawable; |
| pdraw->psc = psc; |
| |
| if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable)) { |
| Xfree(pdraw); |
| return NULL; |
| } |
| |
| /* Create a new drawable */ |
| pdraw->driDrawable = |
| (*psc->legacy->createNewDrawable) (psc->__driScreen, |
| config->driConfig, |
| hwDrawable, |
| GLX_WINDOW_BIT, |
| empty_attribute_list, pdraw); |
| |
| if (!pdraw->driDrawable) { |
| XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable); |
| Xfree(pdraw); |
| return NULL; |
| } |
| |
| pdraw->destroyDrawable = driDestroyDrawable; |
| |
| return pdraw; |
| } |
| |
| static int64_t |
| driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2, |
| int64_t unused3) |
| { |
| (*pdraw->psc->core->swapBuffers) (pdraw->driDrawable); |
| return 0; |
| } |
| |
| static void |
| driCopySubBuffer(__GLXDRIdrawable * pdraw, |
| int x, int y, int width, int height) |
| { |
| (*pdraw->psc->driCopySubBuffer->copySubBuffer) (pdraw->driDrawable, |
| x, y, width, height); |
| } |
| |
| static void |
| driDestroyScreen(__GLXscreenConfigs * psc) |
| { |
| /* Free the direct rendering per screen data */ |
| if (psc->__driScreen) |
| (*psc->core->destroyScreen) (psc->__driScreen); |
| psc->__driScreen = NULL; |
| if (psc->driver) |
| dlclose(psc->driver); |
| } |
| |
| static __GLXDRIscreen * |
| driCreateScreen(__GLXscreenConfigs * psc, int screen, |
| __GLXdisplayPrivate * priv) |
| { |
| __GLXDRIdisplayPrivate *pdp; |
| __GLXDRIscreen *psp; |
| const __DRIextension **extensions; |
| char *driverName; |
| int i; |
| |
| psp = Xcalloc(1, sizeof *psp); |
| if (psp == NULL) |
| return NULL; |
| |
| if (!driGetDriverName(priv->dpy, screen, &driverName)) { |
| Xfree(psp); |
| return NULL; |
| } |
| |
| psc->driver = driOpenDriver(driverName); |
| Xfree(driverName); |
| if (psc->driver == NULL) { |
| Xfree(psp); |
| return NULL; |
| } |
| |
| extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); |
| if (extensions == NULL) { |
| ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); |
| Xfree(psp); |
| return NULL; |
| } |
| |
| 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) { |
| Xfree(psp); |
| return NULL; |
| } |
| |
| pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay; |
| psc->__driScreen = CallCreateNewScreen(psc->dpy, screen, psc, pdp); |
| if (psc->__driScreen == NULL) { |
| dlclose(psc->driver); |
| Xfree(psp); |
| return NULL; |
| } |
| |
| driBindExtensions(psc); |
| driBindCommonExtensions(psc); |
| |
| if (psc->driCopySubBuffer) |
| psp->copySubBuffer = driCopySubBuffer; |
| |
| psp->destroyScreen = driDestroyScreen; |
| psp->createContext = driCreateContext; |
| psp->createDrawable = driCreateDrawable; |
| psp->swapBuffers = driSwapBuffers; |
| psp->waitX = NULL; |
| psp->waitGL = NULL; |
| |
| return psp; |
| } |
| |
| /* Called from __glXFreeDisplayPrivate. |
| */ |
| static void |
| driDestroyDisplay(__GLXDRIdisplay * dpy) |
| { |
| Xfree(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) |
| { |
| __GLXDRIdisplayPrivate *pdpyp; |
| int eventBase, errorBase; |
| int major, minor, patch; |
| |
| if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) { |
| return NULL; |
| } |
| |
| if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) { |
| return NULL; |
| } |
| |
| pdpyp = Xmalloc(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 */ |