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
,
283 #ifndef GLX_USE_APPLEGL
286 * Perform the required libGL-side initialization and call the client-side
287 * driver's \c __driCreateNewScreen function.
289 * \param dpy Display pointer.
290 * \param scrn Screen number on the display.
291 * \param psc DRI screen information.
292 * \param driDpy DRI display information.
293 * \param createNewScreen Pointer to the client-side driver's
294 * \c __driCreateNewScreen function.
295 * \returns A pointer to the \c __DRIscreen structure returned by
296 * the client-side driver on success, or \c NULL on failure.
299 CallCreateNewScreen(Display
* dpy
, int scrn
, __GLXscreenConfigs
* psc
,
300 __GLXDRIdisplayPrivate
* driDpy
)
304 drmAddress pSAREA
= MAP_FAILED
;
306 __DRIversion ddx_version
;
307 __DRIversion dri_version
;
308 __DRIversion drm_version
;
309 __DRIframebuffer framebuffer
;
314 drmVersionPtr version
;
319 const __DRIconfig
**driver_configs
;
320 __GLcontextModes
*visual
;
322 /* DRI protocol version. */
323 dri_version
.major
= driDpy
->driMajor
;
324 dri_version
.minor
= driDpy
->driMinor
;
325 dri_version
.patch
= driDpy
->driPatch
;
327 framebuffer
.base
= MAP_FAILED
;
328 framebuffer
.dev_priv
= NULL
;
330 if (!XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
331 ErrorMessageF("XF86DRIOpenConnection failed\n");
335 fd
= drmOpenOnce(NULL
, BusID
, &newlyopened
);
337 Xfree(BusID
); /* No longer needed */
340 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd
));
344 if (drmGetMagic(fd
, &magic
)) {
345 ErrorMessageF("drmGetMagic failed\n");
349 version
= drmGetVersion(fd
);
351 drm_version
.major
= version
->version_major
;
352 drm_version
.minor
= version
->version_minor
;
353 drm_version
.patch
= version
->version_patchlevel
;
354 drmFreeVersion(version
);
357 drm_version
.major
= -1;
358 drm_version
.minor
= -1;
359 drm_version
.patch
= -1;
362 if (newlyopened
&& !XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
363 ErrorMessageF("XF86DRIAuthConnection failed\n");
367 /* Get device name (like "tdfx") and the ddx version numbers.
368 * We'll check the version in each DRI driver's "createNewScreen"
370 if (!XF86DRIGetClientDriverName(dpy
, scrn
,
373 &ddx_version
.patch
, &driverName
)) {
374 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
378 Xfree(driverName
); /* No longer needed. */
381 * Get device-specific info. pDevPriv will point to a struct
382 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
383 * has information about the screen size, depth, pitch, ancilliary
384 * buffers, DRM mmap handles, etc.
386 if (!XF86DRIGetDeviceInfo(dpy
, scrn
, &hFB
, &junk
,
387 &framebuffer
.size
, &framebuffer
.stride
,
388 &framebuffer
.dev_priv_size
,
389 &framebuffer
.dev_priv
)) {
390 ErrorMessageF("XF86DRIGetDeviceInfo failed");
394 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
395 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
397 /* Map the framebuffer region. */
398 status
= drmMap(fd
, hFB
, framebuffer
.size
,
399 (drmAddressPtr
) & framebuffer
.base
);
401 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status
));
405 /* Map the SAREA region. Further mmap regions may be setup in
406 * each DRI driver's "createNewScreen" function.
408 status
= drmMap(fd
, hSAREA
, SAREA_MAX
, &pSAREA
);
410 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status
));
414 psp
= (*psc
->legacy
->createNewScreen
) (scrn
,
422 &driver_configs
, psc
);
425 ErrorMessageF("Calling driver entry point failed");
429 psc
->configs
= driConvertConfigs(psc
->core
, psc
->configs
, driver_configs
);
430 psc
->visuals
= driConvertConfigs(psc
->core
, psc
->visuals
, driver_configs
);
432 psc
->driver_configs
= driver_configs
;
434 /* Visuals with depth != screen depth are subject to automatic compositing
435 * in the X server, so DRI1 can't render to them properly. Mark them as
436 * non-conformant to prevent apps from picking them up accidentally.
438 for (visual
= psc
->visuals
; visual
; visual
= visual
->next
) {
439 XVisualInfo
template;
440 XVisualInfo
*visuals
;
444 template.visualid
= visual
->visualID
;
446 visuals
= XGetVisualInfo(dpy
, mask
, &template, &num_visuals
);
449 if (num_visuals
> 0 && visuals
->depth
!= DefaultDepth(dpy
, scrn
))
450 visual
->visualRating
= GLX_NON_CONFORMANT_CONFIG
;
459 if (pSAREA
!= MAP_FAILED
)
460 drmUnmap(pSAREA
, SAREA_MAX
);
462 if (framebuffer
.base
!= MAP_FAILED
)
463 drmUnmap((drmAddress
) framebuffer
.base
, framebuffer
.size
);
465 if (framebuffer
.dev_priv
!= NULL
)
466 Xfree(framebuffer
.dev_priv
);
471 XF86DRICloseConnection(dpy
, scrn
);
473 ErrorMessageF("reverting to software direct rendering\n");
478 #else /* !GLX_USE_APPLEGL */
481 CallCreateNewScreen(Display
* dpy
, int scrn
, __GLXscreenConfigs
* psc
,
482 __GLXDRIdisplayPrivate
* driDpy
)
487 #endif /* !GLX_USE_APPLEGL */
490 driDestroyContext(__GLXDRIcontext
* context
,
491 __GLXscreenConfigs
* psc
, Display
* dpy
)
493 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
495 (*psc
->core
->destroyContext
) (pcp
->driContext
);
497 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
502 driBindContext(__GLXDRIcontext
* context
,
503 __GLXDRIdrawable
* draw
, __GLXDRIdrawable
* read
)
505 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
506 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
508 return (*core
->bindContext
) (pcp
->driContext
,
509 draw
->driDrawable
, read
->driDrawable
);
513 driUnbindContext(__GLXDRIcontext
* context
)
515 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
516 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
518 (*core
->unbindContext
) (pcp
->driContext
);
521 static __GLXDRIcontext
*
522 driCreateContext(__GLXscreenConfigs
* psc
,
523 const __GLcontextModes
* mode
,
524 GLXContext gc
, GLXContext shareList
, int renderType
)
526 __GLXDRIcontextPrivate
*pcp
, *pcp_shared
;
527 drm_context_t hwContext
;
528 __DRIcontext
*shared
= NULL
;
529 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) mode
;
531 if (!psc
|| !psc
->driScreen
)
535 pcp_shared
= (__GLXDRIcontextPrivate
*) shareList
->driContext
;
536 shared
= pcp_shared
->driContext
;
539 pcp
= Xmalloc(sizeof *pcp
);
544 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
546 &pcp
->hwContextID
, &hwContext
)) {
552 (*psc
->legacy
->createNewContext
) (psc
->__driScreen
,
554 renderType
, shared
, hwContext
, pcp
);
555 if (pcp
->driContext
== NULL
) {
556 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
561 pcp
->base
.destroyContext
= driDestroyContext
;
562 pcp
->base
.bindContext
= driBindContext
;
563 pcp
->base
.unbindContext
= driUnbindContext
;
569 driDestroyDrawable(__GLXDRIdrawable
* pdraw
)
571 __GLXscreenConfigs
*psc
= pdraw
->psc
;
573 (*psc
->core
->destroyDrawable
) (pdraw
->driDrawable
);
574 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, pdraw
->drawable
);
578 static __GLXDRIdrawable
*
579 driCreateDrawable(__GLXscreenConfigs
* psc
,
581 GLXDrawable drawable
, const __GLcontextModes
* modes
)
583 __GLXDRIdrawable
*pdraw
;
584 drm_drawable_t hwDrawable
;
585 void *empty_attribute_list
= NULL
;
586 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) modes
;
588 /* Old dri can't handle GLX 1.3+ drawable constructors. */
589 if (xDrawable
!= drawable
)
592 pdraw
= Xmalloc(sizeof(*pdraw
));
596 pdraw
->drawable
= drawable
;
599 if (!XF86DRICreateDrawable(psc
->dpy
, psc
->scr
, drawable
, &hwDrawable
)) {
604 /* Create a new drawable */
606 (*psc
->legacy
->createNewDrawable
) (psc
->__driScreen
,
610 empty_attribute_list
, pdraw
);
612 if (!pdraw
->driDrawable
) {
613 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
618 pdraw
->destroyDrawable
= driDestroyDrawable
;
624 driSwapBuffers(__GLXDRIdrawable
* pdraw
)
626 (*pdraw
->psc
->core
->swapBuffers
) (pdraw
->driDrawable
);
630 driCopySubBuffer(__GLXDRIdrawable
* pdraw
,
631 int x
, int y
, int width
, int height
)
633 (*pdraw
->psc
->driCopySubBuffer
->copySubBuffer
) (pdraw
->driDrawable
,
634 x
, y
, width
, height
);
638 driDestroyScreen(__GLXscreenConfigs
* psc
)
640 /* Free the direct rendering per screen data */
641 if (psc
->__driScreen
)
642 (*psc
->core
->destroyScreen
) (psc
->__driScreen
);
643 psc
->__driScreen
= NULL
;
645 dlclose(psc
->driver
);
648 static __GLXDRIscreen
*
649 driCreateScreen(__GLXscreenConfigs
* psc
, int screen
,
650 __GLXdisplayPrivate
* priv
)
652 __GLXDRIdisplayPrivate
*pdp
;
654 const __DRIextension
**extensions
;
658 psp
= Xcalloc(1, sizeof *psp
);
662 /* Initialize per screen dynamic client GLX extensions */
663 psc
->ext_list_first_time
= GL_TRUE
;
665 if (!driGetDriverName(priv
->dpy
, screen
, &driverName
)) {
670 psc
->driver
= driOpenDriver(driverName
);
672 if (psc
->driver
== NULL
) {
677 extensions
= dlsym(psc
->driver
, __DRI_DRIVER_EXTENSIONS
);
678 if (extensions
== NULL
) {
679 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
684 for (i
= 0; extensions
[i
]; i
++) {
685 if (strcmp(extensions
[i
]->name
, __DRI_CORE
) == 0)
686 psc
->core
= (__DRIcoreExtension
*) extensions
[i
];
687 if (strcmp(extensions
[i
]->name
, __DRI_LEGACY
) == 0)
688 psc
->legacy
= (__DRIlegacyExtension
*) extensions
[i
];
691 if (psc
->core
== NULL
|| psc
->legacy
== NULL
) {
696 pdp
= (__GLXDRIdisplayPrivate
*) priv
->driDisplay
;
697 psc
->__driScreen
= CallCreateNewScreen(psc
->dpy
, screen
, psc
, pdp
);
698 if (psc
->__driScreen
== NULL
) {
699 dlclose(psc
->driver
);
704 driBindExtensions(psc
, 0);
705 if (psc
->driCopySubBuffer
)
706 psp
->copySubBuffer
= driCopySubBuffer
;
708 psp
->destroyScreen
= driDestroyScreen
;
709 psp
->createContext
= driCreateContext
;
710 psp
->createDrawable
= driCreateDrawable
;
711 psp
->swapBuffers
= driSwapBuffers
;
718 /* Called from __glXFreeDisplayPrivate.
721 driDestroyDisplay(__GLXDRIdisplay
* dpy
)
727 * Allocate, initialize and return a __DRIdisplayPrivate object.
728 * This is called from __glXInitialize() when we are given a new
731 _X_HIDDEN __GLXDRIdisplay
*
732 driCreateDisplay(Display
* dpy
)
734 __GLXDRIdisplayPrivate
*pdpyp
;
735 int eventBase
, errorBase
;
736 int major
, minor
, patch
;
738 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
742 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
746 pdpyp
= Xmalloc(sizeof *pdpyp
);
751 pdpyp
->driMajor
= major
;
752 pdpyp
->driMinor
= minor
;
753 pdpyp
->driPatch
= patch
;
755 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
756 pdpyp
->base
.createScreen
= driCreateScreen
;
761 #endif /* GLX_DIRECT_RENDERING */