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