1 /* -*- mode: c; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3; coding: utf-8-unix -*- */
2 /**************************************************************************
4 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sub license, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
15 The above copyright notice and this permission notice (including the
16 next paragraph) shall be included in all copies or substantial portions
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
23 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
31 * Kevin E. Martin <kevin@precisioninsight.com>
32 * Brian Paul <brian@precisioninsight.com>
36 #ifdef GLX_DIRECT_RENDERING
39 #include <X11/extensions/Xfixes.h>
40 #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
,
258 #ifndef GLX_USE_APPLEGL
261 * Perform the required libGL-side initialization and call the client-side
262 * driver's \c __driCreateNewScreen function.
264 * \param dpy Display pointer.
265 * \param scrn Screen number on the display.
266 * \param psc DRI screen information.
267 * \param driDpy DRI display information.
268 * \param createNewScreen Pointer to the client-side driver's
269 * \c __driCreateNewScreen function.
270 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
271 * the client-side driver on success, or \c NULL on failure.
274 CallCreateNewScreen(Display
*dpy
, int scrn
, __GLXscreenConfigs
*psc
,
275 __GLXDRIdisplayPrivate
* driDpy
)
279 drmAddress pSAREA
= MAP_FAILED
;
281 __DRIversion ddx_version
;
282 __DRIversion dri_version
;
283 __DRIversion drm_version
;
284 __DRIframebuffer framebuffer
;
289 drmVersionPtr version
;
294 const __DRIconfig
**driver_configs
;
296 /* DRI protocol version. */
297 dri_version
.major
= driDpy
->driMajor
;
298 dri_version
.minor
= driDpy
->driMinor
;
299 dri_version
.patch
= driDpy
->driPatch
;
301 framebuffer
.base
= MAP_FAILED
;
302 framebuffer
.dev_priv
= NULL
;
304 if (!XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
305 ErrorMessageF("XF86DRIOpenConnection failed\n");
309 fd
= drmOpenOnce(NULL
, BusID
, &newlyopened
);
311 Xfree(BusID
); /* No longer needed */
314 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd
));
318 if (drmGetMagic(fd
, &magic
)) {
319 ErrorMessageF("drmGetMagic failed\n");
323 version
= drmGetVersion(fd
);
325 drm_version
.major
= version
->version_major
;
326 drm_version
.minor
= version
->version_minor
;
327 drm_version
.patch
= version
->version_patchlevel
;
328 drmFreeVersion(version
);
331 drm_version
.major
= -1;
332 drm_version
.minor
= -1;
333 drm_version
.patch
= -1;
336 if (newlyopened
&& !XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
337 ErrorMessageF("XF86DRIAuthConnection failed\n");
341 /* Get device name (like "tdfx") and the ddx version numbers.
342 * We'll check the version in each DRI driver's "createNewScreen"
344 if (!XF86DRIGetClientDriverName(dpy
, scrn
,
349 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
353 Xfree(driverName
); /* No longer needed. */
356 * Get device-specific info. pDevPriv will point to a struct
357 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
358 * has information about the screen size, depth, pitch, ancilliary
359 * buffers, DRM mmap handles, etc.
361 if (!XF86DRIGetDeviceInfo(dpy
, scrn
, &hFB
, &junk
,
362 &framebuffer
.size
, &framebuffer
.stride
,
363 &framebuffer
.dev_priv_size
, &framebuffer
.dev_priv
)) {
364 ErrorMessageF("XF86DRIGetDeviceInfo failed");
368 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
369 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
371 /* Map the framebuffer region. */
372 status
= drmMap(fd
, hFB
, framebuffer
.size
,
373 (drmAddressPtr
)&framebuffer
.base
);
375 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status
));
379 /* Map the SAREA region. Further mmap regions may be setup in
380 * each DRI driver's "createNewScreen" function.
382 status
= drmMap(fd
, hSAREA
, SAREA_MAX
, &pSAREA
);
384 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status
));
388 psp
= (*psc
->legacy
->createNewScreen
)(scrn
,
400 ErrorMessageF("Calling driver entry point failed");
404 psc
->configs
= driConvertConfigs(psc
->core
, psc
->configs
, driver_configs
);
405 psc
->visuals
= driConvertConfigs(psc
->core
, psc
->visuals
, driver_configs
);
410 if (pSAREA
!= MAP_FAILED
)
411 drmUnmap(pSAREA
, SAREA_MAX
);
413 if (framebuffer
.base
!= MAP_FAILED
)
414 drmUnmap((drmAddress
)framebuffer
.base
, framebuffer
.size
);
416 if (framebuffer
.dev_priv
!= NULL
)
417 Xfree(framebuffer
.dev_priv
);
422 XF86DRICloseConnection(dpy
, scrn
);
424 ErrorMessageF("reverting to software direct rendering\n");
429 #else /* !GLX_USE_APPLEGL */
432 CallCreateNewScreen(Display
*dpy
, int scrn
, __GLXscreenConfigs
*psc
,
433 __GLXDRIdisplayPrivate
* driDpy
)
438 #endif /* !GLX_USE_APPLEGL */
440 static void driDestroyContext(__GLXDRIcontext
*context
,
441 __GLXscreenConfigs
*psc
, Display
*dpy
)
443 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
445 (*psc
->core
->destroyContext
)(pcp
->driContext
);
447 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
451 static Bool
driBindContext(__GLXDRIcontext
*context
,
452 __GLXDRIdrawable
*draw
, __GLXDRIdrawable
*read
)
454 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
455 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
457 return (*core
->bindContext
)(pcp
->driContext
,
462 static void driUnbindContext(__GLXDRIcontext
*context
)
464 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
465 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
467 (*core
->unbindContext
)(pcp
->driContext
);
470 static __GLXDRIcontext
*driCreateContext(__GLXscreenConfigs
*psc
,
471 const __GLcontextModes
*mode
,
473 GLXContext shareList
, int renderType
)
475 __GLXDRIcontextPrivate
*pcp
, *pcp_shared
;
476 drm_context_t hwContext
;
477 __DRIcontext
*shared
= NULL
;
478 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) mode
;
480 if (!psc
|| !psc
->driScreen
)
484 pcp_shared
= (__GLXDRIcontextPrivate
*) shareList
->driContext
;
485 shared
= pcp_shared
->driContext
;
488 pcp
= Xmalloc(sizeof *pcp
);
493 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
495 &pcp
->hwContextID
, &hwContext
)) {
501 (*psc
->legacy
->createNewContext
)(psc
->__driScreen
,
507 if (pcp
->driContext
== NULL
) {
508 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
513 pcp
->base
.destroyContext
= driDestroyContext
;
514 pcp
->base
.bindContext
= driBindContext
;
515 pcp
->base
.unbindContext
= driUnbindContext
;
520 static void driDestroyDrawable(__GLXDRIdrawable
*pdraw
)
522 __GLXscreenConfigs
*psc
= pdraw
->psc
;
524 (*psc
->core
->destroyDrawable
)(pdraw
->driDrawable
);
525 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, pdraw
->drawable
);
529 static __GLXDRIdrawable
*driCreateDrawable(__GLXscreenConfigs
*psc
,
531 GLXDrawable drawable
,
532 const __GLcontextModes
*modes
)
534 __GLXDRIdrawable
*pdraw
;
535 drm_drawable_t hwDrawable
;
536 void *empty_attribute_list
= NULL
;
537 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) modes
;
539 /* Old dri can't handle GLX 1.3+ drawable constructors. */
540 if (xDrawable
!= drawable
)
543 pdraw
= Xmalloc(sizeof(*pdraw
));
547 pdraw
->drawable
= drawable
;
550 if (!XF86DRICreateDrawable(psc
->dpy
, psc
->scr
, drawable
, &hwDrawable
))
553 /* Create a new drawable */
555 (*psc
->legacy
->createNewDrawable
)(psc
->__driScreen
,
559 empty_attribute_list
,
562 if (!pdraw
->driDrawable
) {
563 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
568 pdraw
->destroyDrawable
= driDestroyDrawable
;
573 static void driSwapBuffers(__GLXDRIdrawable
*pdraw
)
575 (*pdraw
->psc
->core
->swapBuffers
)(pdraw
->driDrawable
);
578 static void driDestroyScreen(__GLXscreenConfigs
*psc
)
580 /* Free the direct rendering per screen data */
581 if (psc
->__driScreen
)
582 (*psc
->core
->destroyScreen
)(psc
->__driScreen
);
583 psc
->__driScreen
= NULL
;
585 dlclose(psc
->driver
);
588 static __GLXDRIscreen
*driCreateScreen(__GLXscreenConfigs
*psc
, int screen
,
589 __GLXdisplayPrivate
*priv
)
591 __GLXDRIdisplayPrivate
*pdp
;
593 const __DRIextension
**extensions
;
597 psp
= Xmalloc(sizeof *psp
);
601 /* Initialize per screen dynamic client GLX extensions */
602 psc
->ext_list_first_time
= GL_TRUE
;
604 if (!driGetDriverName(priv
->dpy
, screen
, &driverName
)) {
609 psc
->driver
= driOpenDriver(driverName
);
611 if (psc
->driver
== NULL
) {
616 extensions
= dlsym(psc
->driver
, __DRI_DRIVER_EXTENSIONS
);
617 if (extensions
== NULL
) {
618 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
623 for (i
= 0; extensions
[i
]; i
++) {
624 if (strcmp(extensions
[i
]->name
, __DRI_CORE
) == 0)
625 psc
->core
= (__DRIcoreExtension
*) extensions
[i
];
626 if (strcmp(extensions
[i
]->name
, __DRI_LEGACY
) == 0)
627 psc
->legacy
= (__DRIlegacyExtension
*) extensions
[i
];
630 if (psc
->core
== NULL
|| psc
->legacy
== NULL
) {
635 pdp
= (__GLXDRIdisplayPrivate
*) priv
->driDisplay
;
637 CallCreateNewScreen(psc
->dpy
, screen
, psc
, pdp
);
638 if (psc
->__driScreen
== NULL
) {
639 dlclose(psc
->driver
);
644 driBindExtensions(psc
, 0);
646 psp
->destroyScreen
= driDestroyScreen
;
647 psp
->createContext
= driCreateContext
;
648 psp
->createDrawable
= driCreateDrawable
;
649 psp
->swapBuffers
= driSwapBuffers
;
654 /* Called from __glXFreeDisplayPrivate.
656 static void driDestroyDisplay(__GLXDRIdisplay
*dpy
)
662 * Allocate, initialize and return a __DRIdisplayPrivate object.
663 * This is called from __glXInitialize() when we are given a new
666 _X_HIDDEN __GLXDRIdisplay
*driCreateDisplay(Display
*dpy
)
668 __GLXDRIdisplayPrivate
*pdpyp
;
669 int eventBase
, errorBase
;
670 int major
, minor
, patch
;
672 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
676 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
680 pdpyp
= Xmalloc(sizeof *pdpyp
);
685 pdpyp
->driMajor
= major
;
686 pdpyp
->driMinor
= minor
;
687 pdpyp
->driPatch
= patch
;
689 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
690 pdpyp
->base
.createScreen
= driCreateScreen
;
695 #endif /* GLX_DIRECT_RENDERING */