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