Revert pointless reindents to avoid merge conflicts.
[mesa.git] / src / glx / x11 / dri_glx.c
1 /* -*- mode: c; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3; coding: utf-8-unix -*- */
2 /**************************************************************************
3
4 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
5 All Rights Reserved.
6
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:
14
15 The above copyright notice and this permission notice (including the
16 next paragraph) shall be included in all copies or substantial portions
17 of the Software.
18
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.
26
27 **************************************************************************/
28
29 /*
30 * Authors:
31 * Kevin E. Martin <kevin@precisioninsight.com>
32 * Brian Paul <brian@precisioninsight.com>
33 *
34 */
35
36 #ifdef GLX_DIRECT_RENDERING
37
38 #include <X11/Xlib.h>
39 #include <X11/extensions/Xfixes.h>
40 #include <X11/extensions/Xdamage.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 ErrorMessageF("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 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
315 goto handle_error;
316 }
317
318 if (drmGetMagic(fd, &magic)) {
319 ErrorMessageF("drmGetMagic failed\n");
320 goto handle_error;
321 }
322
323 version = drmGetVersion(fd);
324 if (version) {
325 drm_version.major = version->version_major;
326 drm_version.minor = version->version_minor;
327 drm_version.patch = version->version_patchlevel;
328 drmFreeVersion(version);
329 }
330 else {
331 drm_version.major = -1;
332 drm_version.minor = -1;
333 drm_version.patch = -1;
334 }
335
336 if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
337 ErrorMessageF("XF86DRIAuthConnection failed\n");
338 goto handle_error;
339 }
340
341 /* Get device name (like "tdfx") and the ddx version numbers.
342 * We'll check the version in each DRI driver's "createNewScreen"
343 * function. */
344 if (!XF86DRIGetClientDriverName(dpy, scrn,
345 &ddx_version.major,
346 &ddx_version.minor,
347 &ddx_version.patch,
348 &driverName)) {
349 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
350 goto handle_error;
351 }
352
353 Xfree(driverName); /* No longer needed. */
354
355 /*
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.
360 */
361 if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
362 &framebuffer.size, &framebuffer.stride,
363 &framebuffer.dev_priv_size, &framebuffer.dev_priv)) {
364 ErrorMessageF("XF86DRIGetDeviceInfo failed");
365 goto handle_error;
366 }
367
368 framebuffer.width = DisplayWidth(dpy, scrn);
369 framebuffer.height = DisplayHeight(dpy, scrn);
370
371 /* Map the framebuffer region. */
372 status = drmMap(fd, hFB, framebuffer.size,
373 (drmAddressPtr)&framebuffer.base);
374 if (status != 0) {
375 ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status));
376 goto handle_error;
377 }
378
379 /* Map the SAREA region. Further mmap regions may be setup in
380 * each DRI driver's "createNewScreen" function.
381 */
382 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
383 if (status != 0) {
384 ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status));
385 goto handle_error;
386 }
387
388 psp = (*psc->legacy->createNewScreen)(scrn,
389 &ddx_version,
390 &dri_version,
391 &drm_version,
392 &framebuffer,
393 pSAREA,
394 fd,
395 loader_extensions,
396 &driver_configs,
397 psc);
398
399 if (psp == NULL) {
400 ErrorMessageF("Calling driver entry point failed");
401 goto handle_error;
402 }
403
404 psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs);
405 psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs);
406
407 return psp;
408
409 handle_error:
410 if (pSAREA != MAP_FAILED)
411 drmUnmap(pSAREA, SAREA_MAX);
412
413 if (framebuffer.base != MAP_FAILED)
414 drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
415
416 if (framebuffer.dev_priv != NULL)
417 Xfree(framebuffer.dev_priv);
418
419 if (fd >= 0)
420 drmCloseOnce(fd);
421
422 XF86DRICloseConnection(dpy, scrn);
423
424 ErrorMessageF("reverting to software direct rendering\n");
425
426 return NULL;
427 }
428
429 #else /* !GLX_USE_APPLEGL */
430
431 static void *
432 CallCreateNewScreen(Display *dpy, int scrn, __GLXscreenConfigs *psc,
433 __GLXDRIdisplayPrivate * driDpy)
434 {
435 return NULL;
436 }
437
438 #endif /* !GLX_USE_APPLEGL */
439
440 static void driDestroyContext(__GLXDRIcontext *context,
441 __GLXscreenConfigs *psc, Display *dpy)
442 {
443 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
444
445 (*psc->core->destroyContext)(pcp->driContext);
446
447 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
448 Xfree(pcp);
449 }
450
451 static Bool driBindContext(__GLXDRIcontext *context,
452 __GLXDRIdrawable *draw, __GLXDRIdrawable *read)
453 {
454 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
455 const __DRIcoreExtension *core = pcp->psc->core;
456
457 return (*core->bindContext)(pcp->driContext,
458 draw->driDrawable,
459 read->driDrawable);
460 }
461
462 static void driUnbindContext(__GLXDRIcontext *context)
463 {
464 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
465 const __DRIcoreExtension *core = pcp->psc->core;
466
467 (*core->unbindContext)(pcp->driContext);
468 }
469
470 static __GLXDRIcontext *driCreateContext(__GLXscreenConfigs *psc,
471 const __GLcontextModes *mode,
472 GLXContext gc,
473 GLXContext shareList, int renderType)
474 {
475 __GLXDRIcontextPrivate *pcp, *pcp_shared;
476 drm_context_t hwContext;
477 __DRIcontext *shared = NULL;
478 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
479
480 if (!psc || !psc->driScreen)
481 return NULL;
482
483 if (shareList) {
484 pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
485 shared = pcp_shared->driContext;
486 }
487
488 pcp = Xmalloc(sizeof *pcp);
489 if (pcp == NULL)
490 return NULL;
491
492 pcp->psc = psc;
493 if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr,
494 mode->visualID,
495 &pcp->hwContextID, &hwContext)) {
496 Xfree(pcp);
497 return NULL;
498 }
499
500 pcp->driContext =
501 (*psc->legacy->createNewContext)(psc->__driScreen,
502 config->driConfig,
503 renderType,
504 shared,
505 hwContext,
506 pcp);
507 if (pcp->driContext == NULL) {
508 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
509 Xfree(pcp);
510 return NULL;
511 }
512
513 pcp->base.destroyContext = driDestroyContext;
514 pcp->base.bindContext = driBindContext;
515 pcp->base.unbindContext = driUnbindContext;
516
517 return &pcp->base;
518 }
519
520 static void driDestroyDrawable(__GLXDRIdrawable *pdraw)
521 {
522 __GLXscreenConfigs *psc = pdraw->psc;
523
524 (*psc->core->destroyDrawable)(pdraw->driDrawable);
525 XF86DRIDestroyDrawable(psc->dpy, psc->scr, pdraw->drawable);
526 Xfree(pdraw);
527 }
528
529 static __GLXDRIdrawable *driCreateDrawable(__GLXscreenConfigs *psc,
530 XID xDrawable,
531 GLXDrawable drawable,
532 const __GLcontextModes *modes)
533 {
534 __GLXDRIdrawable *pdraw;
535 drm_drawable_t hwDrawable;
536 void *empty_attribute_list = NULL;
537 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
538
539 /* Old dri can't handle GLX 1.3+ drawable constructors. */
540 if (xDrawable != drawable)
541 return NULL;
542
543 pdraw = Xmalloc(sizeof(*pdraw));
544 if (!pdraw)
545 return NULL;
546
547 pdraw->drawable = drawable;
548 pdraw->psc = psc;
549
550 if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable))
551 return NULL;
552
553 /* Create a new drawable */
554 pdraw->driDrawable =
555 (*psc->legacy->createNewDrawable)(psc->__driScreen,
556 config->driConfig,
557 hwDrawable,
558 GLX_WINDOW_BIT,
559 empty_attribute_list,
560 pdraw);
561
562 if (!pdraw->driDrawable) {
563 XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
564 Xfree(pdraw);
565 return NULL;
566 }
567
568 pdraw->destroyDrawable = driDestroyDrawable;
569
570 return pdraw;
571 }
572
573 static void driSwapBuffers(__GLXDRIdrawable *pdraw)
574 {
575 (*pdraw->psc->core->swapBuffers)(pdraw->driDrawable);
576 }
577
578 static void driDestroyScreen(__GLXscreenConfigs *psc)
579 {
580 /* Free the direct rendering per screen data */
581 if (psc->__driScreen)
582 (*psc->core->destroyScreen)(psc->__driScreen);
583 psc->__driScreen = NULL;
584 if (psc->driver)
585 dlclose(psc->driver);
586 }
587
588 static __GLXDRIscreen *driCreateScreen(__GLXscreenConfigs *psc, int screen,
589 __GLXdisplayPrivate *priv)
590 {
591 __GLXDRIdisplayPrivate *pdp;
592 __GLXDRIscreen *psp;
593 const __DRIextension **extensions;
594 char *driverName;
595 int i;
596
597 psp = Xmalloc(sizeof *psp);
598 if (psp == NULL)
599 return NULL;
600
601 /* Initialize per screen dynamic client GLX extensions */
602 psc->ext_list_first_time = GL_TRUE;
603
604 if (!driGetDriverName(priv->dpy, screen, &driverName)) {
605 Xfree(psp);
606 return NULL;
607 }
608
609 psc->driver = driOpenDriver(driverName);
610 Xfree(driverName);
611 if (psc->driver == NULL) {
612 Xfree(psp);
613 return NULL;
614 }
615
616 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
617 if (extensions == NULL) {
618 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
619 Xfree(psp);
620 return NULL;
621 }
622
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];
628 }
629
630 if (psc->core == NULL || psc->legacy == NULL) {
631 Xfree(psp);
632 return NULL;
633 }
634
635 pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
636 psc->__driScreen =
637 CallCreateNewScreen(psc->dpy, screen, psc, pdp);
638 if (psc->__driScreen == NULL) {
639 dlclose(psc->driver);
640 Xfree(psp);
641 return NULL;
642 }
643
644 driBindExtensions(psc, 0);
645
646 psp->destroyScreen = driDestroyScreen;
647 psp->createContext = driCreateContext;
648 psp->createDrawable = driCreateDrawable;
649 psp->swapBuffers = driSwapBuffers;
650
651 return psp;
652 }
653
654 /* Called from __glXFreeDisplayPrivate.
655 */
656 static void driDestroyDisplay(__GLXDRIdisplay *dpy)
657 {
658 Xfree(dpy);
659 }
660
661 /*
662 * Allocate, initialize and return a __DRIdisplayPrivate object.
663 * This is called from __glXInitialize() when we are given a new
664 * display pointer.
665 */
666 _X_HIDDEN __GLXDRIdisplay *driCreateDisplay(Display *dpy)
667 {
668 __GLXDRIdisplayPrivate *pdpyp;
669 int eventBase, errorBase;
670 int major, minor, patch;
671
672 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
673 return NULL;
674 }
675
676 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
677 return NULL;
678 }
679
680 pdpyp = Xmalloc(sizeof *pdpyp);
681 if (!pdpyp) {
682 return NULL;
683 }
684
685 pdpyp->driMajor = major;
686 pdpyp->driMinor = minor;
687 pdpyp->driPatch = patch;
688
689 pdpyp->base.destroyDisplay = driDestroyDisplay;
690 pdpyp->base.createScreen = driCreateScreen;
691
692 return &pdpyp->base;
693 }
694
695 #endif /* GLX_DIRECT_RENDERING */