glx: add dri_common.c ala xserver
[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 /**
259 * Perform the required libGL-side initialization and call the client-side
260 * driver's \c __driCreateNewScreen function.
261 *
262 * \param dpy Display pointer.
263 * \param scrn Screen number on the display.
264 * \param psc DRI screen information.
265 * \param driDpy DRI display information.
266 * \param createNewScreen Pointer to the client-side driver's
267 * \c __driCreateNewScreen function.
268 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
269 * the client-side driver on success, or \c NULL on failure.
270 *
271 * \todo This function needs to be modified to remove context-modes from the
272 * list stored in the \c __GLXscreenConfigsRec to match the list
273 * returned by the client-side driver.
274 */
275 static void *
276 CallCreateNewScreen(Display *dpy, int scrn, __GLXscreenConfigs *psc,
277 __GLXDRIdisplayPrivate * driDpy)
278 {
279 void *psp = NULL;
280 #ifndef GLX_USE_APPLEGL
281 drm_handle_t hSAREA;
282 drmAddress pSAREA = MAP_FAILED;
283 char *BusID;
284 __DRIversion ddx_version;
285 __DRIversion dri_version;
286 __DRIversion drm_version;
287 __DRIframebuffer framebuffer;
288 int fd = -1;
289 int status;
290 const char * err_msg;
291 const char * err_extra;
292 const __DRIconfig **driver_configs;
293
294 dri_version.major = driDpy->driMajor;
295 dri_version.minor = driDpy->driMinor;
296 dri_version.patch = driDpy->driPatch;
297
298 err_msg = "XF86DRIOpenConnection";
299 err_extra = NULL;
300
301 framebuffer.base = MAP_FAILED;
302 framebuffer.dev_priv = NULL;
303
304 if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
305 int newlyopened;
306 fd = drmOpenOnce(NULL,BusID, &newlyopened);
307 Xfree(BusID); /* No longer needed */
308
309 err_msg = "open DRM";
310 err_extra = strerror( -fd );
311
312 if (fd >= 0) {
313 drm_magic_t magic;
314
315 err_msg = "drmGetMagic";
316 err_extra = NULL;
317
318 if (!drmGetMagic(fd, &magic)) {
319 drmVersionPtr version = drmGetVersion(fd);
320 if (version) {
321 drm_version.major = version->version_major;
322 drm_version.minor = version->version_minor;
323 drm_version.patch = version->version_patchlevel;
324 drmFreeVersion(version);
325 }
326 else {
327 drm_version.major = -1;
328 drm_version.minor = -1;
329 drm_version.patch = -1;
330 }
331
332 err_msg = "XF86DRIAuthConnection";
333 if (!newlyopened || XF86DRIAuthConnection(dpy, scrn, magic)) {
334 char *driverName;
335
336 /*
337 * Get device name (like "tdfx") and the ddx version
338 * numbers. We'll check the version in each DRI driver's
339 * "createNewScreen" function.
340 */
341 err_msg = "XF86DRIGetClientDriverName";
342 if (XF86DRIGetClientDriverName(dpy, scrn,
343 &ddx_version.major,
344 &ddx_version.minor,
345 &ddx_version.patch,
346 &driverName)) {
347 drm_handle_t hFB;
348 int junk;
349
350 /* No longer needed. */
351 Xfree( driverName );
352
353
354 /*
355 * Get device-specific info. pDevPriv will point to a struct
356 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
357 * that has information about the screen size, depth, pitch,
358 * ancilliary buffers, DRM mmap handles, etc.
359 */
360 err_msg = "XF86DRIGetDeviceInfo";
361 if (XF86DRIGetDeviceInfo(dpy, scrn,
362 &hFB,
363 &junk,
364 &framebuffer.size,
365 &framebuffer.stride,
366 &framebuffer.dev_priv_size,
367 &framebuffer.dev_priv)) {
368 framebuffer.width = DisplayWidth(dpy, scrn);
369 framebuffer.height = DisplayHeight(dpy, scrn);
370
371 /*
372 * Map the framebuffer region.
373 */
374 status = drmMap(fd, hFB, framebuffer.size,
375 (drmAddressPtr)&framebuffer.base);
376
377 err_msg = "drmMap of framebuffer";
378 err_extra = strerror( -status );
379
380 if ( status == 0 ) {
381 /*
382 * Map the SAREA region. Further mmap regions
383 * may be setup in each DRI driver's
384 * "createNewScreen" function.
385 */
386 status = drmMap(fd, hSAREA, SAREA_MAX,
387 &pSAREA);
388
389 err_msg = "drmMap of sarea";
390 err_extra = strerror( -status );
391
392 if ( status == 0 ) {
393 err_msg = "InitDriver";
394 err_extra = NULL;
395 psp = (*psc->legacy->createNewScreen)(scrn,
396 & ddx_version,
397 & dri_version,
398 & drm_version,
399 & framebuffer,
400 pSAREA,
401 fd,
402 loader_extensions,
403 & driver_configs,
404 psc);
405
406 if (psp) {
407 psc->configs =
408 driConvertConfigs(psc->core,
409 psc->configs,
410 driver_configs);
411 psc->visuals =
412 driConvertConfigs(psc->core,
413 psc->visuals,
414 driver_configs);
415 }
416 }
417 }
418 }
419 }
420 }
421 }
422 }
423 }
424
425 if ( psp == NULL ) {
426 if ( pSAREA != MAP_FAILED ) {
427 (void)drmUnmap(pSAREA, SAREA_MAX);
428 }
429
430 if ( framebuffer.base != MAP_FAILED ) {
431 (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
432 }
433
434 if ( framebuffer.dev_priv != NULL ) {
435 Xfree(framebuffer.dev_priv);
436 }
437
438 if ( fd >= 0 ) {
439 (void)drmCloseOnce(fd);
440 }
441
442 (void)XF86DRICloseConnection(dpy, scrn);
443
444 if ( err_extra != NULL ) {
445 fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg,
446 err_extra);
447 }
448 else {
449 fprintf(stderr, "libGL error: %s failed\n", err_msg );
450 }
451
452 fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
453 }
454 #endif /* !GLX_USE_APPLEGL */
455
456 return psp;
457 }
458
459 static void driDestroyContext(__GLXDRIcontext *context,
460 __GLXscreenConfigs *psc, Display *dpy)
461 {
462 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
463
464 (*psc->core->destroyContext)(pcp->driContext);
465
466 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
467 }
468
469 static Bool driBindContext(__GLXDRIcontext *context,
470 __GLXDRIdrawable *draw, __GLXDRIdrawable *read)
471 {
472 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
473 const __DRIcoreExtension *core = pcp->psc->core;
474
475 return (*core->bindContext)(pcp->driContext,
476 draw->driDrawable,
477 read->driDrawable);
478 }
479
480 static void driUnbindContext(__GLXDRIcontext *context)
481 {
482 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
483 const __DRIcoreExtension *core = pcp->psc->core;
484
485 (*core->unbindContext)(pcp->driContext);
486 }
487
488 static __GLXDRIcontext *driCreateContext(__GLXscreenConfigs *psc,
489 const __GLcontextModes *mode,
490 GLXContext gc,
491 GLXContext shareList, int renderType)
492 {
493 __GLXDRIcontextPrivate *pcp, *pcp_shared;
494 drm_context_t hwContext;
495 __DRIcontext *shared = NULL;
496 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
497
498 if (!psc || !psc->driScreen)
499 return NULL;
500
501 if (shareList) {
502 pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
503 shared = pcp_shared->driContext;
504 }
505
506 pcp = Xmalloc(sizeof *pcp);
507 if (pcp == NULL)
508 return NULL;
509
510 pcp->psc = psc;
511 if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr,
512 mode->visualID,
513 &pcp->hwContextID, &hwContext)) {
514 Xfree(pcp);
515 return NULL;
516 }
517
518 pcp->driContext =
519 (*psc->legacy->createNewContext)(psc->__driScreen,
520 config->driConfig,
521 renderType,
522 shared,
523 hwContext,
524 pcp);
525 if (pcp->driContext == NULL) {
526 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
527 Xfree(pcp);
528 return NULL;
529 }
530
531 pcp->base.destroyContext = driDestroyContext;
532 pcp->base.bindContext = driBindContext;
533 pcp->base.unbindContext = driUnbindContext;
534
535 return &pcp->base;
536 }
537
538 static void driDestroyDrawable(__GLXDRIdrawable *pdraw)
539 {
540 __GLXscreenConfigs *psc = pdraw->psc;
541
542 (*psc->core->destroyDrawable)(pdraw->driDrawable);
543 XF86DRIDestroyDrawable(psc->dpy, psc->scr, pdraw->drawable);
544 Xfree(pdraw);
545 }
546
547 static __GLXDRIdrawable *driCreateDrawable(__GLXscreenConfigs *psc,
548 XID xDrawable,
549 GLXDrawable drawable,
550 const __GLcontextModes *modes)
551 {
552 __GLXDRIdrawable *pdraw;
553 drm_drawable_t hwDrawable;
554 void *empty_attribute_list = NULL;
555 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
556
557 /* Old dri can't handle GLX 1.3+ drawable constructors. */
558 if (xDrawable != drawable)
559 return NULL;
560
561 pdraw = Xmalloc(sizeof(*pdraw));
562 if (!pdraw)
563 return NULL;
564
565 pdraw->drawable = drawable;
566 pdraw->psc = psc;
567
568 if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable))
569 return NULL;
570
571 /* Create a new drawable */
572 pdraw->driDrawable =
573 (*psc->legacy->createNewDrawable)(psc->__driScreen,
574 config->driConfig,
575 hwDrawable,
576 GLX_WINDOW_BIT,
577 empty_attribute_list,
578 pdraw);
579
580 if (!pdraw->driDrawable) {
581 XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
582 Xfree(pdraw);
583 return NULL;
584 }
585
586 pdraw->destroyDrawable = driDestroyDrawable;
587
588 return pdraw;
589 }
590
591 static void driDestroyScreen(__GLXscreenConfigs *psc)
592 {
593 /* Free the direct rendering per screen data */
594 if (psc->__driScreen)
595 (*psc->core->destroyScreen)(psc->__driScreen);
596 psc->__driScreen = NULL;
597 if (psc->driver)
598 dlclose(psc->driver);
599 }
600
601 static __GLXDRIscreen *driCreateScreen(__GLXscreenConfigs *psc, int screen,
602 __GLXdisplayPrivate *priv)
603 {
604 __GLXDRIdisplayPrivate *pdp;
605 __GLXDRIscreen *psp;
606 const __DRIextension **extensions;
607 char *driverName;
608 int i;
609
610 psp = Xmalloc(sizeof *psp);
611 if (psp == NULL)
612 return NULL;
613
614 /* Initialize per screen dynamic client GLX extensions */
615 psc->ext_list_first_time = GL_TRUE;
616
617 if (!driGetDriverName(priv->dpy, screen, &driverName)) {
618 Xfree(psp);
619 return NULL;
620 }
621
622 psc->driver = driOpenDriver(driverName);
623 Xfree(driverName);
624 if (psc->driver == NULL) {
625 Xfree(psp);
626 return NULL;
627 }
628
629 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
630 if (extensions == NULL) {
631 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
632 Xfree(psp);
633 return NULL;
634 }
635
636 for (i = 0; extensions[i]; i++) {
637 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
638 psc->core = (__DRIcoreExtension *) extensions[i];
639 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
640 psc->legacy = (__DRIlegacyExtension *) extensions[i];
641 }
642
643 if (psc->core == NULL || psc->legacy == NULL) {
644 Xfree(psp);
645 return NULL;
646 }
647
648 pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
649 psc->__driScreen =
650 CallCreateNewScreen(psc->dpy, screen, psc, pdp);
651 if (psc->__driScreen == NULL) {
652 dlclose(psc->driver);
653 Xfree(psp);
654 return NULL;
655 }
656
657 driBindExtensions(psc);
658
659 psp->destroyScreen = driDestroyScreen;
660 psp->createContext = driCreateContext;
661 psp->createDrawable = driCreateDrawable;
662
663 return psp;
664 }
665
666 /* Called from __glXFreeDisplayPrivate.
667 */
668 static void driDestroyDisplay(__GLXDRIdisplay *dpy)
669 {
670 Xfree(dpy);
671 }
672
673 /*
674 * Allocate, initialize and return a __DRIdisplayPrivate object.
675 * This is called from __glXInitialize() when we are given a new
676 * display pointer.
677 */
678 _X_HIDDEN __GLXDRIdisplay *driCreateDisplay(Display *dpy)
679 {
680 __GLXDRIdisplayPrivate *pdpyp;
681 int eventBase, errorBase;
682 int major, minor, patch;
683
684 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
685 return NULL;
686 }
687
688 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
689 return NULL;
690 }
691
692 pdpyp = Xmalloc(sizeof *pdpyp);
693 if (!pdpyp) {
694 return NULL;
695 }
696
697 pdpyp->driMajor = major;
698 pdpyp->driMinor = minor;
699 pdpyp->driPatch = patch;
700
701 pdpyp->base.destroyDisplay = driDestroyDisplay;
702 pdpyp->base.createScreen = driCreateScreen;
703
704 return &pdpyp->base;
705 }
706
707 #endif /* GLX_DIRECT_RENDERING */