egl: eglGetProcAddress() stub
[profile/ivi/mesa.git] / src / gallium / winsys / egl_xlib / egl_xlib.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  * EGL / softpipe / xlib winsys module
30  *
31  * Authors: Brian Paul
32  */
33
34
35 #include <X11/Xutil.h>
36
37 #include "pipe/p_compiler.h"
38 #include "pipe/p_format.h"
39 #include "pipe/p_state.h"
40 #include "pipe/p_util.h"
41 #include "pipe/p_winsys.h"
42 #include "softpipe/sp_winsys.h"
43
44 #include "eglconfig.h"
45 #include "eglconfigutil.h"
46 #include "eglcontext.h"
47 #include "egldisplay.h"
48 #include "egldriver.h"
49 #include "eglglobals.h"
50 #include "egllog.h"
51 #include "eglsurface.h"
52
53 #include "state_tracker/st_public.h"
54
55 #include "sw_winsys.h"
56
57
58 /** subclass of _EGLDriver */
59 struct xlib_egl_driver
60 {
61    _EGLDriver Base;   /**< base class */
62
63    struct pipe_winsys *winsys;
64    struct pipe_screen *screen;
65 };
66
67
68 /** subclass of _EGLContext */
69 struct xlib_egl_context
70 {
71    _EGLContext Base;   /**< base class */
72
73    struct pipe_context *pipe;   /**< Gallium driver context */
74    struct st_context *Context;  /**< Mesa/gallium state tracker context */
75 };
76
77
78 /** subclass of _EGLSurface */
79 struct xlib_egl_surface
80 {
81    _EGLSurface Base;   /**< base class */
82
83    Display *Dpy;  /**< The X Display of the window */
84    Window Win;    /**< The user-created window ID */
85    GC Gc;
86    XVisualInfo VisInfo;
87
88    struct pipe_winsys *winsys;
89
90    struct st_framebuffer *Framebuffer;
91 };
92
93
94 /** cast wrapper */
95 static INLINE struct xlib_egl_driver *
96 xlib_egl_driver(_EGLDriver *drv)
97 {
98    return (struct xlib_egl_driver *) drv;
99 }
100
101
102 static struct xlib_egl_surface *
103 lookup_surface(EGLSurface surf)
104 {
105    _EGLSurface *surface = _eglLookupSurface(surf);
106    return (struct xlib_egl_surface *) surface;
107 }
108
109
110 static struct xlib_egl_context *
111 lookup_context(EGLContext surf)
112 {
113    _EGLContext *context = _eglLookupContext(surf);
114    return (struct xlib_egl_context *) context;
115 }
116
117
118 /**
119  * XXX temporary
120  * Need to query X server's GLX visuals.
121  */
122 static void
123 init_configs(_EGLDriver *drv, EGLDisplay dpy)
124 {
125    _EGLDisplay *disp = _eglLookupDisplay(dpy);
126    int i;
127
128    for (i = 0; i < 2; i++) {
129       _EGLConfig config;
130       int id = i + 1;
131       _eglInitConfig(&config, id);
132       SET_CONFIG_ATTRIB(&config, EGL_RED_SIZE, 8);
133       SET_CONFIG_ATTRIB(&config, EGL_GREEN_SIZE, 8);
134       SET_CONFIG_ATTRIB(&config, EGL_BLUE_SIZE, 8);
135       SET_CONFIG_ATTRIB(&config, EGL_ALPHA_SIZE, 8);
136       if (i > 0) {
137          SET_CONFIG_ATTRIB(&config, EGL_DEPTH_SIZE, 24);
138          SET_CONFIG_ATTRIB(&config, EGL_STENCIL_SIZE, 8);
139       }
140       _eglAddConfig(disp, &config);
141    }
142 }
143
144
145
146 /**
147  * Called via eglInitialize(), drv->API.Initialize().
148  */
149 static EGLBoolean
150 xlib_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
151                    EGLint *minor, EGLint *major)
152 {
153    /* visual configs */
154
155    init_configs(drv, dpy);
156
157
158    drv->Initialized = EGL_TRUE;
159
160    /* we're supporting EGL 1.4 */
161    *minor = 1;
162    *major = 4;
163
164    return EGL_TRUE;
165 }
166
167
168 /**
169  * Called via eglTerminate(), drv->API.Terminate().
170  */
171 static EGLBoolean
172 xlib_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
173 {
174
175    return EGL_TRUE;
176 }
177
178
179 static _EGLProc
180 xlib_eglGetProcAddress(const char *procname)
181 {
182    /* XXX for each supported API, evaluate GetProcAddress(name) */
183    /*
184    return _glapi_get_proc_address(procname);
185    */
186    return NULL;
187 }
188
189
190 static void
191 get_drawable_visual_info(Display *dpy, Drawable d, XVisualInfo *visInfo)
192 {
193    XWindowAttributes attr;
194    XVisualInfo visTemp, *vis;
195    int num_visuals;
196
197    XGetWindowAttributes(dpy, d, &attr);
198
199    visTemp.screen = DefaultScreen(dpy);
200    visTemp.visualid = attr.visual->visualid;
201    vis = XGetVisualInfo(dpy,
202                         (VisualScreenMask | VisualIDMask),
203                         &visTemp, &num_visuals);
204    if (vis)
205       *visInfo = *vis;
206
207    XFree(vis);
208 }
209
210
211
212 /** Get size of given window */
213 static Status
214 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
215 {
216    Window root;
217    Status stat;
218    int xpos, ypos;
219    unsigned int w, h, bw, depth;
220    stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
221    *width = w;
222    *height = h;
223    return stat;
224 }
225
226
227 static void
228 check_and_update_buffer_size(struct xlib_egl_surface *surface)
229 {
230    uint width, height;
231    get_drawable_size(surface->Dpy, surface->Win, &width, &height);
232    st_resize_framebuffer(surface->Framebuffer, width, height);
233    surface->Base.Width = width;
234    surface->Base.Height = height;
235 }
236
237
238
239 static void
240 display_surface(struct pipe_winsys *pws,
241                 struct pipe_surface *psurf,
242                 struct xlib_egl_surface *xsurf)
243 {
244    XImage *ximage;
245    void *data;
246
247    ximage = XCreateImage(xsurf->Dpy,
248                          xsurf->VisInfo.visual,
249                          xsurf->VisInfo.depth,
250                          ZPixmap, 0,   /* format, offset */
251                          NULL,         /* data */
252                          0, 0,         /* size */
253                          32,           /* bitmap_pad */
254                          0);           /* bytes_per_line */
255
256
257    assert(ximage->format);
258    assert(ximage->bitmap_unit);
259
260    data = pws->buffer_map(pws, psurf->buffer, 0);
261
262    /* update XImage's fields */
263    ximage->data = data;
264    ximage->width = psurf->width;
265    ximage->height = psurf->height;
266    ximage->bytes_per_line = psurf->pitch * psurf->cpp;
267    
268    XPutImage(xsurf->Dpy, xsurf->Win, xsurf->Gc,
269              ximage, 0, 0, 0, 0, psurf->width, psurf->height);
270
271    XSync(xsurf->Dpy, 0);
272
273    ximage->data = NULL;
274    XDestroyImage(ximage);
275
276    pws->buffer_unmap(pws, psurf->buffer);
277 }
278
279
280
281 /** Display gallium surface in X window */
282 static void
283 flush_frontbuffer(struct pipe_winsys *pws,
284                   struct pipe_surface *psurf,
285                   void *context_private)
286 {
287    struct xlib_egl_surface *xsurf = (struct xlib_egl_surface *) context_private;
288    display_surface(pws, psurf, xsurf);
289 }
290
291
292
293 /**
294  * Called via eglCreateContext(), drv->API.CreateContext().
295  */
296 static EGLContext
297 xlib_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
298                       EGLContext share_list, const EGLint *attrib_list)
299 {
300    struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
301    _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
302    struct xlib_egl_context *ctx;
303    struct st_context *share_ctx = NULL; /* XXX fix */
304    __GLcontextModes visual;
305
306    ctx = CALLOC_STRUCT(xlib_egl_context);
307    if (!ctx)
308       return EGL_NO_CONTEXT;
309
310    /* let EGL lib init the common stuff */
311    if (!_eglInitContext(drv, dpy, &ctx->Base, config, attrib_list)) {
312       free(ctx);
313       return EGL_NO_CONTEXT;
314    }
315
316    if (ctx->Base.ClientAPI != EGL_OPENGL_API) {
317       _eglError(EGL_BAD_MATCH, "eglCreateContext(only OpenGL API supported)");
318       free(ctx);
319       return EGL_NO_CONTEXT;
320    }
321
322    /* create a softpipe context */
323    ctx->pipe = softpipe_create(xdrv->screen, xdrv->winsys, NULL);
324
325    /* Now do xlib / state tracker inits here */
326    _eglConfigToContextModesRec(conf, &visual);
327    ctx->Context = st_create_context(ctx->pipe, &visual, share_ctx);
328
329    _eglSaveContext(&ctx->Base);
330
331    return _eglGetContextHandle(&ctx->Base);
332 }
333
334
335 static EGLBoolean
336 xlib_eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx)
337 {
338    struct xlib_egl_context *context = lookup_context(ctx);
339    if (context) {
340       if (context->Base.IsBound) {
341          context->Base.DeletePending = EGL_TRUE;
342       }
343       else {
344          st_destroy_context(context->Context);
345          free(context);
346       }
347       return EGL_TRUE;
348    }
349    else {
350       _eglError(EGL_BAD_CONTEXT, "eglDestroyContext");
351       return EGL_TRUE;
352    }
353 }
354
355
356 /**
357  * Called via eglMakeCurrent(), drv->API.MakeCurrent().
358  */
359 static EGLBoolean
360 xlib_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy,
361                     EGLSurface draw, EGLSurface read, EGLContext ctx)
362 {
363    struct xlib_egl_context *context = lookup_context(ctx);
364    struct xlib_egl_surface *draw_surf = lookup_surface(draw);
365    struct xlib_egl_surface *read_surf = lookup_surface(read);
366
367    if (!_eglMakeCurrent(drv, dpy, draw, read, context))
368       return EGL_FALSE;
369
370    st_make_current((context ? context->Context : NULL),
371                    (draw_surf ? draw_surf->Framebuffer : NULL),
372                    (read_surf ? read_surf->Framebuffer : NULL));
373
374    check_and_update_buffer_size(draw_surf);
375
376    return EGL_TRUE;
377 }
378
379
380 static enum pipe_format
381 choose_color_format(const __GLcontextModes *visual)
382 {
383    if (visual->redBits == 8 &&
384        visual->greenBits == 8 &&
385        visual->blueBits == 8 &&
386        visual->alphaBits == 8) {
387       /* XXX this really also depends on the ordering of R,G,B,A */
388       return PIPE_FORMAT_A8R8G8B8_UNORM;
389    }
390    else {
391       assert(0);
392       return PIPE_FORMAT_NONE;
393    }
394 }
395
396
397 static enum pipe_format
398 choose_depth_format(const __GLcontextModes *visual)
399 {
400    if (visual->depthBits > 0)
401       return PIPE_FORMAT_S8Z24_UNORM;
402    else
403       return PIPE_FORMAT_NONE;
404 }
405
406
407 static enum pipe_format
408 choose_stencil_format(const __GLcontextModes *visual)
409 {
410    if (visual->stencilBits > 0)
411       return PIPE_FORMAT_S8Z24_UNORM;
412    else
413       return PIPE_FORMAT_NONE;
414 }
415
416
417 /**
418  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
419  */
420 static EGLSurface
421 xlib_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
422                             NativeWindowType window, const EGLint *attrib_list)
423 {
424    struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
425    _EGLDisplay *disp = _eglLookupDisplay(dpy);
426    _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
427
428    struct xlib_egl_surface *surf;
429    __GLcontextModes visual;
430    uint width, height;
431
432    surf = CALLOC_STRUCT(xlib_egl_surface);
433    if (!surf)
434       return EGL_NO_SURFACE;
435
436    /* Let EGL lib init the common stuff */
437    if (!_eglInitSurface(drv, dpy, &surf->Base, EGL_WINDOW_BIT,
438                         config, attrib_list)) {
439       free(surf);
440       return EGL_NO_SURFACE;
441    }
442
443    _eglSaveSurface(&surf->Base);
444
445    /*
446     * Now init the Xlib and gallium stuff
447     */
448    surf->Win = (Window) window;  /* The X window ID */
449    surf->Dpy = disp->Xdpy;  /* The X display */
450    surf->Gc = XCreateGC(surf->Dpy, surf->Win, 0, NULL);
451
452    surf->winsys = xdrv->winsys;
453
454    _eglConfigToContextModesRec(conf, &visual);
455    get_drawable_size(surf->Dpy, surf->Win, &width, &height);
456    get_drawable_visual_info(surf->Dpy, surf->Win, &surf->VisInfo);
457
458    surf->Base.Width = width;
459    surf->Base.Height = height;
460
461    /* Create GL statetracker framebuffer */
462    surf->Framebuffer = st_create_framebuffer(&visual,
463                                              choose_color_format(&visual),
464                                              choose_depth_format(&visual),
465                                              choose_stencil_format(&visual),
466                                              width, height,
467                                              (void *) surf);
468
469    st_resize_framebuffer(surf->Framebuffer, width, height);
470
471    return _eglGetSurfaceHandle(&surf->Base);
472 }
473
474
475 static EGLBoolean
476 xlib_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
477 {
478    struct xlib_egl_surface *surf = lookup_surface(surface);
479    if (surf) {
480       _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
481       if (surf->Base.IsBound) {
482          surf->Base.DeletePending = EGL_TRUE;
483       }
484       else {
485          st_unreference_framebuffer(&surf->Framebuffer);
486          free(surf);
487       }
488       return EGL_TRUE;
489    }
490    else {
491       _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
492       return EGL_FALSE;
493    }
494 }
495
496
497 static EGLBoolean
498 xlib_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
499 {
500    /* error checking step: */
501    if (!_eglSwapBuffers(drv, dpy, draw))
502       return EGL_FALSE;
503
504    {
505       struct xlib_egl_surface *xsurf = lookup_surface(draw);
506       struct pipe_winsys *pws = xsurf->winsys;
507       struct pipe_surface *psurf =
508          st_get_framebuffer_surface(xsurf->Framebuffer, ST_SURFACE_BACK_LEFT);
509
510       st_notify_swapbuffers(xsurf->Framebuffer);
511
512       display_surface(pws, psurf, xsurf);
513
514       check_and_update_buffer_size(xsurf);
515    }
516
517    return EGL_TRUE;
518 }
519
520
521 /**
522  * This is the main entrypoint into the driver.
523  * Called by libEGL to instantiate an _EGLDriver object.
524  */
525 _EGLDriver *
526 _eglMain(_EGLDisplay *dpy, const char *args)
527 {
528    struct xlib_egl_driver *xdrv;
529
530    _eglLog(_EGL_INFO, "Entering EGL/Xlib _eglMain(%s)", args);
531
532    xdrv = CALLOC_STRUCT(xlib_egl_driver);
533    if (!xdrv)
534       return NULL;
535
536    _eglInitDriverFallbacks(&xdrv->Base);
537    xdrv->Base.API.Initialize = xlib_eglInitialize;
538    xdrv->Base.API.Terminate = xlib_eglTerminate;
539    xdrv->Base.API.GetProcAddress = xlib_eglGetProcAddress;
540    xdrv->Base.API.CreateContext = xlib_eglCreateContext;
541    xdrv->Base.API.DestroyContext = xlib_eglDestroyContext;
542    xdrv->Base.API.CreateWindowSurface = xlib_eglCreateWindowSurface;
543    xdrv->Base.API.DestroySurface = xlib_eglDestroySurface;
544    xdrv->Base.API.MakeCurrent = xlib_eglMakeCurrent;
545    xdrv->Base.API.SwapBuffers = xlib_eglSwapBuffers;
546
547    xdrv->Base.ClientAPIsMask = EGL_OPENGL_BIT /*| EGL_OPENGL_ES_BIT*/;
548
549    xdrv->Base.Name = "Xlib/softpipe";
550
551    /* create one winsys and use it for all contexts/surfaces */
552    xdrv->winsys = create_sw_winsys();
553    xdrv->winsys->flush_frontbuffer = flush_frontbuffer;
554
555    xdrv->screen = softpipe_create_screen(xdrv->winsys);
556
557    return &xdrv->Base;
558 }
559