70873c2cc41f7158b56620fc4f08fe713eb9739a
[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 <unistd.h>
38 #include <X11/Xlibint.h>
39 #include <X11/extensions/Xext.h>
40 #include <X11/extensions/extutil.h>
41 #include <X11/extensions/Xfixes.h>
42 #include <X11/extensions/Xdamage.h>
43 #include "glheader.h"
44 #include "glxclient.h"
45 #include "xf86dri.h"
46 #include "sarea.h"
47 #include <stdio.h>
48 #include <dlfcn.h>
49 #include <sys/types.h>
50 #include <stdarg.h>
51 #include "glcontextmodes.h"
52 #include <sys/mman.h>
53 #include "xf86drm.h"
54
55 #ifndef RTLD_NOW
56 #define RTLD_NOW 0
57 #endif
58 #ifndef RTLD_GLOBAL
59 #define RTLD_GLOBAL 0
60 #endif
61
62 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate;
63 typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate;
64 typedef struct __GLXDRIconfigPrivateRec __GLXDRIconfigPrivate;
65
66 struct __GLXDRIdisplayPrivateRec {
67 __GLXDRIdisplay base;
68
69 /*
70 ** XFree86-DRI version information
71 */
72 int driMajor;
73 int driMinor;
74 int driPatch;
75 };
76
77 struct __GLXDRIcontextPrivateRec {
78 __GLXDRIcontext base;
79 __DRIcontext *driContext;
80 XID hwContextID;
81 __GLXscreenConfigs *psc;
82 };
83
84 struct __GLXDRIconfigPrivateRec {
85 __GLcontextModes modes;
86 const __DRIconfig *driConfig;
87 };
88
89 #ifndef DEFAULT_DRIVER_DIR
90 /* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
91 #define DEFAULT_DRIVER_DIR "/usr/X11R6/lib/modules/dri"
92 #endif
93
94 static void InfoMessageF(const char *f, ...)
95 {
96 va_list args;
97 const char *env;
98
99 if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) {
100 fprintf(stderr, "libGL: ");
101 va_start(args, f);
102 vfprintf(stderr, f, args);
103 va_end(args);
104 }
105 }
106
107 extern void ErrorMessageF(const char *f, ...);
108
109 /**
110 * Print error to stderr, unless LIBGL_DEBUG=="quiet".
111 */
112 _X_HIDDEN void ErrorMessageF(const char *f, ...)
113 {
114 va_list args;
115 const char *env;
116
117 if ((env = getenv("LIBGL_DEBUG")) && !strstr(env, "quiet")) {
118 fprintf(stderr, "libGL error: ");
119 va_start(args, f);
120 vfprintf(stderr, f, args);
121 va_end(args);
122 }
123 }
124
125 extern void *driOpenDriver(const char *driverName);
126
127 /**
128 * Try to \c dlopen the named driver.
129 *
130 * This function adds the "_dri.so" suffix to the driver name and searches the
131 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
132 * order to find the driver.
133 *
134 * \param driverName - a name like "tdfx", "i810", "mga", etc.
135 *
136 * \returns
137 * A handle from \c dlopen, or \c NULL if driver file not found.
138 */
139 _X_HIDDEN void *driOpenDriver(const char *driverName)
140 {
141 void *glhandle, *handle;
142 const char *libPaths, *p, *next;
143 char realDriverName[200];
144 int len;
145
146 /* Attempt to make sure libGL symbols will be visible to the driver */
147 glhandle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL);
148
149 libPaths = NULL;
150 if (geteuid() == getuid()) {
151 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
152 libPaths = getenv("LIBGL_DRIVERS_PATH");
153 if (!libPaths)
154 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
155 }
156 if (libPaths == NULL)
157 libPaths = DEFAULT_DRIVER_DIR;
158
159 handle = NULL;
160 for (p = libPaths; *p; p = next) {
161 next = strchr(p, ':');
162 if (next == NULL) {
163 len = strlen(p);
164 next = p + len;
165 } else {
166 len = next - p;
167 next++;
168 }
169
170 #ifdef GLX_USE_TLS
171 snprintf(realDriverName, sizeof realDriverName,
172 "%.*s/tls/%s_dri.so", len, p, driverName);
173 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
174 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
175 #endif
176
177 if ( handle == NULL ) {
178 snprintf(realDriverName, sizeof realDriverName,
179 "%.*s/%s_dri.so", len, p, driverName);
180 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
181 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
182 }
183
184 if ( handle != NULL )
185 break;
186 else
187 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
188 }
189
190 if (!handle)
191 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName);
192
193 if (glhandle)
194 dlclose(glhandle);
195
196 return handle;
197 }
198
199
200 /*
201 * Given a display pointer and screen number, determine the name of
202 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
203 * Return True for success, False for failure.
204 */
205 static Bool GetDriverName(Display *dpy, int scrNum, char **driverName)
206 {
207 int directCapable;
208 Bool b;
209 int driverMajor, driverMinor, driverPatch;
210
211 *driverName = NULL;
212
213 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
214 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
215 return False;
216 }
217 if (!directCapable) {
218 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
219 return False;
220 }
221
222 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
223 &driverPatch, driverName);
224 if (!b) {
225 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum);
226 return False;
227 }
228
229 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
230 driverMajor, driverMinor, driverPatch, *driverName, scrNum);
231
232 return True;
233 }
234
235
236 /*
237 * Given a display pointer and screen number, return a __DRIdriver handle.
238 * Return NULL if anything goes wrong.
239 */
240 static void *driGetDriver(Display *dpy, int scrNum)
241 {
242 char *driverName;
243 void *ret;
244
245 if (GetDriverName(dpy, scrNum, &driverName)) {
246 ret = driOpenDriver(driverName);
247 if (driverName)
248 Xfree(driverName);
249 return ret;
250 }
251 return NULL;
252 }
253
254 /*
255 * Exported function for querying the DRI driver for a given screen.
256 *
257 * The returned char pointer points to a static array that will be
258 * overwritten by subsequent calls.
259 */
260 PUBLIC const char *glXGetScreenDriver (Display *dpy, int scrNum) {
261 static char ret[32];
262 char *driverName;
263 if (GetDriverName(dpy, scrNum, &driverName)) {
264 int len;
265 if (!driverName)
266 return NULL;
267 len = strlen (driverName);
268 if (len >= 31)
269 return NULL;
270 memcpy (ret, driverName, len+1);
271 Xfree(driverName);
272 return ret;
273 }
274 return NULL;
275 }
276
277
278 /*
279 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
280 *
281 * The returned char pointer points directly into the driver. Therefore
282 * it should be treated as a constant.
283 *
284 * If the driver was not found or does not support configuration NULL is
285 * returned.
286 *
287 * Note: The driver remains opened after this function returns.
288 */
289 PUBLIC const char *glXGetDriverConfig (const char *driverName)
290 {
291 void *handle = driOpenDriver (driverName);
292 if (handle)
293 return dlsym (handle, "__driConfigOptions");
294 else
295 return NULL;
296 }
297
298 extern void
299 driFilterModes(__GLcontextModes ** server_modes,
300 const __GLcontextModes * driver_modes);
301
302 _X_HIDDEN void
303 driFilterModes(__GLcontextModes ** server_modes,
304 const __GLcontextModes * driver_modes)
305 {
306 __GLcontextModes * m;
307 __GLcontextModes ** prev_next;
308 const __GLcontextModes * check;
309
310 if (driver_modes == NULL) {
311 fprintf(stderr, "libGL warning: 3D driver returned no fbconfigs.\n");
312 return;
313 }
314
315 /* For each mode in server_modes, check to see if a matching mode exists
316 * in driver_modes. If not, then the mode is not available.
317 */
318
319 prev_next = server_modes;
320 for ( m = *prev_next ; m != NULL ; m = *prev_next ) {
321 GLboolean do_delete = GL_TRUE;
322
323 for ( check = driver_modes ; check != NULL ; check = check->next ) {
324 if ( _gl_context_modes_are_same( m, check ) ) {
325 do_delete = GL_FALSE;
326 break;
327 }
328 }
329
330 /* The 3D has to support all the modes that match the GLX visuals
331 * sent from the X server.
332 */
333 if ( do_delete && (m->visualID != 0) ) {
334 do_delete = GL_FALSE;
335
336 /* don't warn for this visual (Novell #247471 / X.Org #6689) */
337 if (m->visualRating != GLX_NON_CONFORMANT_CONFIG) {
338 fprintf(stderr, "libGL warning: 3D driver claims to not "
339 "support visual 0x%02x\n", m->visualID);
340 }
341 }
342
343 if ( do_delete ) {
344 *prev_next = m->next;
345
346 m->next = NULL;
347 _gl_context_modes_destroy( m );
348 }
349 else {
350 prev_next = & m->next;
351 }
352 }
353 }
354
355 #ifdef XDAMAGE_1_1_INTERFACE
356
357 static GLboolean has_damage_post(Display *dpy)
358 {
359 static GLboolean inited = GL_FALSE;
360 static GLboolean has_damage;
361
362 if (!inited) {
363 int major, minor;
364
365 if (XDamageQueryVersion(dpy, &major, &minor) &&
366 major == 1 && minor >= 1)
367 {
368 has_damage = GL_TRUE;
369 } else {
370 has_damage = GL_FALSE;
371 }
372 inited = GL_TRUE;
373 }
374
375 return has_damage;
376 }
377
378 static void __glXReportDamage(__DRIdrawable *driDraw,
379 int x, int y,
380 drm_clip_rect_t *rects, int num_rects,
381 GLboolean front_buffer,
382 void *loaderPrivate)
383 {
384 XRectangle *xrects;
385 XserverRegion region;
386 int i;
387 int x_off, y_off;
388 __GLXDRIdrawable *glxDraw = loaderPrivate;
389 __GLXscreenConfigs *psc = glxDraw->psc;
390 Display *dpy = psc->dpy;
391 Drawable drawable;
392
393 if (!has_damage_post(dpy))
394 return;
395
396 if (front_buffer) {
397 x_off = x;
398 y_off = y;
399 drawable = RootWindow(dpy, psc->scr);
400 } else{
401 x_off = 0;
402 y_off = 0;
403 drawable = glxDraw->xDrawable;
404 }
405
406 xrects = malloc(sizeof(XRectangle) * num_rects);
407 if (xrects == NULL)
408 return;
409
410 for (i = 0; i < num_rects; i++) {
411 xrects[i].x = rects[i].x1 + x_off;
412 xrects[i].y = rects[i].y1 + y_off;
413 xrects[i].width = rects[i].x2 - rects[i].x1;
414 xrects[i].height = rects[i].y2 - rects[i].y1;
415 }
416 region = XFixesCreateRegion(dpy, xrects, num_rects);
417 free(xrects);
418 XDamageAdd(dpy, drawable, region);
419 XFixesDestroyRegion(dpy, region);
420 }
421
422 static const __DRIdamageExtension damageExtension = {
423 { __DRI_DAMAGE, __DRI_DAMAGE_VERSION },
424 __glXReportDamage,
425 };
426
427 #endif
428
429 static GLboolean
430 __glXDRIGetDrawableInfo(__DRIdrawable *drawable,
431 unsigned int *index, unsigned int *stamp,
432 int *X, int *Y, int *W, int *H,
433 int *numClipRects, drm_clip_rect_t ** pClipRects,
434 int *backX, int *backY,
435 int *numBackClipRects, drm_clip_rect_t **pBackClipRects,
436 void *loaderPrivate)
437 {
438 __GLXDRIdrawable *glxDraw = loaderPrivate;
439 __GLXscreenConfigs *psc = glxDraw->psc;
440 Display *dpy = psc->dpy;
441
442 return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
443 index, stamp, X, Y, W, H,
444 numClipRects, pClipRects,
445 backX, backY,
446 numBackClipRects, pBackClipRects);
447 }
448
449 _X_HIDDEN const __DRIsystemTimeExtension systemTimeExtension = {
450 { __DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION },
451 __glXGetUST,
452 __driGetMscRateOML,
453 };
454
455 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
456 { __DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION },
457 __glXDRIGetDrawableInfo
458 };
459
460 static const __DRIextension *loader_extensions[] = {
461 &systemTimeExtension.base,
462 &getDrawableInfoExtension.base,
463
464 #ifdef XDAMAGE_1_1_INTERFACE
465 &damageExtension.base,
466 #endif
467
468 NULL
469 };
470
471 #define __ATTRIB(attrib, field) \
472 { attrib, offsetof(__GLcontextModes, field) }
473
474 static const struct { unsigned int attrib, offset; } attribMap[] = {
475 __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
476 __ATTRIB(__DRI_ATTRIB_LEVEL, level),
477 __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
478 __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
479 __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
480 __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
481 __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
482 __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
483 __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
484 __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
485 __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
486 __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
487 __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
488 __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
489 __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
490 __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
491 __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
492 #if 0
493 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel),
494 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentIndex),
495 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed),
496 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen),
497 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue),
498 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha),
499 __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask),
500 __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask),
501 __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask),
502 __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask),
503 #endif
504 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth),
505 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight),
506 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels),
507 __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth),
508 __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight),
509 #if 0
510 __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod),
511 #endif
512 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
513 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
514 __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture),
515 __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
516 };
517
518 #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
519
520 static int
521 scalarEqual(__GLcontextModes *mode, unsigned int attrib, unsigned int value)
522 {
523 unsigned int glxValue;
524 int i;
525
526 for (i = 0; i < ARRAY_SIZE(attribMap); i++)
527 if (attribMap[i].attrib == attrib) {
528 glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset);
529 return glxValue == GLX_DONT_CARE || glxValue == value;
530 }
531
532 return GL_TRUE; /* Is a non-existing attribute equal to value? */
533 }
534
535 static int
536 driConfigEqual(const __DRIcoreExtension *core,
537 __GLcontextModes *modes, const __DRIconfig *driConfig)
538 {
539 unsigned int attrib, value, glxValue;
540 int i;
541
542 i = 0;
543 while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) {
544 switch (attrib) {
545 case __DRI_ATTRIB_RENDER_TYPE:
546 glxValue = 0;
547 if (value & __DRI_ATTRIB_RGBA_BIT) {
548 glxValue |= GLX_RGBA_BIT;
549 } else if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) {
550 glxValue |= GLX_COLOR_INDEX_BIT;
551 }
552 if (glxValue != modes->renderType)
553 return GL_FALSE;
554 break;
555
556 case __DRI_ATTRIB_CONFIG_CAVEAT:
557 if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
558 glxValue = GLX_NON_CONFORMANT_CONFIG;
559 else if (value & __DRI_ATTRIB_SLOW_BIT)
560 glxValue = GLX_SLOW_CONFIG;
561 else
562 glxValue = GLX_NONE;
563 if (glxValue != modes->visualRating)
564 return GL_FALSE;
565 break;
566
567 case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS:
568 glxValue = 0;
569 if (value & __DRI_ATTRIB_TEXTURE_1D_BIT)
570 glxValue |= GLX_TEXTURE_1D_BIT_EXT;
571 if (value & __DRI_ATTRIB_TEXTURE_2D_BIT)
572 glxValue |= GLX_TEXTURE_2D_BIT_EXT;
573 if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT)
574 glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT;
575 if (modes->bindToTextureTargets != GLX_DONT_CARE &&
576 glxValue != modes->bindToTextureTargets)
577 return GL_FALSE;
578 break;
579
580 default:
581 if (!scalarEqual(modes, attrib, value))
582 return GL_FALSE;
583 }
584 }
585
586 return GL_TRUE;
587 }
588
589 static __GLcontextModes *
590 createDriMode(const __DRIcoreExtension *core,
591 __GLcontextModes *modes, const __DRIconfig **driConfigs)
592 {
593 __GLXDRIconfigPrivate *config;
594 int i;
595
596 for (i = 0; driConfigs[i]; i++) {
597 if (driConfigEqual(core, modes, driConfigs[i]))
598 break;
599 }
600
601 if (driConfigs[i] == NULL)
602 return NULL;
603
604 config = Xmalloc(sizeof *config);
605 if (config == NULL)
606 return NULL;
607
608 config->modes = *modes;
609 config->driConfig = driConfigs[i];
610
611 return &config->modes;
612 }
613
614 extern __GLcontextModes *
615 driConvertConfigs(const __DRIcoreExtension *core,
616 __GLcontextModes *modes, const __DRIconfig **configs);
617
618 _X_HIDDEN __GLcontextModes *
619 driConvertConfigs(const __DRIcoreExtension *core,
620 __GLcontextModes *modes, const __DRIconfig **configs)
621 {
622 __GLcontextModes head, *tail, *m;
623
624 tail = &head;
625 head.next = NULL;
626 for (m = modes; m; m = m->next) {
627 tail->next = createDriMode(core, m, configs);
628 if (tail->next == NULL) {
629 /* no matching dri config for m */
630 continue;
631 }
632
633
634 tail = tail->next;
635 }
636
637 _gl_context_modes_destroy(modes);
638
639 return head.next;
640 }
641
642 /**
643 * Perform the required libGL-side initialization and call the client-side
644 * driver's \c __driCreateNewScreen function.
645 *
646 * \param dpy Display pointer.
647 * \param scrn Screen number on the display.
648 * \param psc DRI screen information.
649 * \param driDpy DRI display information.
650 * \param createNewScreen Pointer to the client-side driver's
651 * \c __driCreateNewScreen function.
652 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
653 * the client-side driver on success, or \c NULL on failure.
654 *
655 * \todo This function needs to be modified to remove context-modes from the
656 * list stored in the \c __GLXscreenConfigsRec to match the list
657 * returned by the client-side driver.
658 */
659 static void *
660 CallCreateNewScreen(Display *dpy, int scrn, __GLXscreenConfigs *psc,
661 __GLXDRIdisplayPrivate * driDpy)
662 {
663 void *psp = NULL;
664 #ifndef GLX_USE_APPLEGL
665 drm_handle_t hSAREA;
666 drmAddress pSAREA = MAP_FAILED;
667 char *BusID;
668 __DRIversion ddx_version;
669 __DRIversion dri_version;
670 __DRIversion drm_version;
671 __DRIframebuffer framebuffer;
672 int fd = -1;
673 int status;
674 const char * err_msg;
675 const char * err_extra;
676 const __DRIconfig **driver_configs;
677
678 dri_version.major = driDpy->driMajor;
679 dri_version.minor = driDpy->driMinor;
680 dri_version.patch = driDpy->driPatch;
681
682 err_msg = "XF86DRIOpenConnection";
683 err_extra = NULL;
684
685 framebuffer.base = MAP_FAILED;
686 framebuffer.dev_priv = NULL;
687
688 if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
689 int newlyopened;
690 fd = drmOpenOnce(NULL,BusID, &newlyopened);
691 Xfree(BusID); /* No longer needed */
692
693 err_msg = "open DRM";
694 err_extra = strerror( -fd );
695
696 if (fd >= 0) {
697 drm_magic_t magic;
698
699 err_msg = "drmGetMagic";
700 err_extra = NULL;
701
702 if (!drmGetMagic(fd, &magic)) {
703 drmVersionPtr version = drmGetVersion(fd);
704 if (version) {
705 drm_version.major = version->version_major;
706 drm_version.minor = version->version_minor;
707 drm_version.patch = version->version_patchlevel;
708 drmFreeVersion(version);
709 }
710 else {
711 drm_version.major = -1;
712 drm_version.minor = -1;
713 drm_version.patch = -1;
714 }
715
716 err_msg = "XF86DRIAuthConnection";
717 if (!newlyopened || XF86DRIAuthConnection(dpy, scrn, magic)) {
718 char *driverName;
719
720 /*
721 * Get device name (like "tdfx") and the ddx version
722 * numbers. We'll check the version in each DRI driver's
723 * "createNewScreen" function.
724 */
725 err_msg = "XF86DRIGetClientDriverName";
726 if (XF86DRIGetClientDriverName(dpy, scrn,
727 &ddx_version.major,
728 &ddx_version.minor,
729 &ddx_version.patch,
730 &driverName)) {
731 drm_handle_t hFB;
732 int junk;
733
734 /* No longer needed. */
735 Xfree( driverName );
736
737
738 /*
739 * Get device-specific info. pDevPriv will point to a struct
740 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
741 * that has information about the screen size, depth, pitch,
742 * ancilliary buffers, DRM mmap handles, etc.
743 */
744 err_msg = "XF86DRIGetDeviceInfo";
745 if (XF86DRIGetDeviceInfo(dpy, scrn,
746 &hFB,
747 &junk,
748 &framebuffer.size,
749 &framebuffer.stride,
750 &framebuffer.dev_priv_size,
751 &framebuffer.dev_priv)) {
752 framebuffer.width = DisplayWidth(dpy, scrn);
753 framebuffer.height = DisplayHeight(dpy, scrn);
754
755 /*
756 * Map the framebuffer region.
757 */
758 status = drmMap(fd, hFB, framebuffer.size,
759 (drmAddressPtr)&framebuffer.base);
760
761 err_msg = "drmMap of framebuffer";
762 err_extra = strerror( -status );
763
764 if ( status == 0 ) {
765 /*
766 * Map the SAREA region. Further mmap regions
767 * may be setup in each DRI driver's
768 * "createNewScreen" function.
769 */
770 status = drmMap(fd, hSAREA, SAREA_MAX,
771 &pSAREA);
772
773 err_msg = "drmMap of sarea";
774 err_extra = strerror( -status );
775
776 if ( status == 0 ) {
777 err_msg = "InitDriver";
778 err_extra = NULL;
779 psp = (*psc->legacy->createNewScreen)(scrn,
780 & ddx_version,
781 & dri_version,
782 & drm_version,
783 & framebuffer,
784 pSAREA,
785 fd,
786 loader_extensions,
787 & driver_configs,
788 psc);
789
790 if (psp) {
791 psc->configs =
792 driConvertConfigs(psc->core,
793 psc->configs,
794 driver_configs);
795 psc->visuals =
796 driConvertConfigs(psc->core,
797 psc->visuals,
798 driver_configs);
799 }
800 }
801 }
802 }
803 }
804 }
805 }
806 }
807 }
808
809 if ( psp == NULL ) {
810 if ( pSAREA != MAP_FAILED ) {
811 (void)drmUnmap(pSAREA, SAREA_MAX);
812 }
813
814 if ( framebuffer.base != MAP_FAILED ) {
815 (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
816 }
817
818 if ( framebuffer.dev_priv != NULL ) {
819 Xfree(framebuffer.dev_priv);
820 }
821
822 if ( fd >= 0 ) {
823 (void)drmCloseOnce(fd);
824 }
825
826 (void)XF86DRICloseConnection(dpy, scrn);
827
828 if ( err_extra != NULL ) {
829 fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg,
830 err_extra);
831 }
832 else {
833 fprintf(stderr, "libGL error: %s failed\n", err_msg );
834 }
835
836 fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
837 }
838 #endif /* !GLX_USE_APPLEGL */
839
840 return psp;
841 }
842
843 static void driDestroyContext(__GLXDRIcontext *context,
844 __GLXscreenConfigs *psc, Display *dpy)
845 {
846 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
847
848 (*psc->core->destroyContext)(pcp->driContext);
849
850 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
851 }
852
853 static Bool driBindContext(__GLXDRIcontext *context,
854 __GLXDRIdrawable *draw, __GLXDRIdrawable *read)
855 {
856 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
857 const __DRIcoreExtension *core = pcp->psc->core;
858
859 return (*core->bindContext)(pcp->driContext,
860 draw->driDrawable,
861 read->driDrawable);
862 }
863
864 static void driUnbindContext(__GLXDRIcontext *context)
865 {
866 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
867 const __DRIcoreExtension *core = pcp->psc->core;
868
869 (*core->unbindContext)(pcp->driContext);
870 }
871
872 static __GLXDRIcontext *driCreateContext(__GLXscreenConfigs *psc,
873 const __GLcontextModes *mode,
874 GLXContext gc,
875 GLXContext shareList, int renderType)
876 {
877 __GLXDRIcontextPrivate *pcp, *pcp_shared;
878 drm_context_t hwContext;
879 __DRIcontext *shared = NULL;
880 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
881
882 if (psc && psc->driScreen) {
883 if (shareList) {
884 pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
885 shared = pcp_shared->driContext;
886 }
887
888 pcp = Xmalloc(sizeof *pcp);
889 if (pcp == NULL)
890 return NULL;
891
892 pcp->psc = psc;
893 if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr,
894 mode->visualID,
895 &pcp->hwContextID, &hwContext)) {
896 Xfree(pcp);
897 return NULL;
898 }
899
900 pcp->driContext =
901 (*psc->legacy->createNewContext)(psc->__driScreen,
902 config->driConfig,
903 renderType,
904 shared,
905 hwContext,
906 pcp);
907 if (pcp->driContext == NULL) {
908 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
909 Xfree(pcp);
910 return NULL;
911 }
912
913 pcp->base.destroyContext = driDestroyContext;
914 pcp->base.bindContext = driBindContext;
915 pcp->base.unbindContext = driUnbindContext;
916
917 return &pcp->base;
918 }
919
920 return NULL;
921 }
922
923 static void driDestroyDrawable(__GLXDRIdrawable *pdraw)
924 {
925 __GLXscreenConfigs *psc = pdraw->psc;
926
927 (*psc->core->destroyDrawable)(pdraw->driDrawable);
928 XF86DRIDestroyDrawable(psc->dpy, psc->scr, pdraw->drawable);
929 Xfree(pdraw);
930 }
931
932 static __GLXDRIdrawable *driCreateDrawable(__GLXscreenConfigs *psc,
933 XID xDrawable,
934 GLXDrawable drawable,
935 const __GLcontextModes *modes)
936 {
937 __GLXDRIdrawable *pdraw;
938 drm_drawable_t hwDrawable;
939 void *empty_attribute_list = NULL;
940 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
941
942 /* Old dri can't handle GLX 1.3+ drawable constructors. */
943 if (xDrawable != drawable)
944 return NULL;
945
946 pdraw = Xmalloc(sizeof(*pdraw));
947 if (!pdraw)
948 return NULL;
949
950 pdraw->drawable = drawable;
951 pdraw->psc = psc;
952
953 if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable))
954 return NULL;
955
956 /* Create a new drawable */
957 pdraw->driDrawable =
958 (*psc->legacy->createNewDrawable)(psc->__driScreen,
959 config->driConfig,
960 hwDrawable,
961 GLX_WINDOW_BIT,
962 empty_attribute_list,
963 pdraw);
964
965 if (!pdraw->driDrawable) {
966 XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
967 Xfree(pdraw);
968 return NULL;
969 }
970
971 pdraw->destroyDrawable = driDestroyDrawable;
972
973 return pdraw;
974 }
975
976 static void driDestroyScreen(__GLXscreenConfigs *psc)
977 {
978 /* Free the direct rendering per screen data */
979 if (psc->__driScreen)
980 (*psc->core->destroyScreen)(psc->__driScreen);
981 psc->__driScreen = NULL;
982 if (psc->driver)
983 dlclose(psc->driver);
984 }
985
986 void
987 driBindExtensions(__GLXscreenConfigs *psc);
988
989 static __GLXDRIscreen *driCreateScreen(__GLXscreenConfigs *psc, int screen,
990 __GLXdisplayPrivate *priv)
991 {
992 __GLXDRIdisplayPrivate *pdp;
993 __GLXDRIscreen *psp;
994 const __DRIextension **extensions;
995 int i;
996
997 psp = Xmalloc(sizeof *psp);
998 if (psp == NULL)
999 return NULL;
1000
1001 /* Initialize per screen dynamic client GLX extensions */
1002 psc->ext_list_first_time = GL_TRUE;
1003
1004 psc->driver = driGetDriver(priv->dpy, screen);
1005 if (psc->driver == NULL) {
1006 Xfree(psp);
1007 return NULL;
1008 }
1009
1010 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
1011 if (extensions == NULL) {
1012 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
1013 Xfree(psp);
1014 return NULL;
1015 }
1016
1017 for (i = 0; extensions[i]; i++) {
1018 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
1019 psc->core = (__DRIcoreExtension *) extensions[i];
1020 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
1021 psc->legacy = (__DRIlegacyExtension *) extensions[i];
1022 }
1023
1024 if (psc->core == NULL || psc->legacy == NULL) {
1025 Xfree(psp);
1026 return NULL;
1027 }
1028
1029 pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
1030 psc->__driScreen =
1031 CallCreateNewScreen(psc->dpy, screen, psc, pdp);
1032 if (psc->__driScreen == NULL) {
1033 dlclose(psc->driver);
1034 Xfree(psp);
1035 return NULL;
1036 }
1037
1038 driBindExtensions(psc);
1039
1040 psp->destroyScreen = driDestroyScreen;
1041 psp->createContext = driCreateContext;
1042 psp->createDrawable = driCreateDrawable;
1043
1044 return psp;
1045 }
1046
1047 /* Called from __glXFreeDisplayPrivate.
1048 */
1049 static void driDestroyDisplay(__GLXDRIdisplay *dpy)
1050 {
1051 Xfree(dpy);
1052 }
1053
1054 /*
1055 * Allocate, initialize and return a __DRIdisplayPrivate object.
1056 * This is called from __glXInitialize() when we are given a new
1057 * display pointer.
1058 */
1059 _X_HIDDEN __GLXDRIdisplay *driCreateDisplay(Display *dpy)
1060 {
1061 __GLXDRIdisplayPrivate *pdpyp;
1062 int eventBase, errorBase;
1063 int major, minor, patch;
1064
1065 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
1066 return NULL;
1067 }
1068
1069 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
1070 return NULL;
1071 }
1072
1073 pdpyp = Xmalloc(sizeof *pdpyp);
1074 if (!pdpyp) {
1075 return NULL;
1076 }
1077
1078 pdpyp->driMajor = major;
1079 pdpyp->driMinor = minor;
1080 pdpyp->driPatch = patch;
1081
1082 pdpyp->base.destroyDisplay = driDestroyDisplay;
1083 pdpyp->base.createScreen = driCreateScreen;
1084
1085 return &pdpyp->base;
1086 }
1087
1088 #endif /* GLX_DIRECT_RENDERING */