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