glx: Add an error message when a direct renderer's createScreen() routine fails
[mesa.git] / src / glx / 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 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
36
37 #include <X11/Xlib.h>
38 #include <X11/extensions/Xfixes.h>
39 #include <X11/extensions/Xdamage.h>
40 #include "glxclient.h"
41 #include "xf86dri.h"
42 #include "dri2.h"
43 #include "sarea.h"
44 #include <dlfcn.h>
45 #include <sys/types.h>
46 #include <sys/mman.h>
47 #include "xf86drm.h"
48 #include "dri_common.h"
49
50 struct dri_display
51 {
52 __GLXDRIdisplay base;
53
54 /*
55 ** XFree86-DRI version information
56 */
57 int driMajor;
58 int driMinor;
59 int driPatch;
60 };
61
62 struct dri_screen
63 {
64 struct glx_screen base;
65
66 __DRIscreen *driScreen;
67 __GLXDRIscreen vtable;
68 const __DRIlegacyExtension *legacy;
69 const __DRIcoreExtension *core;
70 const __DRIswapControlExtension *swapControl;
71 const __DRImediaStreamCounterExtension *msc;
72 const __DRIconfig **driver_configs;
73 const __DRIcopySubBufferExtension *driCopySubBuffer;
74
75 void *driver;
76 int fd;
77 };
78
79 struct dri_context
80 {
81 struct glx_context base;
82 __DRIcontext *driContext;
83 XID hwContextID;
84 };
85
86 struct dri_drawable
87 {
88 __GLXDRIdrawable base;
89
90 __DRIdrawable *driDrawable;
91 };
92
93 /*
94 * Given a display pointer and screen number, determine the name of
95 * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc).
96 * Return True for success, False for failure.
97 */
98 static Bool
99 driGetDriverName(Display * dpy, int scrNum, char **driverName)
100 {
101 int directCapable;
102 Bool b;
103 int event, error;
104 int driverMajor, driverMinor, driverPatch;
105
106 *driverName = NULL;
107
108 if (XF86DRIQueryExtension(dpy, &event, &error)) { /* DRI1 */
109 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
110 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
111 return False;
112 }
113 if (!directCapable) {
114 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
115 return False;
116 }
117
118 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
119 &driverPatch, driverName);
120 if (!b) {
121 ErrorMessageF("Cannot determine driver name for screen %d\n",
122 scrNum);
123 return False;
124 }
125
126 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
127 driverMajor, driverMinor, driverPatch, *driverName,
128 scrNum);
129
130 return True;
131 }
132 else if (DRI2QueryExtension(dpy, &event, &error)) { /* DRI2 */
133 char *dev;
134 Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev);
135
136 if (ret)
137 free(dev);
138
139 return ret;
140 }
141
142 return False;
143 }
144
145 /*
146 * Exported function for querying the DRI driver for a given screen.
147 *
148 * The returned char pointer points to a static array that will be
149 * overwritten by subsequent calls.
150 */
151 _X_EXPORT const char *
152 glXGetScreenDriver(Display * dpy, int scrNum)
153 {
154 static char ret[32];
155 char *driverName;
156 if (driGetDriverName(dpy, scrNum, &driverName)) {
157 int len;
158 if (!driverName)
159 return NULL;
160 len = strlen(driverName);
161 if (len >= 31)
162 return NULL;
163 memcpy(ret, driverName, len + 1);
164 free(driverName);
165 return ret;
166 }
167 return NULL;
168 }
169
170 /*
171 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
172 *
173 * The returned char pointer points directly into the driver. Therefore
174 * it should be treated as a constant.
175 *
176 * If the driver was not found or does not support configuration NULL is
177 * returned.
178 *
179 * Note: The driver remains opened after this function returns.
180 */
181 _X_EXPORT const char *
182 glXGetDriverConfig(const char *driverName)
183 {
184 void *handle = driOpenDriver(driverName);
185 const __DRIextension **extensions;
186
187 if (!handle)
188 return NULL;
189
190 extensions = driGetDriverExtensions(handle, driverName);
191 if (extensions) {
192 for (int i = 0; extensions[i]; i++) {
193 if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) == 0)
194 return ((__DRIconfigOptionsExtension *)extensions[i])->xml;
195 }
196 }
197
198 /* Fall back to the old method */
199 return dlsym(handle, "__driConfigOptions");
200 }
201
202 #ifdef XDAMAGE_1_1_INTERFACE
203
204 static GLboolean
205 has_damage_post(Display * dpy)
206 {
207 static GLboolean inited = GL_FALSE;
208 static GLboolean has_damage;
209
210 if (!inited) {
211 int major, minor;
212
213 if (XDamageQueryVersion(dpy, &major, &minor) &&
214 major == 1 && minor >= 1) {
215 has_damage = GL_TRUE;
216 }
217 else {
218 has_damage = GL_FALSE;
219 }
220 inited = GL_TRUE;
221 }
222
223 return has_damage;
224 }
225
226 static void
227 __glXReportDamage(__DRIdrawable * driDraw,
228 int x, int y,
229 drm_clip_rect_t * rects, int num_rects,
230 GLboolean front_buffer, void *loaderPrivate)
231 {
232 XRectangle *xrects;
233 XserverRegion region;
234 int i;
235 int x_off, y_off;
236 __GLXDRIdrawable *glxDraw = loaderPrivate;
237 struct glx_screen *psc = glxDraw->psc;
238 Display *dpy = psc->dpy;
239 Drawable drawable;
240
241 if (!has_damage_post(dpy))
242 return;
243
244 if (front_buffer) {
245 x_off = x;
246 y_off = y;
247 drawable = RootWindow(dpy, psc->scr);
248 }
249 else {
250 x_off = 0;
251 y_off = 0;
252 drawable = glxDraw->xDrawable;
253 }
254
255 xrects = malloc(sizeof(XRectangle) * num_rects);
256 if (xrects == NULL)
257 return;
258
259 for (i = 0; i < num_rects; i++) {
260 xrects[i].x = rects[i].x1 + x_off;
261 xrects[i].y = rects[i].y1 + y_off;
262 xrects[i].width = rects[i].x2 - rects[i].x1;
263 xrects[i].height = rects[i].y2 - rects[i].y1;
264 }
265 region = XFixesCreateRegion(dpy, xrects, num_rects);
266 free(xrects);
267 XDamageAdd(dpy, drawable, region);
268 XFixesDestroyRegion(dpy, region);
269 }
270
271 static const __DRIdamageExtension damageExtension = {
272 .base = {__DRI_DAMAGE, 1 },
273
274 .reportDamage = __glXReportDamage,
275 };
276
277 #endif
278
279 static GLboolean
280 __glXDRIGetDrawableInfo(__DRIdrawable * drawable,
281 unsigned int *index, unsigned int *stamp,
282 int *X, int *Y, int *W, int *H,
283 int *numClipRects, drm_clip_rect_t ** pClipRects,
284 int *backX, int *backY,
285 int *numBackClipRects,
286 drm_clip_rect_t ** pBackClipRects,
287 void *loaderPrivate)
288 {
289 __GLXDRIdrawable *glxDraw = loaderPrivate;
290 struct glx_screen *psc = glxDraw->psc;
291 Display *dpy = psc->dpy;
292
293 return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
294 index, stamp, X, Y, W, H,
295 numClipRects, pClipRects,
296 backX, backY,
297 numBackClipRects, pBackClipRects);
298 }
299
300 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
301 .base = {__DRI_GET_DRAWABLE_INFO, 1 },
302
303 .getDrawableInfo = __glXDRIGetDrawableInfo
304 };
305
306 static const __DRIextension *loader_extensions[] = {
307 &systemTimeExtension.base,
308 &getDrawableInfoExtension.base,
309 #ifdef XDAMAGE_1_1_INTERFACE
310 &damageExtension.base,
311 #endif
312 NULL
313 };
314
315 /**
316 * Perform the required libGL-side initialization and call the client-side
317 * driver's \c __driCreateNewScreen function.
318 *
319 * \param dpy Display pointer.
320 * \param scrn Screen number on the display.
321 * \param psc DRI screen information.
322 * \param driDpy DRI display information.
323 * \param createNewScreen Pointer to the client-side driver's
324 * \c __driCreateNewScreen function.
325 * \returns A pointer to the \c __DRIscreen structure returned by
326 * the client-side driver on success, or \c NULL on failure.
327 */
328 static void *
329 CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
330 struct dri_display * driDpy)
331 {
332 void *psp = NULL;
333 drm_handle_t hSAREA;
334 drmAddress pSAREA = MAP_FAILED;
335 char *BusID;
336 __DRIversion ddx_version;
337 __DRIversion dri_version;
338 __DRIversion drm_version;
339 __DRIframebuffer framebuffer;
340 int fd = -1;
341 int status;
342
343 drm_magic_t magic;
344 drmVersionPtr version;
345 int newlyopened;
346 char *driverName;
347 drm_handle_t hFB;
348 int junk;
349 const __DRIconfig **driver_configs;
350 struct glx_config *visual, *configs = NULL, *visuals = NULL;
351
352 /* DRI protocol version. */
353 dri_version.major = driDpy->driMajor;
354 dri_version.minor = driDpy->driMinor;
355 dri_version.patch = driDpy->driPatch;
356
357 framebuffer.base = MAP_FAILED;
358 framebuffer.dev_priv = NULL;
359 framebuffer.size = 0;
360
361 if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
362 ErrorMessageF("XF86DRIOpenConnection failed\n");
363 goto handle_error;
364 }
365
366 fd = drmOpenOnce(NULL, BusID, &newlyopened);
367
368 free(BusID); /* No longer needed */
369
370 if (fd < 0) {
371 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
372 goto handle_error;
373 }
374
375 if (drmGetMagic(fd, &magic)) {
376 ErrorMessageF("drmGetMagic failed\n");
377 goto handle_error;
378 }
379
380 version = drmGetVersion(fd);
381 if (version) {
382 drm_version.major = version->version_major;
383 drm_version.minor = version->version_minor;
384 drm_version.patch = version->version_patchlevel;
385 drmFreeVersion(version);
386 }
387 else {
388 drm_version.major = -1;
389 drm_version.minor = -1;
390 drm_version.patch = -1;
391 }
392
393 if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
394 ErrorMessageF("XF86DRIAuthConnection failed\n");
395 goto handle_error;
396 }
397
398 /* Get device name (like "radeon") and the ddx version numbers.
399 * We'll check the version in each DRI driver's "createNewScreen"
400 * function. */
401 if (!XF86DRIGetClientDriverName(dpy, scrn,
402 &ddx_version.major,
403 &ddx_version.minor,
404 &ddx_version.patch, &driverName)) {
405 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
406 goto handle_error;
407 }
408
409 free(driverName); /* No longer needed. */
410
411 /*
412 * Get device-specific info. pDevPriv will point to a struct
413 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
414 * has information about the screen size, depth, pitch, ancilliary
415 * buffers, DRM mmap handles, etc.
416 */
417 if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
418 &framebuffer.size, &framebuffer.stride,
419 &framebuffer.dev_priv_size,
420 &framebuffer.dev_priv)) {
421 ErrorMessageF("XF86DRIGetDeviceInfo failed\n");
422 goto handle_error;
423 }
424
425 framebuffer.width = DisplayWidth(dpy, scrn);
426 framebuffer.height = DisplayHeight(dpy, scrn);
427
428 /* Map the framebuffer region. */
429 status = drmMap(fd, hFB, framebuffer.size,
430 (drmAddressPtr) & framebuffer.base);
431 if (status != 0) {
432 ErrorMessageF("drmMap of framebuffer failed (%s)\n", strerror(-status));
433 goto handle_error;
434 }
435
436 /* Map the SAREA region. Further mmap regions may be setup in
437 * each DRI driver's "createNewScreen" function.
438 */
439 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
440 if (status != 0) {
441 ErrorMessageF("drmMap of SAREA failed (%s)\n", strerror(-status));
442 goto handle_error;
443 }
444
445 psp = (*psc->legacy->createNewScreen) (scrn,
446 &ddx_version,
447 &dri_version,
448 &drm_version,
449 &framebuffer,
450 pSAREA,
451 fd,
452 loader_extensions,
453 &driver_configs, psc);
454
455 if (psp == NULL) {
456 ErrorMessageF("Calling driver entry point failed\n");
457 goto handle_error;
458 }
459
460 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
461 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
462
463 if (!configs || !visuals) {
464 ErrorMessageF("No matching fbConfigs or visuals found\n");
465 goto handle_error;
466 }
467
468 glx_config_destroy_list(psc->base.configs);
469 psc->base.configs = configs;
470 glx_config_destroy_list(psc->base.visuals);
471 psc->base.visuals = visuals;
472
473 psc->driver_configs = driver_configs;
474
475 /* Visuals with depth != screen depth are subject to automatic compositing
476 * in the X server, so DRI1 can't render to them properly. Mark them as
477 * non-conformant to prevent apps from picking them up accidentally.
478 */
479 for (visual = psc->base.visuals; visual; visual = visual->next) {
480 XVisualInfo template;
481 XVisualInfo *visuals;
482 int num_visuals;
483 long mask;
484
485 template.visualid = visual->visualID;
486 mask = VisualIDMask;
487 visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals);
488
489 if (visuals) {
490 if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
491 visual->visualRating = GLX_NON_CONFORMANT_CONFIG;
492
493 free(visuals);
494 }
495 }
496
497 return psp;
498
499 handle_error:
500 if (configs)
501 glx_config_destroy_list(configs);
502 if (visuals)
503 glx_config_destroy_list(visuals);
504
505 if (pSAREA != MAP_FAILED)
506 drmUnmap(pSAREA, SAREA_MAX);
507
508 if (framebuffer.base != MAP_FAILED)
509 drmUnmap((drmAddress) framebuffer.base, framebuffer.size);
510
511 free(framebuffer.dev_priv);
512
513 if (fd >= 0)
514 drmCloseOnce(fd);
515
516 XF86DRICloseConnection(dpy, scrn);
517
518 ErrorMessageF("reverting to software direct rendering\n");
519
520 return NULL;
521 }
522
523 static void
524 dri_destroy_context(struct glx_context * context)
525 {
526 struct dri_context *pcp = (struct dri_context *) context;
527 struct dri_screen *psc = (struct dri_screen *) context->psc;
528
529 driReleaseDrawables(&pcp->base);
530
531 free((char *) context->extensions);
532
533 (*psc->core->destroyContext) (pcp->driContext);
534
535 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
536 free(pcp);
537 }
538
539 static int
540 dri_bind_context(struct glx_context *context, struct glx_context *old,
541 GLXDrawable draw, GLXDrawable read)
542 {
543 struct dri_context *pcp = (struct dri_context *) context;
544 struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
545 struct dri_drawable *pdraw, *pread;
546
547 pdraw = (struct dri_drawable *) driFetchDrawable(context, draw);
548 pread = (struct dri_drawable *) driFetchDrawable(context, read);
549
550 driReleaseDrawables(&pcp->base);
551
552 if (pdraw == NULL || pread == NULL)
553 return GLXBadDrawable;
554
555 if ((*psc->core->bindContext) (pcp->driContext,
556 pdraw->driDrawable, pread->driDrawable))
557 return Success;
558
559 return GLXBadContext;
560 }
561
562 static void
563 dri_unbind_context(struct glx_context *context, struct glx_context *new)
564 {
565 struct dri_context *pcp = (struct dri_context *) context;
566 struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
567
568 (*psc->core->unbindContext) (pcp->driContext);
569 }
570
571 static const struct glx_context_vtable dri_context_vtable = {
572 .destroy = dri_destroy_context,
573 .bind = dri_bind_context,
574 .unbind = dri_unbind_context,
575 .wait_gl = NULL,
576 .wait_x = NULL,
577 .use_x_font = DRI_glXUseXFont,
578 .bind_tex_image = NULL,
579 .release_tex_image = NULL,
580 .get_proc_address = NULL,
581 };
582
583 static struct glx_context *
584 dri_create_context(struct glx_screen *base,
585 struct glx_config *config_base,
586 struct glx_context *shareList, int renderType)
587 {
588 struct dri_context *pcp, *pcp_shared;
589 struct dri_screen *psc = (struct dri_screen *) base;
590 drm_context_t hwContext;
591 __DRIcontext *shared = NULL;
592 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
593
594 if (!psc->base.driScreen)
595 return NULL;
596
597 /* Check the renderType value */
598 if (!validate_renderType_against_config(config_base, renderType))
599 return NULL;
600
601 if (shareList) {
602 /* If the shareList context is not a DRI context, we cannot possibly
603 * create a DRI context that shares it.
604 */
605 if (shareList->vtable->destroy != dri_destroy_context) {
606 return NULL;
607 }
608
609 pcp_shared = (struct dri_context *) shareList;
610 shared = pcp_shared->driContext;
611 }
612
613 pcp = calloc(1, sizeof *pcp);
614 if (pcp == NULL)
615 return NULL;
616
617 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
618 free(pcp);
619 return NULL;
620 }
621
622 pcp->base.renderType = renderType;
623
624 if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr,
625 config->base.visualID,
626 &pcp->hwContextID, &hwContext)) {
627 free(pcp);
628 return NULL;
629 }
630
631 pcp->driContext =
632 (*psc->legacy->createNewContext) (psc->driScreen,
633 config->driConfig,
634 renderType, shared, hwContext, pcp);
635 if (pcp->driContext == NULL) {
636 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
637 free(pcp);
638 return NULL;
639 }
640
641 pcp->base.vtable = &dri_context_vtable;
642
643 return &pcp->base;
644 }
645
646 static void
647 driDestroyDrawable(__GLXDRIdrawable * pdraw)
648 {
649 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
650 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
651
652 (*psc->core->destroyDrawable) (pdp->driDrawable);
653 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable);
654 free(pdraw);
655 }
656
657 static __GLXDRIdrawable *
658 driCreateDrawable(struct glx_screen *base,
659 XID xDrawable,
660 GLXDrawable drawable, struct glx_config *config_base)
661 {
662 drm_drawable_t hwDrawable;
663 void *empty_attribute_list = NULL;
664 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
665 struct dri_screen *psc = (struct dri_screen *) base;
666 struct dri_drawable *pdp;
667
668 /* Old dri can't handle GLX 1.3+ drawable constructors. */
669 if (xDrawable != drawable)
670 return NULL;
671
672 pdp = calloc(1, sizeof *pdp);
673 if (!pdp)
674 return NULL;
675
676 pdp->base.drawable = drawable;
677 pdp->base.psc = &psc->base;
678
679 if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr,
680 drawable, &hwDrawable)) {
681 free(pdp);
682 return NULL;
683 }
684
685 /* Create a new drawable */
686 pdp->driDrawable =
687 (*psc->legacy->createNewDrawable) (psc->driScreen,
688 config->driConfig,
689 hwDrawable,
690 GLX_WINDOW_BIT,
691 empty_attribute_list, pdp);
692
693 if (!pdp->driDrawable) {
694 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable);
695 free(pdp);
696 return NULL;
697 }
698
699 pdp->base.destroyDrawable = driDestroyDrawable;
700
701 return &pdp->base;
702 }
703
704 static int64_t
705 driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
706 int64_t unused3, Bool flush)
707 {
708 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
709 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
710
711 if (flush) {
712 glFlush();
713 }
714
715 (*psc->core->swapBuffers) (pdp->driDrawable);
716 return 0;
717 }
718
719 static void
720 driCopySubBuffer(__GLXDRIdrawable * pdraw,
721 int x, int y, int width, int height, Bool flush)
722 {
723 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
724 struct dri_screen *psc = (struct dri_screen *) pdp->base.psc;
725
726 if (flush) {
727 glFlush();
728 }
729
730 (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable,
731 x, y, width, height);
732 }
733
734 static void
735 driDestroyScreen(struct glx_screen *base)
736 {
737 struct dri_screen *psc = (struct dri_screen *) base;
738
739 /* Free the direct rendering per screen data */
740 if (psc->driScreen)
741 (*psc->core->destroyScreen) (psc->driScreen);
742 driDestroyConfigs(psc->driver_configs);
743 psc->driScreen = NULL;
744 if (psc->driver)
745 dlclose(psc->driver);
746 }
747
748 static int
749 driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
750 {
751 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
752
753 if (pdraw != NULL) {
754 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
755
756 if (psc->swapControl != NULL) {
757 psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
758 return 0;
759 }
760 }
761 return GLX_BAD_CONTEXT;
762 }
763
764 static int
765 driGetSwapInterval(__GLXDRIdrawable *pdraw)
766 {
767 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
768
769 if (pdraw != NULL) {
770 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
771
772 if (psc->swapControl != NULL)
773 return psc->swapControl->getSwapInterval(pdp->driDrawable);
774 }
775 return 0;
776 }
777
778 /* Bind DRI1 specific extensions */
779 static void
780 driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions)
781 {
782 int i;
783
784 for (i = 0; extensions[i]; i++) {
785 /* No DRI2 support for swap_control at the moment, since SwapBuffers
786 * is done by the X server */
787 if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
788 psc->swapControl = (__DRIswapControlExtension *) extensions[i];
789 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
790 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
791 }
792
793 if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) {
794 psc->msc = (__DRImediaStreamCounterExtension *) extensions[i];
795 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
796 }
797
798 if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
799 psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
800 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
801 }
802
803 if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
804 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
805 }
806 /* Ignore unknown extensions */
807 }
808 }
809
810 static const struct glx_screen_vtable dri_screen_vtable = {
811 .create_context = dri_create_context,
812 .create_context_attribs = NULL,
813 .query_renderer_integer = NULL,
814 .query_renderer_string = NULL,
815 };
816
817 static struct glx_screen *
818 driCreateScreen(int screen, struct glx_display *priv)
819 {
820 struct dri_display *pdp;
821 __GLXDRIscreen *psp;
822 const __DRIextension **extensions;
823 struct dri_screen *psc;
824 char *driverName;
825 int i;
826
827 psc = calloc(1, sizeof *psc);
828 if (psc == NULL)
829 return NULL;
830
831 if (!glx_screen_init(&psc->base, screen, priv)) {
832 free(psc);
833 return NULL;
834 }
835
836 if (!driGetDriverName(priv->dpy, screen, &driverName)) {
837 goto cleanup;
838 }
839
840 psc->driver = driOpenDriver(driverName);
841 if (psc->driver == NULL)
842 goto cleanup;
843
844 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
845 if (extensions == NULL) {
846 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
847 goto cleanup;
848 }
849
850 for (i = 0; extensions[i]; i++) {
851 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
852 psc->core = (__DRIcoreExtension *) extensions[i];
853 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
854 psc->legacy = (__DRIlegacyExtension *) extensions[i];
855 }
856
857 if (psc->core == NULL || psc->legacy == NULL)
858 goto cleanup;
859
860 pdp = (struct dri_display *) priv->driDisplay;
861 psc->driScreen =
862 CallCreateNewScreen(psc->base.dpy, screen, psc, pdp);
863 if (psc->driScreen == NULL)
864 goto cleanup;
865
866 extensions = psc->core->getExtensions(psc->driScreen);
867 driBindExtensions(psc, extensions);
868
869 psc->base.vtable = &dri_screen_vtable;
870 psp = &psc->vtable;
871 psc->base.driScreen = psp;
872 if (psc->driCopySubBuffer)
873 psp->copySubBuffer = driCopySubBuffer;
874
875 psp->destroyScreen = driDestroyScreen;
876 psp->createDrawable = driCreateDrawable;
877 psp->swapBuffers = driSwapBuffers;
878
879 psp->setSwapInterval = driSetSwapInterval;
880 psp->getSwapInterval = driGetSwapInterval;
881
882 free(driverName);
883
884 return &psc->base;
885
886 cleanup:
887 CriticalErrorMessageF("failed to load driver: %s\n", driverName);
888
889 free(driverName);
890
891 if (psc->driver)
892 dlclose(psc->driver);
893 glx_screen_cleanup(&psc->base);
894 free(psc);
895
896 return NULL;
897 }
898
899 /* Called from __glXFreeDisplayPrivate.
900 */
901 static void
902 driDestroyDisplay(__GLXDRIdisplay * dpy)
903 {
904 free(dpy);
905 }
906
907 /*
908 * Allocate, initialize and return a __DRIdisplayPrivate object.
909 * This is called from __glXInitialize() when we are given a new
910 * display pointer.
911 */
912 _X_HIDDEN __GLXDRIdisplay *
913 driCreateDisplay(Display * dpy)
914 {
915 struct dri_display *pdpyp;
916 int eventBase, errorBase;
917 int major, minor, patch;
918
919 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
920 return NULL;
921 }
922
923 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
924 return NULL;
925 }
926
927 pdpyp = malloc(sizeof *pdpyp);
928 if (!pdpyp) {
929 return NULL;
930 }
931
932 pdpyp->driMajor = major;
933 pdpyp->driMinor = minor;
934 pdpyp->driPatch = patch;
935
936 pdpyp->base.destroyDisplay = driDestroyDisplay;
937 pdpyp->base.createScreen = driCreateScreen;
938
939 return &pdpyp->base;
940 }
941
942 #endif /* GLX_DIRECT_RENDERING */