OSDN Git Service

518091a2d14b5b1b2447f31a75ffa9d5c1cdbb6e
[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 #include <assert.h>
43 #include <stdlib.h>
44 #include <X11/Xlib.h>
45
46 #include "glxinit.h"
47 #include "driinit.h"
48 #include "glapi/glapi.h" /* for glapi functions */
49
50 #include "eglconfig.h"
51 #include "eglcontext.h"
52 #include "egldisplay.h"
53 #include "egldriver.h"
54 #include "eglglobals.h"
55 #include "egllog.h"
56 #include "eglsurface.h"
57
58 #define CALLOC_STRUCT(T)   (struct T *) calloc(1, sizeof(struct T))
59
60 /** subclass of _EGLDriver */
61 struct xdri_egl_driver
62 {
63    _EGLDriver Base;   /**< base class */
64 };
65
66
67 /** driver data of _EGLDisplay */
68 struct xdri_egl_display
69 {
70    Display *dpy;
71    __GLXdisplayPrivate *dpyPriv;
72    __GLXDRIdisplay *driDisplay;
73
74    __GLXscreenConfigs *psc;
75    EGLint scr;
76 };
77
78
79 /** subclass of _EGLContext */
80 struct xdri_egl_context
81 {
82    _EGLContext Base;   /**< base class */
83
84    /* just enough info to create dri contexts */
85    GLXContext dummy_gc;
86
87    __GLXDRIcontext *driContext;
88 };
89
90
91 /** subclass of _EGLSurface */
92 struct xdri_egl_surface
93 {
94    _EGLSurface Base;   /**< base class */
95
96    Drawable drawable;
97    __GLXDRIdrawable *driDrawable;
98 };
99
100
101 /** subclass of _EGLConfig */
102 struct xdri_egl_config
103 {
104    _EGLConfig Base;   /**< base class */
105
106    const __GLcontextModes *mode;  /**< corresponding GLX mode */
107 };
108
109
110
111 /** cast wrapper */
112 static INLINE struct xdri_egl_driver *
113 xdri_egl_driver(_EGLDriver *drv)
114 {
115    return (struct xdri_egl_driver *) drv;
116 }
117
118
119 static INLINE struct xdri_egl_display *
120 lookup_display(_EGLDisplay *dpy)
121 {
122    return (struct xdri_egl_display *) dpy->DriverData;
123 }
124
125
126 /** Map EGLSurface handle to xdri_egl_surface object */
127 static INLINE struct xdri_egl_surface *
128 lookup_surface(_EGLSurface *surface)
129 {
130    return (struct xdri_egl_surface *) surface;
131 }
132
133
134 /** Map EGLContext handle to xdri_egl_context object */
135 static INLINE struct xdri_egl_context *
136 lookup_context(_EGLContext *context)
137 {
138    return (struct xdri_egl_context *) context;
139 }
140
141
142 /** Map EGLConfig handle to xdri_egl_config object */
143 static INLINE struct xdri_egl_config *
144 lookup_config(_EGLConfig *conf)
145 {
146    return (struct xdri_egl_config *) conf;
147 }
148
149
150 /** Get size of given window */
151 static Status
152 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
153 {
154    Window root;
155    Status stat;
156    int xpos, ypos;
157    unsigned int w, h, bw, depth;
158    stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
159    *width = w;
160    *height = h;
161    return stat;
162 }
163
164
165 /**
166  * Produce a set of EGL configs.
167  */
168 static EGLint
169 create_configs(_EGLDisplay *disp, const __GLcontextModes *m, EGLint first_id)
170 {
171    static const EGLint all_apis = (EGL_OPENGL_ES_BIT |
172                                    EGL_OPENGL_ES2_BIT |
173                                    EGL_OPENVG_BIT |
174                                    EGL_OPENGL_BIT);
175    int id = first_id;
176
177    for (; m; m = m->next) {
178       /* add double buffered visual */
179       if (m->doubleBufferMode) {
180          struct xdri_egl_config *config = CALLOC_STRUCT(xdri_egl_config);
181
182          _eglInitConfig(&config->Base, id++);
183
184          SET_CONFIG_ATTRIB(&config->Base, EGL_BUFFER_SIZE, m->rgbBits);
185          SET_CONFIG_ATTRIB(&config->Base, EGL_RED_SIZE, m->redBits);
186          SET_CONFIG_ATTRIB(&config->Base, EGL_GREEN_SIZE, m->greenBits);
187          SET_CONFIG_ATTRIB(&config->Base, EGL_BLUE_SIZE, m->blueBits);
188          SET_CONFIG_ATTRIB(&config->Base, EGL_ALPHA_SIZE, m->alphaBits);
189          SET_CONFIG_ATTRIB(&config->Base, EGL_DEPTH_SIZE, m->depthBits);
190          SET_CONFIG_ATTRIB(&config->Base, EGL_STENCIL_SIZE, m->stencilBits);
191          SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLES, m->samples);
192          SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLE_BUFFERS, m->sampleBuffers);
193          SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_ID, m->visualID);
194          SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_TYPE, m->visualType);
195          SET_CONFIG_ATTRIB(&config->Base, EGL_CONFORMANT, all_apis);
196          SET_CONFIG_ATTRIB(&config->Base, EGL_RENDERABLE_TYPE, all_apis);
197          SET_CONFIG_ATTRIB(&config->Base, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
198
199          /* XXX possibly other things to init... */
200
201          /* Ptr from EGL config to GLcontextMode.  Used in CreateContext(). */
202          config->mode = m;
203
204          _eglAddConfig(disp, &config->Base);
205       }
206    }
207
208    return id;
209 }
210
211
212 /**
213  * Called via eglInitialize(), xdri_dpy->API.Initialize().
214  */
215 static EGLBoolean
216 xdri_eglInitialize(_EGLDriver *drv, _EGLDisplay *dpy,
217                    EGLint *minor, EGLint *major)
218 {
219    struct xdri_egl_display *xdri_dpy;
220    __GLXdisplayPrivate *dpyPriv;
221    __GLXDRIdisplay *driDisplay;
222    __GLXscreenConfigs *psc;
223    EGLint first_id = 1;
224    int scr;
225
226    xdri_dpy = CALLOC_STRUCT(xdri_egl_display);
227    if (!xdri_dpy)
228       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
229
230    xdri_dpy->dpy = (Display *) dpy->NativeDisplay;
231    if (!xdri_dpy->dpy) {
232       xdri_dpy->dpy = XOpenDisplay(NULL);
233       if (!xdri_dpy->dpy) {
234          free(xdri_dpy);
235          return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
236       }
237    }
238
239    dpyPriv = __glXInitialize(xdri_dpy->dpy);
240    if (!dpyPriv) {
241       _eglLog(_EGL_WARNING, "failed to create GLX display");
242       free(xdri_dpy);
243       return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
244    }
245
246    driDisplay = __driCreateDisplay(dpyPriv, NULL);
247    if (!driDisplay) {
248       _eglLog(_EGL_WARNING, "failed to create DRI display");
249       free(xdri_dpy);
250       return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
251    }
252
253    scr = DefaultScreen(xdri_dpy->dpy);
254    psc = &dpyPriv->screenConfigs[scr];
255
256    xdri_dpy->dpyPriv = dpyPriv;
257    xdri_dpy->driDisplay = driDisplay;
258    xdri_dpy->psc = psc;
259    xdri_dpy->scr = scr;
260
261    psc->driScreen = driDisplay->createScreen(psc, scr, dpyPriv);
262    if (!psc->driScreen) {
263       _eglLog(_EGL_WARNING, "failed to create DRI screen #%d", scr);
264       free(xdri_dpy);
265       return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
266    }
267
268    /* add visuals and fbconfigs */
269    first_id = create_configs(dpy, psc->visuals, first_id);
270    create_configs(dpy, psc->configs, first_id);
271
272    dpy->DriverData = xdri_dpy;
273    dpy->ClientAPIsMask = (EGL_OPENGL_BIT |
274                           EGL_OPENGL_ES_BIT |
275                           EGL_OPENGL_ES2_BIT |
276                           EGL_OPENVG_BIT);
277
278    /* we're supporting EGL 1.4 */
279    *minor = 1;
280    *major = 4;
281
282    return EGL_TRUE;
283 }
284
285
286 /**
287  * Called via eglTerminate(), drv->API.Terminate().
288  */
289 static EGLBoolean
290 xdri_eglTerminate(_EGLDriver *drv, _EGLDisplay *dpy)
291 {
292    struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
293    __GLXscreenConfigs *psc;
294
295    _eglReleaseDisplayResources(drv, dpy);
296    _eglCleanupDisplay(dpy);
297
298    psc = xdri_dpy->psc;
299    if (psc->driver_configs) {
300       unsigned int i;
301       for (i = 0; psc->driver_configs[i]; i++)
302          free((__DRIconfig *) psc->driver_configs[i]);
303       free(psc->driver_configs);
304       psc->driver_configs = NULL;
305    }
306    if (psc->driScreen) {
307       psc->driScreen->destroyScreen(psc);
308       free(psc->driScreen);
309       psc->driScreen = NULL;
310    }
311
312    xdri_dpy->driDisplay->destroyDisplay(xdri_dpy->driDisplay);
313    __glXRelease(xdri_dpy->dpyPriv);
314
315    free(xdri_dpy);
316    dpy->DriverData = NULL;
317
318    return EGL_TRUE;
319 }
320
321
322 /*
323  * Called from eglGetProcAddress() via drv->API.GetProcAddress().
324  */
325 static _EGLProc
326 xdri_eglGetProcAddress(const char *procname)
327 {
328    /* the symbol is defined in libGL.so */
329    return (_EGLProc) _glapi_get_proc_address(procname);
330 }
331
332
333 /**
334  * Called via eglCreateContext(), drv->API.CreateContext().
335  */
336 static _EGLContext *
337 xdri_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
338                       _EGLContext *share_list, const EGLint *attrib_list)
339 {
340    struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
341    struct xdri_egl_config *xdri_config = lookup_config(conf);
342    struct xdri_egl_context *shared = lookup_context(share_list);
343    __GLXscreenConfigs *psc = xdri_dpy->psc;
344    int renderType = GLX_RGBA_BIT;
345    struct xdri_egl_context *xdri_ctx;
346
347    xdri_ctx = CALLOC_STRUCT(xdri_egl_context);
348    if (!xdri_ctx) {
349       _eglError(EGL_BAD_ALLOC, "eglCreateContext");
350       return NULL;
351    }
352
353    xdri_ctx->dummy_gc = CALLOC_STRUCT(__GLXcontextRec);
354    if (!xdri_ctx->dummy_gc) {
355       _eglError(EGL_BAD_ALLOC, "eglCreateContext");
356       free(xdri_ctx);
357       return NULL;
358    }
359
360    if (!_eglInitContext(drv, &xdri_ctx->Base, &xdri_config->Base, attrib_list)) {
361       free(xdri_ctx->dummy_gc);
362       free(xdri_ctx);
363       return NULL;
364    }
365
366    xdri_ctx->driContext =
367       psc->driScreen->createContext(psc,
368                                     xdri_config->mode,
369                                     xdri_ctx->dummy_gc,
370                                     (shared) ? shared->dummy_gc : NULL,
371                                     renderType);
372    if (!xdri_ctx->driContext) {
373       free(xdri_ctx->dummy_gc);
374       free(xdri_ctx);
375       return NULL;
376    }
377
378    /* fill in the required field */
379    xdri_ctx->dummy_gc->driContext = xdri_ctx->driContext;
380
381    return &xdri_ctx->Base;
382 }
383
384
385 static EGLBoolean
386 xdri_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
387 {
388    struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
389    struct xdri_egl_context *xdri_ctx = lookup_context(ctx);
390
391    if (!_eglIsContextBound(ctx)) {
392       xdri_ctx->driContext->destroyContext(xdri_ctx->driContext,
393                                            xdri_dpy->psc, xdri_dpy->dpy);
394       free(xdri_ctx->dummy_gc);
395       free(xdri_ctx);
396    }
397
398    return EGL_TRUE;
399 }
400
401
402 /**
403  * Called via eglMakeCurrent(), drv->API.MakeCurrent().
404  */
405 static EGLBoolean
406 xdri_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *d,
407                     _EGLSurface *r, _EGLContext *context)
408 {
409    struct xdri_egl_context *xdri_ctx = lookup_context(context);
410    struct xdri_egl_surface *draw = lookup_surface(d);
411    struct xdri_egl_surface *read = lookup_surface(r);
412
413    if (!_eglMakeCurrent(drv, dpy, d, r, context))
414       return EGL_FALSE;
415
416    /* the symbol is defined in libGL.so */
417    _glapi_check_multithread();
418
419    if (xdri_ctx) {
420       if (!xdri_ctx->driContext->bindContext(xdri_ctx->driContext,
421                                              draw->driDrawable,
422                                              read->driDrawable)) {
423          return EGL_FALSE;
424       }
425    }
426    else {
427       _EGLContext *old = _eglGetCurrentContext();
428       if (old) {
429          xdri_ctx = lookup_context(old);
430          xdri_ctx->driContext->unbindContext(xdri_ctx->driContext);
431       }
432    }
433
434    return EGL_TRUE;
435 }
436
437
438 /**
439  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
440  */
441 static _EGLSurface *
442 xdri_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
443                             NativeWindowType window, const EGLint *attrib_list)
444 {
445    struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
446    struct xdri_egl_config *xdri_config = lookup_config(conf);
447    struct xdri_egl_surface *xdri_surf;
448    uint width, height;
449
450    xdri_surf = CALLOC_STRUCT(xdri_egl_surface);
451    if (!xdri_surf) {
452       _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
453       return NULL;
454    }
455
456    if (!_eglInitSurface(drv, &xdri_surf->Base, EGL_WINDOW_BIT,
457                         &xdri_config->Base, attrib_list)) {
458       free(xdri_surf);
459       return NULL;
460    }
461
462    xdri_surf->driDrawable =
463       xdri_dpy->psc->driScreen->createDrawable(xdri_dpy->psc,
464                                                (XID) window,
465                                                (GLXDrawable) window,
466                                                xdri_config->mode);
467    if (!xdri_surf->driDrawable) {
468       free(xdri_surf);
469       return NULL;
470    }
471
472    xdri_surf->drawable = (Drawable) window;
473
474    get_drawable_size(xdri_dpy->dpy, window, &width, &height);
475    xdri_surf->Base.Width = width;
476    xdri_surf->Base.Height = height;
477
478    return &xdri_surf->Base;
479 }
480
481
482 /**
483  * Called via eglCreatePbufferSurface(), drv->API.CreatePbufferSurface().
484  */
485 static _EGLSurface *
486 xdri_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
487                              const EGLint *attrib_list)
488 {
489    return NULL;
490 }
491
492
493
494 static EGLBoolean
495 xdri_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface)
496 {
497    struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
498
499    if (!_eglIsSurfaceBound(&xdri_surf->Base)) {
500       xdri_surf->driDrawable->destroyDrawable(xdri_surf->driDrawable);
501       free(xdri_surf);
502    }
503
504    return EGL_TRUE;
505 }
506
507
508 static EGLBoolean
509 xdri_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
510                      EGLint buffer)
511 {
512    return EGL_FALSE;
513 }
514
515
516 static EGLBoolean
517 xdri_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
518                         EGLint buffer)
519 {
520    return EGL_FALSE;
521 }
522
523
524 static EGLBoolean
525 xdri_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw)
526 {
527    struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
528    struct xdri_egl_surface *xdri_surf = lookup_surface(draw);
529
530    xdri_dpy->psc->driScreen->swapBuffers(xdri_surf->driDrawable);
531
532    return EGL_TRUE;
533 }
534
535
536 static void
537 xdri_Unload(_EGLDriver *drv)
538 {
539    struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
540    free(xdri_drv);
541 }
542
543
544 /**
545  * This is the main entrypoint into the driver, called by libEGL.
546  * Create a new _EGLDriver object and init its dispatch table.
547  */
548 _EGLDriver *
549 _eglMain(const char *args)
550 {
551    struct xdri_egl_driver *xdri_drv = CALLOC_STRUCT(xdri_egl_driver);
552    if (!xdri_drv)
553       return NULL;
554
555    _eglInitDriverFallbacks(&xdri_drv->Base);
556    xdri_drv->Base.API.Initialize = xdri_eglInitialize;
557    xdri_drv->Base.API.Terminate = xdri_eglTerminate;
558
559    xdri_drv->Base.API.GetProcAddress = xdri_eglGetProcAddress;
560
561    xdri_drv->Base.API.CreateContext = xdri_eglCreateContext;
562    xdri_drv->Base.API.DestroyContext = xdri_eglDestroyContext;
563    xdri_drv->Base.API.MakeCurrent = xdri_eglMakeCurrent;
564    xdri_drv->Base.API.CreateWindowSurface = xdri_eglCreateWindowSurface;
565    xdri_drv->Base.API.CreatePbufferSurface = xdri_eglCreatePbufferSurface;
566    xdri_drv->Base.API.DestroySurface = xdri_eglDestroySurface;
567    xdri_drv->Base.API.BindTexImage = xdri_eglBindTexImage;
568    xdri_drv->Base.API.ReleaseTexImage = xdri_eglReleaseTexImage;
569    xdri_drv->Base.API.SwapBuffers = xdri_eglSwapBuffers;
570
571    xdri_drv->Base.Name = "X/DRI";
572    xdri_drv->Base.Unload = xdri_Unload;
573
574    return &xdri_drv->Base;
575 }