0f8496c0fba815ec696d8d125d9378a3d55c61fb
[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 coudl 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
68
69 #define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
70
71
72 /** subclass of _EGLDriver */
73 struct xdri_egl_driver
74 {
75 _EGLDriver Base; /**< base class */
76
77 const char *dri_driver_name; /**< name of DRI driver to load */
78 void *dri_driver_handle; /**< returned by dlopen(dri_driver_name) */
79
80 int chipset;
81 int minor;
82 int drmFD;
83
84 __DRIscreen driScreen;
85 __DRIframebuffer framebuffer;
86 drm_handle_t hSAREA;
87 drmAddress pSAREA;
88 char *busID;
89 drm_magic_t magic;
90 };
91
92
93 /** subclass of _EGLContext */
94 struct xdri_egl_context
95 {
96 _EGLContext Base; /**< base class */
97
98 __DRIcontext driContext;
99 };
100
101
102 /** subclass of _EGLSurface */
103 struct xdri_egl_surface
104 {
105 _EGLSurface Base; /**< base class */
106
107 __DRIid driDrawable; /**< DRI surface */
108 drm_drawable_t hDrawable;
109 };
110
111
112 /** subclass of _EGLConfig */
113 struct xdri_egl_config
114 {
115 _EGLConfig Base; /**< base class */
116
117 const __GLcontextModes *mode; /**< corresponding GLX mode */
118 };
119
120
121 /* XXX temp hack */
122 static struct xdri_egl_driver *TheDriver = NULL;
123
124
125 /** cast wrapper */
126 static struct xdri_egl_driver *
127 xdri_egl_driver(_EGLDriver *drv)
128 {
129 return (struct xdri_egl_driver *) drv;
130 }
131
132
133 /** Map EGLSurface handle to xdri_egl_surface object */
134 static struct xdri_egl_surface *
135 lookup_surface(EGLSurface surf)
136 {
137 _EGLSurface *surface = _eglLookupSurface(surf);
138 return (struct xdri_egl_surface *) surface;
139 }
140
141
142 /** Map EGLContext handle to xdri_egl_context object */
143 static struct xdri_egl_context *
144 lookup_context(EGLContext c)
145 {
146 _EGLContext *context = _eglLookupContext(c);
147 return (struct xdri_egl_context *) context;
148 }
149
150
151 /** Map EGLConfig handle to xdri_egl_config object */
152 static struct xdri_egl_config *
153 lookup_config(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config)
154 {
155 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
156 return (struct xdri_egl_config *) conf;
157 }
158
159
160
161 /** Get size of given window */
162 static Status
163 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
164 {
165 Window root;
166 Status stat;
167 int xpos, ypos;
168 unsigned int w, h, bw, depth;
169 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
170 *width = w;
171 *height = h;
172 return stat;
173 }
174
175
176 /**
177 * Produce a set of EGL configs.
178 * Note that we get the list of GLcontextModes from the GLX library.
179 * This dependency on GLX lib will be removed someday.
180 */
181 static void
182 create_configs(_EGLDisplay *disp)
183 {
184 const __GLcontextModes *m;
185 __GLXdisplayPrivate *priv = __glXInitialize(disp->Xdpy);
186 __GLXscreenConfigs *scrn = priv->screenConfigs;
187 int id = 1;
188
189 for (m = scrn->configs; m; m = m->next) {
190 /* EGL requires double-buffered configs */
191 if (m->doubleBufferMode) {
192 struct xdri_egl_config *config = CALLOC_STRUCT(xdri_egl_config);
193
194 _eglInitConfig(&config->Base, id++);
195
196 SET_CONFIG_ATTRIB(&config->Base, EGL_BUFFER_SIZE, m->rgbBits);
197 SET_CONFIG_ATTRIB(&config->Base, EGL_RED_SIZE, m->redBits);
198 SET_CONFIG_ATTRIB(&config->Base, EGL_GREEN_SIZE, m->greenBits);
199 SET_CONFIG_ATTRIB(&config->Base, EGL_BLUE_SIZE, m->blueBits);
200 SET_CONFIG_ATTRIB(&config->Base, EGL_ALPHA_SIZE, m->alphaBits);
201 SET_CONFIG_ATTRIB(&config->Base, EGL_DEPTH_SIZE, m->depthBits);
202 SET_CONFIG_ATTRIB(&config->Base, EGL_STENCIL_SIZE, m->stencilBits);
203 SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_ID, m->visualID);
204 SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_TYPE, m->visualType);
205 /* XXX only window rendering allowed ATM */
206 SET_CONFIG_ATTRIB(&config->Base, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
207
208 /* XXX possibly other things to init... */
209
210 /* Ptr from EGL config to GLcontextMode. Used in CreateContext(). */
211 config->mode = m;
212
213 _eglAddConfig(disp, &config->Base);
214 }
215 }
216 }
217
218
219 /**
220 * Called via __DRIinterfaceMethods object
221 */
222 static __DRIfuncPtr
223 dri_get_proc_address(const char * proc_name)
224 {
225 return NULL;
226 }
227
228
229 static void
230 dri_context_modes_destroy(__GLcontextModes *modes)
231 {
232 _eglLog(_EGL_DEBUG, "%s", __FUNCTION__);
233
234 while (modes) {
235 __GLcontextModes * const next = modes->next;
236 free(modes);
237 modes = next;
238 }
239 }
240
241
242 /**
243 * Create a linked list of 'count' GLcontextModes.
244 * These are used during the client/server visual negotiation phase,
245 * then discarded.
246 */
247 static __GLcontextModes *
248 dri_context_modes_create(unsigned count, size_t minimum_size)
249 {
250 /* This code copied from libGLX, and modified */
251 const size_t size = (minimum_size > sizeof(__GLcontextModes))
252 ? minimum_size : sizeof(__GLcontextModes);
253 __GLcontextModes * head = NULL;
254 __GLcontextModes ** next;
255 unsigned i;
256
257 next = & head;
258 for (i = 0 ; i < count ; i++) {
259 *next = (__GLcontextModes *) calloc(1, size);
260 if (*next == NULL) {
261 dri_context_modes_destroy(head);
262 head = NULL;
263 break;
264 }
265
266 (*next)->doubleBufferMode = 1;
267 (*next)->visualID = GLX_DONT_CARE;
268 (*next)->visualType = GLX_DONT_CARE;
269 (*next)->visualRating = GLX_NONE;
270 (*next)->transparentPixel = GLX_NONE;
271 (*next)->transparentRed = GLX_DONT_CARE;
272 (*next)->transparentGreen = GLX_DONT_CARE;
273 (*next)->transparentBlue = GLX_DONT_CARE;
274 (*next)->transparentAlpha = GLX_DONT_CARE;
275 (*next)->transparentIndex = GLX_DONT_CARE;
276 (*next)->xRenderable = GLX_DONT_CARE;
277 (*next)->fbconfigID = GLX_DONT_CARE;
278 (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML;
279 (*next)->bindToTextureRgb = GLX_DONT_CARE;
280 (*next)->bindToTextureRgba = GLX_DONT_CARE;
281 (*next)->bindToMipmapTexture = GLX_DONT_CARE;
282 (*next)->bindToTextureTargets = 0;
283 (*next)->yInverted = GLX_DONT_CARE;
284
285 next = & ((*next)->next);
286 }
287
288 return head;
289 }
290
291
292 static __DRIscreen *
293 dri_find_dri_screen(__DRInativeDisplay *ndpy, int scrn)
294 {
295 assert(TheDriver);
296
297 return &TheDriver->driScreen;
298 }
299
300
301 static GLboolean
302 dri_window_exists(__DRInativeDisplay *ndpy, __DRIid draw)
303 {
304 return EGL_TRUE;
305 }
306
307
308 static GLboolean
309 dri_create_context(__DRInativeDisplay *ndpy, int screenNum, int configID,
310 void * contextID, drm_context_t * hw_context)
311 {
312 assert(configID >= 0);
313 return XF86DRICreateContextWithConfig(ndpy, screenNum,
314 configID, contextID, hw_context);
315 }
316
317
318 static GLboolean
319 dri_destroy_context(__DRInativeDisplay * ndpy, int screen, __DRIid context)
320 {
321 return XF86DRIDestroyContext(ndpy, screen, context);
322 }
323
324
325 static GLboolean
326 dri_create_drawable(__DRInativeDisplay * ndpy, int screen,
327 __DRIid drawable, drm_drawable_t * hHWDrawable)
328 {
329 _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__);
330
331 /* Create DRI drawable for given window ID (drawable) */
332 if (!XF86DRICreateDrawable(ndpy, screen, drawable, hHWDrawable))
333 return EGL_FALSE;
334
335 return EGL_TRUE;
336 }
337
338
339 static GLboolean
340 dri_destroy_drawable(__DRInativeDisplay * ndpy, int screen, __DRIid drawable)
341 {
342 _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__);
343 return XF86DRIDestroyDrawable(ndpy, screen, drawable);
344 }
345
346
347 static GLboolean
348 dri_get_drawable_info(__DRInativeDisplay *ndpy, int scrn,
349 __DRIid draw, unsigned int * index, unsigned int * stamp,
350 int * x, int * y, int * width, int * height,
351 int * numClipRects, drm_clip_rect_t ** pClipRects,
352 int * backX, int * backY,
353 int * numBackClipRects,
354 drm_clip_rect_t ** pBackClipRects)
355 {
356 _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__);
357
358 if (!XF86DRIGetDrawableInfo(ndpy, scrn, draw, index, stamp,
359 x, y, width, height,
360 numClipRects, pClipRects,
361 backX, backY,
362 numBackClipRects, pBackClipRects)) {
363 return EGL_FALSE;
364 }
365
366 return EGL_TRUE;
367 }
368
369
370 /**
371 * Table of functions exported by the loader to the driver.
372 */
373 static const __DRIinterfaceMethods interface_methods = {
374 dri_get_proc_address,
375
376 dri_context_modes_create,
377 dri_context_modes_destroy,
378
379 dri_find_dri_screen,
380 dri_window_exists,
381
382 dri_create_context,
383 dri_destroy_context,
384
385 dri_create_drawable,
386 dri_destroy_drawable,
387 dri_get_drawable_info,
388
389 NULL,/*__eglGetUST,*/
390 NULL,/*__eglGetMSCRate,*/
391 };
392
393
394
395 static EGLBoolean
396 init_drm(struct xdri_egl_driver *xdri_drv, _EGLDisplay *disp)
397 {
398 static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
399 PFNCREATENEWSCREENFUNC createNewScreen;
400 int api_ver = 0;/*__glXGetInternalVersion();*/
401 __DRIversion ddx_version;
402 __DRIversion dri_version;
403 __DRIversion drm_version;
404 drmVersionPtr version;
405 drm_handle_t hFB;
406 int newlyopened;
407 int status;
408 __GLcontextModes *modes;
409 int scrn = DefaultScreen(disp->Xdpy);
410
411 createNewScreen = (PFNCREATENEWSCREENFUNC)
412 dlsym(xdri_drv->dri_driver_handle, createNewScreenName);
413 if (!createNewScreen) {
414 _eglLog(_EGL_WARNING, "XDRI: Couldn't find %s function in the driver.",
415 createNewScreenName);
416 return EGL_FALSE;
417 }
418 else {
419 _eglLog(_EGL_DEBUG, "XDRI: Found %s", createNewScreenName);
420 }
421
422 /*
423 * Get the DRI X extension version.
424 */
425 dri_version.major = 4;
426 dri_version.minor = 0;
427 dri_version.patch = 0;
428
429
430 if (!XF86DRIOpenConnection(disp->Xdpy, scrn,
431 &xdri_drv->hSAREA, &xdri_drv->busID)) {
432 _eglLog(_EGL_WARNING, "XF86DRIOpenConnection failed");
433 }
434
435 xdri_drv->drmFD = drmOpenOnce(NULL, xdri_drv->busID, &newlyopened);
436 if (xdri_drv->drmFD < 0) {
437 perror("drmOpenOnce failed: ");
438 return EGL_FALSE;
439 }
440 else {
441 _eglLog(_EGL_DEBUG, "XDRI: drmOpenOnce returned %d", xdri_drv->drmFD);
442 }
443
444
445 if (drmGetMagic(xdri_drv->drmFD, &xdri_drv->magic)) {
446 perror("drmGetMagic failed: ");
447 return EGL_FALSE;
448 }
449
450 version = drmGetVersion(xdri_drv->drmFD);
451 if (version) {
452 drm_version.major = version->version_major;
453 drm_version.minor = version->version_minor;
454 drm_version.patch = version->version_patchlevel;
455 drmFreeVersion(version);
456 _eglLog(_EGL_DEBUG, "XDRI: Got DRM version %d.%d.%d",
457 drm_version.major,
458 drm_version.minor,
459 drm_version.patch);
460 }
461 else {
462 drm_version.major = -1;
463 drm_version.minor = -1;
464 drm_version.patch = -1;
465 _eglLog(_EGL_WARNING, "XDRI: drmGetVersion() failed");
466 return EGL_FALSE;
467 }
468
469 /* Authenticate w/ server.
470 */
471 if (!XF86DRIAuthConnection(disp->Xdpy, scrn, xdri_drv->magic)) {
472 _eglLog(_EGL_WARNING, "XDRI: XF86DRIAuthConnection() failed");
473 return EGL_FALSE;
474 }
475 else {
476 _eglLog(_EGL_DEBUG, "XDRI: XF86DRIAuthConnection() success");
477 }
478
479 /* Get ddx version.
480 */
481 {
482 char *driverName;
483
484 /*
485 * Get device name (like "tdfx") and the ddx version
486 * numbers. We'll check the version in each DRI driver's
487 * "createNewScreen" function.
488 */
489 if (!XF86DRIGetClientDriverName(disp->Xdpy, scrn,
490 &ddx_version.major,
491 &ddx_version.minor,
492 &ddx_version.patch,
493 &driverName)) {
494 _eglLog(_EGL_WARNING, "XDRI: XF86DRIGetClientDriverName failed");
495 return EGL_FALSE;
496 }
497 else {
498 _eglLog(_EGL_DEBUG, "XDRI: XF86DRIGetClientDriverName returned %s", driverName);
499 }
500 }
501
502 /* Get framebuffer info.
503 */
504 {
505 int junk;
506 if (!XF86DRIGetDeviceInfo(disp->Xdpy, scrn,
507 &hFB,
508 &junk,
509 &xdri_drv->framebuffer.size,
510 &xdri_drv->framebuffer.stride,
511 &xdri_drv->framebuffer.dev_priv_size,
512 &xdri_drv->framebuffer.dev_priv)) {
513 _eglLog(_EGL_WARNING, "XDRI: XF86DRIGetDeviceInfo() failed");
514 return EGL_FALSE;
515 }
516 else {
517 _eglLog(_EGL_DEBUG, "XDRI: XF86DRIGetDeviceInfo() success");
518 }
519 xdri_drv->framebuffer.width = DisplayWidth(disp->Xdpy, scrn);
520 xdri_drv->framebuffer.height = DisplayHeight(disp->Xdpy, scrn);
521 }
522
523 /* Map the framebuffer region. (this may not be needed)
524 */
525 status = drmMap(xdri_drv->drmFD, hFB, xdri_drv->framebuffer.size,
526 (drmAddressPtr) &xdri_drv->framebuffer.base);
527 if (status != 0) {
528 _eglLog(_EGL_WARNING, "XDRI: drmMap(framebuffer) failed");
529 return EGL_FALSE;
530 }
531 else {
532 _eglLog(_EGL_DEBUG, "XDRI: drmMap(framebuffer) success");
533 }
534
535 /* Map the SAREA region.
536 */
537 status = drmMap(xdri_drv->drmFD, xdri_drv->hSAREA, SAREA_MAX, &xdri_drv->pSAREA);
538 if (status != 0) {
539 _eglLog(_EGL_WARNING, "XDRI: drmMap(sarea) failed");
540 return EGL_FALSE;
541 }
542 else {
543 _eglLog(_EGL_DEBUG, "XDRI: drmMap(sarea) success");
544 }
545
546 /* Create the DRI screen.
547 */
548 xdri_drv->driScreen.private = createNewScreen(disp->Xdpy,
549 scrn, /* screen number */
550 &xdri_drv->driScreen,
551 NULL, /* visuals */
552 &ddx_version,
553 &dri_version,
554 &drm_version,
555 &xdri_drv->framebuffer,
556 xdri_drv->pSAREA,
557 xdri_drv->drmFD,
558 api_ver,
559 &interface_methods,
560 &modes);
561 if (!xdri_drv->driScreen.private) {
562 _eglLog(_EGL_WARNING, "XDRI: create new screen failed");
563 return EGL_FALSE;
564 }
565 else {
566 _eglLog(_EGL_DEBUG, "XDRI: create new screen success");
567 }
568
569 create_configs(disp);
570
571 /* print modes / debug */
572 if (0) {
573 __GLcontextModes *m;
574
575 for (m = modes; m; m = m->next) {
576 _eglLog(_EGL_DEBUG,
577 "mode ID 0x%x rgba %d %d %d %d z %d s %d db %d\n",
578 m->visualID,
579 m->redBits, m->greenBits, m->blueBits, m->alphaBits,
580 m->depthBits, m->stencilBits, m->doubleBufferMode);
581 }
582 }
583
584 return EGL_TRUE;
585 }
586
587
588 /**
589 * Load the DRI driver named by "xdri_drv->dri_driver_name".
590 * Basically, dlopen() the library to set "xdri_drv->dri_driver_handle".
591 *
592 * Later, we'll call dlsym(createNewScreenName) to get a pointer to
593 * the driver's createNewScreen() function which is the bootstrap function.
594 *
595 * \return EGL_TRUE for success, EGL_FALSE for failure
596 */
597 static EGLBoolean
598 load_dri_driver(struct xdri_egl_driver *xdri_drv)
599 {
600 char filename[100];
601 int flags = RTLD_NOW;
602
603 /* try "egl_xxx_dri.so" first */
604 snprintf(filename, sizeof(filename), "egl_%s.so", xdri_drv->dri_driver_name);
605 _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s)", filename);
606 xdri_drv->dri_driver_handle = dlopen(filename, flags);
607 if (xdri_drv->dri_driver_handle) {
608 _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s) OK", filename);
609 return EGL_TRUE;
610 }
611 else {
612 _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s) fail (%s)", filename, dlerror());
613 }
614
615 /* try regular "xxx_dri.so" next */
616 snprintf(filename, sizeof(filename), "%s.so", xdri_drv->dri_driver_name);
617 _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s)", filename);
618 xdri_drv->dri_driver_handle = dlopen(filename, flags);
619 if (xdri_drv->dri_driver_handle) {
620 _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s) OK", filename);
621 return EGL_TRUE;
622 }
623
624 _eglLog(_EGL_WARNING, "XDRI Could not open %s (%s)", filename, dlerror());
625 return EGL_FALSE;
626 }
627
628
629 /**
630 * Called via eglInitialize(), xdri_drv->API.Initialize().
631 */
632 static EGLBoolean
633 xdri_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
634 EGLint *minor, EGLint *major)
635 {
636 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
637 _EGLDisplay *disp = _eglLookupDisplay(dpy);
638 static char name[100];
639
640 _eglLog(_EGL_DEBUG, "XDRI: eglInitialize");
641
642 if (!disp->Xdpy) {
643 disp->Xdpy = XOpenDisplay(NULL);
644 if (!disp->Xdpy) {
645 _eglLog(_EGL_WARNING, "XDRI: XOpenDisplay failed");
646 return EGL_FALSE;
647 }
648 }
649
650 /* choose the DRI driver to load */
651 xdri_drv->dri_driver_name = _eglChooseDRMDriver(0);
652 if (!load_dri_driver(xdri_drv))
653 return EGL_FALSE;
654
655 if (!init_drm(xdri_drv, disp))
656 return EGL_FALSE;
657
658 xdri_drv->Base.Initialized = EGL_TRUE;
659
660 snprintf(name, sizeof(name), "X/DRI:%s", xdri_drv->dri_driver_name);
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 * Called via eglTerminate(), drv->API.Terminate().
673 */
674 static EGLBoolean
675 xdri_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
676 {
677 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
678
679 _eglLog(_EGL_DEBUG, "XDRI: eglTerminate");
680
681 _eglLog(_EGL_DEBUG, "XDRI: Closing %s", xdri_drv->dri_driver_name);
682 dlclose(xdri_drv->dri_driver_handle);
683 xdri_drv->dri_driver_handle = NULL;
684
685 free((void*) xdri_drv->dri_driver_name);
686
687 return EGL_TRUE;
688 }
689
690
691 /*
692 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
693 */
694 static _EGLProc
695 xdri_eglGetProcAddress(const char *procname)
696 {
697 #if 0
698 _EGLDriver *drv = NULL;
699
700 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
701 /*_EGLDisplay *disp = _eglLookupDisplay(dpy);*/
702 _EGLProc *proc = xdri_drv->driScreen.getProcAddress(procname);
703 return proc;
704 #elif 1
705 /* This is a bit of a hack to get at the gallium/Mesa state tracker
706 * function st_get_proc_address(). This will probably change at
707 * some point.
708 */
709 _EGLProc (*st_get_proc_addr)(const char *procname);
710 st_get_proc_addr = dlsym(NULL, "st_get_proc_address");
711 if (st_get_proc_addr) {
712 return st_get_proc_addr(procname);
713 }
714 return NULL;
715 #else
716 return NULL;
717 #endif
718 }
719
720
721 /**
722 * Called via eglCreateContext(), drv->API.CreateContext().
723 */
724 static EGLContext
725 xdri_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
726 EGLContext share_list, const EGLint *attrib_list)
727 {
728 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
729 _EGLDisplay *disp = _eglLookupDisplay(dpy);
730 struct xdri_egl_config *xdri_config = lookup_config(drv, dpy, config);
731 void *shared = NULL;
732 int renderType = GLX_RGBA_BIT;
733
734 struct xdri_egl_context *xdri_ctx = CALLOC_STRUCT(xdri_egl_context);
735 if (!xdri_ctx)
736 return EGL_NO_CONTEXT;
737
738 if (!_eglInitContext(drv, dpy, &xdri_ctx->Base, config, attrib_list)) {
739 free(xdri_ctx);
740 return EGL_NO_CONTEXT;
741 }
742
743 assert(xdri_config);
744
745 xdri_ctx->driContext.private =
746 xdri_drv->driScreen.createNewContext(disp->Xdpy,
747 xdri_config->mode, renderType,
748 shared, &xdri_ctx->driContext);
749 if (!xdri_ctx->driContext.private) {
750 _eglLog(_EGL_DEBUG, "driScreen.createNewContext failed");
751 free(xdri_ctx);
752 return EGL_NO_CONTEXT;
753 }
754
755 xdri_ctx->driContext.mode = xdri_config->mode;
756
757 return _eglGetContextHandle(&xdri_ctx->Base);
758 }
759
760
761 /**
762 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
763 */
764 static EGLBoolean
765 xdri_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
766 EGLSurface r, EGLContext context)
767 {
768 _EGLDisplay *disp = _eglLookupDisplay(dpy);
769 struct xdri_egl_context *xdri_ctx = lookup_context(context);
770 struct xdri_egl_surface *xdri_draw = lookup_surface(d);
771 struct xdri_egl_surface *xdri_read = lookup_surface(r);
772 __DRIid draw = xdri_draw->driDrawable;
773 __DRIid read = xdri_read->driDrawable;
774 int scrn = DefaultScreen(disp->Xdpy);
775
776 if (!_eglMakeCurrent(drv, dpy, d, r, context))
777 return EGL_FALSE;
778
779
780 if (!xdri_ctx->driContext.bindContext(disp->Xdpy, scrn, draw, read,
781 &xdri_ctx->driContext)) {
782 return EGL_FALSE;
783 }
784
785 return EGL_TRUE;
786 }
787
788
789 /**
790 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
791 */
792 static EGLSurface
793 xdri_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
794 NativeWindowType window, const EGLint *attrib_list)
795 {
796 _EGLDisplay *disp = _eglLookupDisplay(dpy);
797 struct xdri_egl_surface *xdri_surf;
798 int scrn = DefaultScreen(disp->Xdpy);
799 uint width, height;
800
801 xdri_surf = CALLOC_STRUCT(xdri_egl_surface);
802 if (!xdri_surf)
803 return EGL_NO_SURFACE;
804
805 if (!_eglInitSurface(drv, dpy, &xdri_surf->Base, EGL_WINDOW_BIT,
806 config, attrib_list)) {
807 free(xdri_surf);
808 return EGL_FALSE;
809 }
810
811 if (!XF86DRICreateDrawable(disp->Xdpy, scrn, window, &xdri_surf->hDrawable)) {
812 free(xdri_surf);
813 return EGL_FALSE;
814 }
815
816 xdri_surf->driDrawable = window;
817
818 _eglSaveSurface(&xdri_surf->Base);
819
820 get_drawable_size(disp->Xdpy, window, &width, &height);
821 xdri_surf->Base.Width = width;
822 xdri_surf->Base.Height = height;
823
824 _eglLog(_EGL_DEBUG,
825 "XDRI: CreateWindowSurface win 0x%x handle %d hDrawable %d",
826 (int) window, _eglGetSurfaceHandle(&xdri_surf->Base),
827 (int) xdri_surf->hDrawable);
828
829 return _eglGetSurfaceHandle(&xdri_surf->Base);
830 }
831
832
833 static EGLBoolean
834 xdri_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
835 {
836 struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
837 if (xdri_surf) {
838 _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
839 if (xdri_surf->Base.IsBound) {
840 xdri_surf->Base.DeletePending = EGL_TRUE;
841 }
842 else {
843 /*
844 st_unreference_framebuffer(&surf->Framebuffer);
845 */
846 free(xdri_surf);
847 }
848 return EGL_TRUE;
849 }
850 else {
851 _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
852 return EGL_FALSE;
853 }
854 }
855
856
857 static EGLBoolean
858 xdri_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
859 {
860 _EGLDisplay *disp = _eglLookupDisplay(dpy);
861
862 _eglLog(_EGL_DEBUG, "XDRI: EGL SwapBuffers");
863
864 /* error checking step: */
865 if (!_eglSwapBuffers(drv, dpy, draw))
866 return EGL_FALSE;
867
868 {
869 struct xdri_egl_surface *xdri_surf = lookup_surface(draw);
870 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
871 __DRIscreen *psc = &xdri_drv->driScreen;
872 __DRIdrawable * const pdraw = psc->getDrawable(disp->Xdpy,
873 xdri_surf->driDrawable,
874 psc->private);
875
876 if (pdraw)
877 pdraw->swapBuffers(disp->Xdpy, pdraw->private);
878 else
879 _eglLog(_EGL_WARNING, "pdraw is null in SwapBuffers");
880 }
881
882 return EGL_TRUE;
883 }
884
885
886 /**
887 * This is the main entrypoint into the driver, called by libEGL.
888 * Create a new _EGLDriver object and init its dispatch table.
889 */
890 _EGLDriver *
891 _eglMain(_EGLDisplay *disp, const char *args)
892 {
893 struct xdri_egl_driver *xdri_drv = CALLOC_STRUCT(xdri_egl_driver);
894 if (!xdri_drv)
895 return NULL;
896
897 /* XXX temp hack */
898 TheDriver = xdri_drv;
899
900 _eglInitDriverFallbacks(&xdri_drv->Base);
901 xdri_drv->Base.API.Initialize = xdri_eglInitialize;
902 xdri_drv->Base.API.Terminate = xdri_eglTerminate;
903
904 xdri_drv->Base.API.GetProcAddress = xdri_eglGetProcAddress;
905
906 xdri_drv->Base.API.CreateContext = xdri_eglCreateContext;
907 xdri_drv->Base.API.MakeCurrent = xdri_eglMakeCurrent;
908 xdri_drv->Base.API.CreateWindowSurface = xdri_eglCreateWindowSurface;
909 xdri_drv->Base.API.DestroySurface = xdri_eglDestroySurface;
910 xdri_drv->Base.API.SwapBuffers = xdri_eglSwapBuffers;
911
912 xdri_drv->Base.ClientAPIsMask = (EGL_OPENGL_BIT |
913 EGL_OPENGL_ES_BIT |
914 EGL_OPENGL_ES2_BIT |
915 EGL_OPENVG_BIT);
916 xdri_drv->Base.Name = "X/DRI";
917
918 _eglLog(_EGL_DEBUG, "XDRI: main(%s)", args);
919
920 return &xdri_drv->Base;
921 }