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