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