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