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>
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
{
58 ** XFree86-DRI version information
65 struct __GLXDRIcontextPrivateRec
{
67 __DRIcontext
*driContext
;
69 __GLXscreenConfigs
*psc
;
73 * Given a display pointer and screen number, determine the name of
74 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
75 * Return True for success, False for failure.
77 static Bool
driGetDriverName(Display
*dpy
, int scrNum
, char **driverName
)
81 int driverMajor
, driverMinor
, driverPatch
;
85 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
86 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
90 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
94 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
95 &driverPatch
, driverName
);
97 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum
);
101 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
102 driverMajor
, driverMinor
, driverPatch
, *driverName
, scrNum
);
108 * Exported function for querying the DRI driver for a given screen.
110 * The returned char pointer points to a static array that will be
111 * overwritten by subsequent calls.
113 PUBLIC
const char *glXGetScreenDriver (Display
*dpy
, int scrNum
) {
116 if (driGetDriverName(dpy
, scrNum
, &driverName
)) {
120 len
= strlen (driverName
);
123 memcpy (ret
, driverName
, len
+1);
131 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
133 * The returned char pointer points directly into the driver. Therefore
134 * it should be treated as a constant.
136 * If the driver was not found or does not support configuration NULL is
139 * Note: The driver remains opened after this function returns.
141 PUBLIC
const char *glXGetDriverConfig (const char *driverName
)
143 void *handle
= driOpenDriver (driverName
);
145 return dlsym (handle
, "__driConfigOptions");
150 #ifdef XDAMAGE_1_1_INTERFACE
152 static GLboolean
has_damage_post(Display
*dpy
)
154 static GLboolean inited
= GL_FALSE
;
155 static GLboolean has_damage
;
160 if (XDamageQueryVersion(dpy
, &major
, &minor
) &&
161 major
== 1 && minor
>= 1)
163 has_damage
= GL_TRUE
;
165 has_damage
= GL_FALSE
;
173 static void __glXReportDamage(__DRIdrawable
*driDraw
,
175 drm_clip_rect_t
*rects
, int num_rects
,
176 GLboolean front_buffer
,
180 XserverRegion region
;
183 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
184 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
185 Display
*dpy
= psc
->dpy
;
188 if (!has_damage_post(dpy
))
194 drawable
= RootWindow(dpy
, psc
->scr
);
198 drawable
= glxDraw
->xDrawable
;
201 xrects
= malloc(sizeof(XRectangle
) * num_rects
);
205 for (i
= 0; i
< num_rects
; i
++) {
206 xrects
[i
].x
= rects
[i
].x1
+ x_off
;
207 xrects
[i
].y
= rects
[i
].y1
+ y_off
;
208 xrects
[i
].width
= rects
[i
].x2
- rects
[i
].x1
;
209 xrects
[i
].height
= rects
[i
].y2
- rects
[i
].y1
;
211 region
= XFixesCreateRegion(dpy
, xrects
, num_rects
);
213 XDamageAdd(dpy
, drawable
, region
);
214 XFixesDestroyRegion(dpy
, region
);
217 static const __DRIdamageExtension damageExtension
= {
218 { __DRI_DAMAGE
, __DRI_DAMAGE_VERSION
},
225 __glXDRIGetDrawableInfo(__DRIdrawable
*drawable
,
226 unsigned int *index
, unsigned int *stamp
,
227 int *X
, int *Y
, int *W
, int *H
,
228 int *numClipRects
, drm_clip_rect_t
** pClipRects
,
229 int *backX
, int *backY
,
230 int *numBackClipRects
, drm_clip_rect_t
**pBackClipRects
,
233 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
234 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
235 Display
*dpy
= psc
->dpy
;
237 return XF86DRIGetDrawableInfo(dpy
, psc
->scr
, glxDraw
->drawable
,
238 index
, stamp
, X
, Y
, W
, H
,
239 numClipRects
, pClipRects
,
241 numBackClipRects
, pBackClipRects
);
244 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension
= {
245 { __DRI_GET_DRAWABLE_INFO
, __DRI_GET_DRAWABLE_INFO_VERSION
},
246 __glXDRIGetDrawableInfo
249 static const __DRIextension
*loader_extensions
[] = {
250 &systemTimeExtension
.base
,
251 &getDrawableInfoExtension
.base
,
252 #ifdef XDAMAGE_1_1_INTERFACE
253 &damageExtension
.base
,
259 * Perform the required libGL-side initialization and call the client-side
260 * driver's \c __driCreateNewScreen function.
262 * \param dpy Display pointer.
263 * \param scrn Screen number on the display.
264 * \param psc DRI screen information.
265 * \param driDpy DRI display information.
266 * \param createNewScreen Pointer to the client-side driver's
267 * \c __driCreateNewScreen function.
268 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
269 * the client-side driver on success, or \c NULL on failure.
271 * \todo This function needs to be modified to remove context-modes from the
272 * list stored in the \c __GLXscreenConfigsRec to match the list
273 * returned by the client-side driver.
276 CallCreateNewScreen(Display
*dpy
, int scrn
, __GLXscreenConfigs
*psc
,
277 __GLXDRIdisplayPrivate
* driDpy
)
280 #ifndef GLX_USE_APPLEGL
282 drmAddress pSAREA
= MAP_FAILED
;
284 __DRIversion ddx_version
;
285 __DRIversion dri_version
;
286 __DRIversion drm_version
;
287 __DRIframebuffer framebuffer
;
290 const char * err_msg
;
291 const char * err_extra
;
292 const __DRIconfig
**driver_configs
;
294 dri_version
.major
= driDpy
->driMajor
;
295 dri_version
.minor
= driDpy
->driMinor
;
296 dri_version
.patch
= driDpy
->driPatch
;
298 err_msg
= "XF86DRIOpenConnection";
301 framebuffer
.base
= MAP_FAILED
;
302 framebuffer
.dev_priv
= NULL
;
304 if (XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
306 fd
= drmOpenOnce(NULL
,BusID
, &newlyopened
);
307 Xfree(BusID
); /* No longer needed */
309 err_msg
= "open DRM";
310 err_extra
= strerror( -fd
);
315 err_msg
= "drmGetMagic";
318 if (!drmGetMagic(fd
, &magic
)) {
319 drmVersionPtr version
= drmGetVersion(fd
);
321 drm_version
.major
= version
->version_major
;
322 drm_version
.minor
= version
->version_minor
;
323 drm_version
.patch
= version
->version_patchlevel
;
324 drmFreeVersion(version
);
327 drm_version
.major
= -1;
328 drm_version
.minor
= -1;
329 drm_version
.patch
= -1;
332 err_msg
= "XF86DRIAuthConnection";
333 if (!newlyopened
|| XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
337 * Get device name (like "tdfx") and the ddx version
338 * numbers. We'll check the version in each DRI driver's
339 * "createNewScreen" function.
341 err_msg
= "XF86DRIGetClientDriverName";
342 if (XF86DRIGetClientDriverName(dpy
, scrn
,
350 /* No longer needed. */
355 * Get device-specific info. pDevPriv will point to a struct
356 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
357 * that has information about the screen size, depth, pitch,
358 * ancilliary buffers, DRM mmap handles, etc.
360 err_msg
= "XF86DRIGetDeviceInfo";
361 if (XF86DRIGetDeviceInfo(dpy
, scrn
,
366 &framebuffer
.dev_priv_size
,
367 &framebuffer
.dev_priv
)) {
368 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
369 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
372 * Map the framebuffer region.
374 status
= drmMap(fd
, hFB
, framebuffer
.size
,
375 (drmAddressPtr
)&framebuffer
.base
);
377 err_msg
= "drmMap of framebuffer";
378 err_extra
= strerror( -status
);
382 * Map the SAREA region. Further mmap regions
383 * may be setup in each DRI driver's
384 * "createNewScreen" function.
386 status
= drmMap(fd
, hSAREA
, SAREA_MAX
,
389 err_msg
= "drmMap of sarea";
390 err_extra
= strerror( -status
);
393 err_msg
= "InitDriver";
395 psp
= (*psc
->legacy
->createNewScreen
)(scrn
,
408 driConvertConfigs(psc
->core
,
412 driConvertConfigs(psc
->core
,
426 if ( pSAREA
!= MAP_FAILED
) {
427 (void)drmUnmap(pSAREA
, SAREA_MAX
);
430 if ( framebuffer
.base
!= MAP_FAILED
) {
431 (void)drmUnmap((drmAddress
)framebuffer
.base
, framebuffer
.size
);
434 if ( framebuffer
.dev_priv
!= NULL
) {
435 Xfree(framebuffer
.dev_priv
);
439 (void)drmCloseOnce(fd
);
442 (void)XF86DRICloseConnection(dpy
, scrn
);
444 if ( err_extra
!= NULL
) {
445 fprintf(stderr
, "libGL error: %s failed (%s)\n", err_msg
,
449 fprintf(stderr
, "libGL error: %s failed\n", err_msg
);
452 fprintf(stderr
, "libGL error: reverting to (slow) indirect rendering\n");
454 #endif /* !GLX_USE_APPLEGL */
459 static void driDestroyContext(__GLXDRIcontext
*context
,
460 __GLXscreenConfigs
*psc
, Display
*dpy
)
462 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
464 (*psc
->core
->destroyContext
)(pcp
->driContext
);
466 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
469 static Bool
driBindContext(__GLXDRIcontext
*context
,
470 __GLXDRIdrawable
*draw
, __GLXDRIdrawable
*read
)
472 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
473 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
475 return (*core
->bindContext
)(pcp
->driContext
,
480 static void driUnbindContext(__GLXDRIcontext
*context
)
482 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
483 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
485 (*core
->unbindContext
)(pcp
->driContext
);
488 static __GLXDRIcontext
*driCreateContext(__GLXscreenConfigs
*psc
,
489 const __GLcontextModes
*mode
,
491 GLXContext shareList
, int renderType
)
493 __GLXDRIcontextPrivate
*pcp
, *pcp_shared
;
494 drm_context_t hwContext
;
495 __DRIcontext
*shared
= NULL
;
496 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) mode
;
498 if (!psc
|| !psc
->driScreen
)
502 pcp_shared
= (__GLXDRIcontextPrivate
*) shareList
->driContext
;
503 shared
= pcp_shared
->driContext
;
506 pcp
= Xmalloc(sizeof *pcp
);
511 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
513 &pcp
->hwContextID
, &hwContext
)) {
519 (*psc
->legacy
->createNewContext
)(psc
->__driScreen
,
525 if (pcp
->driContext
== NULL
) {
526 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
531 pcp
->base
.destroyContext
= driDestroyContext
;
532 pcp
->base
.bindContext
= driBindContext
;
533 pcp
->base
.unbindContext
= driUnbindContext
;
538 static void driDestroyDrawable(__GLXDRIdrawable
*pdraw
)
540 __GLXscreenConfigs
*psc
= pdraw
->psc
;
542 (*psc
->core
->destroyDrawable
)(pdraw
->driDrawable
);
543 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, pdraw
->drawable
);
547 static __GLXDRIdrawable
*driCreateDrawable(__GLXscreenConfigs
*psc
,
549 GLXDrawable drawable
,
550 const __GLcontextModes
*modes
)
552 __GLXDRIdrawable
*pdraw
;
553 drm_drawable_t hwDrawable
;
554 void *empty_attribute_list
= NULL
;
555 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) modes
;
557 /* Old dri can't handle GLX 1.3+ drawable constructors. */
558 if (xDrawable
!= drawable
)
561 pdraw
= Xmalloc(sizeof(*pdraw
));
565 pdraw
->drawable
= drawable
;
568 if (!XF86DRICreateDrawable(psc
->dpy
, psc
->scr
, drawable
, &hwDrawable
))
571 /* Create a new drawable */
573 (*psc
->legacy
->createNewDrawable
)(psc
->__driScreen
,
577 empty_attribute_list
,
580 if (!pdraw
->driDrawable
) {
581 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
586 pdraw
->destroyDrawable
= driDestroyDrawable
;
591 static void driDestroyScreen(__GLXscreenConfigs
*psc
)
593 /* Free the direct rendering per screen data */
594 if (psc
->__driScreen
)
595 (*psc
->core
->destroyScreen
)(psc
->__driScreen
);
596 psc
->__driScreen
= NULL
;
598 dlclose(psc
->driver
);
601 static __GLXDRIscreen
*driCreateScreen(__GLXscreenConfigs
*psc
, int screen
,
602 __GLXdisplayPrivate
*priv
)
604 __GLXDRIdisplayPrivate
*pdp
;
606 const __DRIextension
**extensions
;
610 psp
= Xmalloc(sizeof *psp
);
614 /* Initialize per screen dynamic client GLX extensions */
615 psc
->ext_list_first_time
= GL_TRUE
;
617 if (!driGetDriverName(priv
->dpy
, screen
, &driverName
)) {
622 psc
->driver
= driOpenDriver(driverName
);
624 if (psc
->driver
== NULL
) {
629 extensions
= dlsym(psc
->driver
, __DRI_DRIVER_EXTENSIONS
);
630 if (extensions
== NULL
) {
631 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
636 for (i
= 0; extensions
[i
]; i
++) {
637 if (strcmp(extensions
[i
]->name
, __DRI_CORE
) == 0)
638 psc
->core
= (__DRIcoreExtension
*) extensions
[i
];
639 if (strcmp(extensions
[i
]->name
, __DRI_LEGACY
) == 0)
640 psc
->legacy
= (__DRIlegacyExtension
*) extensions
[i
];
643 if (psc
->core
== NULL
|| psc
->legacy
== NULL
) {
648 pdp
= (__GLXDRIdisplayPrivate
*) priv
->driDisplay
;
650 CallCreateNewScreen(psc
->dpy
, screen
, psc
, pdp
);
651 if (psc
->__driScreen
== NULL
) {
652 dlclose(psc
->driver
);
657 driBindExtensions(psc
);
659 psp
->destroyScreen
= driDestroyScreen
;
660 psp
->createContext
= driCreateContext
;
661 psp
->createDrawable
= driCreateDrawable
;
666 /* Called from __glXFreeDisplayPrivate.
668 static void driDestroyDisplay(__GLXDRIdisplay
*dpy
)
674 * Allocate, initialize and return a __DRIdisplayPrivate object.
675 * This is called from __glXInitialize() when we are given a new
678 _X_HIDDEN __GLXDRIdisplay
*driCreateDisplay(Display
*dpy
)
680 __GLXDRIdisplayPrivate
*pdpyp
;
681 int eventBase
, errorBase
;
682 int major
, minor
, patch
;
684 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
688 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
692 pdpyp
= Xmalloc(sizeof *pdpyp
);
697 pdpyp
->driMajor
= major
;
698 pdpyp
->driMinor
= minor
;
699 pdpyp
->driPatch
= patch
;
701 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
702 pdpyp
->base
.createScreen
= driCreateScreen
;
707 #endif /* GLX_DIRECT_RENDERING */