OSDN Git Service

34d69def6a53767a012fffb0e0284e3970beccd8
[android-x86/external-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, &xdri_ctx->Base, &xdri_config->Base, 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 _eglLinkContext(&xdri_ctx->Base, &disp);
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_config *xdri_config = lookup_config(drv, dpy, config);
839    struct xdri_egl_surface *xdri_surf;
840    int scrn = DefaultScreen(disp->Xdpy);
841    uint width, height;
842
843    xdri_surf = CALLOC_STRUCT(xdri_egl_surface);
844    if (!xdri_surf)
845       return EGL_NO_SURFACE;
846
847    if (!_eglInitSurface(drv, &xdri_surf->Base, EGL_WINDOW_BIT,
848                         &xdri_config->Base, attrib_list)) {
849       free(xdri_surf);
850       return EGL_FALSE;
851    }
852
853    if (!XF86DRICreateDrawable(disp->Xdpy, scrn, window, &xdri_surf->hDrawable)) {
854       free(xdri_surf);
855       return EGL_FALSE;
856    }
857
858    xdri_surf->driDrawable = window;
859
860    _eglLinkSurface(&xdri_surf->Base, disp);
861
862    get_drawable_size(disp->Xdpy, window, &width, &height);
863    xdri_surf->Base.Width = width;
864    xdri_surf->Base.Height = height;
865
866    _eglLog(_EGL_DEBUG,
867            "XDRI: CreateWindowSurface win 0x%x  handle %d  hDrawable %d",
868            (int) window, _eglGetSurfaceHandle(&xdri_surf->Base),
869            (int) xdri_surf->hDrawable);
870
871    return _eglGetSurfaceHandle(&xdri_surf->Base);
872 }
873
874
875 /**
876  * Called via eglCreatePbufferSurface(), drv->API.CreatePbufferSurface().
877  */
878 static EGLSurface
879 xdri_eglCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
880                              const EGLint *attrib_list)
881 {
882    _EGLDisplay *disp = _eglLookupDisplay(dpy);
883    struct xdri_egl_surface *xdri_surf;
884    struct xdri_egl_config *xdri_config = lookup_config(drv, dpy, config);
885    int scrn = DefaultScreen(disp->Xdpy);
886    Window window;
887
888    xdri_surf = CALLOC_STRUCT(xdri_egl_surface);
889    if (!xdri_surf)
890       return EGL_NO_SURFACE;
891
892    if (!_eglInitSurface(drv, &xdri_surf->Base, EGL_PBUFFER_BIT,
893                         &xdri_config->Base, attrib_list)) {
894       free(xdri_surf);
895       return EGL_FALSE;
896    }
897
898    /* Create a dummy X window */
899    {
900       Window root = RootWindow(disp->Xdpy, scrn);
901       XSetWindowAttributes attr;
902       XVisualInfo *visInfo, visTemplate;
903       unsigned mask;
904       int nvis;
905
906       visTemplate.visualid = xdri_config->mode->visualID;
907       visInfo = XGetVisualInfo(disp->Xdpy, VisualIDMask, &visTemplate, &nvis);
908       if (!visInfo) {
909          return EGL_NO_SURFACE;
910       }
911
912       attr.background_pixel = 0;
913       attr.border_pixel = 0;
914       attr.colormap = XCreateColormap(disp->Xdpy, root,
915                                       visInfo->visual, AllocNone);
916       attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
917       mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
918       
919       window = XCreateWindow(disp->Xdpy, root, 0, 0,
920                              xdri_surf->Base.Width, xdri_surf->Base.Height,
921                              0, visInfo->depth, InputOutput,
922                              visInfo->visual, mask, &attr);
923
924       /*XMapWindow(disp->Xdpy, window);*/
925       XFree(visInfo);
926
927       /* set hints and properties */
928       /*
929       sizehints.width = xdri_surf->Base.Width;
930       sizehints.height = xdri_surf->Base.Height;
931       sizehints.flags = USPosition;
932       XSetNormalHints(disp->Xdpy, window, &sizehints);
933       */
934    }
935
936    if (!XF86DRICreateDrawable(disp->Xdpy, scrn, window, &xdri_surf->hDrawable)) {
937       free(xdri_surf);
938       return EGL_FALSE;
939    }
940
941    xdri_surf->driDrawable = window;
942
943    _eglLinkSurface(&xdri_surf->Base, disp);
944
945    _eglLog(_EGL_DEBUG,
946            "XDRI: CreatePbufferSurface handle %d  hDrawable %d",
947            _eglGetSurfaceHandle(&xdri_surf->Base),
948            (int) xdri_surf->hDrawable);
949
950    return _eglGetSurfaceHandle(&xdri_surf->Base);
951 }
952
953
954
955 static EGLBoolean
956 xdri_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
957 {
958    struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
959    if (xdri_surf) {
960       _eglUnlinkSurface(&xdri_surf->Base);
961       if (xdri_surf->Base.IsBound) {
962          xdri_surf->Base.DeletePending = EGL_TRUE;
963       }
964       else {
965          /*
966          st_unreference_framebuffer(surf->Framebuffer);
967          */
968          free(xdri_surf);
969       }
970       return EGL_TRUE;
971    }
972    else {
973       _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
974       return EGL_FALSE;
975    }
976 }
977
978
979 static EGLBoolean
980 xdri_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
981                      EGLint buffer)
982 {
983    typedef int (*bind_teximage)(__DRInativeDisplay *dpy,
984                                 __DRIid surface, __DRIscreen *psc,
985                                 int buffer, int target, int format,
986                                 int level, int mipmap);
987
988    bind_teximage egl_dri_bind_teximage;
989
990    _EGLDisplay *disp = _eglLookupDisplay(dpy);
991
992    struct xdri_egl_context *xdri_ctx = current_context();
993    struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
994    struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
995
996    __DRIid dri_surf = xdri_surf ? xdri_surf->driDrawable : 0;
997
998    __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs;
999    __DRIscreen *psc = &scrnConf->driScreen;
1000
1001    /* this call just does error checking */
1002    if (!_eglBindTexImage(drv, dpy, surface, buffer)) {
1003       return EGL_FALSE;
1004    }
1005
1006    egl_dri_bind_teximage =
1007       (bind_teximage) dlsym(NULL, "egl_dri_bind_teximage");
1008    if (egl_dri_bind_teximage) {
1009       return egl_dri_bind_teximage(disp->Xdpy, dri_surf, psc,
1010                                    buffer,
1011                                    xdri_surf->Base.TextureTarget,
1012                                    xdri_surf->Base.TextureFormat,
1013                                    xdri_surf->Base.MipmapLevel,
1014                                    xdri_surf->Base.MipmapTexture);
1015    }
1016    else {
1017       /* fallback path based on glCopyTexImage() */
1018       /* Get/save currently bound 2D texobj name */
1019       glGetIntegerv_t glGetIntegerv_func = 
1020          (glGetIntegerv_t) dlsym(NULL, "glGetIntegerv");
1021       GLint curTexObj = 0;
1022       if (glGetIntegerv_func) {
1023          (*glGetIntegerv_func)(GL_TEXTURE_BINDING_2D, &curTexObj);
1024       }
1025       xdri_ctx->bound_tex_object = curTexObj;
1026    }
1027
1028    return EGL_FALSE;
1029 }
1030
1031
1032 static EGLBoolean
1033 xdri_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
1034                         EGLint buffer)
1035 {
1036    typedef int (*release_teximage)(__DRInativeDisplay *dpy,
1037                                    __DRIid surface, __DRIscreen *psc,
1038                                    int buffer, int target, int format,
1039                                    int level, int mipmap);
1040    release_teximage egl_dri_release_teximage;
1041
1042    _EGLDisplay *disp = _eglLookupDisplay(dpy);
1043
1044    struct xdri_egl_context *xdri_ctx = current_context();
1045    struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
1046    struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
1047
1048    __DRIid dri_surf = xdri_surf ? xdri_surf->driDrawable : 0;
1049
1050    __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs;
1051    __DRIscreen *psc = &scrnConf->driScreen;
1052
1053    /* this call just does error checking */
1054    if (!_eglReleaseTexImage(drv, dpy, surface, buffer)) {
1055       return EGL_FALSE;
1056    }
1057
1058    egl_dri_release_teximage =
1059       (release_teximage) dlsym(NULL, "egl_dri_release_teximage");
1060    if (egl_dri_release_teximage) {
1061       return egl_dri_release_teximage(disp->Xdpy, dri_surf, psc,
1062                                       buffer,
1063                                       xdri_surf->Base.TextureTarget,
1064                                       xdri_surf->Base.TextureFormat,
1065                                       xdri_surf->Base.MipmapLevel,
1066                                       xdri_surf->Base.MipmapTexture);
1067    }
1068    else {
1069       /* fallback path based on glCopyTexImage() */
1070       glGetIntegerv_t glGetIntegerv_func = 
1071          (glGetIntegerv_t) dlsym(NULL, "glGetIntegerv");
1072       glBindTexture_t glBindTexture_func = 
1073          (glBindTexture_t) dlsym(NULL, "glBindTexture");
1074       glCopyTexImage2D_t glCopyTexImage2D_func = 
1075          (glCopyTexImage2D_t) dlsym(NULL, "glCopyTexImage2D");
1076       GLint curTexObj;
1077       GLenum intFormat;
1078       GLint level, width, height;
1079
1080       if (xdri_surf->Base.TextureFormat == EGL_TEXTURE_RGBA)
1081          intFormat = GL_RGBA;
1082       else
1083          intFormat = GL_RGB;
1084       level = xdri_surf->Base.MipmapLevel;
1085       width = xdri_surf->Base.Width >> level;
1086       height = xdri_surf->Base.Height >> level;
1087
1088       if (width > 0 && height > 0 &&
1089           glGetIntegerv_func && glBindTexture_func && glCopyTexImage2D_func) {
1090          glGetIntegerv_func(GL_TEXTURE_BINDING_2D, &curTexObj);
1091          /* restore texobj from time of eglBindTexImage() call */
1092          if (curTexObj != xdri_ctx->bound_tex_object)
1093             glBindTexture_func(GL_TEXTURE_2D, xdri_ctx->bound_tex_object);
1094          /* copy pbuffer image to texture */
1095          glCopyTexImage2D_func(GL_TEXTURE_2D,
1096                                level,
1097                                intFormat,
1098                                0, 0, width, height, 0);
1099          /* restore current texture */
1100          if (curTexObj != xdri_ctx->bound_tex_object)
1101             glBindTexture_func(GL_TEXTURE_2D, curTexObj);
1102       }
1103       xdri_ctx->bound_tex_object = -1;
1104    }
1105
1106    return EGL_FALSE;
1107 }
1108
1109
1110 static EGLBoolean
1111 xdri_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
1112 {
1113    _EGLDisplay *disp = _eglLookupDisplay(dpy);
1114
1115    _eglLog(_EGL_DEBUG, "XDRI: EGL SwapBuffers");
1116
1117    /* error checking step: */
1118    if (!_eglSwapBuffers(drv, dpy, draw))
1119       return EGL_FALSE;
1120
1121    {
1122       struct xdri_egl_surface *xdri_surf = lookup_surface(draw);
1123       struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
1124       __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs;
1125       __DRIscreen *psc = &scrnConf->driScreen;
1126       __DRIdrawable * const pdraw = psc->getDrawable(disp->Xdpy,
1127                                                      xdri_surf->driDrawable,
1128                                                      psc->private);
1129
1130       if (pdraw)
1131          pdraw->swapBuffers(disp->Xdpy, pdraw->private);
1132       else
1133          _eglLog(_EGL_WARNING, "pdraw is null in SwapBuffers");
1134    }
1135
1136    return EGL_TRUE;
1137 }
1138
1139
1140 /**
1141  * This is the main entrypoint into the driver, called by libEGL.
1142  * Create a new _EGLDriver object and init its dispatch table.
1143  */
1144 _EGLDriver *
1145 _eglMain(_EGLDisplay *disp, const char *args)
1146 {
1147    struct xdri_egl_driver *xdri_drv = CALLOC_STRUCT(xdri_egl_driver);
1148    if (!xdri_drv)
1149       return NULL;
1150
1151    /* Tell libGL to prefer the EGL drivers over regular DRI drivers */
1152    __glXPreferEGL(1);
1153
1154    _eglInitDriverFallbacks(&xdri_drv->Base);
1155    xdri_drv->Base.API.Initialize = xdri_eglInitialize;
1156    xdri_drv->Base.API.Terminate = xdri_eglTerminate;
1157
1158    xdri_drv->Base.API.GetProcAddress = xdri_eglGetProcAddress;
1159
1160    xdri_drv->Base.API.CreateContext = xdri_eglCreateContext;
1161    xdri_drv->Base.API.MakeCurrent = xdri_eglMakeCurrent;
1162    xdri_drv->Base.API.CreateWindowSurface = xdri_eglCreateWindowSurface;
1163    xdri_drv->Base.API.CreatePbufferSurface = xdri_eglCreatePbufferSurface;
1164    xdri_drv->Base.API.DestroySurface = xdri_eglDestroySurface;
1165    xdri_drv->Base.API.BindTexImage = xdri_eglBindTexImage;
1166    xdri_drv->Base.API.ReleaseTexImage = xdri_eglReleaseTexImage;
1167    xdri_drv->Base.API.SwapBuffers = xdri_eglSwapBuffers;
1168
1169    xdri_drv->Base.ClientAPIsMask = (EGL_OPENGL_BIT |
1170                                     EGL_OPENGL_ES_BIT |
1171                                     EGL_OPENGL_ES2_BIT |
1172                                     EGL_OPENVG_BIT);
1173    xdri_drv->Base.Name = "X/DRI";
1174
1175    _eglLog(_EGL_DEBUG, "XDRI: main(%s)", args);
1176
1177    return &xdri_drv->Base;
1178 }