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