1 /**************************************************************************
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sub license, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * Kevin E. Martin <kevin@precisioninsight.com>
31 * Brian Paul <brian@precisioninsight.com>
35 #ifdef GLX_DIRECT_RENDERING
38 #include <X11/extensions/Xfixes.h>
39 #include <X11/extensions/Xdamage.h>
40 #include "glxclient.h"
41 #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
)
85 int driverMajor
, driverMinor
, driverPatch
;
89 if (XF86DRIQueryExtension(dpy
, &event
, &error
)) { /* DRI1 */
90 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
91 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
95 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
99 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
100 &driverPatch
, driverName
);
102 ErrorMessageF("Cannot determine driver name for screen %d\n",
107 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
108 driverMajor
, driverMinor
, driverPatch
, *driverName
,
113 else if (DRI2QueryExtension(dpy
, &event
, &error
)) { /* DRI2 */
115 Bool ret
= DRI2Connect(dpy
, RootWindow(dpy
, scrNum
), driverName
, &dev
);
127 * Exported function for querying the DRI driver for a given screen.
129 * The returned char pointer points to a static array that will be
130 * overwritten by subsequent calls.
133 glXGetScreenDriver(Display
* dpy
, int scrNum
)
137 if (driGetDriverName(dpy
, scrNum
, &driverName
)) {
141 len
= strlen(driverName
);
144 memcpy(ret
, driverName
, len
+ 1);
152 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
154 * The returned char pointer points directly into the driver. Therefore
155 * it should be treated as a constant.
157 * If the driver was not found or does not support configuration NULL is
160 * Note: The driver remains opened after this function returns.
163 glXGetDriverConfig(const char *driverName
)
165 void *handle
= driOpenDriver(driverName
);
167 return dlsym(handle
, "__driConfigOptions");
172 #ifdef XDAMAGE_1_1_INTERFACE
175 has_damage_post(Display
* dpy
)
177 static GLboolean inited
= GL_FALSE
;
178 static GLboolean has_damage
;
183 if (XDamageQueryVersion(dpy
, &major
, &minor
) &&
184 major
== 1 && minor
>= 1) {
185 has_damage
= GL_TRUE
;
188 has_damage
= GL_FALSE
;
197 __glXReportDamage(__DRIdrawable
* driDraw
,
199 drm_clip_rect_t
* rects
, int num_rects
,
200 GLboolean front_buffer
, void *loaderPrivate
)
203 XserverRegion region
;
206 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
207 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
208 Display
*dpy
= psc
->dpy
;
211 if (!has_damage_post(dpy
))
217 drawable
= RootWindow(dpy
, psc
->scr
);
222 drawable
= glxDraw
->xDrawable
;
225 xrects
= malloc(sizeof(XRectangle
) * num_rects
);
229 for (i
= 0; i
< num_rects
; i
++) {
230 xrects
[i
].x
= rects
[i
].x1
+ x_off
;
231 xrects
[i
].y
= rects
[i
].y1
+ y_off
;
232 xrects
[i
].width
= rects
[i
].x2
- rects
[i
].x1
;
233 xrects
[i
].height
= rects
[i
].y2
- rects
[i
].y1
;
235 region
= XFixesCreateRegion(dpy
, xrects
, num_rects
);
237 XDamageAdd(dpy
, drawable
, region
);
238 XFixesDestroyRegion(dpy
, region
);
241 static const __DRIdamageExtension damageExtension
= {
242 {__DRI_DAMAGE
, __DRI_DAMAGE_VERSION
},
249 __glXDRIGetDrawableInfo(__DRIdrawable
* drawable
,
250 unsigned int *index
, unsigned int *stamp
,
251 int *X
, int *Y
, int *W
, int *H
,
252 int *numClipRects
, drm_clip_rect_t
** pClipRects
,
253 int *backX
, int *backY
,
254 int *numBackClipRects
,
255 drm_clip_rect_t
** pBackClipRects
,
258 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
259 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
260 Display
*dpy
= psc
->dpy
;
262 return XF86DRIGetDrawableInfo(dpy
, psc
->scr
, glxDraw
->drawable
,
263 index
, stamp
, X
, Y
, W
, H
,
264 numClipRects
, pClipRects
,
266 numBackClipRects
, pBackClipRects
);
269 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension
= {
270 {__DRI_GET_DRAWABLE_INFO
, __DRI_GET_DRAWABLE_INFO_VERSION
},
271 __glXDRIGetDrawableInfo
274 static const __DRIextension
*loader_extensions
[] = {
275 &systemTimeExtension
.base
,
276 &getDrawableInfoExtension
.base
,
277 #ifdef XDAMAGE_1_1_INTERFACE
278 &damageExtension
.base
,
284 * Perform the required libGL-side initialization and call the client-side
285 * driver's \c __driCreateNewScreen function.
287 * \param dpy Display pointer.
288 * \param scrn Screen number on the display.
289 * \param psc DRI screen information.
290 * \param driDpy DRI display information.
291 * \param createNewScreen Pointer to the client-side driver's
292 * \c __driCreateNewScreen function.
293 * \returns A pointer to the \c __DRIscreen structure returned by
294 * the client-side driver on success, or \c NULL on failure.
297 CallCreateNewScreen(Display
* dpy
, int scrn
, __GLXscreenConfigs
* psc
,
298 __GLXDRIdisplayPrivate
* driDpy
)
302 drmAddress pSAREA
= MAP_FAILED
;
304 __DRIversion ddx_version
;
305 __DRIversion dri_version
;
306 __DRIversion drm_version
;
307 __DRIframebuffer framebuffer
;
312 drmVersionPtr version
;
317 const __DRIconfig
**driver_configs
;
318 __GLcontextModes
*visual
;
320 /* DRI protocol version. */
321 dri_version
.major
= driDpy
->driMajor
;
322 dri_version
.minor
= driDpy
->driMinor
;
323 dri_version
.patch
= driDpy
->driPatch
;
325 framebuffer
.base
= MAP_FAILED
;
326 framebuffer
.dev_priv
= NULL
;
328 if (!XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
329 ErrorMessageF("XF86DRIOpenConnection failed\n");
333 fd
= drmOpenOnce(NULL
, BusID
, &newlyopened
);
335 Xfree(BusID
); /* No longer needed */
338 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd
));
342 if (drmGetMagic(fd
, &magic
)) {
343 ErrorMessageF("drmGetMagic failed\n");
347 version
= drmGetVersion(fd
);
349 drm_version
.major
= version
->version_major
;
350 drm_version
.minor
= version
->version_minor
;
351 drm_version
.patch
= version
->version_patchlevel
;
352 drmFreeVersion(version
);
355 drm_version
.major
= -1;
356 drm_version
.minor
= -1;
357 drm_version
.patch
= -1;
360 if (newlyopened
&& !XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
361 ErrorMessageF("XF86DRIAuthConnection failed\n");
365 /* Get device name (like "tdfx") and the ddx version numbers.
366 * We'll check the version in each DRI driver's "createNewScreen"
368 if (!XF86DRIGetClientDriverName(dpy
, scrn
,
371 &ddx_version
.patch
, &driverName
)) {
372 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
376 Xfree(driverName
); /* No longer needed. */
379 * Get device-specific info. pDevPriv will point to a struct
380 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
381 * has information about the screen size, depth, pitch, ancilliary
382 * buffers, DRM mmap handles, etc.
384 if (!XF86DRIGetDeviceInfo(dpy
, scrn
, &hFB
, &junk
,
385 &framebuffer
.size
, &framebuffer
.stride
,
386 &framebuffer
.dev_priv_size
,
387 &framebuffer
.dev_priv
)) {
388 ErrorMessageF("XF86DRIGetDeviceInfo failed");
392 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
393 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
395 /* Map the framebuffer region. */
396 status
= drmMap(fd
, hFB
, framebuffer
.size
,
397 (drmAddressPtr
) & framebuffer
.base
);
399 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status
));
403 /* Map the SAREA region. Further mmap regions may be setup in
404 * each DRI driver's "createNewScreen" function.
406 status
= drmMap(fd
, hSAREA
, SAREA_MAX
, &pSAREA
);
408 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status
));
412 psp
= (*psc
->legacy
->createNewScreen
) (scrn
,
420 &driver_configs
, psc
);
423 ErrorMessageF("Calling driver entry point failed");
427 psc
->configs
= driConvertConfigs(psc
->core
, psc
->configs
, driver_configs
);
428 psc
->visuals
= driConvertConfigs(psc
->core
, psc
->visuals
, driver_configs
);
430 psc
->driver_configs
= driver_configs
;
432 /* Visuals with depth != screen depth are subject to automatic compositing
433 * in the X server, so DRI1 can't render to them properly. Mark them as
434 * non-conformant to prevent apps from picking them up accidentally.
436 for (visual
= psc
->visuals
; visual
; visual
= visual
->next
) {
437 XVisualInfo
template;
438 XVisualInfo
*visuals
;
442 template.visualid
= visual
->visualID
;
444 visuals
= XGetVisualInfo(dpy
, mask
, &template, &num_visuals
);
447 if (num_visuals
> 0 && visuals
->depth
!= DefaultDepth(dpy
, scrn
))
448 visual
->visualRating
= GLX_NON_CONFORMANT_CONFIG
;
457 if (pSAREA
!= MAP_FAILED
)
458 drmUnmap(pSAREA
, SAREA_MAX
);
460 if (framebuffer
.base
!= MAP_FAILED
)
461 drmUnmap((drmAddress
) framebuffer
.base
, framebuffer
.size
);
463 if (framebuffer
.dev_priv
!= NULL
)
464 Xfree(framebuffer
.dev_priv
);
469 XF86DRICloseConnection(dpy
, scrn
);
471 ErrorMessageF("reverting to software direct rendering\n");
477 driDestroyContext(__GLXDRIcontext
* context
,
478 __GLXscreenConfigs
* psc
, Display
* dpy
)
480 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
482 (*psc
->core
->destroyContext
) (pcp
->driContext
);
484 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
489 driBindContext(__GLXDRIcontext
* context
,
490 __GLXDRIdrawable
* draw
, __GLXDRIdrawable
* read
)
492 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
493 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
495 return (*core
->bindContext
) (pcp
->driContext
,
496 draw
->driDrawable
, read
->driDrawable
);
500 driUnbindContext(__GLXDRIcontext
* context
)
502 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
503 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
505 (*core
->unbindContext
) (pcp
->driContext
);
508 static __GLXDRIcontext
*
509 driCreateContext(__GLXscreenConfigs
* psc
,
510 const __GLcontextModes
* mode
,
511 GLXContext gc
, GLXContext shareList
, int renderType
)
513 __GLXDRIcontextPrivate
*pcp
, *pcp_shared
;
514 drm_context_t hwContext
;
515 __DRIcontext
*shared
= NULL
;
516 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) mode
;
518 if (!psc
|| !psc
->driScreen
)
522 pcp_shared
= (__GLXDRIcontextPrivate
*) shareList
->driContext
;
523 shared
= pcp_shared
->driContext
;
526 pcp
= Xmalloc(sizeof *pcp
);
531 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
533 &pcp
->hwContextID
, &hwContext
)) {
539 (*psc
->legacy
->createNewContext
) (psc
->__driScreen
,
541 renderType
, shared
, hwContext
, pcp
);
542 if (pcp
->driContext
== NULL
) {
543 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
548 pcp
->base
.destroyContext
= driDestroyContext
;
549 pcp
->base
.bindContext
= driBindContext
;
550 pcp
->base
.unbindContext
= driUnbindContext
;
556 driDestroyDrawable(__GLXDRIdrawable
* pdraw
)
558 __GLXscreenConfigs
*psc
= pdraw
->psc
;
560 (*psc
->core
->destroyDrawable
) (pdraw
->driDrawable
);
561 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, pdraw
->drawable
);
565 static __GLXDRIdrawable
*
566 driCreateDrawable(__GLXscreenConfigs
* psc
,
568 GLXDrawable drawable
, const __GLcontextModes
* modes
)
570 __GLXDRIdrawable
*pdraw
;
571 drm_drawable_t hwDrawable
;
572 void *empty_attribute_list
= NULL
;
573 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) modes
;
575 /* Old dri can't handle GLX 1.3+ drawable constructors. */
576 if (xDrawable
!= drawable
)
579 pdraw
= Xmalloc(sizeof(*pdraw
));
583 pdraw
->drawable
= drawable
;
586 if (!XF86DRICreateDrawable(psc
->dpy
, psc
->scr
, drawable
, &hwDrawable
)) {
591 /* Create a new drawable */
593 (*psc
->legacy
->createNewDrawable
) (psc
->__driScreen
,
597 empty_attribute_list
, pdraw
);
599 if (!pdraw
->driDrawable
) {
600 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
605 pdraw
->destroyDrawable
= driDestroyDrawable
;
611 driSwapBuffers(__GLXDRIdrawable
* pdraw
, int64_t unused1
, int64_t unused2
,
614 (*pdraw
->psc
->core
->swapBuffers
) (pdraw
->driDrawable
);
619 driCopySubBuffer(__GLXDRIdrawable
* pdraw
,
620 int x
, int y
, int width
, int height
)
622 (*pdraw
->psc
->driCopySubBuffer
->copySubBuffer
) (pdraw
->driDrawable
,
623 x
, y
, width
, height
);
627 driDestroyScreen(__GLXscreenConfigs
* psc
)
629 /* Free the direct rendering per screen data */
630 if (psc
->__driScreen
)
631 (*psc
->core
->destroyScreen
) (psc
->__driScreen
);
632 psc
->__driScreen
= NULL
;
634 dlclose(psc
->driver
);
637 static __GLXDRIscreen
*
638 driCreateScreen(__GLXscreenConfigs
* psc
, int screen
,
639 __GLXdisplayPrivate
* priv
)
641 __GLXDRIdisplayPrivate
*pdp
;
643 const __DRIextension
**extensions
;
647 psp
= Xcalloc(1, sizeof *psp
);
651 /* Initialize per screen dynamic client GLX extensions */
652 psc
->ext_list_first_time
= GL_TRUE
;
654 if (!driGetDriverName(priv
->dpy
, screen
, &driverName
)) {
659 psc
->driver
= driOpenDriver(driverName
);
661 if (psc
->driver
== NULL
) {
666 extensions
= dlsym(psc
->driver
, __DRI_DRIVER_EXTENSIONS
);
667 if (extensions
== NULL
) {
668 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
673 for (i
= 0; extensions
[i
]; i
++) {
674 if (strcmp(extensions
[i
]->name
, __DRI_CORE
) == 0)
675 psc
->core
= (__DRIcoreExtension
*) extensions
[i
];
676 if (strcmp(extensions
[i
]->name
, __DRI_LEGACY
) == 0)
677 psc
->legacy
= (__DRIlegacyExtension
*) extensions
[i
];
680 if (psc
->core
== NULL
|| psc
->legacy
== NULL
) {
685 pdp
= (__GLXDRIdisplayPrivate
*) priv
->driDisplay
;
686 psc
->__driScreen
= CallCreateNewScreen(psc
->dpy
, screen
, psc
, pdp
);
687 if (psc
->__driScreen
== NULL
) {
688 dlclose(psc
->driver
);
693 driBindExtensions(psc
);
694 driBindCommonExtensions(psc
);
696 if (psc
->driCopySubBuffer
)
697 psp
->copySubBuffer
= driCopySubBuffer
;
699 psp
->destroyScreen
= driDestroyScreen
;
700 psp
->createContext
= driCreateContext
;
701 psp
->createDrawable
= driCreateDrawable
;
702 psp
->swapBuffers
= driSwapBuffers
;
709 /* Called from __glXFreeDisplayPrivate.
712 driDestroyDisplay(__GLXDRIdisplay
* dpy
)
718 * Allocate, initialize and return a __DRIdisplayPrivate object.
719 * This is called from __glXInitialize() when we are given a new
722 _X_HIDDEN __GLXDRIdisplay
*
723 driCreateDisplay(Display
* dpy
)
725 __GLXDRIdisplayPrivate
*pdpyp
;
726 int eventBase
, errorBase
;
727 int major
, minor
, patch
;
729 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
733 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
737 pdpyp
= Xmalloc(sizeof *pdpyp
);
742 pdpyp
->driMajor
= major
;
743 pdpyp
->driMinor
= minor
;
744 pdpyp
->driPatch
= patch
;
746 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
747 pdpyp
->base
.createScreen
= driCreateScreen
;
752 #endif /* GLX_DIRECT_RENDERING */