glx/dri: use the implemented version of __DRIdamageExtension
[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 static const struct glx_context_vtable dri_context_vtable;
94
95 /*
96 * Given a display pointer and screen number, determine the name of
97 * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc).
98 * Return True for success, False for failure.
99 */
100 static Bool
101 driGetDriverName(Display * dpy, int scrNum, char **driverName)
102 {
103 int directCapable;
104 Bool b;
105 int event, error;
106 int driverMajor, driverMinor, driverPatch;
107
108 *driverName = NULL;
109
110 if (XF86DRIQueryExtension(dpy, &event, &error)) { /* DRI1 */
111 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
112 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
113 return False;
114 }
115 if (!directCapable) {
116 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
117 return False;
118 }
119
120 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
121 &driverPatch, driverName);
122 if (!b) {
123 ErrorMessageF("Cannot determine driver name for screen %d\n",
124 scrNum);
125 return False;
126 }
127
128 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
129 driverMajor, driverMinor, driverPatch, *driverName,
130 scrNum);
131
132 return True;
133 }
134 else if (DRI2QueryExtension(dpy, &event, &error)) { /* DRI2 */
135 char *dev;
136 Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev);
137
138 if (ret)
139 free(dev);
140
141 return ret;
142 }
143
144 return False;
145 }
146
147 /*
148 * Exported function for querying the DRI driver for a given screen.
149 *
150 * The returned char pointer points to a static array that will be
151 * overwritten by subsequent calls.
152 */
153 _X_EXPORT const char *
154 glXGetScreenDriver(Display * dpy, int scrNum)
155 {
156 static char ret[32];
157 char *driverName;
158 if (driGetDriverName(dpy, scrNum, &driverName)) {
159 int len;
160 if (!driverName)
161 return NULL;
162 len = strlen(driverName);
163 if (len >= 31)
164 return NULL;
165 memcpy(ret, driverName, len + 1);
166 free(driverName);
167 return ret;
168 }
169 return NULL;
170 }
171
172 /*
173 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
174 *
175 * The returned char pointer points directly into the driver. Therefore
176 * it should be treated as a constant.
177 *
178 * If the driver was not found or does not support configuration NULL is
179 * returned.
180 *
181 * Note: The driver remains opened after this function returns.
182 */
183 _X_EXPORT const char *
184 glXGetDriverConfig(const char *driverName)
185 {
186 void *handle = driOpenDriver(driverName);
187 const __DRIextension **extensions;
188
189 if (!handle)
190 return NULL;
191
192 extensions = driGetDriverExtensions(handle, driverName);
193 if (extensions) {
194 for (int i = 0; extensions[i]; i++) {
195 if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) == 0)
196 return ((__DRIconfigOptionsExtension *)extensions[i])->xml;
197 }
198 }
199
200 /* Fall back to the old method */
201 return dlsym(handle, "__driConfigOptions");
202 }
203
204 #ifdef XDAMAGE_1_1_INTERFACE
205
206 static GLboolean
207 has_damage_post(Display * dpy)
208 {
209 static GLboolean inited = GL_FALSE;
210 static GLboolean has_damage;
211
212 if (!inited) {
213 int major, minor;
214
215 if (XDamageQueryVersion(dpy, &major, &minor) &&
216 major == 1 && minor >= 1) {
217 has_damage = GL_TRUE;
218 }
219 else {
220 has_damage = GL_FALSE;
221 }
222 inited = GL_TRUE;
223 }
224
225 return has_damage;
226 }
227
228 static void
229 __glXReportDamage(__DRIdrawable * driDraw,
230 int x, int y,
231 drm_clip_rect_t * rects, int num_rects,
232 GLboolean front_buffer, void *loaderPrivate)
233 {
234 XRectangle *xrects;
235 XserverRegion region;
236 int i;
237 int x_off, y_off;
238 __GLXDRIdrawable *glxDraw = loaderPrivate;
239 struct glx_screen *psc = glxDraw->psc;
240 Display *dpy = psc->dpy;
241 Drawable drawable;
242
243 if (!has_damage_post(dpy))
244 return;
245
246 if (front_buffer) {
247 x_off = x;
248 y_off = y;
249 drawable = RootWindow(dpy, psc->scr);
250 }
251 else {
252 x_off = 0;
253 y_off = 0;
254 drawable = glxDraw->xDrawable;
255 }
256
257 xrects = malloc(sizeof(XRectangle) * num_rects);
258 if (xrects == NULL)
259 return;
260
261 for (i = 0; i < num_rects; i++) {
262 xrects[i].x = rects[i].x1 + x_off;
263 xrects[i].y = rects[i].y1 + y_off;
264 xrects[i].width = rects[i].x2 - rects[i].x1;
265 xrects[i].height = rects[i].y2 - rects[i].y1;
266 }
267 region = XFixesCreateRegion(dpy, xrects, num_rects);
268 free(xrects);
269 XDamageAdd(dpy, drawable, region);
270 XFixesDestroyRegion(dpy, region);
271 }
272
273 static const __DRIdamageExtension damageExtension = {
274 .base = {__DRI_DAMAGE, 1 },
275
276 .reportDamage = __glXReportDamage,
277 };
278
279 #endif
280
281 static GLboolean
282 __glXDRIGetDrawableInfo(__DRIdrawable * drawable,
283 unsigned int *index, unsigned int *stamp,
284 int *X, int *Y, int *W, int *H,
285 int *numClipRects, drm_clip_rect_t ** pClipRects,
286 int *backX, int *backY,
287 int *numBackClipRects,
288 drm_clip_rect_t ** pBackClipRects,
289 void *loaderPrivate)
290 {
291 __GLXDRIdrawable *glxDraw = loaderPrivate;
292 struct glx_screen *psc = glxDraw->psc;
293 Display *dpy = psc->dpy;
294
295 return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
296 index, stamp, X, Y, W, H,
297 numClipRects, pClipRects,
298 backX, backY,
299 numBackClipRects, pBackClipRects);
300 }
301
302 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
303 .base = {__DRI_GET_DRAWABLE_INFO, 1 },
304
305 .getDrawableInfo = __glXDRIGetDrawableInfo
306 };
307
308 static const __DRIextension *loader_extensions[] = {
309 &systemTimeExtension.base,
310 &getDrawableInfoExtension.base,
311 #ifdef XDAMAGE_1_1_INTERFACE
312 &damageExtension.base,
313 #endif
314 NULL
315 };
316
317 /**
318 * Perform the required libGL-side initialization and call the client-side
319 * driver's \c __driCreateNewScreen function.
320 *
321 * \param dpy Display pointer.
322 * \param scrn Screen number on the display.
323 * \param psc DRI screen information.
324 * \param driDpy DRI display information.
325 * \param createNewScreen Pointer to the client-side driver's
326 * \c __driCreateNewScreen function.
327 * \returns A pointer to the \c __DRIscreen structure returned by
328 * the client-side driver on success, or \c NULL on failure.
329 */
330 static void *
331 CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
332 struct dri_display * driDpy)
333 {
334 void *psp = NULL;
335 drm_handle_t hSAREA;
336 drmAddress pSAREA = MAP_FAILED;
337 char *BusID;
338 __DRIversion ddx_version;
339 __DRIversion dri_version;
340 __DRIversion drm_version;
341 __DRIframebuffer framebuffer;
342 int fd = -1;
343 int status;
344
345 drm_magic_t magic;
346 drmVersionPtr version;
347 int newlyopened;
348 char *driverName;
349 drm_handle_t hFB;
350 int junk;
351 const __DRIconfig **driver_configs;
352 struct glx_config *visual, *configs = NULL, *visuals = NULL;
353
354 /* DRI protocol version. */
355 dri_version.major = driDpy->driMajor;
356 dri_version.minor = driDpy->driMinor;
357 dri_version.patch = driDpy->driPatch;
358
359 framebuffer.base = MAP_FAILED;
360 framebuffer.dev_priv = NULL;
361 framebuffer.size = 0;
362
363 if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
364 ErrorMessageF("XF86DRIOpenConnection failed\n");
365 goto handle_error;
366 }
367
368 fd = drmOpenOnce(NULL, BusID, &newlyopened);
369
370 free(BusID); /* No longer needed */
371
372 if (fd < 0) {
373 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
374 goto handle_error;
375 }
376
377 if (drmGetMagic(fd, &magic)) {
378 ErrorMessageF("drmGetMagic failed\n");
379 goto handle_error;
380 }
381
382 version = drmGetVersion(fd);
383 if (version) {
384 drm_version.major = version->version_major;
385 drm_version.minor = version->version_minor;
386 drm_version.patch = version->version_patchlevel;
387 drmFreeVersion(version);
388 }
389 else {
390 drm_version.major = -1;
391 drm_version.minor = -1;
392 drm_version.patch = -1;
393 }
394
395 if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
396 ErrorMessageF("XF86DRIAuthConnection failed\n");
397 goto handle_error;
398 }
399
400 /* Get device name (like "radeon") and the ddx version numbers.
401 * We'll check the version in each DRI driver's "createNewScreen"
402 * function. */
403 if (!XF86DRIGetClientDriverName(dpy, scrn,
404 &ddx_version.major,
405 &ddx_version.minor,
406 &ddx_version.patch, &driverName)) {
407 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
408 goto handle_error;
409 }
410
411 free(driverName); /* No longer needed. */
412
413 /*
414 * Get device-specific info. pDevPriv will point to a struct
415 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
416 * has information about the screen size, depth, pitch, ancilliary
417 * buffers, DRM mmap handles, etc.
418 */
419 if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
420 &framebuffer.size, &framebuffer.stride,
421 &framebuffer.dev_priv_size,
422 &framebuffer.dev_priv)) {
423 ErrorMessageF("XF86DRIGetDeviceInfo failed\n");
424 goto handle_error;
425 }
426
427 framebuffer.width = DisplayWidth(dpy, scrn);
428 framebuffer.height = DisplayHeight(dpy, scrn);
429
430 /* Map the framebuffer region. */
431 status = drmMap(fd, hFB, framebuffer.size,
432 (drmAddressPtr) & framebuffer.base);
433 if (status != 0) {
434 ErrorMessageF("drmMap of framebuffer failed (%s)\n", strerror(-status));
435 goto handle_error;
436 }
437
438 /* Map the SAREA region. Further mmap regions may be setup in
439 * each DRI driver's "createNewScreen" function.
440 */
441 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
442 if (status != 0) {
443 ErrorMessageF("drmMap of SAREA failed (%s)\n", strerror(-status));
444 goto handle_error;
445 }
446
447 psp = (*psc->legacy->createNewScreen) (scrn,
448 &ddx_version,
449 &dri_version,
450 &drm_version,
451 &framebuffer,
452 pSAREA,
453 fd,
454 loader_extensions,
455 &driver_configs, psc);
456
457 if (psp == NULL) {
458 ErrorMessageF("Calling driver entry point failed\n");
459 goto handle_error;
460 }
461
462 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
463 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
464
465 if (!configs || !visuals)
466 goto handle_error;
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 dri_destroy_context,
573 dri_bind_context,
574 dri_unbind_context,
575 NULL,
576 NULL,
577 DRI_glXUseXFont,
578 NULL,
579 NULL,
580 NULL, /* get_proc_address */
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 dri_create_context,
812 NULL
813 };
814
815 static struct glx_screen *
816 driCreateScreen(int screen, struct glx_display *priv)
817 {
818 struct dri_display *pdp;
819 __GLXDRIscreen *psp;
820 const __DRIextension **extensions;
821 struct dri_screen *psc;
822 char *driverName;
823 int i;
824
825 psc = calloc(1, sizeof *psc);
826 if (psc == NULL)
827 return NULL;
828
829 if (!glx_screen_init(&psc->base, screen, priv)) {
830 free(psc);
831 return NULL;
832 }
833
834 if (!driGetDriverName(priv->dpy, screen, &driverName)) {
835 goto cleanup;
836 }
837
838 psc->driver = driOpenDriver(driverName);
839 if (psc->driver == NULL)
840 goto cleanup;
841
842 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
843 if (extensions == NULL) {
844 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
845 goto cleanup;
846 }
847
848 for (i = 0; extensions[i]; i++) {
849 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
850 psc->core = (__DRIcoreExtension *) extensions[i];
851 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
852 psc->legacy = (__DRIlegacyExtension *) extensions[i];
853 }
854
855 if (psc->core == NULL || psc->legacy == NULL)
856 goto cleanup;
857
858 pdp = (struct dri_display *) priv->driDisplay;
859 psc->driScreen =
860 CallCreateNewScreen(psc->base.dpy, screen, psc, pdp);
861 if (psc->driScreen == NULL)
862 goto cleanup;
863
864 extensions = psc->core->getExtensions(psc->driScreen);
865 driBindExtensions(psc, extensions);
866
867 psc->base.vtable = &dri_screen_vtable;
868 psp = &psc->vtable;
869 psc->base.driScreen = psp;
870 if (psc->driCopySubBuffer)
871 psp->copySubBuffer = driCopySubBuffer;
872
873 psp->destroyScreen = driDestroyScreen;
874 psp->createDrawable = driCreateDrawable;
875 psp->swapBuffers = driSwapBuffers;
876
877 psp->setSwapInterval = driSetSwapInterval;
878 psp->getSwapInterval = driGetSwapInterval;
879
880 free(driverName);
881
882 return &psc->base;
883
884 cleanup:
885 CriticalErrorMessageF("failed to load driver: %s\n", driverName);
886
887 free(driverName);
888
889 if (psc->driver)
890 dlclose(psc->driver);
891 glx_screen_cleanup(&psc->base);
892 free(psc);
893
894 return NULL;
895 }
896
897 /* Called from __glXFreeDisplayPrivate.
898 */
899 static void
900 driDestroyDisplay(__GLXDRIdisplay * dpy)
901 {
902 free(dpy);
903 }
904
905 /*
906 * Allocate, initialize and return a __DRIdisplayPrivate object.
907 * This is called from __glXInitialize() when we are given a new
908 * display pointer.
909 */
910 _X_HIDDEN __GLXDRIdisplay *
911 driCreateDisplay(Display * dpy)
912 {
913 struct dri_display *pdpyp;
914 int eventBase, errorBase;
915 int major, minor, patch;
916
917 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
918 return NULL;
919 }
920
921 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
922 return NULL;
923 }
924
925 pdpyp = malloc(sizeof *pdpyp);
926 if (!pdpyp) {
927 return NULL;
928 }
929
930 pdpyp->driMajor = major;
931 pdpyp->driMinor = minor;
932 pdpyp->driPatch = patch;
933
934 pdpyp->base.destroyDisplay = driDestroyDisplay;
935 pdpyp->base.createScreen = driCreateScreen;
936
937 return &pdpyp->base;
938 }
939
940 #endif /* GLX_DIRECT_RENDERING */