9ff71588dff3329cb644596092ded6fb565e238b
[mesa.git] / src / egl / drivers / xdri / egl_xdri.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, 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 TUNGSTEN GRAPHICS 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 /**
30 * Code to interface a DRI driver to libEGL.
31 * Note that unlike previous DRI/EGL interfaces, this one is meant to
32 * be used _with_ X. Applications will use eglCreateWindowSurface()
33 * to render into X-created windows.
34 *
35 * This is an EGL driver that, in turn, loads a regular DRI driver.
36 * There are some dependencies on code in libGL, but those could be
37 * removed with some effort.
38 *
39 * Authors: Brian Paul
40 */
41
42
43 #include <assert.h>
44 #include <stdio.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #include "dlfcn.h"
49 #include <X11/Xlib.h>
50 #include <GL/gl.h>
51 #include "xf86dri.h"
52 #include "glxclient.h"
53 #include "dri_util.h"
54 #include "drm_sarea.h"
55
56 #define _EGL_PLATFORM_X
57
58 #include "eglconfig.h"
59 #include "eglcontext.h"
60 #include "egldisplay.h"
61 #include "egldriver.h"
62 #include "eglglobals.h"
63 #include "eglhash.h"
64 #include "egllog.h"
65 #include "eglsurface.h"
66
67 #include <GL/gl.h>
68
69 typedef void (*glGetIntegerv_t)(GLenum, GLint *);
70 typedef void (*glBindTexture_t)(GLenum, GLuint);
71 typedef void (*glCopyTexImage2D_t)(GLenum, GLint, GLenum, GLint, GLint,
72 GLint, GLint, GLint);
73
74
75 #define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
76
77
78 /** subclass of _EGLDriver */
79 struct xdri_egl_driver
80 {
81 _EGLDriver Base; /**< base class */
82
83 const char *dri_driver_name; /**< name of DRI driver to load */
84 void *dri_driver_handle; /**< returned by dlopen(dri_driver_name) */
85
86 __GLXdisplayPrivate *glx_priv;
87
88
89 /* XXX we're not actually using these at this time: */
90 int chipset;
91 int minor;
92 int drmFD;
93
94 __DRIframebuffer framebuffer;
95 drm_handle_t hSAREA;
96 drmAddress pSAREA;
97 char *busID;
98 drm_magic_t magic;
99 };
100
101
102 /** subclass of _EGLContext */
103 struct xdri_egl_context
104 {
105 _EGLContext Base; /**< base class */
106
107 __DRIcontext driContext;
108
109 GLint bound_tex_object;
110 };
111
112
113 /** subclass of _EGLSurface */
114 struct xdri_egl_surface
115 {
116 _EGLSurface Base; /**< base class */
117
118 __DRIid driDrawable; /**< DRI surface */
119 drm_drawable_t hDrawable;
120 };
121
122
123 /** subclass of _EGLConfig */
124 struct xdri_egl_config
125 {
126 _EGLConfig Base; /**< base class */
127
128 const __GLcontextModes *mode; /**< corresponding GLX mode */
129 };
130
131
132
133 /** cast wrapper */
134 static struct xdri_egl_driver *
135 xdri_egl_driver(_EGLDriver *drv)
136 {
137 return (struct xdri_egl_driver *) drv;
138 }
139
140
141 /** Map EGLSurface handle to xdri_egl_surface object */
142 static struct xdri_egl_surface *
143 lookup_surface(EGLSurface surf)
144 {
145 _EGLSurface *surface = _eglLookupSurface(surf);
146 return (struct xdri_egl_surface *) surface;
147 }
148
149
150 /** Map EGLContext handle to xdri_egl_context object */
151 static struct xdri_egl_context *
152 lookup_context(EGLContext c)
153 {
154 _EGLContext *context = _eglLookupContext(c);
155 return (struct xdri_egl_context *) context;
156 }
157
158 static struct xdri_egl_context *
159 current_context(void)
160 {
161 return (struct xdri_egl_context *) _eglGetCurrentContext();
162 }
163
164 /** Map EGLConfig handle to xdri_egl_config object */
165 static struct xdri_egl_config *
166 lookup_config(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config)
167 {
168 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
169 return (struct xdri_egl_config *) conf;
170 }
171
172
173
174 /** Get size of given window */
175 static Status
176 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
177 {
178 Window root;
179 Status stat;
180 int xpos, ypos;
181 unsigned int w, h, bw, depth;
182 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
183 *width = w;
184 *height = h;
185 return stat;
186 }
187
188
189 /**
190 * Produce a set of EGL configs.
191 * Note that we get the list of GLcontextModes from the GLX library.
192 * This dependency on GLX lib will be removed someday.
193 */
194 static void
195 create_configs(_EGLDisplay *disp, __GLXdisplayPrivate *glx_priv)
196 {
197 static const EGLint all_apis = (EGL_OPENGL_ES_BIT |
198 EGL_OPENGL_ES2_BIT |
199 EGL_OPENVG_BIT |
200 EGL_OPENGL_BIT);
201 __GLXscreenConfigs *scrn = glx_priv->screenConfigs;
202 const __GLcontextModes *m;
203 int id = 1;
204
205 for (m = scrn->configs; m; m = m->next) {
206 /* EGL requires double-buffered configs */
207 if (m->doubleBufferMode) {
208 struct xdri_egl_config *config = CALLOC_STRUCT(xdri_egl_config);
209
210 _eglInitConfig(&config->Base, id++);
211
212 SET_CONFIG_ATTRIB(&config->Base, EGL_BUFFER_SIZE, m->rgbBits);
213 SET_CONFIG_ATTRIB(&config->Base, EGL_RED_SIZE, m->redBits);
214 SET_CONFIG_ATTRIB(&config->Base, EGL_GREEN_SIZE, m->greenBits);
215 SET_CONFIG_ATTRIB(&config->Base, EGL_BLUE_SIZE, m->blueBits);
216 SET_CONFIG_ATTRIB(&config->Base, EGL_ALPHA_SIZE, m->alphaBits);
217 SET_CONFIG_ATTRIB(&config->Base, EGL_DEPTH_SIZE, m->depthBits);
218 SET_CONFIG_ATTRIB(&config->Base, EGL_STENCIL_SIZE, m->stencilBits);
219 SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLES, m->samples);
220 SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLE_BUFFERS, m->sampleBuffers);
221 SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_ID, m->visualID);
222 SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_TYPE, m->visualType);
223 SET_CONFIG_ATTRIB(&config->Base, EGL_CONFORMANT, all_apis);
224 SET_CONFIG_ATTRIB(&config->Base, EGL_RENDERABLE_TYPE, all_apis);
225 /* XXX only window rendering allowed ATM */
226 SET_CONFIG_ATTRIB(&config->Base, EGL_SURFACE_TYPE,
227 (EGL_WINDOW_BIT | EGL_PBUFFER_BIT));
228
229 /* XXX possibly other things to init... */
230
231 /* Ptr from EGL config to GLcontextMode. Used in CreateContext(). */
232 config->mode = m;
233
234 _eglAddConfig(disp, &config->Base);
235 }
236 }
237 }
238
239
240 /**
241 * Called via __DRIinterfaceMethods object
242 */
243 static __DRIfuncPtr
244 dri_get_proc_address(const char * proc_name)
245 {
246 return NULL;
247 }
248
249
250 static void
251 dri_context_modes_destroy(__GLcontextModes *modes)
252 {
253 _eglLog(_EGL_DEBUG, "%s", __FUNCTION__);
254
255 while (modes) {
256 __GLcontextModes * const next = modes->next;
257 free(modes);
258 modes = next;
259 }
260 }
261
262
263 /**
264 * Create a linked list of 'count' GLcontextModes.
265 * These are used during the client/server visual negotiation phase,
266 * then discarded.
267 */
268 static __GLcontextModes *
269 dri_context_modes_create(unsigned count, size_t minimum_size)
270 {
271 /* This code copied from libGLX, and modified */
272 const size_t size = (minimum_size > sizeof(__GLcontextModes))
273 ? minimum_size : sizeof(__GLcontextModes);
274 __GLcontextModes * head = NULL;
275 __GLcontextModes ** next;
276 unsigned i;
277
278 next = & head;
279 for (i = 0 ; i < count ; i++) {
280 *next = (__GLcontextModes *) calloc(1, size);
281 if (*next == NULL) {
282 dri_context_modes_destroy(head);
283 head = NULL;
284 break;
285 }
286
287 (*next)->doubleBufferMode = 1;
288 (*next)->visualID = GLX_DONT_CARE;
289 (*next)->visualType = GLX_DONT_CARE;
290 (*next)->visualRating = GLX_NONE;
291 (*next)->transparentPixel = GLX_NONE;
292 (*next)->transparentRed = GLX_DONT_CARE;
293 (*next)->transparentGreen = GLX_DONT_CARE;
294 (*next)->transparentBlue = GLX_DONT_CARE;
295 (*next)->transparentAlpha = GLX_DONT_CARE;
296 (*next)->transparentIndex = GLX_DONT_CARE;
297 (*next)->xRenderable = GLX_DONT_CARE;
298 (*next)->fbconfigID = GLX_DONT_CARE;
299 (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML;
300 (*next)->bindToTextureRgb = GLX_DONT_CARE;
301 (*next)->bindToTextureRgba = GLX_DONT_CARE;
302 (*next)->bindToMipmapTexture = GLX_DONT_CARE;
303 (*next)->bindToTextureTargets = 0;
304 (*next)->yInverted = GLX_DONT_CARE;
305
306 next = & ((*next)->next);
307 }
308
309 return head;
310 }
311
312
313 static __DRIscreen *
314 dri_find_dri_screen(__DRInativeDisplay *ndpy, int scrn)
315 {
316 __GLXdisplayPrivate *priv = __glXInitialize(ndpy);
317 __GLXscreenConfigs *scrnConf = priv->screenConfigs;
318 return &scrnConf->driScreen;
319 }
320
321
322 static GLboolean
323 dri_window_exists(__DRInativeDisplay *ndpy, __DRIid draw)
324 {
325 return EGL_TRUE;
326 }
327
328
329 static GLboolean
330 dri_create_context(__DRInativeDisplay *ndpy, int screenNum, int configID,
331 void * contextID, drm_context_t * hw_context)
332 {
333 assert(configID >= 0);
334 return XF86DRICreateContextWithConfig(ndpy, screenNum,
335 configID, contextID, hw_context);
336 }
337
338
339 static GLboolean
340 dri_destroy_context(__DRInativeDisplay * ndpy, int screen, __DRIid context)
341 {
342 return XF86DRIDestroyContext(ndpy, screen, context);
343 }
344
345
346 static GLboolean
347 dri_create_drawable(__DRInativeDisplay * ndpy, int screen,
348 __DRIid drawable, drm_drawable_t * hHWDrawable)
349 {
350 _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__);
351
352 /* Create DRI drawable for given window ID (drawable) */
353 if (!XF86DRICreateDrawable(ndpy, screen, drawable, hHWDrawable))
354 return EGL_FALSE;
355
356 return EGL_TRUE;
357 }
358
359
360 static GLboolean
361 dri_destroy_drawable(__DRInativeDisplay * ndpy, int screen, __DRIid drawable)
362 {
363 _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__);
364 return XF86DRIDestroyDrawable(ndpy, screen, drawable);
365 }
366
367
368 static GLboolean
369 dri_get_drawable_info(__DRInativeDisplay *ndpy, int scrn,
370 __DRIid draw, unsigned int * index, unsigned int * stamp,
371 int * x, int * y, int * width, int * height,
372 int * numClipRects, drm_clip_rect_t ** pClipRects,
373 int * backX, int * backY,
374 int * numBackClipRects,
375 drm_clip_rect_t ** pBackClipRects)
376 {
377 _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__);
378
379 if (!XF86DRIGetDrawableInfo(ndpy, scrn, draw, index, stamp,
380 x, y, width, height,
381 numClipRects, pClipRects,
382 backX, backY,
383 numBackClipRects, pBackClipRects)) {
384 return EGL_FALSE;
385 }
386
387 return EGL_TRUE;
388 }
389
390
391 /**
392 * Table of functions exported by the loader to the driver.
393 */
394 static const __DRIinterfaceMethods interface_methods = {
395 dri_get_proc_address,
396
397 dri_context_modes_create,
398 dri_context_modes_destroy,
399
400 dri_find_dri_screen,
401 dri_window_exists,
402
403 dri_create_context,
404 dri_destroy_context,
405
406 dri_create_drawable,
407 dri_destroy_drawable,
408 dri_get_drawable_info,
409
410 NULL,/*__eglGetUST,*/
411 NULL,/*__eglGetMSCRate,*/
412 };
413
414
415
416 static EGLBoolean
417 init_drm(struct xdri_egl_driver *xdri_drv, _EGLDisplay *disp)
418 {
419 __DRIversion ddx_version;
420 __DRIversion dri_version;
421 __DRIversion drm_version;
422 drmVersionPtr version;
423 drm_handle_t hFB;
424 int newlyopened;
425 int status;
426 int scrn = DefaultScreen(disp->Xdpy);
427
428 #if 0
429 createNewScreen = (PFNCREATENEWSCREENFUNC)
430 dlsym(xdri_drv->dri_driver_handle, createNewScreenName);
431 if (!createNewScreen) {
432 _eglLog(_EGL_WARNING, "XDRI: Couldn't find %s function in the driver.",
433 createNewScreenName);
434 return EGL_FALSE;
435 }
436 else {
437 _eglLog(_EGL_DEBUG, "XDRI: Found %s", createNewScreenName);
438 }
439 #endif
440
441 /*
442 * Get the DRI X extension version.
443 */
444 dri_version.major = 4;
445 dri_version.minor = 0;
446 dri_version.patch = 0;
447
448 if (!XF86DRIOpenConnection(disp->Xdpy, scrn,
449 &xdri_drv->hSAREA, &xdri_drv->busID)) {
450 _eglLog(_EGL_WARNING, "XF86DRIOpenConnection failed");
451 }
452
453 xdri_drv->drmFD = drmOpenOnce(NULL, xdri_drv->busID, &newlyopened);
454 if (xdri_drv->drmFD < 0) {
455 perror("drmOpenOnce failed: ");
456 return EGL_FALSE;
457 }
458 else {
459 _eglLog(_EGL_DEBUG, "XDRI: drmOpenOnce returned %d", xdri_drv->drmFD);
460 }
461
462
463 if (drmGetMagic(xdri_drv->drmFD, &xdri_drv->magic)) {
464 perror("drmGetMagic failed: ");
465 return EGL_FALSE;
466 }
467
468 version = drmGetVersion(xdri_drv->drmFD);
469 if (version) {
470 drm_version.major = version->version_major;
471 drm_version.minor = version->version_minor;
472 drm_version.patch = version->version_patchlevel;
473 drmFreeVersion(version);
474 _eglLog(_EGL_DEBUG, "XDRI: Got DRM version %d.%d.%d",
475 drm_version.major,
476 drm_version.minor,
477 drm_version.patch);
478 }
479 else {
480 drm_version.major = -1;
481 drm_version.minor = -1;
482 drm_version.patch = -1;
483 _eglLog(_EGL_WARNING, "XDRI: drmGetVersion() failed");
484 return EGL_FALSE;
485 }
486
487 /* Authenticate w/ server.
488 */
489 if (!XF86DRIAuthConnection(disp->Xdpy, scrn, xdri_drv->magic)) {
490 _eglLog(_EGL_WARNING, "XDRI: XF86DRIAuthConnection() failed");
491 return EGL_FALSE;
492 }
493 else {
494 _eglLog(_EGL_DEBUG, "XDRI: XF86DRIAuthConnection() success");
495 }
496
497 /* Get ddx version.
498 */
499 {
500 char *driverName;
501
502 /*
503 * Get device name (like "tdfx") and the ddx version
504 * numbers. We'll check the version in each DRI driver's
505 * "createNewScreen" function.
506 */
507 if (!XF86DRIGetClientDriverName(disp->Xdpy, scrn,
508 &ddx_version.major,
509 &ddx_version.minor,
510 &ddx_version.patch,
511 &driverName)) {
512 _eglLog(_EGL_WARNING, "XDRI: XF86DRIGetClientDriverName failed");
513 return EGL_FALSE;
514 }
515 else {
516 _eglLog(_EGL_DEBUG, "XDRI: XF86DRIGetClientDriverName returned %s", driverName);
517 }
518 }
519
520 /* Get framebuffer info.
521 */
522 {
523 int junk;
524 if (!XF86DRIGetDeviceInfo(disp->Xdpy, scrn,
525 &hFB,
526 &junk,
527 &xdri_drv->framebuffer.size,
528 &xdri_drv->framebuffer.stride,
529 &xdri_drv->framebuffer.dev_priv_size,
530 &xdri_drv->framebuffer.dev_priv)) {
531 _eglLog(_EGL_WARNING, "XDRI: XF86DRIGetDeviceInfo() failed");
532 return EGL_FALSE;
533 }
534 else {
535 _eglLog(_EGL_DEBUG, "XDRI: XF86DRIGetDeviceInfo() success");
536 }
537 xdri_drv->framebuffer.width = DisplayWidth(disp->Xdpy, scrn);
538 xdri_drv->framebuffer.height = DisplayHeight(disp->Xdpy, scrn);
539 }
540
541 /* Map the framebuffer region. (this may not be needed)
542 */
543 status = drmMap(xdri_drv->drmFD, hFB, xdri_drv->framebuffer.size,
544 (drmAddressPtr) &xdri_drv->framebuffer.base);
545 if (status != 0) {
546 _eglLog(_EGL_WARNING, "XDRI: drmMap(framebuffer) failed");
547 return EGL_FALSE;
548 }
549 else {
550 _eglLog(_EGL_DEBUG, "XDRI: drmMap(framebuffer) success");
551 }
552
553 /* Map the SAREA region.
554 */
555 status = drmMap(xdri_drv->drmFD, xdri_drv->hSAREA, SAREA_MAX, &xdri_drv->pSAREA);
556 if (status != 0) {
557 _eglLog(_EGL_WARNING, "XDRI: drmMap(sarea) failed");
558 return EGL_FALSE;
559 }
560 else {
561 _eglLog(_EGL_DEBUG, "XDRI: drmMap(sarea) success");
562 }
563
564 return EGL_TRUE;
565 }
566
567
568 /**
569 * Load the DRI driver named by "xdri_drv->dri_driver_name".
570 * Basically, dlopen() the library to set "xdri_drv->dri_driver_handle".
571 *
572 * Later, we'll call dlsym(createNewScreenName) to get a pointer to
573 * the driver's createNewScreen() function which is the bootstrap function.
574 *
575 * \return EGL_TRUE for success, EGL_FALSE for failure
576 */
577 static EGLBoolean
578 load_dri_driver(struct xdri_egl_driver *xdri_drv)
579 {
580 char filename[100];
581 int flags = RTLD_NOW;
582
583 /* try "egl_xxx_dri.so" first */
584 snprintf(filename, sizeof(filename), "egl_%s.so", xdri_drv->dri_driver_name);
585 _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s)", filename);
586 xdri_drv->dri_driver_handle = dlopen(filename, flags);
587 if (xdri_drv->dri_driver_handle) {
588 _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s) OK", filename);
589 return EGL_TRUE;
590 }
591 else {
592 _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s) fail (%s)", filename, dlerror());
593 }
594
595 /* try regular "xxx_dri.so" next */
596 snprintf(filename, sizeof(filename), "%s.so", xdri_drv->dri_driver_name);
597 _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s)", filename);
598 xdri_drv->dri_driver_handle = dlopen(filename, flags);
599 if (xdri_drv->dri_driver_handle) {
600 _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s) OK", filename);
601 return EGL_TRUE;
602 }
603
604 _eglLog(_EGL_WARNING, "XDRI Could not open %s (%s)", filename, dlerror());
605 return EGL_FALSE;
606 }
607
608
609 /**
610 * Called via eglInitialize(), xdri_drv->API.Initialize().
611 */
612 static EGLBoolean
613 xdri_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
614 EGLint *minor, EGLint *major)
615 {
616 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
617 _EGLDisplay *disp = _eglLookupDisplay(dpy);
618 static char name[100];
619
620 _eglLog(_EGL_DEBUG, "XDRI: eglInitialize");
621
622 if (!disp->Xdpy) {
623 disp->Xdpy = XOpenDisplay(NULL);
624 if (!disp->Xdpy) {
625 _eglLog(_EGL_WARNING, "XDRI: XOpenDisplay failed");
626 return EGL_FALSE;
627 }
628 }
629
630 #if 0
631 /* choose the DRI driver to load */
632 xdri_drv->dri_driver_name = _eglChooseDRMDriver(0);
633 if (!load_dri_driver(xdri_drv))
634 return EGL_FALSE;
635 #else
636 (void) load_dri_driver;
637 #endif
638
639 #if 0
640 if (!init_drm(xdri_drv, disp))
641 return EGL_FALSE;
642 #else
643 (void) init_drm;
644 #endif
645
646 /*
647 * NOTE: this call to __glXInitialize() bootstraps the whole GLX/DRI
648 * interface, loads the DRI driver, etc.
649 * This replaces the load_dri_driver() and init_drm() code above.
650 */
651 xdri_drv->glx_priv = __glXInitialize(disp->Xdpy);
652
653 create_configs(disp, xdri_drv->glx_priv);
654
655 xdri_drv->Base.Initialized = EGL_TRUE;
656
657 snprintf(name, sizeof(name), "X/DRI:%s", xdri_drv->dri_driver_name);
658 xdri_drv->Base.Name = name;
659
660 /* we're supporting EGL 1.4 */
661 *minor = 1;
662 *major = 4;
663
664 return EGL_TRUE;
665 }
666
667
668 /*
669 * Do some clean-up that normally occurs in XCloseDisplay().
670 * We do this here because we're about to unload a dynamic library
671 * that has added some per-display extension data and callbacks.
672 * If we don't do this here we'll crash in XCloseDisplay() because it'll
673 * try to call functions that went away when the driver library was unloaded.
674 */
675 static void
676 FreeDisplayExt(Display *dpy)
677 {
678 _XExtension *ext, *next;
679
680 for (ext = dpy->ext_procs; ext; ext = next) {
681 next = ext->next;
682 if (ext->close_display) {
683 ext->close_display(dpy, &ext->codes);
684 ext->close_display = NULL;
685 }
686 if (ext->name)
687 Xfree(ext->name);
688 Xfree(ext);
689 }
690 dpy->ext_procs = NULL;
691
692 _XFreeExtData (dpy->ext_data);
693 dpy->ext_data = NULL;
694 }
695
696
697 /**
698 * Called via eglTerminate(), drv->API.Terminate().
699 */
700 static EGLBoolean
701 xdri_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
702 {
703 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
704 _EGLDisplay *disp = _eglLookupDisplay(dpy);
705
706 _eglLog(_EGL_DEBUG, "XDRI: eglTerminate");
707
708 _eglLog(_EGL_DEBUG, "XDRI: Closing %s", xdri_drv->dri_driver_name);
709
710 FreeDisplayExt(disp->Xdpy);
711
712 #if 0
713 /* this causes a segfault for some reason */
714 dlclose(xdri_drv->dri_driver_handle);
715 #endif
716 xdri_drv->dri_driver_handle = NULL;
717
718 free((void*) xdri_drv->dri_driver_name);
719
720 return EGL_TRUE;
721 }
722
723
724 /*
725 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
726 */
727 static _EGLProc
728 xdri_eglGetProcAddress(const char *procname)
729 {
730 #if 0
731 _EGLDriver *drv = NULL;
732
733 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
734 /*_EGLDisplay *disp = _eglLookupDisplay(dpy);*/
735 _EGLProc *proc = xdri_drv->driScreen.getProcAddress(procname);
736 return proc;
737 #elif 1
738 /* This is a bit of a hack to get at the gallium/Mesa state tracker
739 * function st_get_proc_address(). This will probably change at
740 * some point.
741 */
742 _EGLProc (*st_get_proc_addr)(const char *procname);
743 st_get_proc_addr = dlsym(NULL, "st_get_proc_address");
744 if (st_get_proc_addr) {
745 return st_get_proc_addr(procname);
746 }
747 return NULL;
748 #else
749 return NULL;
750 #endif
751 }
752
753
754 /**
755 * Called via eglCreateContext(), drv->API.CreateContext().
756 */
757 static EGLContext
758 xdri_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
759 EGLContext share_list, const EGLint *attrib_list)
760 {
761 _EGLDisplay *disp = _eglLookupDisplay(dpy);
762 struct xdri_egl_config *xdri_config = lookup_config(drv, dpy, config);
763 void *shared = NULL;
764 int renderType = GLX_RGBA_BIT;
765
766 struct xdri_egl_context *xdri_ctx = CALLOC_STRUCT(xdri_egl_context);
767 if (!xdri_ctx)
768 return EGL_NO_CONTEXT;
769
770 if (!_eglInitContext(drv, dpy, &xdri_ctx->Base, config, attrib_list)) {
771 free(xdri_ctx);
772 return EGL_NO_CONTEXT;
773 }
774
775 assert(xdri_config);
776
777 {
778 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
779 __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs;
780 xdri_ctx->driContext.private =
781 scrnConf->driScreen.createNewContext(disp->Xdpy,
782 xdri_config->mode, renderType,
783 shared, &xdri_ctx->driContext);
784 }
785
786 if (!xdri_ctx->driContext.private) {
787 _eglLog(_EGL_DEBUG, "driScreen.createNewContext failed");
788 free(xdri_ctx);
789 return EGL_NO_CONTEXT;
790 }
791
792 xdri_ctx->driContext.mode = xdri_config->mode;
793
794 return _eglGetContextHandle(&xdri_ctx->Base);
795 }
796
797
798 /**
799 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
800 */
801 static EGLBoolean
802 xdri_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
803 EGLSurface r, EGLContext context)
804 {
805 _EGLDisplay *disp = _eglLookupDisplay(dpy);
806 struct xdri_egl_context *xdri_ctx = lookup_context(context);
807 struct xdri_egl_surface *xdri_draw = lookup_surface(d);
808 struct xdri_egl_surface *xdri_read = lookup_surface(r);
809 __DRIid draw = xdri_draw ? xdri_draw->driDrawable : 0;
810 __DRIid read = xdri_read ? xdri_read->driDrawable : 0;
811 int scrn = DefaultScreen(disp->Xdpy);
812
813 if (!_eglMakeCurrent(drv, dpy, d, r, context))
814 return EGL_FALSE;
815
816
817 if (xdri_ctx &&
818 !xdri_ctx->driContext.bindContext(disp->Xdpy, scrn, draw, read,
819 &xdri_ctx->driContext)) {
820 return EGL_FALSE;
821 }
822
823 return EGL_TRUE;
824 }
825
826
827 /**
828 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
829 */
830 static EGLSurface
831 xdri_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
832 NativeWindowType window, const EGLint *attrib_list)
833 {
834 _EGLDisplay *disp = _eglLookupDisplay(dpy);
835 struct xdri_egl_surface *xdri_surf;
836 int scrn = DefaultScreen(disp->Xdpy);
837 uint width, height;
838
839 xdri_surf = CALLOC_STRUCT(xdri_egl_surface);
840 if (!xdri_surf)
841 return EGL_NO_SURFACE;
842
843 if (!_eglInitSurface(drv, dpy, &xdri_surf->Base, EGL_WINDOW_BIT,
844 config, attrib_list)) {
845 free(xdri_surf);
846 return EGL_FALSE;
847 }
848
849 if (!XF86DRICreateDrawable(disp->Xdpy, scrn, window, &xdri_surf->hDrawable)) {
850 free(xdri_surf);
851 return EGL_FALSE;
852 }
853
854 xdri_surf->driDrawable = window;
855
856 _eglSaveSurface(&xdri_surf->Base);
857
858 get_drawable_size(disp->Xdpy, window, &width, &height);
859 xdri_surf->Base.Width = width;
860 xdri_surf->Base.Height = height;
861
862 _eglLog(_EGL_DEBUG,
863 "XDRI: CreateWindowSurface win 0x%x handle %d hDrawable %d",
864 (int) window, _eglGetSurfaceHandle(&xdri_surf->Base),
865 (int) xdri_surf->hDrawable);
866
867 return _eglGetSurfaceHandle(&xdri_surf->Base);
868 }
869
870
871 /**
872 * Called via eglCreatePbufferSurface(), drv->API.CreatePbufferSurface().
873 */
874 static EGLSurface
875 xdri_eglCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
876 const EGLint *attrib_list)
877 {
878 _EGLDisplay *disp = _eglLookupDisplay(dpy);
879 struct xdri_egl_surface *xdri_surf;
880 struct xdri_egl_config *xdri_config = lookup_config(drv, dpy, config);
881 int scrn = DefaultScreen(disp->Xdpy);
882 Window window;
883
884 xdri_surf = CALLOC_STRUCT(xdri_egl_surface);
885 if (!xdri_surf)
886 return EGL_NO_SURFACE;
887
888 if (!_eglInitSurface(drv, dpy, &xdri_surf->Base, EGL_PBUFFER_BIT,
889 config, attrib_list)) {
890 free(xdri_surf);
891 return EGL_FALSE;
892 }
893
894 /* Create a dummy X window */
895 {
896 Window root = RootWindow(disp->Xdpy, scrn);
897 XSetWindowAttributes attr;
898 XVisualInfo *visInfo, visTemplate;
899 unsigned mask;
900 int nvis;
901
902 visTemplate.visualid = xdri_config->mode->visualID;
903 visInfo = XGetVisualInfo(disp->Xdpy, VisualIDMask, &visTemplate, &nvis);
904 if (!visInfo) {
905 return EGL_NO_SURFACE;
906 }
907
908 attr.background_pixel = 0;
909 attr.border_pixel = 0;
910 attr.colormap = XCreateColormap(disp->Xdpy, root,
911 visInfo->visual, AllocNone);
912 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
913 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
914
915 window = XCreateWindow(disp->Xdpy, root, 0, 0,
916 xdri_surf->Base.Width, xdri_surf->Base.Height,
917 0, visInfo->depth, InputOutput,
918 visInfo->visual, mask, &attr);
919
920 /*XMapWindow(disp->Xdpy, window);*/
921 XFree(visInfo);
922
923 /* set hints and properties */
924 /*
925 sizehints.width = xdri_surf->Base.Width;
926 sizehints.height = xdri_surf->Base.Height;
927 sizehints.flags = USPosition;
928 XSetNormalHints(disp->Xdpy, window, &sizehints);
929 */
930 }
931
932 if (!XF86DRICreateDrawable(disp->Xdpy, scrn, window, &xdri_surf->hDrawable)) {
933 free(xdri_surf);
934 return EGL_FALSE;
935 }
936
937 xdri_surf->driDrawable = window;
938
939 _eglSaveSurface(&xdri_surf->Base);
940
941 _eglLog(_EGL_DEBUG,
942 "XDRI: CreatePbufferSurface handle %d hDrawable %d",
943 _eglGetSurfaceHandle(&xdri_surf->Base),
944 (int) xdri_surf->hDrawable);
945
946 return _eglGetSurfaceHandle(&xdri_surf->Base);
947 }
948
949
950
951 static EGLBoolean
952 xdri_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
953 {
954 struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
955 if (xdri_surf) {
956 _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
957 if (xdri_surf->Base.IsBound) {
958 xdri_surf->Base.DeletePending = EGL_TRUE;
959 }
960 else {
961 /*
962 st_unreference_framebuffer(&surf->Framebuffer);
963 */
964 free(xdri_surf);
965 }
966 return EGL_TRUE;
967 }
968 else {
969 _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
970 return EGL_FALSE;
971 }
972 }
973
974
975 static EGLBoolean
976 xdri_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
977 EGLint buffer)
978 {
979 typedef int (*bind_teximage)(__DRInativeDisplay *dpy,
980 __DRIid surface, __DRIscreen *psc,
981 int buffer, int target, int format,
982 int level, int mipmap);
983
984 bind_teximage egl_dri_bind_teximage;
985
986 _EGLDisplay *disp = _eglLookupDisplay(dpy);
987
988 struct xdri_egl_context *xdri_ctx = current_context();
989 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
990 struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
991
992 __DRIid dri_surf = xdri_surf ? xdri_surf->driDrawable : 0;
993
994 __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs;
995 __DRIscreen *psc = &scrnConf->driScreen;
996
997 /* this call just does error checking */
998 if (!_eglBindTexImage(drv, dpy, surface, buffer)) {
999 return EGL_FALSE;
1000 }
1001
1002 egl_dri_bind_teximage =
1003 (bind_teximage) dlsym(NULL, "egl_dri_bind_teximage");
1004 if (egl_dri_bind_teximage) {
1005 return egl_dri_bind_teximage(disp->Xdpy, dri_surf, psc,
1006 buffer,
1007 xdri_surf->Base.TextureTarget,
1008 xdri_surf->Base.TextureFormat,
1009 xdri_surf->Base.MipmapLevel,
1010 xdri_surf->Base.MipmapTexture);
1011 }
1012 else {
1013 /* fallback path based on glCopyTexImage() */
1014 /* Get/save currently bound 2D texobj name */
1015 glGetIntegerv_t glGetIntegerv_func =
1016 (glGetIntegerv_t) dlsym(NULL, "glGetIntegerv");
1017 GLint curTexObj = 0;
1018 if (glGetIntegerv_func) {
1019 (*glGetIntegerv_func)(GL_TEXTURE_BINDING_2D, &curTexObj);
1020 }
1021 xdri_ctx->bound_tex_object = curTexObj;
1022 }
1023
1024 return EGL_FALSE;
1025 }
1026
1027
1028 static EGLBoolean
1029 xdri_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
1030 EGLint buffer)
1031 {
1032 typedef int (*release_teximage)(__DRInativeDisplay *dpy,
1033 __DRIid surface, __DRIscreen *psc,
1034 int buffer, int target, int format,
1035 int level, int mipmap);
1036 release_teximage egl_dri_release_teximage;
1037
1038 _EGLDisplay *disp = _eglLookupDisplay(dpy);
1039
1040 struct xdri_egl_context *xdri_ctx = current_context();
1041 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
1042 struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
1043
1044 __DRIid dri_surf = xdri_surf ? xdri_surf->driDrawable : 0;
1045
1046 __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs;
1047 __DRIscreen *psc = &scrnConf->driScreen;
1048
1049 /* this call just does error checking */
1050 if (!_eglReleaseTexImage(drv, dpy, surface, buffer)) {
1051 return EGL_FALSE;
1052 }
1053
1054 egl_dri_release_teximage =
1055 (release_teximage) dlsym(NULL, "egl_dri_release_teximage");
1056 if (egl_dri_release_teximage) {
1057 return egl_dri_release_teximage(disp->Xdpy, dri_surf, psc,
1058 buffer,
1059 xdri_surf->Base.TextureTarget,
1060 xdri_surf->Base.TextureFormat,
1061 xdri_surf->Base.MipmapLevel,
1062 xdri_surf->Base.MipmapTexture);
1063 }
1064 else {
1065 /* fallback path based on glCopyTexImage() */
1066 glGetIntegerv_t glGetIntegerv_func =
1067 (glGetIntegerv_t) dlsym(NULL, "glGetIntegerv");
1068 glBindTexture_t glBindTexture_func =
1069 (glBindTexture_t) dlsym(NULL, "glBindTexture");
1070 glCopyTexImage2D_t glCopyTexImage2D_func =
1071 (glCopyTexImage2D_t) dlsym(NULL, "glCopyTexImage2D");
1072 GLint curTexObj;
1073 GLenum intFormat;
1074 GLint level, width, height;
1075
1076 if (xdri_surf->Base.TextureFormat == EGL_TEXTURE_RGBA)
1077 intFormat = GL_RGBA;
1078 else
1079 intFormat = GL_RGB;
1080 level = xdri_surf->Base.MipmapLevel;
1081 width = xdri_surf->Base.Width >> level;
1082 height = xdri_surf->Base.Height >> level;
1083
1084 if (width > 0 && height > 0 &&
1085 glGetIntegerv_func && glBindTexture_func && glCopyTexImage2D_func) {
1086 glGetIntegerv_func(GL_TEXTURE_BINDING_2D, &curTexObj);
1087 /* restore texobj from time of eglBindTexImage() call */
1088 if (curTexObj != xdri_ctx->bound_tex_object)
1089 glBindTexture_func(GL_TEXTURE_2D, xdri_ctx->bound_tex_object);
1090 /* copy pbuffer image to texture */
1091 glCopyTexImage2D_func(GL_TEXTURE_2D,
1092 level,
1093 intFormat,
1094 0, 0, width, height, 0);
1095 /* restore current texture */
1096 if (curTexObj != xdri_ctx->bound_tex_object)
1097 glBindTexture_func(GL_TEXTURE_2D, curTexObj);
1098 }
1099 xdri_ctx->bound_tex_object = -1;
1100 }
1101
1102 return EGL_FALSE;
1103 }
1104
1105
1106 static EGLBoolean
1107 xdri_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
1108 {
1109 _EGLDisplay *disp = _eglLookupDisplay(dpy);
1110
1111 _eglLog(_EGL_DEBUG, "XDRI: EGL SwapBuffers");
1112
1113 /* error checking step: */
1114 if (!_eglSwapBuffers(drv, dpy, draw))
1115 return EGL_FALSE;
1116
1117 {
1118 struct xdri_egl_surface *xdri_surf = lookup_surface(draw);
1119 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
1120 __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs;
1121 __DRIscreen *psc = &scrnConf->driScreen;
1122 __DRIdrawable * const pdraw = psc->getDrawable(disp->Xdpy,
1123 xdri_surf->driDrawable,
1124 psc->private);
1125
1126 if (pdraw)
1127 pdraw->swapBuffers(disp->Xdpy, pdraw->private);
1128 else
1129 _eglLog(_EGL_WARNING, "pdraw is null in SwapBuffers");
1130 }
1131
1132 return EGL_TRUE;
1133 }
1134
1135
1136 /**
1137 * This is the main entrypoint into the driver, called by libEGL.
1138 * Create a new _EGLDriver object and init its dispatch table.
1139 */
1140 _EGLDriver *
1141 _eglMain(_EGLDisplay *disp, const char *args)
1142 {
1143 struct xdri_egl_driver *xdri_drv = CALLOC_STRUCT(xdri_egl_driver);
1144 if (!xdri_drv)
1145 return NULL;
1146
1147 /* Tell libGL to prefer the EGL drivers over regular DRI drivers */
1148 __glXPreferEGL(1);
1149
1150 _eglInitDriverFallbacks(&xdri_drv->Base);
1151 xdri_drv->Base.API.Initialize = xdri_eglInitialize;
1152 xdri_drv->Base.API.Terminate = xdri_eglTerminate;
1153
1154 xdri_drv->Base.API.GetProcAddress = xdri_eglGetProcAddress;
1155
1156 xdri_drv->Base.API.CreateContext = xdri_eglCreateContext;
1157 xdri_drv->Base.API.MakeCurrent = xdri_eglMakeCurrent;
1158 xdri_drv->Base.API.CreateWindowSurface = xdri_eglCreateWindowSurface;
1159 xdri_drv->Base.API.CreatePbufferSurface = xdri_eglCreatePbufferSurface;
1160 xdri_drv->Base.API.DestroySurface = xdri_eglDestroySurface;
1161 xdri_drv->Base.API.BindTexImage = xdri_eglBindTexImage;
1162 xdri_drv->Base.API.ReleaseTexImage = xdri_eglReleaseTexImage;
1163 xdri_drv->Base.API.SwapBuffers = xdri_eglSwapBuffers;
1164
1165 xdri_drv->Base.ClientAPIsMask = (EGL_OPENGL_BIT |
1166 EGL_OPENGL_ES_BIT |
1167 EGL_OPENGL_ES2_BIT |
1168 EGL_OPENVG_BIT);
1169 xdri_drv->Base.Name = "X/DRI";
1170
1171 _eglLog(_EGL_DEBUG, "XDRI: main(%s)", args);
1172
1173 return &xdri_drv->Base;
1174 }