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