Added few more stubs so that control reaches to DestroyDevice().
[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 &damageExtension.base,
385 NULL
386 };
387
388 /**
389 * Perform the required libGL-side initialization and call the client-side
390 * driver's \c __driCreateNewScreen function.
391 *
392 * \param dpy Display pointer.
393 * \param scrn Screen number on the display.
394 * \param psc DRI screen information.
395 * \param driDpy DRI display information.
396 * \param createNewScreen Pointer to the client-side driver's
397 * \c __driCreateNewScreen function.
398 * \returns A pointer to the \c __DRIscreen structure returned by
399 * the client-side driver on success, or \c NULL on failure.
400 */
401 static void *
402 CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
403 struct dri_display * driDpy)
404 {
405 void *psp = NULL;
406 drm_handle_t hSAREA;
407 drmAddress pSAREA = MAP_FAILED;
408 char *BusID;
409 __DRIversion ddx_version;
410 __DRIversion dri_version;
411 __DRIversion drm_version;
412 __DRIframebuffer framebuffer;
413 int fd = -1;
414 int status;
415
416 drm_magic_t magic;
417 drmVersionPtr version;
418 int newlyopened;
419 char *driverName;
420 drm_handle_t hFB;
421 int junk;
422 const __DRIconfig **driver_configs;
423 struct glx_config *visual, *configs = NULL, *visuals = NULL;
424
425 /* DRI protocol version. */
426 dri_version.major = driDpy->driMajor;
427 dri_version.minor = driDpy->driMinor;
428 dri_version.patch = driDpy->driPatch;
429
430 framebuffer.base = MAP_FAILED;
431 framebuffer.dev_priv = NULL;
432 framebuffer.size = 0;
433
434 if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
435 ErrorMessageF("XF86DRIOpenConnection failed\n");
436 goto handle_error;
437 }
438
439 fd = drmOpenOnce(NULL, BusID, &newlyopened);
440
441 free(BusID); /* No longer needed */
442
443 if (fd < 0) {
444 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
445 goto handle_error;
446 }
447
448 if (drmGetMagic(fd, &magic)) {
449 ErrorMessageF("drmGetMagic failed\n");
450 goto handle_error;
451 }
452
453 version = drmGetVersion(fd);
454 if (version) {
455 drm_version.major = version->version_major;
456 drm_version.minor = version->version_minor;
457 drm_version.patch = version->version_patchlevel;
458 drmFreeVersion(version);
459 }
460 else {
461 drm_version.major = -1;
462 drm_version.minor = -1;
463 drm_version.patch = -1;
464 }
465
466 if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
467 ErrorMessageF("XF86DRIAuthConnection failed\n");
468 goto handle_error;
469 }
470
471 /* Get device name (like "radeon") and the ddx version numbers.
472 * We'll check the version in each DRI driver's "createNewScreen"
473 * function. */
474 if (!XF86DRIGetClientDriverName(dpy, scrn,
475 &ddx_version.major,
476 &ddx_version.minor,
477 &ddx_version.patch, &driverName)) {
478 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
479 goto handle_error;
480 }
481
482 free(driverName); /* No longer needed. */
483
484 /*
485 * Get device-specific info. pDevPriv will point to a struct
486 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
487 * has information about the screen size, depth, pitch, ancilliary
488 * buffers, DRM mmap handles, etc.
489 */
490 if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
491 &framebuffer.size, &framebuffer.stride,
492 &framebuffer.dev_priv_size,
493 &framebuffer.dev_priv)) {
494 ErrorMessageF("XF86DRIGetDeviceInfo failed\n");
495 goto handle_error;
496 }
497
498 framebuffer.width = DisplayWidth(dpy, scrn);
499 framebuffer.height = DisplayHeight(dpy, scrn);
500
501 /* Map the framebuffer region. */
502 status = drmMap(fd, hFB, framebuffer.size,
503 (drmAddressPtr) & framebuffer.base);
504 if (status != 0) {
505 ErrorMessageF("drmMap of framebuffer failed (%s)\n", strerror(-status));
506 goto handle_error;
507 }
508
509 /* Map the SAREA region. Further mmap regions may be setup in
510 * each DRI driver's "createNewScreen" function.
511 */
512 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
513 if (status != 0) {
514 ErrorMessageF("drmMap of SAREA failed (%s)\n", strerror(-status));
515 goto handle_error;
516 }
517
518 psp = (*psc->legacy->createNewScreen) (scrn,
519 &ddx_version,
520 &dri_version,
521 &drm_version,
522 &framebuffer,
523 pSAREA,
524 fd,
525 loader_extensions,
526 &driver_configs, psc);
527
528 if (psp == NULL) {
529 ErrorMessageF("Calling driver entry point failed\n");
530 goto handle_error;
531 }
532
533 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
534 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
535
536 if (!configs || !visuals) {
537 ErrorMessageF("No matching fbConfigs or visuals found\n");
538 goto handle_error;
539 }
540
541 glx_config_destroy_list(psc->base.configs);
542 psc->base.configs = configs;
543 glx_config_destroy_list(psc->base.visuals);
544 psc->base.visuals = visuals;
545
546 psc->driver_configs = driver_configs;
547
548 /* Visuals with depth != screen depth are subject to automatic compositing
549 * in the X server, so DRI1 can't render to them properly. Mark them as
550 * non-conformant to prevent apps from picking them up accidentally.
551 */
552 for (visual = psc->base.visuals; visual; visual = visual->next) {
553 XVisualInfo templ;
554 XVisualInfo *visuals;
555 int num_visuals;
556 long mask;
557
558 templ.visualid = visual->visualID;
559 mask = VisualIDMask;
560 visuals = XGetVisualInfo(dpy, mask, &templ, &num_visuals);
561
562 if (visuals) {
563 if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
564 visual->visualRating = GLX_NON_CONFORMANT_CONFIG;
565
566 free(visuals);
567 }
568 }
569
570 return psp;
571
572 handle_error:
573 if (configs)
574 glx_config_destroy_list(configs);
575 if (visuals)
576 glx_config_destroy_list(visuals);
577
578 if (pSAREA != MAP_FAILED)
579 drmUnmap(pSAREA, SAREA_MAX);
580
581 if (framebuffer.base != MAP_FAILED)
582 drmUnmap((drmAddress) framebuffer.base, framebuffer.size);
583
584 free(framebuffer.dev_priv);
585
586 if (fd >= 0)
587 drmCloseOnce(fd);
588
589 XF86DRICloseConnection(dpy, scrn);
590
591 ErrorMessageF("reverting to software direct rendering\n");
592
593 return NULL;
594 }
595
596 static void
597 dri_destroy_context(struct glx_context * context)
598 {
599 struct dri_context *pcp = (struct dri_context *) context;
600 struct dri_screen *psc = (struct dri_screen *) context->psc;
601
602 driReleaseDrawables(&pcp->base);
603
604 free((char *) context->extensions);
605
606 (*psc->core->destroyContext) (pcp->driContext);
607
608 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
609 free(pcp);
610 }
611
612 static int
613 dri_bind_context(struct glx_context *context, struct glx_context *old,
614 GLXDrawable draw, GLXDrawable read)
615 {
616 struct dri_context *pcp = (struct dri_context *) context;
617 struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
618 struct dri_drawable *pdraw, *pread;
619
620 pdraw = (struct dri_drawable *) driFetchDrawable(context, draw);
621 pread = (struct dri_drawable *) driFetchDrawable(context, read);
622
623 driReleaseDrawables(&pcp->base);
624
625 if (pdraw == NULL || pread == NULL)
626 return GLXBadDrawable;
627
628 if ((*psc->core->bindContext) (pcp->driContext,
629 pdraw->driDrawable, pread->driDrawable))
630 return Success;
631
632 return GLXBadContext;
633 }
634
635 static void
636 dri_unbind_context(struct glx_context *context, struct glx_context *new)
637 {
638 struct dri_context *pcp = (struct dri_context *) context;
639 struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
640
641 (*psc->core->unbindContext) (pcp->driContext);
642 }
643
644 static const struct glx_context_vtable dri_context_vtable = {
645 .destroy = dri_destroy_context,
646 .bind = dri_bind_context,
647 .unbind = dri_unbind_context,
648 .wait_gl = NULL,
649 .wait_x = NULL,
650 .use_x_font = DRI_glXUseXFont,
651 .bind_tex_image = NULL,
652 .release_tex_image = NULL,
653 .get_proc_address = NULL,
654 };
655
656 static struct glx_context *
657 dri_create_context(struct glx_screen *base,
658 struct glx_config *config_base,
659 struct glx_context *shareList, int renderType)
660 {
661 struct dri_context *pcp, *pcp_shared;
662 struct dri_screen *psc = (struct dri_screen *) base;
663 drm_context_t hwContext;
664 __DRIcontext *shared = NULL;
665 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
666
667 if (!psc->base.driScreen)
668 return NULL;
669
670 /* Check the renderType value */
671 if (!validate_renderType_against_config(config_base, renderType))
672 return NULL;
673
674 if (shareList) {
675 /* If the shareList context is not a DRI context, we cannot possibly
676 * create a DRI context that shares it.
677 */
678 if (shareList->vtable->destroy != dri_destroy_context) {
679 return NULL;
680 }
681
682 pcp_shared = (struct dri_context *) shareList;
683 shared = pcp_shared->driContext;
684 }
685
686 pcp = calloc(1, sizeof *pcp);
687 if (pcp == NULL)
688 return NULL;
689
690 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
691 free(pcp);
692 return NULL;
693 }
694
695 pcp->base.renderType = renderType;
696
697 if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr,
698 config->base.visualID,
699 &pcp->hwContextID, &hwContext)) {
700 free(pcp);
701 return NULL;
702 }
703
704 pcp->driContext =
705 (*psc->legacy->createNewContext) (psc->driScreen,
706 config->driConfig,
707 renderType, shared, hwContext, pcp);
708 if (pcp->driContext == NULL) {
709 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
710 free(pcp);
711 return NULL;
712 }
713
714 pcp->base.vtable = &dri_context_vtable;
715
716 return &pcp->base;
717 }
718
719 static void
720 driDestroyDrawable(__GLXDRIdrawable * pdraw)
721 {
722 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
723 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
724
725 (*psc->core->destroyDrawable) (pdp->driDrawable);
726 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable);
727 free(pdraw);
728 }
729
730 static __GLXDRIdrawable *
731 driCreateDrawable(struct glx_screen *base,
732 XID xDrawable,
733 GLXDrawable drawable, struct glx_config *config_base)
734 {
735 drm_drawable_t hwDrawable;
736 void *empty_attribute_list = NULL;
737 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
738 struct dri_screen *psc = (struct dri_screen *) base;
739 struct dri_drawable *pdp;
740
741 /* Old dri can't handle GLX 1.3+ drawable constructors. */
742 if (xDrawable != drawable)
743 return NULL;
744
745 pdp = calloc(1, sizeof *pdp);
746 if (!pdp)
747 return NULL;
748
749 pdp->base.drawable = drawable;
750 pdp->base.psc = &psc->base;
751
752 if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr,
753 drawable, &hwDrawable)) {
754 free(pdp);
755 return NULL;
756 }
757
758 /* Create a new drawable */
759 pdp->driDrawable =
760 (*psc->legacy->createNewDrawable) (psc->driScreen,
761 config->driConfig,
762 hwDrawable,
763 GLX_WINDOW_BIT,
764 empty_attribute_list, pdp);
765
766 if (!pdp->driDrawable) {
767 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable);
768 free(pdp);
769 return NULL;
770 }
771
772 pdp->base.destroyDrawable = driDestroyDrawable;
773
774 return &pdp->base;
775 }
776
777 static int64_t
778 driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
779 int64_t unused3, Bool flush)
780 {
781 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
782 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
783
784 if (flush) {
785 glFlush();
786 }
787
788 (*psc->core->swapBuffers) (pdp->driDrawable);
789 return 0;
790 }
791
792 static void
793 driCopySubBuffer(__GLXDRIdrawable * pdraw,
794 int x, int y, int width, int height, Bool flush)
795 {
796 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
797 struct dri_screen *psc = (struct dri_screen *) pdp->base.psc;
798
799 if (flush) {
800 glFlush();
801 }
802
803 (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable,
804 x, y, width, height);
805 }
806
807 static void
808 driDestroyScreen(struct glx_screen *base)
809 {
810 struct dri_screen *psc = (struct dri_screen *) base;
811
812 /* Free the direct rendering per screen data */
813 if (psc->driScreen)
814 (*psc->core->destroyScreen) (psc->driScreen);
815 driDestroyConfigs(psc->driver_configs);
816 psc->driScreen = NULL;
817 if (psc->driver)
818 dlclose(psc->driver);
819 }
820
821 static int
822 driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
823 {
824 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
825
826 if (pdraw != NULL) {
827 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
828
829 if (psc->swapControl != NULL) {
830 psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
831 return 0;
832 }
833 }
834 return GLX_BAD_CONTEXT;
835 }
836
837 static int
838 driGetSwapInterval(__GLXDRIdrawable *pdraw)
839 {
840 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
841
842 if (pdraw != NULL) {
843 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
844
845 if (psc->swapControl != NULL)
846 return psc->swapControl->getSwapInterval(pdp->driDrawable);
847 }
848 return 0;
849 }
850
851 /* Bind DRI1 specific extensions */
852 static void
853 driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions)
854 {
855 int i;
856
857 for (i = 0; extensions[i]; i++) {
858 /* No DRI2 support for swap_control at the moment, since SwapBuffers
859 * is done by the X server */
860 if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
861 psc->swapControl = (__DRIswapControlExtension *) extensions[i];
862 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
863 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
864 }
865
866 if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) {
867 psc->msc = (__DRImediaStreamCounterExtension *) extensions[i];
868 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
869 }
870
871 if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
872 psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
873 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
874 }
875
876 if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
877 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
878 }
879 /* Ignore unknown extensions */
880 }
881 }
882
883 static const struct glx_screen_vtable dri_screen_vtable = {
884 .create_context = dri_create_context,
885 .create_context_attribs = NULL,
886 .query_renderer_integer = NULL,
887 .query_renderer_string = NULL,
888 };
889
890 static struct glx_screen *
891 driCreateScreen(int screen, struct glx_display *priv)
892 {
893 struct dri_display *pdp;
894 __GLXDRIscreen *psp;
895 const __DRIextension **extensions;
896 struct dri_screen *psc;
897 char *driverName;
898 int i;
899
900 psc = calloc(1, sizeof *psc);
901 if (psc == NULL)
902 return NULL;
903
904 if (!glx_screen_init(&psc->base, screen, priv)) {
905 free(psc);
906 return NULL;
907 }
908
909 if (!driGetDriverName(priv->dpy, screen, &driverName)) {
910 goto cleanup;
911 }
912
913 extensions = driOpenDriver(driverName, &psc->driver);
914 if (extensions == NULL) {
915 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
916 goto cleanup;
917 }
918
919 for (i = 0; extensions[i]; i++) {
920 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
921 psc->core = (__DRIcoreExtension *) extensions[i];
922 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
923 psc->legacy = (__DRIlegacyExtension *) extensions[i];
924 }
925
926 if (psc->core == NULL || psc->legacy == NULL)
927 goto cleanup;
928
929 pdp = (struct dri_display *) priv->driDisplay;
930 psc->driScreen =
931 CallCreateNewScreen(psc->base.dpy, screen, psc, pdp);
932 if (psc->driScreen == NULL)
933 goto cleanup;
934
935 extensions = psc->core->getExtensions(psc->driScreen);
936 driBindExtensions(psc, extensions);
937
938 psc->base.vtable = &dri_screen_vtable;
939 psp = &psc->vtable;
940 psc->base.driScreen = psp;
941 if (psc->driCopySubBuffer)
942 psp->copySubBuffer = driCopySubBuffer;
943
944 psp->destroyScreen = driDestroyScreen;
945 psp->createDrawable = driCreateDrawable;
946 psp->swapBuffers = driSwapBuffers;
947
948 psp->setSwapInterval = driSetSwapInterval;
949 psp->getSwapInterval = driGetSwapInterval;
950
951 free(driverName);
952
953 return &psc->base;
954
955 cleanup:
956 CriticalErrorMessageF("failed to load driver: %s\n", driverName);
957
958 free(driverName);
959
960 if (psc->driver)
961 dlclose(psc->driver);
962 glx_screen_cleanup(&psc->base);
963 free(psc);
964
965 return NULL;
966 }
967
968 /* Called from __glXFreeDisplayPrivate.
969 */
970 static void
971 driDestroyDisplay(__GLXDRIdisplay * dpy)
972 {
973 free(dpy);
974 }
975
976 /*
977 * Allocate, initialize and return a __DRIdisplayPrivate object.
978 * This is called from __glXInitialize() when we are given a new
979 * display pointer.
980 */
981 _X_HIDDEN __GLXDRIdisplay *
982 driCreateDisplay(Display * dpy)
983 {
984 struct dri_display *pdpyp;
985 int eventBase, errorBase;
986 int major, minor, patch;
987
988 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
989 return NULL;
990 }
991
992 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
993 return NULL;
994 }
995
996 pdpyp = malloc(sizeof *pdpyp);
997 if (!pdpyp) {
998 return NULL;
999 }
1000
1001 pdpyp->driMajor = major;
1002 pdpyp->driMinor = minor;
1003 pdpyp->driPatch = patch;
1004
1005 pdpyp->base.destroyDisplay = driDestroyDisplay;
1006 pdpyp->base.createScreen = driCreateScreen;
1007
1008 return &pdpyp->base;
1009 }
1010
1011 #endif /* GLX_DIRECT_RENDERING */