1 /* -*- mode: c; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3; coding: utf-8-unix -*- */
2 /**************************************************************************
4 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sub license, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
15 The above copyright notice and this permission notice (including the
16 next paragraph) shall be included in all copies or substantial portions
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
23 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
31 * Kevin E. Martin <kevin@precisioninsight.com>
32 * Brian Paul <brian@precisioninsight.com>
36 #ifdef GLX_DIRECT_RENDERING
39 #include <X11/extensions/Xfixes.h>
40 #include <X11/extensions/Xdamage.h>
41 #include "glxclient.h"
42 #include "glcontextmodes.h"
46 #include <sys/types.h>
49 #include "dri_common.h"
51 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate
;
52 typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate
;
54 struct __GLXDRIdisplayPrivateRec
59 ** XFree86-DRI version information
66 struct __GLXDRIcontextPrivateRec
69 __DRIcontext
*driContext
;
71 __GLXscreenConfigs
*psc
;
75 * Given a display pointer and screen number, determine the name of
76 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
77 * Return True for success, False for failure.
80 driGetDriverName(Display
* dpy
, int scrNum
, char **driverName
)
84 int driverMajor
, driverMinor
, driverPatch
;
88 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
89 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
93 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
97 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
98 &driverPatch
, driverName
);
100 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum
);
104 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
105 driverMajor
, driverMinor
, driverPatch
, *driverName
, scrNum
);
111 * Exported function for querying the DRI driver for a given screen.
113 * The returned char pointer points to a static array that will be
114 * overwritten by subsequent calls.
117 glXGetScreenDriver(Display
* dpy
, int scrNum
)
121 if (driGetDriverName(dpy
, scrNum
, &driverName
)) {
125 len
= strlen(driverName
);
128 memcpy(ret
, driverName
, len
+ 1);
136 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
138 * The returned char pointer points directly into the driver. Therefore
139 * it should be treated as a constant.
141 * If the driver was not found or does not support configuration NULL is
144 * Note: The driver remains opened after this function returns.
147 glXGetDriverConfig(const char *driverName
)
149 void *handle
= driOpenDriver(driverName
);
151 return dlsym(handle
, "__driConfigOptions");
156 #ifdef XDAMAGE_1_1_INTERFACE
159 has_damage_post(Display
* dpy
)
161 static GLboolean inited
= GL_FALSE
;
162 static GLboolean has_damage
;
167 if (XDamageQueryVersion(dpy
, &major
, &minor
) &&
168 major
== 1 && minor
>= 1) {
169 has_damage
= GL_TRUE
;
172 has_damage
= GL_FALSE
;
181 __glXReportDamage(__DRIdrawable
* driDraw
,
183 drm_clip_rect_t
* rects
, int num_rects
,
184 GLboolean front_buffer
, void *loaderPrivate
)
187 XserverRegion region
;
190 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
191 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
192 Display
*dpy
= psc
->dpy
;
195 if (!has_damage_post(dpy
))
201 drawable
= RootWindow(dpy
, psc
->scr
);
206 drawable
= glxDraw
->xDrawable
;
209 xrects
= malloc(sizeof(XRectangle
) * num_rects
);
213 for (i
= 0; i
< num_rects
; i
++) {
214 xrects
[i
].x
= rects
[i
].x1
+ x_off
;
215 xrects
[i
].y
= rects
[i
].y1
+ y_off
;
216 xrects
[i
].width
= rects
[i
].x2
- rects
[i
].x1
;
217 xrects
[i
].height
= rects
[i
].y2
- rects
[i
].y1
;
219 region
= XFixesCreateRegion(dpy
, xrects
, num_rects
);
221 XDamageAdd(dpy
, drawable
, region
);
222 XFixesDestroyRegion(dpy
, region
);
225 static const __DRIdamageExtension damageExtension
= {
226 {__DRI_DAMAGE
, __DRI_DAMAGE_VERSION
},
233 __glXDRIGetDrawableInfo(__DRIdrawable
* drawable
,
234 unsigned int *index
, unsigned int *stamp
,
235 int *X
, int *Y
, int *W
, int *H
,
236 int *numClipRects
, drm_clip_rect_t
** pClipRects
,
237 int *backX
, int *backY
,
238 int *numBackClipRects
,
239 drm_clip_rect_t
** pBackClipRects
,
242 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
243 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
244 Display
*dpy
= psc
->dpy
;
246 return XF86DRIGetDrawableInfo(dpy
, psc
->scr
, glxDraw
->drawable
,
247 index
, stamp
, X
, Y
, W
, H
,
248 numClipRects
, pClipRects
,
250 numBackClipRects
, pBackClipRects
);
253 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension
= {
254 {__DRI_GET_DRAWABLE_INFO
, __DRI_GET_DRAWABLE_INFO_VERSION
},
255 __glXDRIGetDrawableInfo
258 static const __DRIextension
*loader_extensions
[] = {
259 &systemTimeExtension
.base
,
260 &getDrawableInfoExtension
.base
,
261 #ifdef XDAMAGE_1_1_INTERFACE
262 &damageExtension
.base
,
267 #ifndef GLX_USE_APPLEGL
270 * Perform the required libGL-side initialization and call the client-side
271 * driver's \c __driCreateNewScreen function.
273 * \param dpy Display pointer.
274 * \param scrn Screen number on the display.
275 * \param psc DRI screen information.
276 * \param driDpy DRI display information.
277 * \param createNewScreen Pointer to the client-side driver's
278 * \c __driCreateNewScreen function.
279 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
280 * the client-side driver on success, or \c NULL on failure.
283 CallCreateNewScreen(Display
* dpy
, int scrn
, __GLXscreenConfigs
* psc
,
284 __GLXDRIdisplayPrivate
* driDpy
)
288 drmAddress pSAREA
= MAP_FAILED
;
290 __DRIversion ddx_version
;
291 __DRIversion dri_version
;
292 __DRIversion drm_version
;
293 __DRIframebuffer framebuffer
;
298 drmVersionPtr version
;
303 const __DRIconfig
**driver_configs
;
305 /* DRI protocol version. */
306 dri_version
.major
= driDpy
->driMajor
;
307 dri_version
.minor
= driDpy
->driMinor
;
308 dri_version
.patch
= driDpy
->driPatch
;
310 framebuffer
.base
= MAP_FAILED
;
311 framebuffer
.dev_priv
= NULL
;
313 if (!XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
314 ErrorMessageF("XF86DRIOpenConnection failed\n");
318 fd
= drmOpenOnce(NULL
, BusID
, &newlyopened
);
320 Xfree(BusID
); /* No longer needed */
323 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd
));
327 if (drmGetMagic(fd
, &magic
)) {
328 ErrorMessageF("drmGetMagic failed\n");
332 version
= drmGetVersion(fd
);
334 drm_version
.major
= version
->version_major
;
335 drm_version
.minor
= version
->version_minor
;
336 drm_version
.patch
= version
->version_patchlevel
;
337 drmFreeVersion(version
);
340 drm_version
.major
= -1;
341 drm_version
.minor
= -1;
342 drm_version
.patch
= -1;
345 if (newlyopened
&& !XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
346 ErrorMessageF("XF86DRIAuthConnection failed\n");
350 /* Get device name (like "tdfx") and the ddx version numbers.
351 * We'll check the version in each DRI driver's "createNewScreen"
353 if (!XF86DRIGetClientDriverName(dpy
, scrn
,
356 &ddx_version
.patch
, &driverName
)) {
357 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
361 Xfree(driverName
); /* No longer needed. */
364 * Get device-specific info. pDevPriv will point to a struct
365 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
366 * has information about the screen size, depth, pitch, ancilliary
367 * buffers, DRM mmap handles, etc.
369 if (!XF86DRIGetDeviceInfo(dpy
, scrn
, &hFB
, &junk
,
370 &framebuffer
.size
, &framebuffer
.stride
,
371 &framebuffer
.dev_priv_size
,
372 &framebuffer
.dev_priv
)) {
373 ErrorMessageF("XF86DRIGetDeviceInfo failed");
377 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
378 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
380 /* Map the framebuffer region. */
381 status
= drmMap(fd
, hFB
, framebuffer
.size
,
382 (drmAddressPtr
) & framebuffer
.base
);
384 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status
));
388 /* Map the SAREA region. Further mmap regions may be setup in
389 * each DRI driver's "createNewScreen" function.
391 status
= drmMap(fd
, hSAREA
, SAREA_MAX
, &pSAREA
);
393 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status
));
397 psp
= (*psc
->legacy
->createNewScreen
) (scrn
,
405 &driver_configs
, psc
);
408 ErrorMessageF("Calling driver entry point failed");
412 psc
->configs
= driConvertConfigs(psc
->core
, psc
->configs
, driver_configs
);
413 psc
->visuals
= driConvertConfigs(psc
->core
, psc
->visuals
, driver_configs
);
418 if (pSAREA
!= MAP_FAILED
)
419 drmUnmap(pSAREA
, SAREA_MAX
);
421 if (framebuffer
.base
!= MAP_FAILED
)
422 drmUnmap((drmAddress
) framebuffer
.base
, framebuffer
.size
);
424 if (framebuffer
.dev_priv
!= NULL
)
425 Xfree(framebuffer
.dev_priv
);
430 XF86DRICloseConnection(dpy
, scrn
);
432 ErrorMessageF("reverting to software direct rendering\n");
437 #else /* !GLX_USE_APPLEGL */
440 CallCreateNewScreen(Display
* dpy
, int scrn
, __GLXscreenConfigs
* psc
,
441 __GLXDRIdisplayPrivate
* driDpy
)
446 #endif /* !GLX_USE_APPLEGL */
449 driDestroyContext(__GLXDRIcontext
* context
,
450 __GLXscreenConfigs
* psc
, Display
* dpy
)
452 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
454 (*psc
->core
->destroyContext
) (pcp
->driContext
);
456 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
461 driBindContext(__GLXDRIcontext
* context
,
462 __GLXDRIdrawable
* draw
, __GLXDRIdrawable
* read
)
464 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
465 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
467 return (*core
->bindContext
) (pcp
->driContext
,
468 draw
->driDrawable
, read
->driDrawable
);
472 driUnbindContext(__GLXDRIcontext
* context
)
474 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
475 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
477 (*core
->unbindContext
) (pcp
->driContext
);
480 static __GLXDRIcontext
*
481 driCreateContext(__GLXscreenConfigs
* psc
,
482 const __GLcontextModes
* mode
,
483 GLXContext gc
, GLXContext shareList
, int renderType
)
485 __GLXDRIcontextPrivate
*pcp
, *pcp_shared
;
486 drm_context_t hwContext
;
487 __DRIcontext
*shared
= NULL
;
488 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) mode
;
490 if (!psc
|| !psc
->driScreen
)
494 pcp_shared
= (__GLXDRIcontextPrivate
*) shareList
->driContext
;
495 shared
= pcp_shared
->driContext
;
498 pcp
= Xmalloc(sizeof *pcp
);
503 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
505 &pcp
->hwContextID
, &hwContext
)) {
511 (*psc
->legacy
->createNewContext
) (psc
->__driScreen
,
513 renderType
, shared
, hwContext
, pcp
);
514 if (pcp
->driContext
== NULL
) {
515 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
520 pcp
->base
.destroyContext
= driDestroyContext
;
521 pcp
->base
.bindContext
= driBindContext
;
522 pcp
->base
.unbindContext
= driUnbindContext
;
528 driDestroyDrawable(__GLXDRIdrawable
* pdraw
)
530 __GLXscreenConfigs
*psc
= pdraw
->psc
;
532 (*psc
->core
->destroyDrawable
) (pdraw
->driDrawable
);
533 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, pdraw
->drawable
);
537 static __GLXDRIdrawable
*
538 driCreateDrawable(__GLXscreenConfigs
* psc
,
540 GLXDrawable drawable
, const __GLcontextModes
* modes
)
542 __GLXDRIdrawable
*pdraw
;
543 drm_drawable_t hwDrawable
;
544 void *empty_attribute_list
= NULL
;
545 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) modes
;
547 /* Old dri can't handle GLX 1.3+ drawable constructors. */
548 if (xDrawable
!= drawable
)
551 pdraw
= Xmalloc(sizeof(*pdraw
));
555 pdraw
->drawable
= drawable
;
558 if (!XF86DRICreateDrawable(psc
->dpy
, psc
->scr
, drawable
, &hwDrawable
))
561 /* Create a new drawable */
563 (*psc
->legacy
->createNewDrawable
) (psc
->__driScreen
,
567 empty_attribute_list
, pdraw
);
569 if (!pdraw
->driDrawable
) {
570 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
575 pdraw
->destroyDrawable
= driDestroyDrawable
;
581 driSwapBuffers(__GLXDRIdrawable
* pdraw
)
583 (*pdraw
->psc
->core
->swapBuffers
) (pdraw
->driDrawable
);
587 driDestroyScreen(__GLXscreenConfigs
* psc
)
589 /* Free the direct rendering per screen data */
590 if (psc
->__driScreen
)
591 (*psc
->core
->destroyScreen
) (psc
->__driScreen
);
592 psc
->__driScreen
= NULL
;
594 dlclose(psc
->driver
);
597 static __GLXDRIscreen
*
598 driCreateScreen(__GLXscreenConfigs
* psc
, int screen
,
599 __GLXdisplayPrivate
* priv
)
601 __GLXDRIdisplayPrivate
*pdp
;
603 const __DRIextension
**extensions
;
607 psp
= Xmalloc(sizeof *psp
);
611 /* Initialize per screen dynamic client GLX extensions */
612 psc
->ext_list_first_time
= GL_TRUE
;
614 if (!driGetDriverName(priv
->dpy
, screen
, &driverName
)) {
619 psc
->driver
= driOpenDriver(driverName
);
621 if (psc
->driver
== NULL
) {
626 extensions
= dlsym(psc
->driver
, __DRI_DRIVER_EXTENSIONS
);
627 if (extensions
== NULL
) {
628 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
633 for (i
= 0; extensions
[i
]; i
++) {
634 if (strcmp(extensions
[i
]->name
, __DRI_CORE
) == 0)
635 psc
->core
= (__DRIcoreExtension
*) extensions
[i
];
636 if (strcmp(extensions
[i
]->name
, __DRI_LEGACY
) == 0)
637 psc
->legacy
= (__DRIlegacyExtension
*) extensions
[i
];
640 if (psc
->core
== NULL
|| psc
->legacy
== NULL
) {
645 pdp
= (__GLXDRIdisplayPrivate
*) priv
->driDisplay
;
646 psc
->__driScreen
= CallCreateNewScreen(psc
->dpy
, screen
, psc
, pdp
);
647 if (psc
->__driScreen
== NULL
) {
648 dlclose(psc
->driver
);
653 driBindExtensions(psc
, 0);
655 psp
->destroyScreen
= driDestroyScreen
;
656 psp
->createContext
= driCreateContext
;
657 psp
->createDrawable
= driCreateDrawable
;
658 psp
->swapBuffers
= driSwapBuffers
;
663 /* Called from __glXFreeDisplayPrivate.
666 driDestroyDisplay(__GLXDRIdisplay
* dpy
)
672 * Allocate, initialize and return a __DRIdisplayPrivate object.
673 * This is called from __glXInitialize() when we are given a new
676 _X_HIDDEN __GLXDRIdisplay
*
677 driCreateDisplay(Display
* dpy
)
679 __GLXDRIdisplayPrivate
*pdpyp
;
680 int eventBase
, errorBase
;
681 int major
, minor
, patch
;
683 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
687 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
691 pdpyp
= Xmalloc(sizeof *pdpyp
);
696 pdpyp
->driMajor
= major
;
697 pdpyp
->driMinor
= minor
;
698 pdpyp
->driPatch
= patch
;
700 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
701 pdpyp
->base
.createScreen
= driCreateScreen
;
706 #endif /* GLX_DIRECT_RENDERING */