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