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