egl: added EGL_OPENVG_API case (allow all APIs)
[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 <dlfcn.h>
36 #include <X11/Xutil.h>
37
38 #include "pipe/p_compiler.h"
39 #include "pipe/p_format.h"
40 #include "pipe/p_state.h"
41 #include "pipe/p_util.h"
42 #include "pipe/p_winsys.h"
43 #include "softpipe/sp_winsys.h"
44
45 #include "eglconfig.h"
46 #include "eglconfigutil.h"
47 #include "eglcontext.h"
48 #include "egldisplay.h"
49 #include "egldriver.h"
50 #include "eglglobals.h"
51 #include "egllog.h"
52 #include "eglsurface.h"
53
54 #include "state_tracker/st_public.h"
55
56 #include "sw_winsys.h"
57
58
59 /** subclass of _EGLDriver */
60 struct xlib_egl_driver
61 {
62 _EGLDriver Base; /**< base class */
63
64 struct pipe_winsys *winsys;
65 struct pipe_screen *screen;
66 };
67
68
69 /** subclass of _EGLContext */
70 struct xlib_egl_context
71 {
72 _EGLContext Base; /**< base class */
73
74 struct pipe_context *pipe; /**< Gallium driver context */
75 struct st_context *Context; /**< Mesa/gallium state tracker context */
76 };
77
78
79 /** subclass of _EGLSurface */
80 struct xlib_egl_surface
81 {
82 _EGLSurface Base; /**< base class */
83
84 Display *Dpy; /**< The X Display of the window */
85 Window Win; /**< The user-created window ID */
86 GC Gc;
87 XVisualInfo VisInfo;
88
89 struct pipe_winsys *winsys;
90
91 struct st_framebuffer *Framebuffer;
92 };
93
94
95 /** cast wrapper */
96 static INLINE struct xlib_egl_driver *
97 xlib_egl_driver(_EGLDriver *drv)
98 {
99 return (struct xlib_egl_driver *) drv;
100 }
101
102
103 static struct xlib_egl_surface *
104 lookup_surface(EGLSurface surf)
105 {
106 _EGLSurface *surface = _eglLookupSurface(surf);
107 return (struct xlib_egl_surface *) surface;
108 }
109
110
111 static struct xlib_egl_context *
112 lookup_context(EGLContext surf)
113 {
114 _EGLContext *context = _eglLookupContext(surf);
115 return (struct xlib_egl_context *) context;
116 }
117
118
119 static unsigned int
120 bitcount(unsigned int n)
121 {
122 unsigned int bits;
123 for (bits = 0; n > 0; n = n >> 1) {
124 bits += (n & 1);
125 }
126 return bits;
127 }
128
129
130 /**
131 * Create the EGLConfigs. (one per X visual)
132 */
133 static void
134 create_configs(_EGLDriver *drv, EGLDisplay dpy)
135 {
136 static const EGLint all_apis = (EGL_OPENGL_ES_BIT |
137 EGL_OPENGL_ES2_BIT |
138 EGL_OPENVG_BIT |
139 EGL_OPENGL_BIT);
140 _EGLDisplay *disp = _eglLookupDisplay(dpy);
141 XVisualInfo *visInfo, visTemplate;
142 int num_visuals, i;
143
144 /* get list of all X visuals, create an EGL config for each */
145 visTemplate.screen = DefaultScreen(disp->Xdpy);
146 visInfo = XGetVisualInfo(disp->Xdpy, VisualScreenMask,
147 &visTemplate, &num_visuals);
148 if (!visInfo) {
149 printf("egl_xlib.c: couldn't get any X visuals\n");
150 abort();
151 }
152
153 for (i = 0; i < num_visuals; i++) {
154 _EGLConfig *config = calloc(1, sizeof(_EGLConfig));
155 int id = i + 1;
156 int rbits = bitcount(visInfo[i].red_mask);
157 int gbits = bitcount(visInfo[i].green_mask);
158 int bbits = bitcount(visInfo[i].blue_mask);
159 int abits = bbits == 8 ? 8 : 0;
160 int zbits = 24;
161 int sbits = 8;
162 int visid = visInfo[i].visualid;
163 #if defined(__cplusplus) || defined(c_plusplus)
164 int vistype = visInfo[i].c_class;
165 #else
166 int vistype = visInfo[i].class;
167 #endif
168
169 _eglInitConfig(config, id);
170 SET_CONFIG_ATTRIB(config, EGL_BUFFER_SIZE, rbits + gbits + bbits + abits);
171 SET_CONFIG_ATTRIB(config, EGL_RED_SIZE, rbits);
172 SET_CONFIG_ATTRIB(config, EGL_GREEN_SIZE, gbits);
173 SET_CONFIG_ATTRIB(config, EGL_BLUE_SIZE, bbits);
174 SET_CONFIG_ATTRIB(config, EGL_ALPHA_SIZE, abits);
175 SET_CONFIG_ATTRIB(config, EGL_DEPTH_SIZE, zbits);
176 SET_CONFIG_ATTRIB(config, EGL_STENCIL_SIZE, sbits);
177 SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_ID, visid);
178 SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_TYPE, vistype);
179 SET_CONFIG_ATTRIB(config, EGL_NATIVE_RENDERABLE, EGL_FALSE);
180 SET_CONFIG_ATTRIB(config, EGL_CONFORMANT, all_apis);
181 SET_CONFIG_ATTRIB(config, EGL_RENDERABLE_TYPE, all_apis);
182 SET_CONFIG_ATTRIB(config, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
183
184 _eglAddConfig(disp, config);
185 }
186 }
187
188
189 /**
190 * Called via eglInitialize(), drv->API.Initialize().
191 */
192 static EGLBoolean
193 xlib_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
194 EGLint *minor, EGLint *major)
195 {
196 create_configs(drv, dpy);
197
198 drv->Initialized = EGL_TRUE;
199
200 /* we're supporting EGL 1.4 */
201 *minor = 1;
202 *major = 4;
203
204 return EGL_TRUE;
205 }
206
207
208 /**
209 * Called via eglTerminate(), drv->API.Terminate().
210 */
211 static EGLBoolean
212 xlib_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
213 {
214 return EGL_TRUE;
215 }
216
217
218 static _EGLProc
219 xlib_eglGetProcAddress(const char *procname)
220 {
221 return (_EGLProc) st_get_proc_address(procname);
222 }
223
224
225 static void
226 get_drawable_visual_info(Display *dpy, Drawable d, XVisualInfo *visInfo)
227 {
228 XWindowAttributes attr;
229 XVisualInfo visTemp, *vis;
230 int num_visuals;
231
232 XGetWindowAttributes(dpy, d, &attr);
233
234 visTemp.screen = DefaultScreen(dpy);
235 visTemp.visualid = attr.visual->visualid;
236 vis = XGetVisualInfo(dpy,
237 (VisualScreenMask | VisualIDMask),
238 &visTemp, &num_visuals);
239 if (vis)
240 *visInfo = *vis;
241
242 XFree(vis);
243 }
244
245
246
247 /** Get size of given window */
248 static Status
249 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
250 {
251 Window root;
252 Status stat;
253 int xpos, ypos;
254 unsigned int w, h, bw, depth;
255 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
256 *width = w;
257 *height = h;
258 return stat;
259 }
260
261
262 static void
263 check_and_update_buffer_size(struct xlib_egl_surface *surface)
264 {
265 uint width, height;
266 get_drawable_size(surface->Dpy, surface->Win, &width, &height);
267 st_resize_framebuffer(surface->Framebuffer, width, height);
268 surface->Base.Width = width;
269 surface->Base.Height = height;
270 }
271
272
273
274 static void
275 display_surface(struct pipe_winsys *pws,
276 struct pipe_surface *psurf,
277 struct xlib_egl_surface *xsurf)
278 {
279 XImage *ximage;
280 void *data;
281
282 ximage = XCreateImage(xsurf->Dpy,
283 xsurf->VisInfo.visual,
284 xsurf->VisInfo.depth,
285 ZPixmap, 0, /* format, offset */
286 NULL, /* data */
287 0, 0, /* size */
288 32, /* bitmap_pad */
289 0); /* bytes_per_line */
290
291
292 assert(ximage->format);
293 assert(ximage->bitmap_unit);
294
295 data = pws->buffer_map(pws, psurf->buffer, 0);
296
297 /* update XImage's fields */
298 ximage->data = data;
299 ximage->width = psurf->width;
300 ximage->height = psurf->height;
301 ximage->bytes_per_line = psurf->stride;
302
303 XPutImage(xsurf->Dpy, xsurf->Win, xsurf->Gc,
304 ximage, 0, 0, 0, 0, psurf->width, psurf->height);
305
306 XSync(xsurf->Dpy, 0);
307
308 ximage->data = NULL;
309 XDestroyImage(ximage);
310
311 pws->buffer_unmap(pws, psurf->buffer);
312 }
313
314
315
316 /** Display gallium surface in X window */
317 static void
318 flush_frontbuffer(struct pipe_winsys *pws,
319 struct pipe_surface *psurf,
320 void *context_private)
321 {
322 struct xlib_egl_surface *xsurf = (struct xlib_egl_surface *) context_private;
323 display_surface(pws, psurf, xsurf);
324 }
325
326
327
328 /**
329 * Called via eglCreateContext(), drv->API.CreateContext().
330 */
331 static EGLContext
332 xlib_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
333 EGLContext share_list, const EGLint *attrib_list)
334 {
335 struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
336 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
337 struct xlib_egl_context *ctx;
338 struct st_context *share_ctx = NULL; /* XXX fix */
339 __GLcontextModes visual;
340
341 ctx = CALLOC_STRUCT(xlib_egl_context);
342 if (!ctx)
343 return EGL_NO_CONTEXT;
344
345 /* let EGL lib init the common stuff */
346 if (!_eglInitContext(drv, dpy, &ctx->Base, config, attrib_list)) {
347 free(ctx);
348 return EGL_NO_CONTEXT;
349 }
350
351 /* API-dependent context creation */
352 switch (ctx->Base.ClientAPI) {
353 case EGL_OPENVG_API:
354 case EGL_OPENGL_ES_API:
355 _eglLog(_EGL_DEBUG, "Create Context for ES version %d\n",
356 ctx->Base.ClientVersion);
357 /* fall-through */
358 case EGL_OPENGL_API:
359 /* create a softpipe context */
360 ctx->pipe = softpipe_create(xdrv->screen, xdrv->winsys, NULL);
361 /* Now do xlib / state tracker inits here */
362 _eglConfigToContextModesRec(conf, &visual);
363 ctx->Context = st_create_context(ctx->pipe, &visual, share_ctx);
364 break;
365 default:
366 _eglError(EGL_BAD_MATCH, "eglCreateContext(unsupported API)");
367 free(ctx);
368 return EGL_NO_CONTEXT;
369 }
370
371 _eglSaveContext(&ctx->Base);
372
373 return _eglGetContextHandle(&ctx->Base);
374 }
375
376
377 static EGLBoolean
378 xlib_eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx)
379 {
380 struct xlib_egl_context *context = lookup_context(ctx);
381 if (context) {
382 if (context->Base.IsBound) {
383 context->Base.DeletePending = EGL_TRUE;
384 }
385 else {
386 /* API-dependent clean-up */
387 switch (context->Base.ClientAPI) {
388 case EGL_OPENGL_ES_API:
389 /* fall-through */
390 case EGL_OPENGL_API:
391 st_destroy_context(context->Context);
392 break;
393 default:
394 assert(0);
395 }
396 free(context);
397 }
398 return EGL_TRUE;
399 }
400 else {
401 _eglError(EGL_BAD_CONTEXT, "eglDestroyContext");
402 return EGL_TRUE;
403 }
404 }
405
406
407 /**
408 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
409 */
410 static EGLBoolean
411 xlib_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy,
412 EGLSurface draw, EGLSurface read, EGLContext ctx)
413 {
414 struct xlib_egl_context *context = lookup_context(ctx);
415 struct xlib_egl_surface *draw_surf = lookup_surface(draw);
416 struct xlib_egl_surface *read_surf = lookup_surface(read);
417
418 if (!_eglMakeCurrent(drv, dpy, draw, read, context))
419 return EGL_FALSE;
420
421 st_make_current((context ? context->Context : NULL),
422 (draw_surf ? draw_surf->Framebuffer : NULL),
423 (read_surf ? read_surf->Framebuffer : NULL));
424
425 if (draw_surf)
426 check_and_update_buffer_size(draw_surf);
427 if (read_surf && read_surf != draw_surf)
428 check_and_update_buffer_size(draw_surf);
429
430 return EGL_TRUE;
431 }
432
433
434 static enum pipe_format
435 choose_color_format(const __GLcontextModes *visual)
436 {
437 if (visual->redBits == 8 &&
438 visual->greenBits == 8 &&
439 visual->blueBits == 8 &&
440 visual->alphaBits == 8) {
441 /* XXX this really also depends on the ordering of R,G,B,A */
442 return PIPE_FORMAT_A8R8G8B8_UNORM;
443 }
444 else {
445 assert(0);
446 return PIPE_FORMAT_NONE;
447 }
448 }
449
450
451 static enum pipe_format
452 choose_depth_format(const __GLcontextModes *visual)
453 {
454 if (visual->depthBits > 0)
455 return PIPE_FORMAT_S8Z24_UNORM;
456 else
457 return PIPE_FORMAT_NONE;
458 }
459
460
461 static enum pipe_format
462 choose_stencil_format(const __GLcontextModes *visual)
463 {
464 if (visual->stencilBits > 0)
465 return PIPE_FORMAT_S8Z24_UNORM;
466 else
467 return PIPE_FORMAT_NONE;
468 }
469
470
471 /**
472 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
473 */
474 static EGLSurface
475 xlib_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
476 NativeWindowType window, const EGLint *attrib_list)
477 {
478 struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
479 _EGLDisplay *disp = _eglLookupDisplay(dpy);
480 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
481
482 struct xlib_egl_surface *surf;
483 __GLcontextModes visual;
484 uint width, height;
485
486 surf = CALLOC_STRUCT(xlib_egl_surface);
487 if (!surf)
488 return EGL_NO_SURFACE;
489
490 /* Let EGL lib init the common stuff */
491 if (!_eglInitSurface(drv, dpy, &surf->Base, EGL_WINDOW_BIT,
492 config, attrib_list)) {
493 free(surf);
494 return EGL_NO_SURFACE;
495 }
496
497 _eglSaveSurface(&surf->Base);
498
499 /*
500 * Now init the Xlib and gallium stuff
501 */
502 surf->Win = (Window) window; /* The X window ID */
503 surf->Dpy = disp->Xdpy; /* The X display */
504 surf->Gc = XCreateGC(surf->Dpy, surf->Win, 0, NULL);
505
506 surf->winsys = xdrv->winsys;
507
508 _eglConfigToContextModesRec(conf, &visual);
509 get_drawable_size(surf->Dpy, surf->Win, &width, &height);
510 get_drawable_visual_info(surf->Dpy, surf->Win, &surf->VisInfo);
511
512 surf->Base.Width = width;
513 surf->Base.Height = height;
514
515 /* Create GL statetracker framebuffer */
516 surf->Framebuffer = st_create_framebuffer(&visual,
517 choose_color_format(&visual),
518 choose_depth_format(&visual),
519 choose_stencil_format(&visual),
520 width, height,
521 (void *) surf);
522
523 st_resize_framebuffer(surf->Framebuffer, width, height);
524
525 return _eglGetSurfaceHandle(&surf->Base);
526 }
527
528
529 static EGLBoolean
530 xlib_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
531 {
532 struct xlib_egl_surface *surf = lookup_surface(surface);
533 if (surf) {
534 _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
535 if (surf->Base.IsBound) {
536 surf->Base.DeletePending = EGL_TRUE;
537 }
538 else {
539 XFreeGC(surf->Dpy, surf->Gc);
540 st_unreference_framebuffer(&surf->Framebuffer);
541 free(surf);
542 }
543 return EGL_TRUE;
544 }
545 else {
546 _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
547 return EGL_FALSE;
548 }
549 }
550
551
552 static EGLBoolean
553 xlib_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
554 {
555 /* error checking step: */
556 if (!_eglSwapBuffers(drv, dpy, draw))
557 return EGL_FALSE;
558
559 {
560 struct xlib_egl_surface *xsurf = lookup_surface(draw);
561 struct pipe_winsys *pws = xsurf->winsys;
562 struct pipe_surface *psurf =
563 st_get_framebuffer_surface(xsurf->Framebuffer, ST_SURFACE_BACK_LEFT);
564
565 st_notify_swapbuffers(xsurf->Framebuffer);
566
567 display_surface(pws, psurf, xsurf);
568
569 check_and_update_buffer_size(xsurf);
570 }
571
572 return EGL_TRUE;
573 }
574
575
576 /**
577 * Determine which API(s) is(are) present by looking for some specific
578 * global symbols.
579 */
580 static EGLint
581 find_supported_apis(void)
582 {
583 EGLint mask = 0;
584 void *handle;
585
586 handle = dlopen(NULL, 0);
587
588 if (dlsym(handle, "st_api_OpenGL_ES1"))
589 mask |= EGL_OPENGL_ES_BIT;
590
591 if (dlsym(handle, "st_api_OpenGL_ES2"))
592 mask |= EGL_OPENGL_ES2_BIT;
593
594 if (dlsym(handle, "st_api_OpenGL"))
595 mask |= EGL_OPENGL_BIT;
596
597 if (dlsym(handle, "st_api_OpenVG"))
598 mask |= EGL_OPENVG_BIT;
599
600 dlclose(handle);
601
602 return mask;
603 }
604
605
606 /**
607 * This is the main entrypoint into the driver.
608 * Called by libEGL to instantiate an _EGLDriver object.
609 */
610 _EGLDriver *
611 _eglMain(_EGLDisplay *dpy, const char *args)
612 {
613 struct xlib_egl_driver *xdrv;
614
615 _eglLog(_EGL_INFO, "Entering EGL/Xlib _eglMain(%s)", args);
616
617 xdrv = CALLOC_STRUCT(xlib_egl_driver);
618 if (!xdrv)
619 return NULL;
620
621 if (!dpy->Xdpy) {
622 dpy->Xdpy = XOpenDisplay(NULL);
623 }
624
625 _eglInitDriverFallbacks(&xdrv->Base);
626 xdrv->Base.API.Initialize = xlib_eglInitialize;
627 xdrv->Base.API.Terminate = xlib_eglTerminate;
628 xdrv->Base.API.GetProcAddress = xlib_eglGetProcAddress;
629 xdrv->Base.API.CreateContext = xlib_eglCreateContext;
630 xdrv->Base.API.DestroyContext = xlib_eglDestroyContext;
631 xdrv->Base.API.CreateWindowSurface = xlib_eglCreateWindowSurface;
632 xdrv->Base.API.DestroySurface = xlib_eglDestroySurface;
633 xdrv->Base.API.MakeCurrent = xlib_eglMakeCurrent;
634 xdrv->Base.API.SwapBuffers = xlib_eglSwapBuffers;
635
636 xdrv->Base.ClientAPIsMask = find_supported_apis();
637 if (xdrv->Base.ClientAPIsMask == 0x0) {
638 /* the app isn't directly linked with any EGL-supprted APIs
639 * (such as libGLESv2.so) so use an EGL utility to see what
640 * APIs might be loaded dynamically on this system.
641 */
642 xdrv->Base.ClientAPIsMask = _eglFindAPIs();
643 }
644
645 xdrv->Base.Name = "Xlib/softpipe";
646
647 /* create one winsys and use it for all contexts/surfaces */
648 xdrv->winsys = create_sw_winsys();
649 xdrv->winsys->flush_frontbuffer = flush_frontbuffer;
650
651 xdrv->screen = softpipe_create_screen(xdrv->winsys);
652
653 return &xdrv->Base;
654 }
655