Only convert configs if screen creation was successful.
[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 driValue;
524 int i;
525
526 for (i = 0; i < ARRAY_SIZE(attribMap); i++)
527 if (attribMap[i].attrib == attrib) {
528 driValue = *(unsigned int *) ((char *) mode + attribMap[i].offset);
529 return driValue == 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 (glxValue != modes->bindToTextureTargets)
576 return GL_FALSE;
577 break;
578
579 default:
580 if (!scalarEqual(modes, attrib, value))
581 return GL_FALSE;
582 }
583 }
584
585 return GL_TRUE;
586 }
587
588 static __GLcontextModes *
589 createDriMode(const __DRIcoreExtension *core,
590 __GLcontextModes *modes, const __DRIconfig **driConfigs)
591 {
592 __GLXDRIconfigPrivate *config;
593 int i;
594
595 for (i = 0; driConfigs[i]; i++) {
596 if (driConfigEqual(core, modes, driConfigs[i]))
597 break;
598 }
599
600 if (driConfigs[i] == NULL)
601 return NULL;
602
603 config = Xmalloc(sizeof *config);
604 if (config == NULL)
605 return NULL;
606
607 config->modes = *modes;
608 config->driConfig = driConfigs[i];
609
610 return &config->modes;
611 }
612
613 extern __GLcontextModes *
614 driConvertConfigs(const __DRIcoreExtension *core,
615 __GLcontextModes *modes, const __DRIconfig **configs);
616
617 _X_HIDDEN __GLcontextModes *
618 driConvertConfigs(const __DRIcoreExtension *core,
619 __GLcontextModes *modes, const __DRIconfig **configs)
620 {
621 __GLcontextModes head, *tail, *m;
622
623 tail = &head;
624 head.next = NULL;
625 for (m = modes; m; m = m->next) {
626 tail->next = createDriMode(core, m, configs);
627 if (tail->next == NULL) {
628 /* no matching dri config for m */
629 continue;
630 }
631
632
633 tail = tail->next;
634 }
635
636 _gl_context_modes_destroy(modes);
637
638 return head.next;
639 }
640
641 /**
642 * Perform the required libGL-side initialization and call the client-side
643 * driver's \c __driCreateNewScreen function.
644 *
645 * \param dpy Display pointer.
646 * \param scrn Screen number on the display.
647 * \param psc DRI screen information.
648 * \param driDpy DRI display information.
649 * \param createNewScreen Pointer to the client-side driver's
650 * \c __driCreateNewScreen function.
651 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
652 * the client-side driver on success, or \c NULL on failure.
653 *
654 * \todo This function needs to be modified to remove context-modes from the
655 * list stored in the \c __GLXscreenConfigsRec to match the list
656 * returned by the client-side driver.
657 */
658 static void *
659 CallCreateNewScreen(Display *dpy, int scrn, __GLXscreenConfigs *psc,
660 __GLXDRIdisplayPrivate * driDpy)
661 {
662 void *psp = NULL;
663 #ifndef GLX_USE_APPLEGL
664 drm_handle_t hSAREA;
665 drmAddress pSAREA = MAP_FAILED;
666 char *BusID;
667 __DRIversion ddx_version;
668 __DRIversion dri_version;
669 __DRIversion drm_version;
670 __DRIframebuffer framebuffer;
671 int fd = -1;
672 int status;
673 const char * err_msg;
674 const char * err_extra;
675 const __DRIconfig **driver_configs;
676
677 dri_version.major = driDpy->driMajor;
678 dri_version.minor = driDpy->driMinor;
679 dri_version.patch = driDpy->driPatch;
680
681 err_msg = "XF86DRIOpenConnection";
682 err_extra = NULL;
683
684 framebuffer.base = MAP_FAILED;
685 framebuffer.dev_priv = NULL;
686
687 if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
688 int newlyopened;
689 fd = drmOpenOnce(NULL,BusID, &newlyopened);
690 Xfree(BusID); /* No longer needed */
691
692 err_msg = "open DRM";
693 err_extra = strerror( -fd );
694
695 if (fd >= 0) {
696 drm_magic_t magic;
697
698 err_msg = "drmGetMagic";
699 err_extra = NULL;
700
701 if (!drmGetMagic(fd, &magic)) {
702 drmVersionPtr version = drmGetVersion(fd);
703 if (version) {
704 drm_version.major = version->version_major;
705 drm_version.minor = version->version_minor;
706 drm_version.patch = version->version_patchlevel;
707 drmFreeVersion(version);
708 }
709 else {
710 drm_version.major = -1;
711 drm_version.minor = -1;
712 drm_version.patch = -1;
713 }
714
715 err_msg = "XF86DRIAuthConnection";
716 if (!newlyopened || XF86DRIAuthConnection(dpy, scrn, magic)) {
717 char *driverName;
718
719 /*
720 * Get device name (like "tdfx") and the ddx version
721 * numbers. We'll check the version in each DRI driver's
722 * "createNewScreen" function.
723 */
724 err_msg = "XF86DRIGetClientDriverName";
725 if (XF86DRIGetClientDriverName(dpy, scrn,
726 &ddx_version.major,
727 &ddx_version.minor,
728 &ddx_version.patch,
729 &driverName)) {
730 drm_handle_t hFB;
731 int junk;
732
733 /* No longer needed. */
734 Xfree( driverName );
735
736
737 /*
738 * Get device-specific info. pDevPriv will point to a struct
739 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
740 * that has information about the screen size, depth, pitch,
741 * ancilliary buffers, DRM mmap handles, etc.
742 */
743 err_msg = "XF86DRIGetDeviceInfo";
744 if (XF86DRIGetDeviceInfo(dpy, scrn,
745 &hFB,
746 &junk,
747 &framebuffer.size,
748 &framebuffer.stride,
749 &framebuffer.dev_priv_size,
750 &framebuffer.dev_priv)) {
751 framebuffer.width = DisplayWidth(dpy, scrn);
752 framebuffer.height = DisplayHeight(dpy, scrn);
753
754 /*
755 * Map the framebuffer region.
756 */
757 status = drmMap(fd, hFB, framebuffer.size,
758 (drmAddressPtr)&framebuffer.base);
759
760 err_msg = "drmMap of framebuffer";
761 err_extra = strerror( -status );
762
763 if ( status == 0 ) {
764 /*
765 * Map the SAREA region. Further mmap regions
766 * may be setup in each DRI driver's
767 * "createNewScreen" function.
768 */
769 status = drmMap(fd, hSAREA, SAREA_MAX,
770 &pSAREA);
771
772 err_msg = "drmMap of sarea";
773 err_extra = strerror( -status );
774
775 if ( status == 0 ) {
776 err_msg = "InitDriver";
777 err_extra = NULL;
778 psp = (*psc->legacy->createNewScreen)(scrn,
779 & ddx_version,
780 & dri_version,
781 & drm_version,
782 & framebuffer,
783 pSAREA,
784 fd,
785 loader_extensions,
786 & driver_configs,
787 psc);
788
789 if (psp) {
790 psc->configs =
791 driConvertConfigs(psc->core,
792 psc->configs,
793 driver_configs);
794 psc->visuals =
795 driConvertConfigs(psc->core,
796 psc->visuals,
797 driver_configs);
798 }
799 }
800 }
801 }
802 }
803 }
804 }
805 }
806 }
807
808 if ( psp == NULL ) {
809 if ( pSAREA != MAP_FAILED ) {
810 (void)drmUnmap(pSAREA, SAREA_MAX);
811 }
812
813 if ( framebuffer.base != MAP_FAILED ) {
814 (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
815 }
816
817 if ( framebuffer.dev_priv != NULL ) {
818 Xfree(framebuffer.dev_priv);
819 }
820
821 if ( fd >= 0 ) {
822 (void)drmCloseOnce(fd);
823 }
824
825 (void)XF86DRICloseConnection(dpy, scrn);
826
827 if ( err_extra != NULL ) {
828 fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg,
829 err_extra);
830 }
831 else {
832 fprintf(stderr, "libGL error: %s failed\n", err_msg );
833 }
834
835 fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
836 }
837 #endif /* !GLX_USE_APPLEGL */
838
839 return psp;
840 }
841
842 static void driDestroyContext(__GLXDRIcontext *context,
843 __GLXscreenConfigs *psc, Display *dpy)
844 {
845 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
846
847 (*psc->core->destroyContext)(pcp->driContext);
848
849 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
850 }
851
852 static Bool driBindContext(__GLXDRIcontext *context,
853 __GLXDRIdrawable *draw, __GLXDRIdrawable *read)
854 {
855 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
856 const __DRIcoreExtension *core = pcp->psc->core;
857
858 return (*core->bindContext)(pcp->driContext,
859 draw->driDrawable,
860 read->driDrawable);
861 }
862
863 static void driUnbindContext(__GLXDRIcontext *context)
864 {
865 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
866 const __DRIcoreExtension *core = pcp->psc->core;
867
868 (*core->unbindContext)(pcp->driContext);
869 }
870
871 static __GLXDRIcontext *driCreateContext(__GLXscreenConfigs *psc,
872 const __GLcontextModes *mode,
873 GLXContext gc,
874 GLXContext shareList, int renderType)
875 {
876 __GLXDRIcontextPrivate *pcp, *pcp_shared;
877 drm_context_t hwContext;
878 __DRIcontext *shared = NULL;
879 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
880
881 if (psc && psc->driScreen) {
882 if (shareList) {
883 pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
884 shared = pcp_shared->driContext;
885 }
886
887 pcp = Xmalloc(sizeof *pcp);
888 if (pcp == NULL)
889 return NULL;
890
891 pcp->psc = psc;
892 if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr,
893 mode->visualID,
894 &pcp->hwContextID, &hwContext)) {
895 Xfree(pcp);
896 return NULL;
897 }
898
899 pcp->driContext =
900 (*psc->legacy->createNewContext)(psc->__driScreen,
901 config->driConfig,
902 renderType,
903 shared,
904 hwContext,
905 pcp);
906 if (pcp->driContext == NULL) {
907 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
908 Xfree(pcp);
909 return NULL;
910 }
911
912 pcp->base.destroyContext = driDestroyContext;
913 pcp->base.bindContext = driBindContext;
914 pcp->base.unbindContext = driUnbindContext;
915
916 return &pcp->base;
917 }
918
919 return NULL;
920 }
921
922 static void driDestroyDrawable(__GLXDRIdrawable *pdraw)
923 {
924 __GLXscreenConfigs *psc = pdraw->psc;
925
926 (*psc->core->destroyDrawable)(pdraw->driDrawable);
927 XF86DRIDestroyDrawable(psc->dpy, psc->scr, pdraw->drawable);
928 Xfree(pdraw);
929 }
930
931 static __GLXDRIdrawable *driCreateDrawable(__GLXscreenConfigs *psc,
932 XID xDrawable,
933 GLXDrawable drawable,
934 const __GLcontextModes *modes)
935 {
936 __GLXDRIdrawable *pdraw;
937 drm_drawable_t hwDrawable;
938 void *empty_attribute_list = NULL;
939 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
940
941 /* Old dri can't handle GLX 1.3+ drawable constructors. */
942 if (xDrawable != drawable)
943 return NULL;
944
945 pdraw = Xmalloc(sizeof(*pdraw));
946 if (!pdraw)
947 return NULL;
948
949 pdraw->drawable = drawable;
950 pdraw->psc = psc;
951
952 if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable))
953 return NULL;
954
955 /* Create a new drawable */
956 pdraw->driDrawable =
957 (*psc->legacy->createNewDrawable)(psc->__driScreen,
958 config->driConfig,
959 hwDrawable,
960 GLX_WINDOW_BIT,
961 empty_attribute_list,
962 pdraw);
963
964 if (!pdraw->driDrawable) {
965 XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
966 Xfree(pdraw);
967 return NULL;
968 }
969
970 pdraw->destroyDrawable = driDestroyDrawable;
971
972 return pdraw;
973 }
974
975 static void driDestroyScreen(__GLXscreenConfigs *psc)
976 {
977 /* Free the direct rendering per screen data */
978 if (psc->__driScreen)
979 (*psc->core->destroyScreen)(psc->__driScreen);
980 psc->__driScreen = NULL;
981 if (psc->driver)
982 dlclose(psc->driver);
983 }
984
985 void
986 driBindExtensions(__GLXscreenConfigs *psc);
987
988 static __GLXDRIscreen *driCreateScreen(__GLXscreenConfigs *psc, int screen,
989 __GLXdisplayPrivate *priv)
990 {
991 __GLXDRIdisplayPrivate *pdp;
992 __GLXDRIscreen *psp;
993 const __DRIextension **extensions;
994 int i;
995
996 psp = Xmalloc(sizeof *psp);
997 if (psp == NULL)
998 return NULL;
999
1000 /* Initialize per screen dynamic client GLX extensions */
1001 psc->ext_list_first_time = GL_TRUE;
1002
1003 psc->driver = driGetDriver(priv->dpy, screen);
1004 if (psc->driver == NULL) {
1005 Xfree(psp);
1006 return NULL;
1007 }
1008
1009 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
1010 if (extensions == NULL) {
1011 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
1012 Xfree(psp);
1013 return NULL;
1014 }
1015
1016 for (i = 0; extensions[i]; i++) {
1017 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
1018 psc->core = (__DRIcoreExtension *) extensions[i];
1019 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
1020 psc->legacy = (__DRIlegacyExtension *) extensions[i];
1021 }
1022
1023 if (psc->core == NULL || psc->legacy == NULL) {
1024 Xfree(psp);
1025 return NULL;
1026 }
1027
1028 pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
1029 psc->__driScreen =
1030 CallCreateNewScreen(psc->dpy, screen, psc, pdp);
1031 if (psc->__driScreen == NULL) {
1032 dlclose(psc->driver);
1033 Xfree(psp);
1034 return NULL;
1035 }
1036
1037 driBindExtensions(psc);
1038
1039 psp->destroyScreen = driDestroyScreen;
1040 psp->createContext = driCreateContext;
1041 psp->createDrawable = driCreateDrawable;
1042
1043 return psp;
1044 }
1045
1046 /* Called from __glXFreeDisplayPrivate.
1047 */
1048 static void driDestroyDisplay(__GLXDRIdisplay *dpy)
1049 {
1050 Xfree(dpy);
1051 }
1052
1053 /*
1054 * Allocate, initialize and return a __DRIdisplayPrivate object.
1055 * This is called from __glXInitialize() when we are given a new
1056 * display pointer.
1057 */
1058 _X_HIDDEN __GLXDRIdisplay *driCreateDisplay(Display *dpy)
1059 {
1060 __GLXDRIdisplayPrivate *pdpyp;
1061 int eventBase, errorBase;
1062 int major, minor, patch;
1063
1064 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
1065 return NULL;
1066 }
1067
1068 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
1069 return NULL;
1070 }
1071
1072 pdpyp = Xmalloc(sizeof *pdpyp);
1073 if (!pdpyp) {
1074 return NULL;
1075 }
1076
1077 pdpyp->driMajor = major;
1078 pdpyp->driMinor = minor;
1079 pdpyp->driPatch = patch;
1080
1081 pdpyp->base.destroyDisplay = driDestroyDisplay;
1082 pdpyp->base.createScreen = driCreateScreen;
1083
1084 return &pdpyp->base;
1085 }
1086
1087 #endif /* GLX_DIRECT_RENDERING */