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"
45 #include <sys/types.h>
48 #include "dri_common.h"
50 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate
;
51 typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate
;
53 struct __GLXDRIdisplayPrivateRec
58 ** XFree86-DRI version information
65 struct __GLXDRIcontextPrivateRec
68 __DRIcontext
*driContext
;
70 __GLXscreenConfigs
*psc
;
74 * Given a display pointer and screen number, determine the name of
75 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
76 * Return True for success, False for failure.
79 driGetDriverName(Display
* dpy
, int scrNum
, char **driverName
)
84 int driverMajor
, driverMinor
, driverPatch
;
88 if (XF86DRIQueryExtension(dpy
, &event
, &error
)) { /* DRI1 */
89 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
90 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
94 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
98 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
99 &driverPatch
, driverName
);
101 ErrorMessageF("Cannot determine driver name for screen %d\n",
106 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
107 driverMajor
, driverMinor
, driverPatch
, *driverName
,
112 else if (DRI2QueryExtension(dpy
, &event
, &error
)) { /* DRI2 */
114 Bool ret
= DRI2Connect(dpy
, RootWindow(dpy
, scrNum
), driverName
, &dev
);
126 * Exported function for querying the DRI driver for a given screen.
128 * The returned char pointer points to a static array that will be
129 * overwritten by subsequent calls.
132 glXGetScreenDriver(Display
* dpy
, int scrNum
)
136 if (driGetDriverName(dpy
, scrNum
, &driverName
)) {
140 len
= strlen(driverName
);
143 memcpy(ret
, driverName
, len
+ 1);
151 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
153 * The returned char pointer points directly into the driver. Therefore
154 * it should be treated as a constant.
156 * If the driver was not found or does not support configuration NULL is
159 * Note: The driver remains opened after this function returns.
162 glXGetDriverConfig(const char *driverName
)
164 void *handle
= driOpenDriver(driverName
);
166 return dlsym(handle
, "__driConfigOptions");
171 #ifdef XDAMAGE_1_1_INTERFACE
174 has_damage_post(Display
* dpy
)
176 static GLboolean inited
= GL_FALSE
;
177 static GLboolean has_damage
;
182 if (XDamageQueryVersion(dpy
, &major
, &minor
) &&
183 major
== 1 && minor
>= 1) {
184 has_damage
= GL_TRUE
;
187 has_damage
= GL_FALSE
;
196 __glXReportDamage(__DRIdrawable
* driDraw
,
198 drm_clip_rect_t
* rects
, int num_rects
,
199 GLboolean front_buffer
, void *loaderPrivate
)
202 XserverRegion region
;
205 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
206 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
207 Display
*dpy
= psc
->dpy
;
210 if (!has_damage_post(dpy
))
216 drawable
= RootWindow(dpy
, psc
->scr
);
221 drawable
= glxDraw
->xDrawable
;
224 xrects
= malloc(sizeof(XRectangle
) * num_rects
);
228 for (i
= 0; i
< num_rects
; i
++) {
229 xrects
[i
].x
= rects
[i
].x1
+ x_off
;
230 xrects
[i
].y
= rects
[i
].y1
+ y_off
;
231 xrects
[i
].width
= rects
[i
].x2
- rects
[i
].x1
;
232 xrects
[i
].height
= rects
[i
].y2
- rects
[i
].y1
;
234 region
= XFixesCreateRegion(dpy
, xrects
, num_rects
);
236 XDamageAdd(dpy
, drawable
, region
);
237 XFixesDestroyRegion(dpy
, region
);
240 static const __DRIdamageExtension damageExtension
= {
241 {__DRI_DAMAGE
, __DRI_DAMAGE_VERSION
},
248 __glXDRIGetDrawableInfo(__DRIdrawable
* drawable
,
249 unsigned int *index
, unsigned int *stamp
,
250 int *X
, int *Y
, int *W
, int *H
,
251 int *numClipRects
, drm_clip_rect_t
** pClipRects
,
252 int *backX
, int *backY
,
253 int *numBackClipRects
,
254 drm_clip_rect_t
** pBackClipRects
,
257 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
258 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
259 Display
*dpy
= psc
->dpy
;
261 return XF86DRIGetDrawableInfo(dpy
, psc
->scr
, glxDraw
->drawable
,
262 index
, stamp
, X
, Y
, W
, H
,
263 numClipRects
, pClipRects
,
265 numBackClipRects
, pBackClipRects
);
268 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension
= {
269 {__DRI_GET_DRAWABLE_INFO
, __DRI_GET_DRAWABLE_INFO_VERSION
},
270 __glXDRIGetDrawableInfo
273 static const __DRIextension
*loader_extensions
[] = {
274 &systemTimeExtension
.base
,
275 &getDrawableInfoExtension
.base
,
276 #ifdef XDAMAGE_1_1_INTERFACE
277 &damageExtension
.base
,
283 * Perform the required libGL-side initialization and call the client-side
284 * driver's \c __driCreateNewScreen function.
286 * \param dpy Display pointer.
287 * \param scrn Screen number on the display.
288 * \param psc DRI screen information.
289 * \param driDpy DRI display information.
290 * \param createNewScreen Pointer to the client-side driver's
291 * \c __driCreateNewScreen function.
292 * \returns A pointer to the \c __DRIscreen structure returned by
293 * the client-side driver on success, or \c NULL on failure.
296 CallCreateNewScreen(Display
* dpy
, int scrn
, __GLXscreenConfigs
* psc
,
297 __GLXDRIdisplayPrivate
* driDpy
)
301 drmAddress pSAREA
= MAP_FAILED
;
303 __DRIversion ddx_version
;
304 __DRIversion dri_version
;
305 __DRIversion drm_version
;
306 __DRIframebuffer framebuffer
;
311 drmVersionPtr version
;
316 const __DRIconfig
**driver_configs
;
317 __GLcontextModes
*visual
;
319 /* DRI protocol version. */
320 dri_version
.major
= driDpy
->driMajor
;
321 dri_version
.minor
= driDpy
->driMinor
;
322 dri_version
.patch
= driDpy
->driPatch
;
324 framebuffer
.base
= MAP_FAILED
;
325 framebuffer
.dev_priv
= NULL
;
327 if (!XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
328 ErrorMessageF("XF86DRIOpenConnection failed\n");
332 fd
= drmOpenOnce(NULL
, BusID
, &newlyopened
);
334 Xfree(BusID
); /* No longer needed */
337 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd
));
341 if (drmGetMagic(fd
, &magic
)) {
342 ErrorMessageF("drmGetMagic failed\n");
346 version
= drmGetVersion(fd
);
348 drm_version
.major
= version
->version_major
;
349 drm_version
.minor
= version
->version_minor
;
350 drm_version
.patch
= version
->version_patchlevel
;
351 drmFreeVersion(version
);
354 drm_version
.major
= -1;
355 drm_version
.minor
= -1;
356 drm_version
.patch
= -1;
359 if (newlyopened
&& !XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
360 ErrorMessageF("XF86DRIAuthConnection failed\n");
364 /* Get device name (like "tdfx") and the ddx version numbers.
365 * We'll check the version in each DRI driver's "createNewScreen"
367 if (!XF86DRIGetClientDriverName(dpy
, scrn
,
370 &ddx_version
.patch
, &driverName
)) {
371 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
375 Xfree(driverName
); /* No longer needed. */
378 * Get device-specific info. pDevPriv will point to a struct
379 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
380 * has information about the screen size, depth, pitch, ancilliary
381 * buffers, DRM mmap handles, etc.
383 if (!XF86DRIGetDeviceInfo(dpy
, scrn
, &hFB
, &junk
,
384 &framebuffer
.size
, &framebuffer
.stride
,
385 &framebuffer
.dev_priv_size
,
386 &framebuffer
.dev_priv
)) {
387 ErrorMessageF("XF86DRIGetDeviceInfo failed");
391 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
392 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
394 /* Map the framebuffer region. */
395 status
= drmMap(fd
, hFB
, framebuffer
.size
,
396 (drmAddressPtr
) & framebuffer
.base
);
398 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status
));
402 /* Map the SAREA region. Further mmap regions may be setup in
403 * each DRI driver's "createNewScreen" function.
405 status
= drmMap(fd
, hSAREA
, SAREA_MAX
, &pSAREA
);
407 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status
));
411 psp
= (*psc
->legacy
->createNewScreen
) (scrn
,
419 &driver_configs
, psc
);
422 ErrorMessageF("Calling driver entry point failed");
426 psc
->configs
= driConvertConfigs(psc
->core
, psc
->configs
, driver_configs
);
427 psc
->visuals
= driConvertConfigs(psc
->core
, psc
->visuals
, driver_configs
);
429 psc
->driver_configs
= driver_configs
;
431 /* Visuals with depth != screen depth are subject to automatic compositing
432 * in the X server, so DRI1 can't render to them properly. Mark them as
433 * non-conformant to prevent apps from picking them up accidentally.
435 for (visual
= psc
->visuals
; visual
; visual
= visual
->next
) {
436 XVisualInfo
template;
437 XVisualInfo
*visuals
;
441 template.visualid
= visual
->visualID
;
443 visuals
= XGetVisualInfo(dpy
, mask
, &template, &num_visuals
);
446 if (num_visuals
> 0 && visuals
->depth
!= DefaultDepth(dpy
, scrn
))
447 visual
->visualRating
= GLX_NON_CONFORMANT_CONFIG
;
456 if (pSAREA
!= MAP_FAILED
)
457 drmUnmap(pSAREA
, SAREA_MAX
);
459 if (framebuffer
.base
!= MAP_FAILED
)
460 drmUnmap((drmAddress
) framebuffer
.base
, framebuffer
.size
);
462 if (framebuffer
.dev_priv
!= NULL
)
463 Xfree(framebuffer
.dev_priv
);
468 XF86DRICloseConnection(dpy
, scrn
);
470 ErrorMessageF("reverting to software direct rendering\n");
476 driDestroyContext(__GLXDRIcontext
* context
,
477 __GLXscreenConfigs
* psc
, Display
* dpy
)
479 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
481 (*psc
->core
->destroyContext
) (pcp
->driContext
);
483 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
488 driBindContext(__GLXDRIcontext
* context
,
489 __GLXDRIdrawable
* draw
, __GLXDRIdrawable
* read
)
491 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
492 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
494 return (*core
->bindContext
) (pcp
->driContext
,
495 draw
->driDrawable
, read
->driDrawable
);
499 driUnbindContext(__GLXDRIcontext
* context
)
501 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
502 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
504 (*core
->unbindContext
) (pcp
->driContext
);
507 static __GLXDRIcontext
*
508 driCreateContext(__GLXscreenConfigs
* psc
,
509 const __GLcontextModes
* mode
,
510 GLXContext gc
, GLXContext shareList
, int renderType
)
512 __GLXDRIcontextPrivate
*pcp
, *pcp_shared
;
513 drm_context_t hwContext
;
514 __DRIcontext
*shared
= NULL
;
515 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) mode
;
517 if (!psc
|| !psc
->driScreen
)
521 pcp_shared
= (__GLXDRIcontextPrivate
*) shareList
->driContext
;
522 shared
= pcp_shared
->driContext
;
525 pcp
= Xmalloc(sizeof *pcp
);
530 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
532 &pcp
->hwContextID
, &hwContext
)) {
538 (*psc
->legacy
->createNewContext
) (psc
->__driScreen
,
540 renderType
, shared
, hwContext
, pcp
);
541 if (pcp
->driContext
== NULL
) {
542 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
547 pcp
->base
.destroyContext
= driDestroyContext
;
548 pcp
->base
.bindContext
= driBindContext
;
549 pcp
->base
.unbindContext
= driUnbindContext
;
555 driDestroyDrawable(__GLXDRIdrawable
* pdraw
)
557 __GLXscreenConfigs
*psc
= pdraw
->psc
;
559 (*psc
->core
->destroyDrawable
) (pdraw
->driDrawable
);
560 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, pdraw
->drawable
);
564 static __GLXDRIdrawable
*
565 driCreateDrawable(__GLXscreenConfigs
* psc
,
567 GLXDrawable drawable
, const __GLcontextModes
* modes
)
569 __GLXDRIdrawable
*pdraw
;
570 drm_drawable_t hwDrawable
;
571 void *empty_attribute_list
= NULL
;
572 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) modes
;
574 /* Old dri can't handle GLX 1.3+ drawable constructors. */
575 if (xDrawable
!= drawable
)
578 pdraw
= Xmalloc(sizeof(*pdraw
));
582 pdraw
->drawable
= drawable
;
585 if (!XF86DRICreateDrawable(psc
->dpy
, psc
->scr
, drawable
, &hwDrawable
)) {
590 /* Create a new drawable */
592 (*psc
->legacy
->createNewDrawable
) (psc
->__driScreen
,
596 empty_attribute_list
, pdraw
);
598 if (!pdraw
->driDrawable
) {
599 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
604 pdraw
->destroyDrawable
= driDestroyDrawable
;
610 driSwapBuffers(__GLXDRIdrawable
* pdraw
, int64_t unused1
, int64_t unused2
,
613 (*pdraw
->psc
->core
->swapBuffers
) (pdraw
->driDrawable
);
618 driCopySubBuffer(__GLXDRIdrawable
* pdraw
,
619 int x
, int y
, int width
, int height
)
621 (*pdraw
->psc
->driCopySubBuffer
->copySubBuffer
) (pdraw
->driDrawable
,
622 x
, y
, width
, height
);
626 driDestroyScreen(__GLXscreenConfigs
* psc
)
628 /* Free the direct rendering per screen data */
629 if (psc
->__driScreen
)
630 (*psc
->core
->destroyScreen
) (psc
->__driScreen
);
631 psc
->__driScreen
= NULL
;
633 dlclose(psc
->driver
);
636 static __GLXDRIscreen
*
637 driCreateScreen(__GLXscreenConfigs
* psc
, int screen
,
638 __GLXdisplayPrivate
* priv
)
640 __GLXDRIdisplayPrivate
*pdp
;
642 const __DRIextension
**extensions
;
646 psp
= Xcalloc(1, sizeof *psp
);
650 /* Initialize per screen dynamic client GLX extensions */
651 psc
->ext_list_first_time
= GL_TRUE
;
653 if (!driGetDriverName(priv
->dpy
, screen
, &driverName
)) {
658 psc
->driver
= driOpenDriver(driverName
);
660 if (psc
->driver
== NULL
) {
665 extensions
= dlsym(psc
->driver
, __DRI_DRIVER_EXTENSIONS
);
666 if (extensions
== NULL
) {
667 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
672 for (i
= 0; extensions
[i
]; i
++) {
673 if (strcmp(extensions
[i
]->name
, __DRI_CORE
) == 0)
674 psc
->core
= (__DRIcoreExtension
*) extensions
[i
];
675 if (strcmp(extensions
[i
]->name
, __DRI_LEGACY
) == 0)
676 psc
->legacy
= (__DRIlegacyExtension
*) extensions
[i
];
679 if (psc
->core
== NULL
|| psc
->legacy
== NULL
) {
684 pdp
= (__GLXDRIdisplayPrivate
*) priv
->driDisplay
;
685 psc
->__driScreen
= CallCreateNewScreen(psc
->dpy
, screen
, psc
, pdp
);
686 if (psc
->__driScreen
== NULL
) {
687 dlclose(psc
->driver
);
692 driBindExtensions(psc
);
693 driBindCommonExtensions(psc
);
695 if (psc
->driCopySubBuffer
)
696 psp
->copySubBuffer
= driCopySubBuffer
;
698 psp
->destroyScreen
= driDestroyScreen
;
699 psp
->createContext
= driCreateContext
;
700 psp
->createDrawable
= driCreateDrawable
;
701 psp
->swapBuffers
= driSwapBuffers
;
708 /* Called from __glXFreeDisplayPrivate.
711 driDestroyDisplay(__GLXDRIdisplay
* dpy
)
717 * Allocate, initialize and return a __DRIdisplayPrivate object.
718 * This is called from __glXInitialize() when we are given a new
721 _X_HIDDEN __GLXDRIdisplay
*
722 driCreateDisplay(Display
* dpy
)
724 __GLXDRIdisplayPrivate
*pdpyp
;
725 int eventBase
, errorBase
;
726 int major
, minor
, patch
;
728 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
732 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
736 pdpyp
= Xmalloc(sizeof *pdpyp
);
741 pdpyp
->driMajor
= major
;
742 pdpyp
->driMinor
= minor
;
743 pdpyp
->driPatch
= patch
;
745 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
746 pdpyp
->base
.createScreen
= driCreateScreen
;
751 #endif /* GLX_DIRECT_RENDERING */