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"
45 #include <sys/types.h>
48 #include "dri_common.h"
50 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate
;
51 typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate
;
53 struct __GLXDRIdisplayPrivateRec
{
57 ** XFree86-DRI version information
64 struct __GLXDRIcontextPrivateRec
{
66 __DRIcontext
*driContext
;
68 __GLXscreenConfigs
*psc
;
72 * Given a display pointer and screen number, determine the name of
73 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
74 * Return True for success, False for failure.
76 static Bool
driGetDriverName(Display
*dpy
, int scrNum
, char **driverName
)
80 int driverMajor
, driverMinor
, driverPatch
;
84 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
85 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
89 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
93 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
94 &driverPatch
, driverName
);
96 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum
);
100 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
101 driverMajor
, driverMinor
, driverPatch
, *driverName
, scrNum
);
107 * Exported function for querying the DRI driver for a given screen.
109 * The returned char pointer points to a static array that will be
110 * overwritten by subsequent calls.
112 PUBLIC
const char *glXGetScreenDriver (Display
*dpy
, int scrNum
) {
115 if (driGetDriverName(dpy
, scrNum
, &driverName
)) {
119 len
= strlen (driverName
);
122 memcpy (ret
, driverName
, len
+1);
130 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
132 * The returned char pointer points directly into the driver. Therefore
133 * it should be treated as a constant.
135 * If the driver was not found or does not support configuration NULL is
138 * Note: The driver remains opened after this function returns.
140 PUBLIC
const char *glXGetDriverConfig (const char *driverName
)
142 void *handle
= driOpenDriver (driverName
);
144 return dlsym (handle
, "__driConfigOptions");
149 #ifdef XDAMAGE_1_1_INTERFACE
151 static GLboolean
has_damage_post(Display
*dpy
)
153 static GLboolean inited
= GL_FALSE
;
154 static GLboolean has_damage
;
159 if (XDamageQueryVersion(dpy
, &major
, &minor
) &&
160 major
== 1 && minor
>= 1)
162 has_damage
= GL_TRUE
;
164 has_damage
= GL_FALSE
;
172 static void __glXReportDamage(__DRIdrawable
*driDraw
,
174 drm_clip_rect_t
*rects
, int num_rects
,
175 GLboolean front_buffer
,
179 XserverRegion region
;
182 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
183 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
184 Display
*dpy
= psc
->dpy
;
187 if (!has_damage_post(dpy
))
193 drawable
= RootWindow(dpy
, psc
->scr
);
197 drawable
= glxDraw
->xDrawable
;
200 xrects
= malloc(sizeof(XRectangle
) * num_rects
);
204 for (i
= 0; i
< num_rects
; i
++) {
205 xrects
[i
].x
= rects
[i
].x1
+ x_off
;
206 xrects
[i
].y
= rects
[i
].y1
+ y_off
;
207 xrects
[i
].width
= rects
[i
].x2
- rects
[i
].x1
;
208 xrects
[i
].height
= rects
[i
].y2
- rects
[i
].y1
;
210 region
= XFixesCreateRegion(dpy
, xrects
, num_rects
);
212 XDamageAdd(dpy
, drawable
, region
);
213 XFixesDestroyRegion(dpy
, region
);
216 static const __DRIdamageExtension damageExtension
= {
217 { __DRI_DAMAGE
, __DRI_DAMAGE_VERSION
},
224 __glXDRIGetDrawableInfo(__DRIdrawable
*drawable
,
225 unsigned int *index
, unsigned int *stamp
,
226 int *X
, int *Y
, int *W
, int *H
,
227 int *numClipRects
, drm_clip_rect_t
** pClipRects
,
228 int *backX
, int *backY
,
229 int *numBackClipRects
, drm_clip_rect_t
**pBackClipRects
,
232 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
233 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
234 Display
*dpy
= psc
->dpy
;
236 return XF86DRIGetDrawableInfo(dpy
, psc
->scr
, glxDraw
->drawable
,
237 index
, stamp
, X
, Y
, W
, H
,
238 numClipRects
, pClipRects
,
240 numBackClipRects
, pBackClipRects
);
243 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension
= {
244 { __DRI_GET_DRAWABLE_INFO
, __DRI_GET_DRAWABLE_INFO_VERSION
},
245 __glXDRIGetDrawableInfo
248 static const __DRIextension
*loader_extensions
[] = {
249 &systemTimeExtension
.base
,
250 &getDrawableInfoExtension
.base
,
251 #ifdef XDAMAGE_1_1_INTERFACE
252 &damageExtension
.base
,
257 #ifndef GLX_USE_APPLEGL
260 * Perform the required libGL-side initialization and call the client-side
261 * driver's \c __driCreateNewScreen function.
263 * \param dpy Display pointer.
264 * \param scrn Screen number on the display.
265 * \param psc DRI screen information.
266 * \param driDpy DRI display information.
267 * \param createNewScreen Pointer to the client-side driver's
268 * \c __driCreateNewScreen function.
269 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
270 * the client-side driver on success, or \c NULL on failure.
273 CallCreateNewScreen(Display
*dpy
, int scrn
, __GLXscreenConfigs
*psc
,
274 __GLXDRIdisplayPrivate
* driDpy
)
278 drmAddress pSAREA
= MAP_FAILED
;
280 __DRIversion ddx_version
;
281 __DRIversion dri_version
;
282 __DRIversion drm_version
;
283 __DRIframebuffer framebuffer
;
288 drmVersionPtr version
;
293 const __DRIconfig
**driver_configs
;
295 /* DRI protocol version. */
296 dri_version
.major
= driDpy
->driMajor
;
297 dri_version
.minor
= driDpy
->driMinor
;
298 dri_version
.patch
= driDpy
->driPatch
;
300 framebuffer
.base
= MAP_FAILED
;
301 framebuffer
.dev_priv
= NULL
;
303 if (!XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
304 ErrorMessageF("XF86DRIOpenConnection failed\n");
308 fd
= drmOpenOnce(NULL
, BusID
, &newlyopened
);
310 Xfree(BusID
); /* No longer needed */
313 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd
));
317 if (drmGetMagic(fd
, &magic
)) {
318 ErrorMessageF("drmGetMagic failed\n");
322 version
= drmGetVersion(fd
);
324 drm_version
.major
= version
->version_major
;
325 drm_version
.minor
= version
->version_minor
;
326 drm_version
.patch
= version
->version_patchlevel
;
327 drmFreeVersion(version
);
330 drm_version
.major
= -1;
331 drm_version
.minor
= -1;
332 drm_version
.patch
= -1;
335 if (newlyopened
&& !XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
336 ErrorMessageF("XF86DRIAuthConnection failed\n");
340 /* Get device name (like "tdfx") and the ddx version numbers.
341 * We'll check the version in each DRI driver's "createNewScreen"
343 if (!XF86DRIGetClientDriverName(dpy
, scrn
,
348 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
352 Xfree(driverName
); /* 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) that
357 * has information about the screen size, depth, pitch, ancilliary
358 * buffers, DRM mmap handles, etc.
360 if (!XF86DRIGetDeviceInfo(dpy
, scrn
, &hFB
, &junk
,
361 &framebuffer
.size
, &framebuffer
.stride
,
362 &framebuffer
.dev_priv_size
, &framebuffer
.dev_priv
)) {
363 ErrorMessageF("XF86DRIGetDeviceInfo failed");
367 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
368 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
370 /* Map the framebuffer region. */
371 status
= drmMap(fd
, hFB
, framebuffer
.size
,
372 (drmAddressPtr
)&framebuffer
.base
);
374 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status
));
378 /* Map the SAREA region. Further mmap regions may be setup in
379 * each DRI driver's "createNewScreen" function.
381 status
= drmMap(fd
, hSAREA
, SAREA_MAX
, &pSAREA
);
383 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status
));
387 psp
= (*psc
->legacy
->createNewScreen
)(scrn
,
399 ErrorMessageF("Calling driver entry point failed");
403 psc
->configs
= driConvertConfigs(psc
->core
, psc
->configs
, driver_configs
);
404 psc
->visuals
= driConvertConfigs(psc
->core
, psc
->visuals
, driver_configs
);
409 if (pSAREA
!= MAP_FAILED
)
410 drmUnmap(pSAREA
, SAREA_MAX
);
412 if (framebuffer
.base
!= MAP_FAILED
)
413 drmUnmap((drmAddress
)framebuffer
.base
, framebuffer
.size
);
415 if (framebuffer
.dev_priv
!= NULL
)
416 Xfree(framebuffer
.dev_priv
);
421 XF86DRICloseConnection(dpy
, scrn
);
423 ErrorMessageF("reverting to software direct rendering\n");
428 #else /* !GLX_USE_APPLEGL */
431 CallCreateNewScreen(Display
*dpy
, int scrn
, __GLXscreenConfigs
*psc
,
432 __GLXDRIdisplayPrivate
* driDpy
)
437 #endif /* !GLX_USE_APPLEGL */
439 static void driDestroyContext(__GLXDRIcontext
*context
,
440 __GLXscreenConfigs
*psc
, Display
*dpy
)
442 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
444 (*psc
->core
->destroyContext
)(pcp
->driContext
);
446 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
450 static Bool
driBindContext(__GLXDRIcontext
*context
,
451 __GLXDRIdrawable
*draw
, __GLXDRIdrawable
*read
)
453 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
454 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
456 return (*core
->bindContext
)(pcp
->driContext
,
461 static void driUnbindContext(__GLXDRIcontext
*context
)
463 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
464 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
466 (*core
->unbindContext
)(pcp
->driContext
);
469 static __GLXDRIcontext
*driCreateContext(__GLXscreenConfigs
*psc
,
470 const __GLcontextModes
*mode
,
472 GLXContext shareList
, int renderType
)
474 __GLXDRIcontextPrivate
*pcp
, *pcp_shared
;
475 drm_context_t hwContext
;
476 __DRIcontext
*shared
= NULL
;
477 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) mode
;
479 if (!psc
|| !psc
->driScreen
)
483 pcp_shared
= (__GLXDRIcontextPrivate
*) shareList
->driContext
;
484 shared
= pcp_shared
->driContext
;
487 pcp
= Xmalloc(sizeof *pcp
);
492 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
494 &pcp
->hwContextID
, &hwContext
)) {
500 (*psc
->legacy
->createNewContext
)(psc
->__driScreen
,
506 if (pcp
->driContext
== NULL
) {
507 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
512 pcp
->base
.destroyContext
= driDestroyContext
;
513 pcp
->base
.bindContext
= driBindContext
;
514 pcp
->base
.unbindContext
= driUnbindContext
;
519 static void driDestroyDrawable(__GLXDRIdrawable
*pdraw
)
521 __GLXscreenConfigs
*psc
= pdraw
->psc
;
523 (*psc
->core
->destroyDrawable
)(pdraw
->driDrawable
);
524 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, pdraw
->drawable
);
528 static __GLXDRIdrawable
*driCreateDrawable(__GLXscreenConfigs
*psc
,
530 GLXDrawable drawable
,
531 const __GLcontextModes
*modes
)
533 __GLXDRIdrawable
*pdraw
;
534 drm_drawable_t hwDrawable
;
535 void *empty_attribute_list
= NULL
;
536 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) modes
;
538 /* Old dri can't handle GLX 1.3+ drawable constructors. */
539 if (xDrawable
!= drawable
)
542 pdraw
= Xmalloc(sizeof(*pdraw
));
546 pdraw
->drawable
= drawable
;
549 if (!XF86DRICreateDrawable(psc
->dpy
, psc
->scr
, drawable
, &hwDrawable
))
552 /* Create a new drawable */
554 (*psc
->legacy
->createNewDrawable
)(psc
->__driScreen
,
558 empty_attribute_list
,
561 if (!pdraw
->driDrawable
) {
562 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
567 pdraw
->destroyDrawable
= driDestroyDrawable
;
572 static void driSwapBuffers(__GLXDRIdrawable
*pdraw
)
574 (*pdraw
->psc
->core
->swapBuffers
)(pdraw
->driDrawable
);
577 static void driDestroyScreen(__GLXscreenConfigs
*psc
)
579 /* Free the direct rendering per screen data */
580 if (psc
->__driScreen
)
581 (*psc
->core
->destroyScreen
)(psc
->__driScreen
);
582 psc
->__driScreen
= NULL
;
584 dlclose(psc
->driver
);
587 static __GLXDRIscreen
*driCreateScreen(__GLXscreenConfigs
*psc
, int screen
,
588 __GLXdisplayPrivate
*priv
)
590 __GLXDRIdisplayPrivate
*pdp
;
592 const __DRIextension
**extensions
;
596 psp
= Xmalloc(sizeof *psp
);
600 /* Initialize per screen dynamic client GLX extensions */
601 psc
->ext_list_first_time
= GL_TRUE
;
603 if (!driGetDriverName(priv
->dpy
, screen
, &driverName
)) {
608 psc
->driver
= driOpenDriver(driverName
);
610 if (psc
->driver
== NULL
) {
615 extensions
= dlsym(psc
->driver
, __DRI_DRIVER_EXTENSIONS
);
616 if (extensions
== NULL
) {
617 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
622 for (i
= 0; extensions
[i
]; i
++) {
623 if (strcmp(extensions
[i
]->name
, __DRI_CORE
) == 0)
624 psc
->core
= (__DRIcoreExtension
*) extensions
[i
];
625 if (strcmp(extensions
[i
]->name
, __DRI_LEGACY
) == 0)
626 psc
->legacy
= (__DRIlegacyExtension
*) extensions
[i
];
629 if (psc
->core
== NULL
|| psc
->legacy
== NULL
) {
634 pdp
= (__GLXDRIdisplayPrivate
*) priv
->driDisplay
;
636 CallCreateNewScreen(psc
->dpy
, screen
, psc
, pdp
);
637 if (psc
->__driScreen
== NULL
) {
638 dlclose(psc
->driver
);
643 driBindExtensions(psc
, 0);
645 psp
->destroyScreen
= driDestroyScreen
;
646 psp
->createContext
= driCreateContext
;
647 psp
->createDrawable
= driCreateDrawable
;
648 psp
->swapBuffers
= driSwapBuffers
;
653 /* Called from __glXFreeDisplayPrivate.
655 static void driDestroyDisplay(__GLXDRIdisplay
*dpy
)
661 * Allocate, initialize and return a __DRIdisplayPrivate object.
662 * This is called from __glXInitialize() when we are given a new
665 _X_HIDDEN __GLXDRIdisplay
*driCreateDisplay(Display
*dpy
)
667 __GLXDRIdisplayPrivate
*pdpyp
;
668 int eventBase
, errorBase
;
669 int major
, minor
, patch
;
671 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
675 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
679 pdpyp
= Xmalloc(sizeof *pdpyp
);
684 pdpyp
->driMajor
= major
;
685 pdpyp
->driMinor
= minor
;
686 pdpyp
->driPatch
= patch
;
688 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
689 pdpyp
->base
.createScreen
= driCreateScreen
;
694 #endif /* GLX_DIRECT_RENDERING */