Merge remote branch 'origin/gallium-0.2' into gallium-0.2
[mesa.git] / src / glx / x11 / dri_glx.c
1 /**************************************************************************
2
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4 All Rights Reserved.
5
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:
13
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
16 of the Software.
17
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.
25
26 **************************************************************************/
27
28 /*
29 * Authors:
30 * Kevin E. Martin <kevin@precisioninsight.com>
31 * Brian Paul <brian@precisioninsight.com>
32 *
33 */
34
35 #ifdef GLX_DIRECT_RENDERING
36
37 #include <X11/Xlib.h>
38 #include <X11/extensions/Xfixes.h>
39 #include <X11/extensions/Xdamage.h>
40 #include "glxclient.h"
41 #include "glcontextmodes.h"
42 #include "xf86dri.h"
43 #include "sarea.h"
44 #include <dlfcn.h>
45 #include <sys/types.h>
46 #include <sys/mman.h>
47 #include "xf86drm.h"
48 #include "dri_common.h"
49
50 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate;
51 typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate;
52
53 struct __GLXDRIdisplayPrivateRec {
54 __GLXDRIdisplay base;
55
56 /*
57 ** XFree86-DRI version information
58 */
59 int driMajor;
60 int driMinor;
61 int driPatch;
62 };
63
64 struct __GLXDRIcontextPrivateRec {
65 __GLXDRIcontext base;
66 __DRIcontext *driContext;
67 XID hwContextID;
68 __GLXscreenConfigs *psc;
69 };
70
71 /*
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.
75 */
76 static Bool driGetDriverName(Display *dpy, int scrNum, char **driverName)
77 {
78 int directCapable;
79 Bool b;
80 int driverMajor, driverMinor, driverPatch;
81
82 *driverName = NULL;
83
84 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
85 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
86 return False;
87 }
88 if (!directCapable) {
89 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
90 return False;
91 }
92
93 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
94 &driverPatch, driverName);
95 if (!b) {
96 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum);
97 return False;
98 }
99
100 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
101 driverMajor, driverMinor, driverPatch, *driverName, scrNum);
102
103 return True;
104 }
105
106 /*
107 * Exported function for querying the DRI driver for a given screen.
108 *
109 * The returned char pointer points to a static array that will be
110 * overwritten by subsequent calls.
111 */
112 PUBLIC const char *glXGetScreenDriver (Display *dpy, int scrNum) {
113 static char ret[32];
114 char *driverName;
115 if (driGetDriverName(dpy, scrNum, &driverName)) {
116 int len;
117 if (!driverName)
118 return NULL;
119 len = strlen (driverName);
120 if (len >= 31)
121 return NULL;
122 memcpy (ret, driverName, len+1);
123 Xfree(driverName);
124 return ret;
125 }
126 return NULL;
127 }
128
129 /*
130 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
131 *
132 * The returned char pointer points directly into the driver. Therefore
133 * it should be treated as a constant.
134 *
135 * If the driver was not found or does not support configuration NULL is
136 * returned.
137 *
138 * Note: The driver remains opened after this function returns.
139 */
140 PUBLIC const char *glXGetDriverConfig (const char *driverName)
141 {
142 void *handle = driOpenDriver (driverName);
143 if (handle)
144 return dlsym (handle, "__driConfigOptions");
145 else
146 return NULL;
147 }
148
149 #ifdef XDAMAGE_1_1_INTERFACE
150
151 static GLboolean has_damage_post(Display *dpy)
152 {
153 static GLboolean inited = GL_FALSE;
154 static GLboolean has_damage;
155
156 if (!inited) {
157 int major, minor;
158
159 if (XDamageQueryVersion(dpy, &major, &minor) &&
160 major == 1 && minor >= 1)
161 {
162 has_damage = GL_TRUE;
163 } else {
164 has_damage = GL_FALSE;
165 }
166 inited = GL_TRUE;
167 }
168
169 return has_damage;
170 }
171
172 static void __glXReportDamage(__DRIdrawable *driDraw,
173 int x, int y,
174 drm_clip_rect_t *rects, int num_rects,
175 GLboolean front_buffer,
176 void *loaderPrivate)
177 {
178 XRectangle *xrects;
179 XserverRegion region;
180 int i;
181 int x_off, y_off;
182 __GLXDRIdrawable *glxDraw = loaderPrivate;
183 __GLXscreenConfigs *psc = glxDraw->psc;
184 Display *dpy = psc->dpy;
185 Drawable drawable;
186
187 if (!has_damage_post(dpy))
188 return;
189
190 if (front_buffer) {
191 x_off = x;
192 y_off = y;
193 drawable = RootWindow(dpy, psc->scr);
194 } else{
195 x_off = 0;
196 y_off = 0;
197 drawable = glxDraw->xDrawable;
198 }
199
200 xrects = malloc(sizeof(XRectangle) * num_rects);
201 if (xrects == NULL)
202 return;
203
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;
209 }
210 region = XFixesCreateRegion(dpy, xrects, num_rects);
211 free(xrects);
212 XDamageAdd(dpy, drawable, region);
213 XFixesDestroyRegion(dpy, region);
214 }
215
216 static const __DRIdamageExtension damageExtension = {
217 { __DRI_DAMAGE, __DRI_DAMAGE_VERSION },
218 __glXReportDamage,
219 };
220
221 #endif
222
223 static GLboolean
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,
230 void *loaderPrivate)
231 {
232 __GLXDRIdrawable *glxDraw = loaderPrivate;
233 __GLXscreenConfigs *psc = glxDraw->psc;
234 Display *dpy = psc->dpy;
235
236 return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
237 index, stamp, X, Y, W, H,
238 numClipRects, pClipRects,
239 backX, backY,
240 numBackClipRects, pBackClipRects);
241 }
242
243 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
244 { __DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION },
245 __glXDRIGetDrawableInfo
246 };
247
248 static const __DRIextension *loader_extensions[] = {
249 &systemTimeExtension.base,
250 &getDrawableInfoExtension.base,
251 #ifdef XDAMAGE_1_1_INTERFACE
252 &damageExtension.base,
253 #endif
254 NULL
255 };
256
257 #ifndef GLX_USE_APPLEGL
258
259 /**
260 * Perform the required libGL-side initialization and call the client-side
261 * driver's \c __driCreateNewScreen function.
262 *
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.
271 */
272 static void *
273 CallCreateNewScreen(Display *dpy, int scrn, __GLXscreenConfigs *psc,
274 __GLXDRIdisplayPrivate * driDpy)
275 {
276 void *psp = NULL;
277 drm_handle_t hSAREA;
278 drmAddress pSAREA = MAP_FAILED;
279 char *BusID;
280 __DRIversion ddx_version;
281 __DRIversion dri_version;
282 __DRIversion drm_version;
283 __DRIframebuffer framebuffer;
284 int fd = -1;
285 int status;
286
287 drm_magic_t magic;
288 drmVersionPtr version;
289 int newlyopened;
290 char *driverName;
291 drm_handle_t hFB;
292 int junk;
293 const __DRIconfig **driver_configs;
294
295 /* DRI protocol version. */
296 dri_version.major = driDpy->driMajor;
297 dri_version.minor = driDpy->driMinor;
298 dri_version.patch = driDpy->driPatch;
299
300 framebuffer.base = MAP_FAILED;
301 framebuffer.dev_priv = NULL;
302
303 if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
304 ErrorMessageF("XF86DRIOpenConnection failed\n");
305 goto handle_error;
306 }
307
308 fd = drmOpenOnce(NULL, BusID, &newlyopened);
309
310 Xfree(BusID); /* No longer needed */
311
312 if (fd < 0) {
313 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
314 goto handle_error;
315 }
316
317 if (drmGetMagic(fd, &magic)) {
318 ErrorMessageF("drmGetMagic failed\n");
319 goto handle_error;
320 }
321
322 version = drmGetVersion(fd);
323 if (version) {
324 drm_version.major = version->version_major;
325 drm_version.minor = version->version_minor;
326 drm_version.patch = version->version_patchlevel;
327 drmFreeVersion(version);
328 }
329 else {
330 drm_version.major = -1;
331 drm_version.minor = -1;
332 drm_version.patch = -1;
333 }
334
335 if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
336 ErrorMessageF("XF86DRIAuthConnection failed\n");
337 goto handle_error;
338 }
339
340 /* Get device name (like "tdfx") and the ddx version numbers.
341 * We'll check the version in each DRI driver's "createNewScreen"
342 * function. */
343 if (!XF86DRIGetClientDriverName(dpy, scrn,
344 &ddx_version.major,
345 &ddx_version.minor,
346 &ddx_version.patch,
347 &driverName)) {
348 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
349 goto handle_error;
350 }
351
352 Xfree(driverName); /* No longer needed. */
353
354 /*
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.
359 */
360 if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
361 &framebuffer.size, &framebuffer.stride,
362 &framebuffer.dev_priv_size, &framebuffer.dev_priv)) {
363 ErrorMessageF("XF86DRIGetDeviceInfo failed");
364 goto handle_error;
365 }
366
367 framebuffer.width = DisplayWidth(dpy, scrn);
368 framebuffer.height = DisplayHeight(dpy, scrn);
369
370 /* Map the framebuffer region. */
371 status = drmMap(fd, hFB, framebuffer.size,
372 (drmAddressPtr)&framebuffer.base);
373 if (status != 0) {
374 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status));
375 goto handle_error;
376 }
377
378 /* Map the SAREA region. Further mmap regions may be setup in
379 * each DRI driver's "createNewScreen" function.
380 */
381 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
382 if (status != 0) {
383 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status));
384 goto handle_error;
385 }
386
387 psp = (*psc->legacy->createNewScreen)(scrn,
388 &ddx_version,
389 &dri_version,
390 &drm_version,
391 &framebuffer,
392 pSAREA,
393 fd,
394 loader_extensions,
395 &driver_configs,
396 psc);
397
398 if (psp == NULL) {
399 ErrorMessageF("Calling driver entry point failed");
400 goto handle_error;
401 }
402
403 psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs);
404 psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs);
405
406 return psp;
407
408 handle_error:
409 if (pSAREA != MAP_FAILED)
410 drmUnmap(pSAREA, SAREA_MAX);
411
412 if (framebuffer.base != MAP_FAILED)
413 drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
414
415 if (framebuffer.dev_priv != NULL)
416 Xfree(framebuffer.dev_priv);
417
418 if (fd >= 0)
419 drmCloseOnce(fd);
420
421 XF86DRICloseConnection(dpy, scrn);
422
423 ErrorMessageF("reverting to software direct rendering\n");
424
425 return NULL;
426 }
427
428 #else /* !GLX_USE_APPLEGL */
429
430 static void *
431 CallCreateNewScreen(Display *dpy, int scrn, __GLXscreenConfigs *psc,
432 __GLXDRIdisplayPrivate * driDpy)
433 {
434 return NULL;
435 }
436
437 #endif /* !GLX_USE_APPLEGL */
438
439 static void driDestroyContext(__GLXDRIcontext *context,
440 __GLXscreenConfigs *psc, Display *dpy)
441 {
442 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
443
444 (*psc->core->destroyContext)(pcp->driContext);
445
446 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
447 Xfree(pcp);
448 }
449
450 static Bool driBindContext(__GLXDRIcontext *context,
451 __GLXDRIdrawable *draw, __GLXDRIdrawable *read)
452 {
453 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
454 const __DRIcoreExtension *core = pcp->psc->core;
455
456 return (*core->bindContext)(pcp->driContext,
457 draw->driDrawable,
458 read->driDrawable);
459 }
460
461 static void driUnbindContext(__GLXDRIcontext *context)
462 {
463 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
464 const __DRIcoreExtension *core = pcp->psc->core;
465
466 (*core->unbindContext)(pcp->driContext);
467 }
468
469 static __GLXDRIcontext *driCreateContext(__GLXscreenConfigs *psc,
470 const __GLcontextModes *mode,
471 GLXContext gc,
472 GLXContext shareList, int renderType)
473 {
474 __GLXDRIcontextPrivate *pcp, *pcp_shared;
475 drm_context_t hwContext;
476 __DRIcontext *shared = NULL;
477 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
478
479 if (!psc || !psc->driScreen)
480 return NULL;
481
482 if (shareList) {
483 pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
484 shared = pcp_shared->driContext;
485 }
486
487 pcp = Xmalloc(sizeof *pcp);
488 if (pcp == NULL)
489 return NULL;
490
491 pcp->psc = psc;
492 if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr,
493 mode->visualID,
494 &pcp->hwContextID, &hwContext)) {
495 Xfree(pcp);
496 return NULL;
497 }
498
499 pcp->driContext =
500 (*psc->legacy->createNewContext)(psc->__driScreen,
501 config->driConfig,
502 renderType,
503 shared,
504 hwContext,
505 pcp);
506 if (pcp->driContext == NULL) {
507 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
508 Xfree(pcp);
509 return NULL;
510 }
511
512 pcp->base.destroyContext = driDestroyContext;
513 pcp->base.bindContext = driBindContext;
514 pcp->base.unbindContext = driUnbindContext;
515
516 return &pcp->base;
517 }
518
519 static void driDestroyDrawable(__GLXDRIdrawable *pdraw)
520 {
521 __GLXscreenConfigs *psc = pdraw->psc;
522
523 (*psc->core->destroyDrawable)(pdraw->driDrawable);
524 XF86DRIDestroyDrawable(psc->dpy, psc->scr, pdraw->drawable);
525 Xfree(pdraw);
526 }
527
528 static __GLXDRIdrawable *driCreateDrawable(__GLXscreenConfigs *psc,
529 XID xDrawable,
530 GLXDrawable drawable,
531 const __GLcontextModes *modes)
532 {
533 __GLXDRIdrawable *pdraw;
534 drm_drawable_t hwDrawable;
535 void *empty_attribute_list = NULL;
536 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
537
538 /* Old dri can't handle GLX 1.3+ drawable constructors. */
539 if (xDrawable != drawable)
540 return NULL;
541
542 pdraw = Xmalloc(sizeof(*pdraw));
543 if (!pdraw)
544 return NULL;
545
546 pdraw->drawable = drawable;
547 pdraw->psc = psc;
548
549 if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable))
550 return NULL;
551
552 /* Create a new drawable */
553 pdraw->driDrawable =
554 (*psc->legacy->createNewDrawable)(psc->__driScreen,
555 config->driConfig,
556 hwDrawable,
557 GLX_WINDOW_BIT,
558 empty_attribute_list,
559 pdraw);
560
561 if (!pdraw->driDrawable) {
562 XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
563 Xfree(pdraw);
564 return NULL;
565 }
566
567 pdraw->destroyDrawable = driDestroyDrawable;
568
569 return pdraw;
570 }
571
572 static void driSwapBuffers(__GLXDRIdrawable *pdraw)
573 {
574 (*pdraw->psc->core->swapBuffers)(pdraw->driDrawable);
575 }
576
577 static void driDestroyScreen(__GLXscreenConfigs *psc)
578 {
579 /* Free the direct rendering per screen data */
580 if (psc->__driScreen)
581 (*psc->core->destroyScreen)(psc->__driScreen);
582 psc->__driScreen = NULL;
583 if (psc->driver)
584 dlclose(psc->driver);
585 }
586
587 static __GLXDRIscreen *driCreateScreen(__GLXscreenConfigs *psc, int screen,
588 __GLXdisplayPrivate *priv)
589 {
590 __GLXDRIdisplayPrivate *pdp;
591 __GLXDRIscreen *psp;
592 const __DRIextension **extensions;
593 char *driverName;
594 int i;
595
596 psp = Xmalloc(sizeof *psp);
597 if (psp == NULL)
598 return NULL;
599
600 /* Initialize per screen dynamic client GLX extensions */
601 psc->ext_list_first_time = GL_TRUE;
602
603 if (!driGetDriverName(priv->dpy, screen, &driverName)) {
604 Xfree(psp);
605 return NULL;
606 }
607
608 psc->driver = driOpenDriver(driverName);
609 Xfree(driverName);
610 if (psc->driver == NULL) {
611 Xfree(psp);
612 return NULL;
613 }
614
615 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
616 if (extensions == NULL) {
617 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
618 Xfree(psp);
619 return NULL;
620 }
621
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];
627 }
628
629 if (psc->core == NULL || psc->legacy == NULL) {
630 Xfree(psp);
631 return NULL;
632 }
633
634 pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
635 psc->__driScreen =
636 CallCreateNewScreen(psc->dpy, screen, psc, pdp);
637 if (psc->__driScreen == NULL) {
638 dlclose(psc->driver);
639 Xfree(psp);
640 return NULL;
641 }
642
643 driBindExtensions(psc, 0);
644
645 psp->destroyScreen = driDestroyScreen;
646 psp->createContext = driCreateContext;
647 psp->createDrawable = driCreateDrawable;
648 psp->swapBuffers = driSwapBuffers;
649
650 return psp;
651 }
652
653 /* Called from __glXFreeDisplayPrivate.
654 */
655 static void driDestroyDisplay(__GLXDRIdisplay *dpy)
656 {
657 Xfree(dpy);
658 }
659
660 /*
661 * Allocate, initialize and return a __DRIdisplayPrivate object.
662 * This is called from __glXInitialize() when we are given a new
663 * display pointer.
664 */
665 _X_HIDDEN __GLXDRIdisplay *driCreateDisplay(Display *dpy)
666 {
667 __GLXDRIdisplayPrivate *pdpyp;
668 int eventBase, errorBase;
669 int major, minor, patch;
670
671 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
672 return NULL;
673 }
674
675 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
676 return NULL;
677 }
678
679 pdpyp = Xmalloc(sizeof *pdpyp);
680 if (!pdpyp) {
681 return NULL;
682 }
683
684 pdpyp->driMajor = major;
685 pdpyp->driMinor = minor;
686 pdpyp->driPatch = patch;
687
688 pdpyp->base.destroyDisplay = driDestroyDisplay;
689 pdpyp->base.createScreen = driCreateScreen;
690
691 return &pdpyp->base;
692 }
693
694 #endif /* GLX_DIRECT_RENDERING */