Merge commit 'origin/gallium-0.1' into gallium-0.2
[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 if (xdri_drv->dri_driver_name)
658 snprintf(name, sizeof(name), "X/DRI:%s", xdri_drv->dri_driver_name);
659 else
660 snprintf(name, sizeof(name), "X/DRI");
661 xdri_drv->Base.Name = name;
662
663 /* we're supporting EGL 1.4 */
664 *minor = 1;
665 *major = 4;
666
667 return EGL_TRUE;
668 }
669
670
671 /*
672 * Do some clean-up that normally occurs in XCloseDisplay().
673 * We do this here because we're about to unload a dynamic library
674 * that has added some per-display extension data and callbacks.
675 * If we don't do this here we'll crash in XCloseDisplay() because it'll
676 * try to call functions that went away when the driver library was unloaded.
677 */
678 static void
679 FreeDisplayExt(Display *dpy)
680 {
681 _XExtension *ext, *next;
682
683 for (ext = dpy->ext_procs; ext; ext = next) {
684 next = ext->next;
685 if (ext->close_display) {
686 ext->close_display(dpy, &ext->codes);
687 ext->close_display = NULL;
688 }
689 if (ext->name)
690 Xfree(ext->name);
691 Xfree(ext);
692 }
693 dpy->ext_procs = NULL;
694
695 _XFreeExtData (dpy->ext_data);
696 dpy->ext_data = NULL;
697 }
698
699
700 /**
701 * Called via eglTerminate(), drv->API.Terminate().
702 */
703 static EGLBoolean
704 xdri_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
705 {
706 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
707 _EGLDisplay *disp = _eglLookupDisplay(dpy);
708
709 _eglLog(_EGL_DEBUG, "XDRI: eglTerminate");
710
711 _eglLog(_EGL_DEBUG, "XDRI: Closing %s", xdri_drv->dri_driver_name);
712
713 FreeDisplayExt(disp->Xdpy);
714
715 #if 0
716 /* this causes a segfault for some reason */
717 dlclose(xdri_drv->dri_driver_handle);
718 #endif
719 xdri_drv->dri_driver_handle = NULL;
720
721 free((void*) xdri_drv->dri_driver_name);
722
723 return EGL_TRUE;
724 }
725
726
727 /*
728 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
729 */
730 static _EGLProc
731 xdri_eglGetProcAddress(const char *procname)
732 {
733 #if 0
734 _EGLDriver *drv = NULL;
735
736 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
737 /*_EGLDisplay *disp = _eglLookupDisplay(dpy);*/
738 _EGLProc *proc = xdri_drv->driScreen.getProcAddress(procname);
739 return proc;
740 #elif 1
741 /* This is a bit of a hack to get at the gallium/Mesa state tracker
742 * function st_get_proc_address(). This will probably change at
743 * some point.
744 */
745 _EGLProc (*st_get_proc_addr)(const char *procname);
746 st_get_proc_addr = dlsym(NULL, "st_get_proc_address");
747 if (st_get_proc_addr) {
748 return st_get_proc_addr(procname);
749 }
750 return NULL;
751 #else
752 return NULL;
753 #endif
754 }
755
756
757 /**
758 * Called via eglCreateContext(), drv->API.CreateContext().
759 */
760 static EGLContext
761 xdri_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
762 EGLContext share_list, const EGLint *attrib_list)
763 {
764 _EGLDisplay *disp = _eglLookupDisplay(dpy);
765 struct xdri_egl_config *xdri_config = lookup_config(drv, dpy, config);
766 void *shared = NULL;
767 int renderType = GLX_RGBA_BIT;
768
769 struct xdri_egl_context *xdri_ctx = CALLOC_STRUCT(xdri_egl_context);
770 if (!xdri_ctx)
771 return EGL_NO_CONTEXT;
772
773 if (!_eglInitContext(drv, dpy, &xdri_ctx->Base, config, attrib_list)) {
774 free(xdri_ctx);
775 return EGL_NO_CONTEXT;
776 }
777
778 assert(xdri_config);
779
780 {
781 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
782 __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs;
783 xdri_ctx->driContext.private =
784 scrnConf->driScreen.createNewContext(disp->Xdpy,
785 xdri_config->mode, renderType,
786 shared, &xdri_ctx->driContext);
787 }
788
789 if (!xdri_ctx->driContext.private) {
790 _eglLog(_EGL_DEBUG, "driScreen.createNewContext failed");
791 free(xdri_ctx);
792 return EGL_NO_CONTEXT;
793 }
794
795 xdri_ctx->driContext.mode = xdri_config->mode;
796
797 return _eglGetContextHandle(&xdri_ctx->Base);
798 }
799
800
801 /**
802 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
803 */
804 static EGLBoolean
805 xdri_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
806 EGLSurface r, EGLContext context)
807 {
808 _EGLDisplay *disp = _eglLookupDisplay(dpy);
809 struct xdri_egl_context *xdri_ctx = lookup_context(context);
810 struct xdri_egl_surface *xdri_draw = lookup_surface(d);
811 struct xdri_egl_surface *xdri_read = lookup_surface(r);
812 __DRIid draw = xdri_draw ? xdri_draw->driDrawable : 0;
813 __DRIid read = xdri_read ? xdri_read->driDrawable : 0;
814 int scrn = DefaultScreen(disp->Xdpy);
815
816 if (!_eglMakeCurrent(drv, dpy, d, r, context))
817 return EGL_FALSE;
818
819
820 if (xdri_ctx &&
821 !xdri_ctx->driContext.bindContext(disp->Xdpy, scrn, draw, read,
822 &xdri_ctx->driContext)) {
823 return EGL_FALSE;
824 }
825
826 return EGL_TRUE;
827 }
828
829
830 /**
831 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
832 */
833 static EGLSurface
834 xdri_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
835 NativeWindowType window, const EGLint *attrib_list)
836 {
837 _EGLDisplay *disp = _eglLookupDisplay(dpy);
838 struct xdri_egl_surface *xdri_surf;
839 int scrn = DefaultScreen(disp->Xdpy);
840 uint width, height;
841
842 xdri_surf = CALLOC_STRUCT(xdri_egl_surface);
843 if (!xdri_surf)
844 return EGL_NO_SURFACE;
845
846 if (!_eglInitSurface(drv, dpy, &xdri_surf->Base, EGL_WINDOW_BIT,
847 config, attrib_list)) {
848 free(xdri_surf);
849 return EGL_FALSE;
850 }
851
852 if (!XF86DRICreateDrawable(disp->Xdpy, scrn, window, &xdri_surf->hDrawable)) {
853 free(xdri_surf);
854 return EGL_FALSE;
855 }
856
857 xdri_surf->driDrawable = window;
858
859 _eglSaveSurface(&xdri_surf->Base);
860
861 get_drawable_size(disp->Xdpy, window, &width, &height);
862 xdri_surf->Base.Width = width;
863 xdri_surf->Base.Height = height;
864
865 _eglLog(_EGL_DEBUG,
866 "XDRI: CreateWindowSurface win 0x%x handle %d hDrawable %d",
867 (int) window, _eglGetSurfaceHandle(&xdri_surf->Base),
868 (int) xdri_surf->hDrawable);
869
870 return _eglGetSurfaceHandle(&xdri_surf->Base);
871 }
872
873
874 /**
875 * Called via eglCreatePbufferSurface(), drv->API.CreatePbufferSurface().
876 */
877 static EGLSurface
878 xdri_eglCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
879 const EGLint *attrib_list)
880 {
881 _EGLDisplay *disp = _eglLookupDisplay(dpy);
882 struct xdri_egl_surface *xdri_surf;
883 struct xdri_egl_config *xdri_config = lookup_config(drv, dpy, config);
884 int scrn = DefaultScreen(disp->Xdpy);
885 Window window;
886
887 xdri_surf = CALLOC_STRUCT(xdri_egl_surface);
888 if (!xdri_surf)
889 return EGL_NO_SURFACE;
890
891 if (!_eglInitSurface(drv, dpy, &xdri_surf->Base, EGL_PBUFFER_BIT,
892 config, attrib_list)) {
893 free(xdri_surf);
894 return EGL_FALSE;
895 }
896
897 /* Create a dummy X window */
898 {
899 Window root = RootWindow(disp->Xdpy, scrn);
900 XSetWindowAttributes attr;
901 XVisualInfo *visInfo, visTemplate;
902 unsigned mask;
903 int nvis;
904
905 visTemplate.visualid = xdri_config->mode->visualID;
906 visInfo = XGetVisualInfo(disp->Xdpy, VisualIDMask, &visTemplate, &nvis);
907 if (!visInfo) {
908 return EGL_NO_SURFACE;
909 }
910
911 attr.background_pixel = 0;
912 attr.border_pixel = 0;
913 attr.colormap = XCreateColormap(disp->Xdpy, root,
914 visInfo->visual, AllocNone);
915 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
916 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
917
918 window = XCreateWindow(disp->Xdpy, root, 0, 0,
919 xdri_surf->Base.Width, xdri_surf->Base.Height,
920 0, visInfo->depth, InputOutput,
921 visInfo->visual, mask, &attr);
922
923 /*XMapWindow(disp->Xdpy, window);*/
924 XFree(visInfo);
925
926 /* set hints and properties */
927 /*
928 sizehints.width = xdri_surf->Base.Width;
929 sizehints.height = xdri_surf->Base.Height;
930 sizehints.flags = USPosition;
931 XSetNormalHints(disp->Xdpy, window, &sizehints);
932 */
933 }
934
935 if (!XF86DRICreateDrawable(disp->Xdpy, scrn, window, &xdri_surf->hDrawable)) {
936 free(xdri_surf);
937 return EGL_FALSE;
938 }
939
940 xdri_surf->driDrawable = window;
941
942 _eglSaveSurface(&xdri_surf->Base);
943
944 _eglLog(_EGL_DEBUG,
945 "XDRI: CreatePbufferSurface handle %d hDrawable %d",
946 _eglGetSurfaceHandle(&xdri_surf->Base),
947 (int) xdri_surf->hDrawable);
948
949 return _eglGetSurfaceHandle(&xdri_surf->Base);
950 }
951
952
953
954 static EGLBoolean
955 xdri_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
956 {
957 struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
958 if (xdri_surf) {
959 _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
960 if (xdri_surf->Base.IsBound) {
961 xdri_surf->Base.DeletePending = EGL_TRUE;
962 }
963 else {
964 /*
965 st_unreference_framebuffer(surf->Framebuffer);
966 */
967 free(xdri_surf);
968 }
969 return EGL_TRUE;
970 }
971 else {
972 _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
973 return EGL_FALSE;
974 }
975 }
976
977
978 static EGLBoolean
979 xdri_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
980 EGLint buffer)
981 {
982 typedef int (*bind_teximage)(__DRInativeDisplay *dpy,
983 __DRIid surface, __DRIscreen *psc,
984 int buffer, int target, int format,
985 int level, int mipmap);
986
987 bind_teximage egl_dri_bind_teximage;
988
989 _EGLDisplay *disp = _eglLookupDisplay(dpy);
990
991 struct xdri_egl_context *xdri_ctx = current_context();
992 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
993 struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
994
995 __DRIid dri_surf = xdri_surf ? xdri_surf->driDrawable : 0;
996
997 __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs;
998 __DRIscreen *psc = &scrnConf->driScreen;
999
1000 /* this call just does error checking */
1001 if (!_eglBindTexImage(drv, dpy, surface, buffer)) {
1002 return EGL_FALSE;
1003 }
1004
1005 egl_dri_bind_teximage =
1006 (bind_teximage) dlsym(NULL, "egl_dri_bind_teximage");
1007 if (egl_dri_bind_teximage) {
1008 return egl_dri_bind_teximage(disp->Xdpy, dri_surf, psc,
1009 buffer,
1010 xdri_surf->Base.TextureTarget,
1011 xdri_surf->Base.TextureFormat,
1012 xdri_surf->Base.MipmapLevel,
1013 xdri_surf->Base.MipmapTexture);
1014 }
1015 else {
1016 /* fallback path based on glCopyTexImage() */
1017 /* Get/save currently bound 2D texobj name */
1018 glGetIntegerv_t glGetIntegerv_func =
1019 (glGetIntegerv_t) dlsym(NULL, "glGetIntegerv");
1020 GLint curTexObj = 0;
1021 if (glGetIntegerv_func) {
1022 (*glGetIntegerv_func)(GL_TEXTURE_BINDING_2D, &curTexObj);
1023 }
1024 xdri_ctx->bound_tex_object = curTexObj;
1025 }
1026
1027 return EGL_FALSE;
1028 }
1029
1030
1031 static EGLBoolean
1032 xdri_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
1033 EGLint buffer)
1034 {
1035 typedef int (*release_teximage)(__DRInativeDisplay *dpy,
1036 __DRIid surface, __DRIscreen *psc,
1037 int buffer, int target, int format,
1038 int level, int mipmap);
1039 release_teximage egl_dri_release_teximage;
1040
1041 _EGLDisplay *disp = _eglLookupDisplay(dpy);
1042
1043 struct xdri_egl_context *xdri_ctx = current_context();
1044 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
1045 struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
1046
1047 __DRIid dri_surf = xdri_surf ? xdri_surf->driDrawable : 0;
1048
1049 __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs;
1050 __DRIscreen *psc = &scrnConf->driScreen;
1051
1052 /* this call just does error checking */
1053 if (!_eglReleaseTexImage(drv, dpy, surface, buffer)) {
1054 return EGL_FALSE;
1055 }
1056
1057 egl_dri_release_teximage =
1058 (release_teximage) dlsym(NULL, "egl_dri_release_teximage");
1059 if (egl_dri_release_teximage) {
1060 return egl_dri_release_teximage(disp->Xdpy, dri_surf, psc,
1061 buffer,
1062 xdri_surf->Base.TextureTarget,
1063 xdri_surf->Base.TextureFormat,
1064 xdri_surf->Base.MipmapLevel,
1065 xdri_surf->Base.MipmapTexture);
1066 }
1067 else {
1068 /* fallback path based on glCopyTexImage() */
1069 glGetIntegerv_t glGetIntegerv_func =
1070 (glGetIntegerv_t) dlsym(NULL, "glGetIntegerv");
1071 glBindTexture_t glBindTexture_func =
1072 (glBindTexture_t) dlsym(NULL, "glBindTexture");
1073 glCopyTexImage2D_t glCopyTexImage2D_func =
1074 (glCopyTexImage2D_t) dlsym(NULL, "glCopyTexImage2D");
1075 GLint curTexObj;
1076 GLenum intFormat;
1077 GLint level, width, height;
1078
1079 if (xdri_surf->Base.TextureFormat == EGL_TEXTURE_RGBA)
1080 intFormat = GL_RGBA;
1081 else
1082 intFormat = GL_RGB;
1083 level = xdri_surf->Base.MipmapLevel;
1084 width = xdri_surf->Base.Width >> level;
1085 height = xdri_surf->Base.Height >> level;
1086
1087 if (width > 0 && height > 0 &&
1088 glGetIntegerv_func && glBindTexture_func && glCopyTexImage2D_func) {
1089 glGetIntegerv_func(GL_TEXTURE_BINDING_2D, &curTexObj);
1090 /* restore texobj from time of eglBindTexImage() call */
1091 if (curTexObj != xdri_ctx->bound_tex_object)
1092 glBindTexture_func(GL_TEXTURE_2D, xdri_ctx->bound_tex_object);
1093 /* copy pbuffer image to texture */
1094 glCopyTexImage2D_func(GL_TEXTURE_2D,
1095 level,
1096 intFormat,
1097 0, 0, width, height, 0);
1098 /* restore current texture */
1099 if (curTexObj != xdri_ctx->bound_tex_object)
1100 glBindTexture_func(GL_TEXTURE_2D, curTexObj);
1101 }
1102 xdri_ctx->bound_tex_object = -1;
1103 }
1104
1105 return EGL_FALSE;
1106 }
1107
1108
1109 static EGLBoolean
1110 xdri_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
1111 {
1112 _EGLDisplay *disp = _eglLookupDisplay(dpy);
1113
1114 _eglLog(_EGL_DEBUG, "XDRI: EGL SwapBuffers");
1115
1116 /* error checking step: */
1117 if (!_eglSwapBuffers(drv, dpy, draw))
1118 return EGL_FALSE;
1119
1120 {
1121 struct xdri_egl_surface *xdri_surf = lookup_surface(draw);
1122 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
1123 __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs;
1124 __DRIscreen *psc = &scrnConf->driScreen;
1125 __DRIdrawable * const pdraw = psc->getDrawable(disp->Xdpy,
1126 xdri_surf->driDrawable,
1127 psc->private);
1128
1129 if (pdraw)
1130 pdraw->swapBuffers(disp->Xdpy, pdraw->private);
1131 else
1132 _eglLog(_EGL_WARNING, "pdraw is null in SwapBuffers");
1133 }
1134
1135 return EGL_TRUE;
1136 }
1137
1138
1139 /**
1140 * This is the main entrypoint into the driver, called by libEGL.
1141 * Create a new _EGLDriver object and init its dispatch table.
1142 */
1143 _EGLDriver *
1144 _eglMain(_EGLDisplay *disp, const char *args)
1145 {
1146 struct xdri_egl_driver *xdri_drv = CALLOC_STRUCT(xdri_egl_driver);
1147 if (!xdri_drv)
1148 return NULL;
1149
1150 /* Tell libGL to prefer the EGL drivers over regular DRI drivers */
1151 __glXPreferEGL(1);
1152
1153 _eglInitDriverFallbacks(&xdri_drv->Base);
1154 xdri_drv->Base.API.Initialize = xdri_eglInitialize;
1155 xdri_drv->Base.API.Terminate = xdri_eglTerminate;
1156
1157 xdri_drv->Base.API.GetProcAddress = xdri_eglGetProcAddress;
1158
1159 xdri_drv->Base.API.CreateContext = xdri_eglCreateContext;
1160 xdri_drv->Base.API.MakeCurrent = xdri_eglMakeCurrent;
1161 xdri_drv->Base.API.CreateWindowSurface = xdri_eglCreateWindowSurface;
1162 xdri_drv->Base.API.CreatePbufferSurface = xdri_eglCreatePbufferSurface;
1163 xdri_drv->Base.API.DestroySurface = xdri_eglDestroySurface;
1164 xdri_drv->Base.API.BindTexImage = xdri_eglBindTexImage;
1165 xdri_drv->Base.API.ReleaseTexImage = xdri_eglReleaseTexImage;
1166 xdri_drv->Base.API.SwapBuffers = xdri_eglSwapBuffers;
1167
1168 xdri_drv->Base.ClientAPIsMask = (EGL_OPENGL_BIT |
1169 EGL_OPENGL_ES_BIT |
1170 EGL_OPENGL_ES2_BIT |
1171 EGL_OPENVG_BIT);
1172 xdri_drv->Base.Name = "X/DRI";
1173
1174 _eglLog(_EGL_DEBUG, "XDRI: main(%s)", args);
1175
1176 return &xdri_drv->Base;
1177 }