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