5c4346cec0d8f09591290b2b6722e00e08f73326
[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 "dri_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 _GLX_PUBLIC 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 /* glXGetDriverConfig must return a pointer with a static lifetime. To avoid
171 * keeping drivers loaded and other leaks, we keep a cache of results here that
172 * is cleared by an atexit handler.
173 */
174 struct driver_config_entry {
175 struct driver_config_entry *next;
176 char *driverName;
177 char *config;
178 };
179
180 static pthread_mutex_t driver_config_mutex = PTHREAD_MUTEX_INITIALIZER;
181 static struct driver_config_entry *driver_config_cache = NULL;
182
183 /* Called as an atexit function. Otherwise, this would have to be called with
184 * driver_config_mutex locked.
185 */
186 static void
187 clear_driver_config_cache()
188 {
189 while (driver_config_cache) {
190 struct driver_config_entry *e = driver_config_cache;
191 driver_config_cache = e->next;
192
193 free(e->driverName);
194 free(e->config);
195 free(e);
196 }
197 }
198
199 static char *
200 get_driver_config(const char *driverName)
201 {
202 void *handle = driOpenDriver(driverName);
203 const __DRIextension **extensions;
204
205 if (!handle)
206 return NULL;
207
208 char *config = NULL;
209
210 extensions = driGetDriverExtensions(handle, driverName);
211 if (extensions) {
212 for (int i = 0; extensions[i]; i++) {
213 if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) != 0)
214 continue;
215
216 __DRIconfigOptionsExtension *ext =
217 (__DRIconfigOptionsExtension *)extensions[i];
218
219 if (ext->base.version >= 2)
220 config = ext->getXml(driverName);
221 else
222 config = strdup(ext->xml);
223
224 break;
225 }
226 }
227
228 if (!config) {
229 /* Fall back to the old method */
230 config = dlsym(handle, "__driConfigOptions");
231 if (config)
232 config = strdup(config);
233 }
234
235 dlclose(handle);
236
237 return config;
238 }
239
240 /*
241 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
242 *
243 * The returned char pointer points directly into the driver. Therefore
244 * it should be treated as a constant.
245 *
246 * If the driver was not found or does not support configuration NULL is
247 * returned.
248 */
249 _GLX_PUBLIC const char *
250 glXGetDriverConfig(const char *driverName)
251 {
252 struct driver_config_entry *e;
253
254 pthread_mutex_lock(&driver_config_mutex);
255
256 for (e = driver_config_cache; e; e = e->next) {
257 if (strcmp(e->driverName, driverName) == 0)
258 goto out;
259 }
260
261 e = malloc(sizeof(*e));
262 if (!e)
263 goto out;
264
265 e->config = get_driver_config(driverName);
266 e->driverName = strdup(driverName);
267 if (!e->config || !e->driverName) {
268 free(e->config);
269 free(e->driverName);
270 free(e);
271 e = NULL;
272 goto out;
273 }
274
275 e->next = driver_config_cache;
276 driver_config_cache = e;
277
278 if (!e->next)
279 atexit(clear_driver_config_cache);
280
281 out:
282 pthread_mutex_unlock(&driver_config_mutex);
283
284 return e ? e->config : NULL;
285 }
286
287 static GLboolean
288 has_damage_post(Display * dpy)
289 {
290 static GLboolean inited = GL_FALSE;
291 static GLboolean has_damage;
292
293 if (!inited) {
294 int major, minor;
295
296 if (XDamageQueryVersion(dpy, &major, &minor) &&
297 major == 1 && minor >= 1) {
298 has_damage = GL_TRUE;
299 }
300 else {
301 has_damage = GL_FALSE;
302 }
303 inited = GL_TRUE;
304 }
305
306 return has_damage;
307 }
308
309 static void
310 __glXReportDamage(__DRIdrawable * driDraw,
311 int x, int y,
312 drm_clip_rect_t * rects, int num_rects,
313 GLboolean front_buffer, void *loaderPrivate)
314 {
315 XRectangle *xrects;
316 XserverRegion region;
317 int i;
318 int x_off, y_off;
319 __GLXDRIdrawable *glxDraw = loaderPrivate;
320 struct glx_screen *psc = glxDraw->psc;
321 Display *dpy = psc->dpy;
322 Drawable drawable;
323
324 if (!has_damage_post(dpy))
325 return;
326
327 if (front_buffer) {
328 x_off = x;
329 y_off = y;
330 drawable = RootWindow(dpy, psc->scr);
331 }
332 else {
333 x_off = 0;
334 y_off = 0;
335 drawable = glxDraw->xDrawable;
336 }
337
338 xrects = malloc(sizeof(XRectangle) * num_rects);
339 if (xrects == NULL)
340 return;
341
342 for (i = 0; i < num_rects; i++) {
343 xrects[i].x = rects[i].x1 + x_off;
344 xrects[i].y = rects[i].y1 + y_off;
345 xrects[i].width = rects[i].x2 - rects[i].x1;
346 xrects[i].height = rects[i].y2 - rects[i].y1;
347 }
348 region = XFixesCreateRegion(dpy, xrects, num_rects);
349 free(xrects);
350 XDamageAdd(dpy, drawable, region);
351 XFixesDestroyRegion(dpy, region);
352 }
353
354 static const __DRIdamageExtension damageExtension = {
355 .base = {__DRI_DAMAGE, 1 },
356
357 .reportDamage = __glXReportDamage,
358 };
359
360 static GLboolean
361 __glXDRIGetDrawableInfo(__DRIdrawable * drawable,
362 unsigned int *index, unsigned int *stamp,
363 int *X, int *Y, int *W, int *H,
364 int *numClipRects, drm_clip_rect_t ** pClipRects,
365 int *backX, int *backY,
366 int *numBackClipRects,
367 drm_clip_rect_t ** pBackClipRects,
368 void *loaderPrivate)
369 {
370 __GLXDRIdrawable *glxDraw = loaderPrivate;
371 struct glx_screen *psc = glxDraw->psc;
372 Display *dpy = psc->dpy;
373
374 return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
375 index, stamp, X, Y, W, H,
376 numClipRects, pClipRects,
377 backX, backY,
378 numBackClipRects, pBackClipRects);
379 }
380
381 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
382 .base = {__DRI_GET_DRAWABLE_INFO, 1 },
383
384 .getDrawableInfo = __glXDRIGetDrawableInfo
385 };
386
387 static const __DRIextension *loader_extensions[] = {
388 &systemTimeExtension.base,
389 &getDrawableInfoExtension.base,
390 #ifdef XDAMAGE_1_1_INTERFACE
391 &damageExtension.base,
392 #endif
393 NULL
394 };
395
396 /**
397 * Perform the required libGL-side initialization and call the client-side
398 * driver's \c __driCreateNewScreen function.
399 *
400 * \param dpy Display pointer.
401 * \param scrn Screen number on the display.
402 * \param psc DRI screen information.
403 * \param driDpy DRI display information.
404 * \param createNewScreen Pointer to the client-side driver's
405 * \c __driCreateNewScreen function.
406 * \returns A pointer to the \c __DRIscreen structure returned by
407 * the client-side driver on success, or \c NULL on failure.
408 */
409 static void *
410 CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
411 struct dri_display * driDpy)
412 {
413 void *psp = NULL;
414 drm_handle_t hSAREA;
415 drmAddress pSAREA = MAP_FAILED;
416 char *BusID;
417 __DRIversion ddx_version;
418 __DRIversion dri_version;
419 __DRIversion drm_version;
420 __DRIframebuffer framebuffer;
421 int fd = -1;
422 int status;
423
424 drm_magic_t magic;
425 drmVersionPtr version;
426 int newlyopened;
427 char *driverName;
428 drm_handle_t hFB;
429 int junk;
430 const __DRIconfig **driver_configs;
431 struct glx_config *visual, *configs = NULL, *visuals = NULL;
432
433 /* DRI protocol version. */
434 dri_version.major = driDpy->driMajor;
435 dri_version.minor = driDpy->driMinor;
436 dri_version.patch = driDpy->driPatch;
437
438 framebuffer.base = MAP_FAILED;
439 framebuffer.dev_priv = NULL;
440 framebuffer.size = 0;
441
442 if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
443 ErrorMessageF("XF86DRIOpenConnection failed\n");
444 goto handle_error;
445 }
446
447 fd = drmOpenOnce(NULL, BusID, &newlyopened);
448
449 free(BusID); /* No longer needed */
450
451 if (fd < 0) {
452 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
453 goto handle_error;
454 }
455
456 if (drmGetMagic(fd, &magic)) {
457 ErrorMessageF("drmGetMagic failed\n");
458 goto handle_error;
459 }
460
461 version = drmGetVersion(fd);
462 if (version) {
463 drm_version.major = version->version_major;
464 drm_version.minor = version->version_minor;
465 drm_version.patch = version->version_patchlevel;
466 drmFreeVersion(version);
467 }
468 else {
469 drm_version.major = -1;
470 drm_version.minor = -1;
471 drm_version.patch = -1;
472 }
473
474 if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
475 ErrorMessageF("XF86DRIAuthConnection failed\n");
476 goto handle_error;
477 }
478
479 /* Get device name (like "radeon") and the ddx version numbers.
480 * We'll check the version in each DRI driver's "createNewScreen"
481 * function. */
482 if (!XF86DRIGetClientDriverName(dpy, scrn,
483 &ddx_version.major,
484 &ddx_version.minor,
485 &ddx_version.patch, &driverName)) {
486 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
487 goto handle_error;
488 }
489
490 free(driverName); /* No longer needed. */
491
492 /*
493 * Get device-specific info. pDevPriv will point to a struct
494 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
495 * has information about the screen size, depth, pitch, ancilliary
496 * buffers, DRM mmap handles, etc.
497 */
498 if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
499 &framebuffer.size, &framebuffer.stride,
500 &framebuffer.dev_priv_size,
501 &framebuffer.dev_priv)) {
502 ErrorMessageF("XF86DRIGetDeviceInfo failed\n");
503 goto handle_error;
504 }
505
506 framebuffer.width = DisplayWidth(dpy, scrn);
507 framebuffer.height = DisplayHeight(dpy, scrn);
508
509 /* Map the framebuffer region. */
510 status = drmMap(fd, hFB, framebuffer.size,
511 (drmAddressPtr) & framebuffer.base);
512 if (status != 0) {
513 ErrorMessageF("drmMap of framebuffer failed (%s)\n", strerror(-status));
514 goto handle_error;
515 }
516
517 /* Map the SAREA region. Further mmap regions may be setup in
518 * each DRI driver's "createNewScreen" function.
519 */
520 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
521 if (status != 0) {
522 ErrorMessageF("drmMap of SAREA failed (%s)\n", strerror(-status));
523 goto handle_error;
524 }
525
526 psp = (*psc->legacy->createNewScreen) (scrn,
527 &ddx_version,
528 &dri_version,
529 &drm_version,
530 &framebuffer,
531 pSAREA,
532 fd,
533 loader_extensions,
534 &driver_configs, psc);
535
536 if (psp == NULL) {
537 ErrorMessageF("Calling driver entry point failed\n");
538 goto handle_error;
539 }
540
541 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
542 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
543
544 if (!configs || !visuals) {
545 ErrorMessageF("No matching fbConfigs or visuals found\n");
546 goto handle_error;
547 }
548
549 glx_config_destroy_list(psc->base.configs);
550 psc->base.configs = configs;
551 glx_config_destroy_list(psc->base.visuals);
552 psc->base.visuals = visuals;
553
554 psc->driver_configs = driver_configs;
555
556 /* Visuals with depth != screen depth are subject to automatic compositing
557 * in the X server, so DRI1 can't render to them properly. Mark them as
558 * non-conformant to prevent apps from picking them up accidentally.
559 */
560 for (visual = psc->base.visuals; visual; visual = visual->next) {
561 XVisualInfo templ;
562 XVisualInfo *visuals;
563 int num_visuals;
564 long mask;
565
566 templ.visualid = visual->visualID;
567 mask = VisualIDMask;
568 visuals = XGetVisualInfo(dpy, mask, &templ, &num_visuals);
569
570 if (visuals) {
571 if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
572 visual->visualRating = GLX_NON_CONFORMANT_CONFIG;
573
574 free(visuals);
575 }
576 }
577
578 return psp;
579
580 handle_error:
581 if (configs)
582 glx_config_destroy_list(configs);
583 if (visuals)
584 glx_config_destroy_list(visuals);
585
586 if (pSAREA != MAP_FAILED)
587 drmUnmap(pSAREA, SAREA_MAX);
588
589 if (framebuffer.base != MAP_FAILED)
590 drmUnmap((drmAddress) framebuffer.base, framebuffer.size);
591
592 free(framebuffer.dev_priv);
593
594 if (fd >= 0)
595 drmCloseOnce(fd);
596
597 XF86DRICloseConnection(dpy, scrn);
598
599 ErrorMessageF("reverting to software direct rendering\n");
600
601 return NULL;
602 }
603
604 static void
605 dri_destroy_context(struct glx_context * context)
606 {
607 struct dri_context *pcp = (struct dri_context *) context;
608 struct dri_screen *psc = (struct dri_screen *) context->psc;
609
610 driReleaseDrawables(&pcp->base);
611
612 free((char *) context->extensions);
613
614 (*psc->core->destroyContext) (pcp->driContext);
615
616 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
617 free(pcp);
618 }
619
620 static int
621 dri_bind_context(struct glx_context *context, struct glx_context *old,
622 GLXDrawable draw, GLXDrawable read)
623 {
624 struct dri_context *pcp = (struct dri_context *) context;
625 struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
626 struct dri_drawable *pdraw, *pread;
627
628 pdraw = (struct dri_drawable *) driFetchDrawable(context, draw);
629 pread = (struct dri_drawable *) driFetchDrawable(context, read);
630
631 driReleaseDrawables(&pcp->base);
632
633 if (pdraw == NULL || pread == NULL)
634 return GLXBadDrawable;
635
636 if ((*psc->core->bindContext) (pcp->driContext,
637 pdraw->driDrawable, pread->driDrawable))
638 return Success;
639
640 return GLXBadContext;
641 }
642
643 static void
644 dri_unbind_context(struct glx_context *context, struct glx_context *new)
645 {
646 struct dri_context *pcp = (struct dri_context *) context;
647 struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
648
649 (*psc->core->unbindContext) (pcp->driContext);
650 }
651
652 static const struct glx_context_vtable dri_context_vtable = {
653 .destroy = dri_destroy_context,
654 .bind = dri_bind_context,
655 .unbind = dri_unbind_context,
656 .wait_gl = NULL,
657 .wait_x = NULL,
658 .use_x_font = DRI_glXUseXFont,
659 .bind_tex_image = NULL,
660 .release_tex_image = NULL,
661 .get_proc_address = NULL,
662 };
663
664 static struct glx_context *
665 dri_create_context(struct glx_screen *base,
666 struct glx_config *config_base,
667 struct glx_context *shareList, int renderType)
668 {
669 struct dri_context *pcp, *pcp_shared;
670 struct dri_screen *psc = (struct dri_screen *) base;
671 drm_context_t hwContext;
672 __DRIcontext *shared = NULL;
673 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
674
675 if (!psc->base.driScreen)
676 return NULL;
677
678 /* Check the renderType value */
679 if (!validate_renderType_against_config(config_base, renderType))
680 return NULL;
681
682 if (shareList) {
683 /* If the shareList context is not a DRI context, we cannot possibly
684 * create a DRI context that shares it.
685 */
686 if (shareList->vtable->destroy != dri_destroy_context) {
687 return NULL;
688 }
689
690 pcp_shared = (struct dri_context *) shareList;
691 shared = pcp_shared->driContext;
692 }
693
694 pcp = calloc(1, sizeof *pcp);
695 if (pcp == NULL)
696 return NULL;
697
698 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
699 free(pcp);
700 return NULL;
701 }
702
703 pcp->base.renderType = renderType;
704
705 if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr,
706 config->base.visualID,
707 &pcp->hwContextID, &hwContext)) {
708 free(pcp);
709 return NULL;
710 }
711
712 pcp->driContext =
713 (*psc->legacy->createNewContext) (psc->driScreen,
714 config->driConfig,
715 renderType, shared, hwContext, pcp);
716 if (pcp->driContext == NULL) {
717 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
718 free(pcp);
719 return NULL;
720 }
721
722 pcp->base.vtable = &dri_context_vtable;
723
724 return &pcp->base;
725 }
726
727 static void
728 driDestroyDrawable(__GLXDRIdrawable * pdraw)
729 {
730 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
731 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
732
733 (*psc->core->destroyDrawable) (pdp->driDrawable);
734 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable);
735 free(pdraw);
736 }
737
738 static __GLXDRIdrawable *
739 driCreateDrawable(struct glx_screen *base,
740 XID xDrawable,
741 GLXDrawable drawable, struct glx_config *config_base)
742 {
743 drm_drawable_t hwDrawable;
744 void *empty_attribute_list = NULL;
745 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
746 struct dri_screen *psc = (struct dri_screen *) base;
747 struct dri_drawable *pdp;
748
749 /* Old dri can't handle GLX 1.3+ drawable constructors. */
750 if (xDrawable != drawable)
751 return NULL;
752
753 pdp = calloc(1, sizeof *pdp);
754 if (!pdp)
755 return NULL;
756
757 pdp->base.drawable = drawable;
758 pdp->base.psc = &psc->base;
759
760 if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr,
761 drawable, &hwDrawable)) {
762 free(pdp);
763 return NULL;
764 }
765
766 /* Create a new drawable */
767 pdp->driDrawable =
768 (*psc->legacy->createNewDrawable) (psc->driScreen,
769 config->driConfig,
770 hwDrawable,
771 GLX_WINDOW_BIT,
772 empty_attribute_list, pdp);
773
774 if (!pdp->driDrawable) {
775 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable);
776 free(pdp);
777 return NULL;
778 }
779
780 pdp->base.destroyDrawable = driDestroyDrawable;
781
782 return &pdp->base;
783 }
784
785 static int64_t
786 driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
787 int64_t unused3, Bool flush)
788 {
789 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
790 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
791
792 if (flush) {
793 glFlush();
794 }
795
796 (*psc->core->swapBuffers) (pdp->driDrawable);
797 return 0;
798 }
799
800 static void
801 driCopySubBuffer(__GLXDRIdrawable * pdraw,
802 int x, int y, int width, int height, Bool flush)
803 {
804 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
805 struct dri_screen *psc = (struct dri_screen *) pdp->base.psc;
806
807 if (flush) {
808 glFlush();
809 }
810
811 (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable,
812 x, y, width, height);
813 }
814
815 static void
816 driDestroyScreen(struct glx_screen *base)
817 {
818 struct dri_screen *psc = (struct dri_screen *) base;
819
820 /* Free the direct rendering per screen data */
821 if (psc->driScreen)
822 (*psc->core->destroyScreen) (psc->driScreen);
823 driDestroyConfigs(psc->driver_configs);
824 psc->driScreen = NULL;
825 if (psc->driver)
826 dlclose(psc->driver);
827 }
828
829 static int
830 driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
831 {
832 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
833
834 if (pdraw != NULL) {
835 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
836
837 if (psc->swapControl != NULL) {
838 psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
839 return 0;
840 }
841 }
842 return GLX_BAD_CONTEXT;
843 }
844
845 static int
846 driGetSwapInterval(__GLXDRIdrawable *pdraw)
847 {
848 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
849
850 if (pdraw != NULL) {
851 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
852
853 if (psc->swapControl != NULL)
854 return psc->swapControl->getSwapInterval(pdp->driDrawable);
855 }
856 return 0;
857 }
858
859 /* Bind DRI1 specific extensions */
860 static void
861 driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions)
862 {
863 int i;
864
865 for (i = 0; extensions[i]; i++) {
866 /* No DRI2 support for swap_control at the moment, since SwapBuffers
867 * is done by the X server */
868 if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
869 psc->swapControl = (__DRIswapControlExtension *) extensions[i];
870 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
871 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
872 }
873
874 if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) {
875 psc->msc = (__DRImediaStreamCounterExtension *) extensions[i];
876 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
877 }
878
879 if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
880 psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
881 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
882 }
883
884 if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
885 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
886 }
887 /* Ignore unknown extensions */
888 }
889 }
890
891 static const struct glx_screen_vtable dri_screen_vtable = {
892 .create_context = dri_create_context,
893 .create_context_attribs = NULL,
894 .query_renderer_integer = NULL,
895 .query_renderer_string = NULL,
896 };
897
898 static struct glx_screen *
899 driCreateScreen(int screen, struct glx_display *priv)
900 {
901 struct dri_display *pdp;
902 __GLXDRIscreen *psp;
903 const __DRIextension **extensions;
904 struct dri_screen *psc;
905 char *driverName;
906 int i;
907
908 psc = calloc(1, sizeof *psc);
909 if (psc == NULL)
910 return NULL;
911
912 if (!glx_screen_init(&psc->base, screen, priv)) {
913 free(psc);
914 return NULL;
915 }
916
917 if (!driGetDriverName(priv->dpy, screen, &driverName)) {
918 goto cleanup;
919 }
920
921 psc->driver = driOpenDriver(driverName);
922 if (psc->driver == NULL)
923 goto cleanup;
924
925 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
926 if (extensions == NULL) {
927 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
928 goto cleanup;
929 }
930
931 for (i = 0; extensions[i]; i++) {
932 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
933 psc->core = (__DRIcoreExtension *) extensions[i];
934 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
935 psc->legacy = (__DRIlegacyExtension *) extensions[i];
936 }
937
938 if (psc->core == NULL || psc->legacy == NULL)
939 goto cleanup;
940
941 pdp = (struct dri_display *) priv->driDisplay;
942 psc->driScreen =
943 CallCreateNewScreen(psc->base.dpy, screen, psc, pdp);
944 if (psc->driScreen == NULL)
945 goto cleanup;
946
947 extensions = psc->core->getExtensions(psc->driScreen);
948 driBindExtensions(psc, extensions);
949
950 psc->base.vtable = &dri_screen_vtable;
951 psp = &psc->vtable;
952 psc->base.driScreen = psp;
953 if (psc->driCopySubBuffer)
954 psp->copySubBuffer = driCopySubBuffer;
955
956 psp->destroyScreen = driDestroyScreen;
957 psp->createDrawable = driCreateDrawable;
958 psp->swapBuffers = driSwapBuffers;
959
960 psp->setSwapInterval = driSetSwapInterval;
961 psp->getSwapInterval = driGetSwapInterval;
962
963 free(driverName);
964
965 return &psc->base;
966
967 cleanup:
968 CriticalErrorMessageF("failed to load driver: %s\n", driverName);
969
970 free(driverName);
971
972 if (psc->driver)
973 dlclose(psc->driver);
974 glx_screen_cleanup(&psc->base);
975 free(psc);
976
977 return NULL;
978 }
979
980 /* Called from __glXFreeDisplayPrivate.
981 */
982 static void
983 driDestroyDisplay(__GLXDRIdisplay * dpy)
984 {
985 free(dpy);
986 }
987
988 /*
989 * Allocate, initialize and return a __DRIdisplayPrivate object.
990 * This is called from __glXInitialize() when we are given a new
991 * display pointer.
992 */
993 _X_HIDDEN __GLXDRIdisplay *
994 driCreateDisplay(Display * dpy)
995 {
996 struct dri_display *pdpyp;
997 int eventBase, errorBase;
998 int major, minor, patch;
999
1000 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
1001 return NULL;
1002 }
1003
1004 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
1005 return NULL;
1006 }
1007
1008 pdpyp = malloc(sizeof *pdpyp);
1009 if (!pdpyp) {
1010 return NULL;
1011 }
1012
1013 pdpyp->driMajor = major;
1014 pdpyp->driMinor = minor;
1015 pdpyp->driPatch = patch;
1016
1017 pdpyp->base.destroyDisplay = driDestroyDisplay;
1018 pdpyp->base.createScreen = driCreateScreen;
1019
1020 return &pdpyp->base;
1021 }
1022
1023 #endif /* GLX_DIRECT_RENDERING */