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 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
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"
55 ** XFree86-DRI version information
65 __DRIcontext
*driContext
;
67 __GLXscreenConfigs
*psc
;
71 * Given a display pointer and screen number, determine the name of
72 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
73 * Return True for success, False for failure.
76 driGetDriverName(Display
* dpy
, int scrNum
, char **driverName
)
81 int driverMajor
, driverMinor
, driverPatch
;
85 if (XF86DRIQueryExtension(dpy
, &event
, &error
)) { /* DRI1 */
86 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
87 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
91 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
95 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
96 &driverPatch
, driverName
);
98 ErrorMessageF("Cannot determine driver name for screen %d\n",
103 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
104 driverMajor
, driverMinor
, driverPatch
, *driverName
,
109 else if (DRI2QueryExtension(dpy
, &event
, &error
)) { /* DRI2 */
111 Bool ret
= DRI2Connect(dpy
, RootWindow(dpy
, scrNum
), driverName
, &dev
);
123 * Exported function for querying the DRI driver for a given screen.
125 * The returned char pointer points to a static array that will be
126 * overwritten by subsequent calls.
129 glXGetScreenDriver(Display
* dpy
, int scrNum
)
133 if (driGetDriverName(dpy
, scrNum
, &driverName
)) {
137 len
= strlen(driverName
);
140 memcpy(ret
, driverName
, len
+ 1);
148 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
150 * The returned char pointer points directly into the driver. Therefore
151 * it should be treated as a constant.
153 * If the driver was not found or does not support configuration NULL is
156 * Note: The driver remains opened after this function returns.
159 glXGetDriverConfig(const char *driverName
)
161 void *handle
= driOpenDriver(driverName
);
163 return dlsym(handle
, "__driConfigOptions");
168 #ifdef XDAMAGE_1_1_INTERFACE
171 has_damage_post(Display
* dpy
)
173 static GLboolean inited
= GL_FALSE
;
174 static GLboolean has_damage
;
179 if (XDamageQueryVersion(dpy
, &major
, &minor
) &&
180 major
== 1 && minor
>= 1) {
181 has_damage
= GL_TRUE
;
184 has_damage
= GL_FALSE
;
193 __glXReportDamage(__DRIdrawable
* driDraw
,
195 drm_clip_rect_t
* rects
, int num_rects
,
196 GLboolean front_buffer
, void *loaderPrivate
)
199 XserverRegion region
;
202 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
203 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
204 Display
*dpy
= psc
->dpy
;
207 if (!has_damage_post(dpy
))
213 drawable
= RootWindow(dpy
, psc
->scr
);
218 drawable
= glxDraw
->xDrawable
;
221 xrects
= malloc(sizeof(XRectangle
) * num_rects
);
225 for (i
= 0; i
< num_rects
; i
++) {
226 xrects
[i
].x
= rects
[i
].x1
+ x_off
;
227 xrects
[i
].y
= rects
[i
].y1
+ y_off
;
228 xrects
[i
].width
= rects
[i
].x2
- rects
[i
].x1
;
229 xrects
[i
].height
= rects
[i
].y2
- rects
[i
].y1
;
231 region
= XFixesCreateRegion(dpy
, xrects
, num_rects
);
233 XDamageAdd(dpy
, drawable
, region
);
234 XFixesDestroyRegion(dpy
, region
);
237 static const __DRIdamageExtension damageExtension
= {
238 {__DRI_DAMAGE
, __DRI_DAMAGE_VERSION
},
245 __glXDRIGetDrawableInfo(__DRIdrawable
* drawable
,
246 unsigned int *index
, unsigned int *stamp
,
247 int *X
, int *Y
, int *W
, int *H
,
248 int *numClipRects
, drm_clip_rect_t
** pClipRects
,
249 int *backX
, int *backY
,
250 int *numBackClipRects
,
251 drm_clip_rect_t
** pBackClipRects
,
254 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
255 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
256 Display
*dpy
= psc
->dpy
;
258 return XF86DRIGetDrawableInfo(dpy
, psc
->scr
, glxDraw
->drawable
,
259 index
, stamp
, X
, Y
, W
, H
,
260 numClipRects
, pClipRects
,
262 numBackClipRects
, pBackClipRects
);
265 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension
= {
266 {__DRI_GET_DRAWABLE_INFO
, __DRI_GET_DRAWABLE_INFO_VERSION
},
267 __glXDRIGetDrawableInfo
270 static const __DRIextension
*loader_extensions
[] = {
271 &systemTimeExtension
.base
,
272 &getDrawableInfoExtension
.base
,
273 #ifdef XDAMAGE_1_1_INTERFACE
274 &damageExtension
.base
,
280 * Perform the required libGL-side initialization and call the client-side
281 * driver's \c __driCreateNewScreen function.
283 * \param dpy Display pointer.
284 * \param scrn Screen number on the display.
285 * \param psc DRI screen information.
286 * \param driDpy DRI display information.
287 * \param createNewScreen Pointer to the client-side driver's
288 * \c __driCreateNewScreen function.
289 * \returns A pointer to the \c __DRIscreen structure returned by
290 * the client-side driver on success, or \c NULL on failure.
293 CallCreateNewScreen(Display
* dpy
, int scrn
, __GLXscreenConfigs
* psc
,
294 struct dri_display
* driDpy
)
298 drmAddress pSAREA
= MAP_FAILED
;
300 __DRIversion ddx_version
;
301 __DRIversion dri_version
;
302 __DRIversion drm_version
;
303 __DRIframebuffer framebuffer
;
308 drmVersionPtr version
;
313 const __DRIconfig
**driver_configs
;
314 __GLcontextModes
*visual
;
316 /* DRI protocol version. */
317 dri_version
.major
= driDpy
->driMajor
;
318 dri_version
.minor
= driDpy
->driMinor
;
319 dri_version
.patch
= driDpy
->driPatch
;
321 framebuffer
.base
= MAP_FAILED
;
322 framebuffer
.dev_priv
= NULL
;
323 framebuffer
.size
= 0;
325 if (!XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
326 ErrorMessageF("XF86DRIOpenConnection failed\n");
330 fd
= drmOpenOnce(NULL
, BusID
, &newlyopened
);
332 Xfree(BusID
); /* No longer needed */
335 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd
));
339 if (drmGetMagic(fd
, &magic
)) {
340 ErrorMessageF("drmGetMagic failed\n");
344 version
= drmGetVersion(fd
);
346 drm_version
.major
= version
->version_major
;
347 drm_version
.minor
= version
->version_minor
;
348 drm_version
.patch
= version
->version_patchlevel
;
349 drmFreeVersion(version
);
352 drm_version
.major
= -1;
353 drm_version
.minor
= -1;
354 drm_version
.patch
= -1;
357 if (newlyopened
&& !XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
358 ErrorMessageF("XF86DRIAuthConnection failed\n");
362 /* Get device name (like "tdfx") and the ddx version numbers.
363 * We'll check the version in each DRI driver's "createNewScreen"
365 if (!XF86DRIGetClientDriverName(dpy
, scrn
,
368 &ddx_version
.patch
, &driverName
)) {
369 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
373 Xfree(driverName
); /* No longer needed. */
376 * Get device-specific info. pDevPriv will point to a struct
377 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
378 * has information about the screen size, depth, pitch, ancilliary
379 * buffers, DRM mmap handles, etc.
381 if (!XF86DRIGetDeviceInfo(dpy
, scrn
, &hFB
, &junk
,
382 &framebuffer
.size
, &framebuffer
.stride
,
383 &framebuffer
.dev_priv_size
,
384 &framebuffer
.dev_priv
)) {
385 ErrorMessageF("XF86DRIGetDeviceInfo failed");
389 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
390 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
392 /* Map the framebuffer region. */
393 status
= drmMap(fd
, hFB
, framebuffer
.size
,
394 (drmAddressPtr
) & framebuffer
.base
);
396 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status
));
400 /* Map the SAREA region. Further mmap regions may be setup in
401 * each DRI driver's "createNewScreen" function.
403 status
= drmMap(fd
, hSAREA
, SAREA_MAX
, &pSAREA
);
405 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status
));
409 psp
= (*psc
->legacy
->createNewScreen
) (scrn
,
417 &driver_configs
, psc
);
420 ErrorMessageF("Calling driver entry point failed");
424 psc
->configs
= driConvertConfigs(psc
->core
, psc
->configs
, driver_configs
);
425 psc
->visuals
= driConvertConfigs(psc
->core
, psc
->visuals
, driver_configs
);
427 psc
->driver_configs
= driver_configs
;
429 /* Visuals with depth != screen depth are subject to automatic compositing
430 * in the X server, so DRI1 can't render to them properly. Mark them as
431 * non-conformant to prevent apps from picking them up accidentally.
433 for (visual
= psc
->visuals
; visual
; visual
= visual
->next
) {
434 XVisualInfo
template;
435 XVisualInfo
*visuals
;
439 template.visualid
= visual
->visualID
;
441 visuals
= XGetVisualInfo(dpy
, mask
, &template, &num_visuals
);
444 if (num_visuals
> 0 && visuals
->depth
!= DefaultDepth(dpy
, scrn
))
445 visual
->visualRating
= GLX_NON_CONFORMANT_CONFIG
;
454 if (pSAREA
!= MAP_FAILED
)
455 drmUnmap(pSAREA
, SAREA_MAX
);
457 if (framebuffer
.base
!= MAP_FAILED
)
458 drmUnmap((drmAddress
) framebuffer
.base
, framebuffer
.size
);
460 if (framebuffer
.dev_priv
!= NULL
)
461 Xfree(framebuffer
.dev_priv
);
466 XF86DRICloseConnection(dpy
, scrn
);
468 ErrorMessageF("reverting to software direct rendering\n");
474 driDestroyContext(__GLXDRIcontext
* context
,
475 __GLXscreenConfigs
* psc
, Display
* dpy
)
477 struct dri_context
*pcp
= (struct dri_context
*) context
;
479 (*psc
->core
->destroyContext
) (pcp
->driContext
);
481 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
486 driBindContext(__GLXDRIcontext
* context
,
487 __GLXDRIdrawable
* draw
, __GLXDRIdrawable
* read
)
489 struct dri_context
*pcp
= (struct dri_context
*) context
;
490 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
492 return (*core
->bindContext
) (pcp
->driContext
,
493 draw
->driDrawable
, read
->driDrawable
);
497 driUnbindContext(__GLXDRIcontext
* context
)
499 struct dri_context
*pcp
= (struct dri_context
*) context
;
500 const __DRIcoreExtension
*core
= pcp
->psc
->core
;
502 (*core
->unbindContext
) (pcp
->driContext
);
505 static __GLXDRIcontext
*
506 driCreateContext(__GLXscreenConfigs
* psc
,
507 const __GLcontextModes
* mode
,
508 GLXContext gc
, GLXContext shareList
, int renderType
)
510 struct dri_context
*pcp
, *pcp_shared
;
511 drm_context_t hwContext
;
512 __DRIcontext
*shared
= NULL
;
513 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) mode
;
515 if (!psc
|| !psc
->driScreen
)
519 pcp_shared
= (struct dri_context
*) shareList
->driContext
;
520 shared
= pcp_shared
->driContext
;
523 pcp
= Xmalloc(sizeof *pcp
);
528 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
530 &pcp
->hwContextID
, &hwContext
)) {
536 (*psc
->legacy
->createNewContext
) (psc
->__driScreen
,
538 renderType
, shared
, hwContext
, pcp
);
539 if (pcp
->driContext
== NULL
) {
540 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
545 pcp
->base
.destroyContext
= driDestroyContext
;
546 pcp
->base
.bindContext
= driBindContext
;
547 pcp
->base
.unbindContext
= driUnbindContext
;
553 driDestroyDrawable(__GLXDRIdrawable
* pdraw
)
555 __GLXscreenConfigs
*psc
= pdraw
->psc
;
557 (*psc
->core
->destroyDrawable
) (pdraw
->driDrawable
);
558 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, pdraw
->drawable
);
562 static __GLXDRIdrawable
*
563 driCreateDrawable(__GLXscreenConfigs
* psc
,
565 GLXDrawable drawable
, const __GLcontextModes
* modes
)
567 __GLXDRIdrawable
*pdraw
;
568 drm_drawable_t hwDrawable
;
569 void *empty_attribute_list
= NULL
;
570 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) modes
;
572 /* Old dri can't handle GLX 1.3+ drawable constructors. */
573 if (xDrawable
!= drawable
)
576 pdraw
= Xmalloc(sizeof(*pdraw
));
580 pdraw
->drawable
= drawable
;
583 if (!XF86DRICreateDrawable(psc
->dpy
, psc
->scr
, drawable
, &hwDrawable
)) {
588 /* Create a new drawable */
590 (*psc
->legacy
->createNewDrawable
) (psc
->__driScreen
,
594 empty_attribute_list
, pdraw
);
596 if (!pdraw
->driDrawable
) {
597 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
602 pdraw
->destroyDrawable
= driDestroyDrawable
;
608 driSwapBuffers(__GLXDRIdrawable
* pdraw
, int64_t unused1
, int64_t unused2
,
611 (*pdraw
->psc
->core
->swapBuffers
) (pdraw
->driDrawable
);
616 driCopySubBuffer(__GLXDRIdrawable
* pdraw
,
617 int x
, int y
, int width
, int height
)
619 (*pdraw
->psc
->driCopySubBuffer
->copySubBuffer
) (pdraw
->driDrawable
,
620 x
, y
, width
, height
);
624 driDestroyScreen(__GLXscreenConfigs
* psc
)
626 /* Free the direct rendering per screen data */
627 if (psc
->__driScreen
)
628 (*psc
->core
->destroyScreen
) (psc
->__driScreen
);
629 psc
->__driScreen
= NULL
;
631 dlclose(psc
->driver
);
634 static const struct glx_context_vtable dri_context_vtable
= {
639 static __GLXDRIscreen
*
640 driCreateScreen(__GLXscreenConfigs
* psc
, int screen
,
641 __GLXdisplayPrivate
* priv
)
643 struct dri_display
*pdp
;
645 const __DRIextension
**extensions
;
649 psp
= Xcalloc(1, sizeof *psp
);
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
= (struct dri_display
*) 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
;
705 psc
->direct_context_vtable
= &dri_context_vtable
;
710 /* Called from __glXFreeDisplayPrivate.
713 driDestroyDisplay(__GLXDRIdisplay
* dpy
)
719 * Allocate, initialize and return a __DRIdisplayPrivate object.
720 * This is called from __glXInitialize() when we are given a new
723 _X_HIDDEN __GLXDRIdisplay
*
724 driCreateDisplay(Display
* dpy
)
726 struct dri_display
*pdpyp
;
727 int eventBase
, errorBase
;
728 int major
, minor
, patch
;
730 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
734 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
738 pdpyp
= Xmalloc(sizeof *pdpyp
);
743 pdpyp
->driMajor
= major
;
744 pdpyp
->driMinor
= minor
;
745 pdpyp
->driPatch
= patch
;
747 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
748 pdpyp
->base
.createScreen
= driCreateScreen
;
753 #endif /* GLX_DIRECT_RENDERING */