egl: open X display if needed
[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 static unsigned int
119 bitcount(unsigned int n)
120 {
121 unsigned int bits;
122 for (bits = 0; n > 0; n = n >> 1) {
123 bits += (n & 1);
124 }
125 return bits;
126 }
127
128
129 /**
130 * Create the EGLConfigs. (one per X visual)
131 */
132 static void
133 create_configs(_EGLDriver *drv, EGLDisplay dpy)
134 {
135 _EGLDisplay *disp = _eglLookupDisplay(dpy);
136 XVisualInfo *visInfo, visTemplate;
137 int num_visuals, i;
138
139 /* get list of all X visuals, create an EGL config for each */
140 visTemplate.screen = DefaultScreen(disp->Xdpy);
141 visInfo = XGetVisualInfo(disp->Xdpy, VisualScreenMask,
142 &visTemplate, &num_visuals);
143 if (!visInfo) {
144 printf("egl_xlib.c: couldn't get any X visuals\n");
145 abort();
146 }
147
148 for (i = 0; i < num_visuals; i++) {
149 _EGLConfig *config = calloc(1, sizeof(_EGLConfig));
150 int id = i + 1;
151 int rbits = bitcount(visInfo[i].red_mask);
152 int gbits = bitcount(visInfo[i].green_mask);
153 int bbits = bitcount(visInfo[i].blue_mask);
154 int abits = bbits == 8 ? 8 : 0;
155 int zbits = 24;
156 int sbits = 8;
157 int visid = visInfo[i].visualid;
158 #if defined(__cplusplus) || defined(c_plusplus)
159 int vistype = visInfo[i].c_class;
160 #else
161 int vistype = visInfo[i].class;
162 #endif
163
164 _eglInitConfig(config, id);
165 SET_CONFIG_ATTRIB(config, EGL_BUFFER_SIZE, rbits + gbits + bbits + abits);
166 SET_CONFIG_ATTRIB(config, EGL_RED_SIZE, rbits);
167 SET_CONFIG_ATTRIB(config, EGL_GREEN_SIZE, gbits);
168 SET_CONFIG_ATTRIB(config, EGL_BLUE_SIZE, bbits);
169 SET_CONFIG_ATTRIB(config, EGL_ALPHA_SIZE, abits);
170 SET_CONFIG_ATTRIB(config, EGL_DEPTH_SIZE, zbits);
171 SET_CONFIG_ATTRIB(config, EGL_STENCIL_SIZE, sbits);
172 SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_ID, visid);
173 SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_TYPE, vistype);
174
175 _eglAddConfig(disp, config);
176 }
177 }
178
179
180 /**
181 * Called via eglInitialize(), drv->API.Initialize().
182 */
183 static EGLBoolean
184 xlib_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
185 EGLint *minor, EGLint *major)
186 {
187 create_configs(drv, dpy);
188
189 drv->Initialized = EGL_TRUE;
190
191 /* we're supporting EGL 1.4 */
192 *minor = 1;
193 *major = 4;
194
195 return EGL_TRUE;
196 }
197
198
199 /**
200 * Called via eglTerminate(), drv->API.Terminate().
201 */
202 static EGLBoolean
203 xlib_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
204 {
205
206 return EGL_TRUE;
207 }
208
209
210 static _EGLProc
211 xlib_eglGetProcAddress(const char *procname)
212 {
213 /* XXX for each supported API, evaluate GetProcAddress(name) */
214 /*
215 return _glapi_get_proc_address(procname);
216 */
217 return NULL;
218 }
219
220
221 static void
222 get_drawable_visual_info(Display *dpy, Drawable d, XVisualInfo *visInfo)
223 {
224 XWindowAttributes attr;
225 XVisualInfo visTemp, *vis;
226 int num_visuals;
227
228 XGetWindowAttributes(dpy, d, &attr);
229
230 visTemp.screen = DefaultScreen(dpy);
231 visTemp.visualid = attr.visual->visualid;
232 vis = XGetVisualInfo(dpy,
233 (VisualScreenMask | VisualIDMask),
234 &visTemp, &num_visuals);
235 if (vis)
236 *visInfo = *vis;
237
238 XFree(vis);
239 }
240
241
242
243 /** Get size of given window */
244 static Status
245 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
246 {
247 Window root;
248 Status stat;
249 int xpos, ypos;
250 unsigned int w, h, bw, depth;
251 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
252 *width = w;
253 *height = h;
254 return stat;
255 }
256
257
258 static void
259 check_and_update_buffer_size(struct xlib_egl_surface *surface)
260 {
261 uint width, height;
262 get_drawable_size(surface->Dpy, surface->Win, &width, &height);
263 st_resize_framebuffer(surface->Framebuffer, width, height);
264 surface->Base.Width = width;
265 surface->Base.Height = height;
266 }
267
268
269
270 static void
271 display_surface(struct pipe_winsys *pws,
272 struct pipe_surface *psurf,
273 struct xlib_egl_surface *xsurf)
274 {
275 XImage *ximage;
276 void *data;
277
278 ximage = XCreateImage(xsurf->Dpy,
279 xsurf->VisInfo.visual,
280 xsurf->VisInfo.depth,
281 ZPixmap, 0, /* format, offset */
282 NULL, /* data */
283 0, 0, /* size */
284 32, /* bitmap_pad */
285 0); /* bytes_per_line */
286
287
288 assert(ximage->format);
289 assert(ximage->bitmap_unit);
290
291 data = pws->buffer_map(pws, psurf->buffer, 0);
292
293 /* update XImage's fields */
294 ximage->data = data;
295 ximage->width = psurf->width;
296 ximage->height = psurf->height;
297 ximage->bytes_per_line = psurf->pitch * psurf->cpp;
298
299 XPutImage(xsurf->Dpy, xsurf->Win, xsurf->Gc,
300 ximage, 0, 0, 0, 0, psurf->width, psurf->height);
301
302 XSync(xsurf->Dpy, 0);
303
304 ximage->data = NULL;
305 XDestroyImage(ximage);
306
307 pws->buffer_unmap(pws, psurf->buffer);
308 }
309
310
311
312 /** Display gallium surface in X window */
313 static void
314 flush_frontbuffer(struct pipe_winsys *pws,
315 struct pipe_surface *psurf,
316 void *context_private)
317 {
318 struct xlib_egl_surface *xsurf = (struct xlib_egl_surface *) context_private;
319 display_surface(pws, psurf, xsurf);
320 }
321
322
323
324 /**
325 * Called via eglCreateContext(), drv->API.CreateContext().
326 */
327 static EGLContext
328 xlib_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
329 EGLContext share_list, const EGLint *attrib_list)
330 {
331 struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
332 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
333 struct xlib_egl_context *ctx;
334 struct st_context *share_ctx = NULL; /* XXX fix */
335 __GLcontextModes visual;
336
337 ctx = CALLOC_STRUCT(xlib_egl_context);
338 if (!ctx)
339 return EGL_NO_CONTEXT;
340
341 /* let EGL lib init the common stuff */
342 if (!_eglInitContext(drv, dpy, &ctx->Base, config, attrib_list)) {
343 free(ctx);
344 return EGL_NO_CONTEXT;
345 }
346
347 /* API-dependent context creation */
348 switch (ctx->Base.ClientAPI) {
349 case EGL_OPENGL_API:
350 /* create a softpipe context */
351 ctx->pipe = softpipe_create(xdrv->screen, xdrv->winsys, NULL);
352 /* Now do xlib / state tracker inits here */
353 _eglConfigToContextModesRec(conf, &visual);
354 ctx->Context = st_create_context(ctx->pipe, &visual, share_ctx);
355 break;
356 default:
357 _eglError(EGL_BAD_MATCH, "eglCreateContext(unsupported API)");
358 free(ctx);
359 return EGL_NO_CONTEXT;
360 }
361
362 _eglSaveContext(&ctx->Base);
363
364 return _eglGetContextHandle(&ctx->Base);
365 }
366
367
368 static EGLBoolean
369 xlib_eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx)
370 {
371 struct xlib_egl_context *context = lookup_context(ctx);
372 if (context) {
373 if (context->Base.IsBound) {
374 context->Base.DeletePending = EGL_TRUE;
375 }
376 else {
377 /* API-dependent clean-up */
378 switch (context->Base.ClientAPI) {
379 case EGL_OPENGL_API:
380 st_destroy_context(context->Context);
381 break;
382 default:
383 assert(0);
384 }
385 free(context);
386 }
387 return EGL_TRUE;
388 }
389 else {
390 _eglError(EGL_BAD_CONTEXT, "eglDestroyContext");
391 return EGL_TRUE;
392 }
393 }
394
395
396 /**
397 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
398 */
399 static EGLBoolean
400 xlib_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy,
401 EGLSurface draw, EGLSurface read, EGLContext ctx)
402 {
403 struct xlib_egl_context *context = lookup_context(ctx);
404 struct xlib_egl_surface *draw_surf = lookup_surface(draw);
405 struct xlib_egl_surface *read_surf = lookup_surface(read);
406
407 if (!_eglMakeCurrent(drv, dpy, draw, read, context))
408 return EGL_FALSE;
409
410 st_make_current((context ? context->Context : NULL),
411 (draw_surf ? draw_surf->Framebuffer : NULL),
412 (read_surf ? read_surf->Framebuffer : NULL));
413
414 check_and_update_buffer_size(draw_surf);
415
416 return EGL_TRUE;
417 }
418
419
420 static enum pipe_format
421 choose_color_format(const __GLcontextModes *visual)
422 {
423 if (visual->redBits == 8 &&
424 visual->greenBits == 8 &&
425 visual->blueBits == 8 &&
426 visual->alphaBits == 8) {
427 /* XXX this really also depends on the ordering of R,G,B,A */
428 return PIPE_FORMAT_A8R8G8B8_UNORM;
429 }
430 else {
431 assert(0);
432 return PIPE_FORMAT_NONE;
433 }
434 }
435
436
437 static enum pipe_format
438 choose_depth_format(const __GLcontextModes *visual)
439 {
440 if (visual->depthBits > 0)
441 return PIPE_FORMAT_S8Z24_UNORM;
442 else
443 return PIPE_FORMAT_NONE;
444 }
445
446
447 static enum pipe_format
448 choose_stencil_format(const __GLcontextModes *visual)
449 {
450 if (visual->stencilBits > 0)
451 return PIPE_FORMAT_S8Z24_UNORM;
452 else
453 return PIPE_FORMAT_NONE;
454 }
455
456
457 /**
458 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
459 */
460 static EGLSurface
461 xlib_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
462 NativeWindowType window, const EGLint *attrib_list)
463 {
464 struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
465 _EGLDisplay *disp = _eglLookupDisplay(dpy);
466 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
467
468 struct xlib_egl_surface *surf;
469 __GLcontextModes visual;
470 uint width, height;
471
472 surf = CALLOC_STRUCT(xlib_egl_surface);
473 if (!surf)
474 return EGL_NO_SURFACE;
475
476 /* Let EGL lib init the common stuff */
477 if (!_eglInitSurface(drv, dpy, &surf->Base, EGL_WINDOW_BIT,
478 config, attrib_list)) {
479 free(surf);
480 return EGL_NO_SURFACE;
481 }
482
483 _eglSaveSurface(&surf->Base);
484
485 /*
486 * Now init the Xlib and gallium stuff
487 */
488 surf->Win = (Window) window; /* The X window ID */
489 surf->Dpy = disp->Xdpy; /* The X display */
490 surf->Gc = XCreateGC(surf->Dpy, surf->Win, 0, NULL);
491
492 surf->winsys = xdrv->winsys;
493
494 _eglConfigToContextModesRec(conf, &visual);
495 get_drawable_size(surf->Dpy, surf->Win, &width, &height);
496 get_drawable_visual_info(surf->Dpy, surf->Win, &surf->VisInfo);
497
498 surf->Base.Width = width;
499 surf->Base.Height = height;
500
501 /* Create GL statetracker framebuffer */
502 surf->Framebuffer = st_create_framebuffer(&visual,
503 choose_color_format(&visual),
504 choose_depth_format(&visual),
505 choose_stencil_format(&visual),
506 width, height,
507 (void *) surf);
508
509 st_resize_framebuffer(surf->Framebuffer, width, height);
510
511 return _eglGetSurfaceHandle(&surf->Base);
512 }
513
514
515 static EGLBoolean
516 xlib_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
517 {
518 struct xlib_egl_surface *surf = lookup_surface(surface);
519 if (surf) {
520 _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
521 if (surf->Base.IsBound) {
522 surf->Base.DeletePending = EGL_TRUE;
523 }
524 else {
525 st_unreference_framebuffer(&surf->Framebuffer);
526 free(surf);
527 }
528 return EGL_TRUE;
529 }
530 else {
531 _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
532 return EGL_FALSE;
533 }
534 }
535
536
537 static EGLBoolean
538 xlib_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
539 {
540 /* error checking step: */
541 if (!_eglSwapBuffers(drv, dpy, draw))
542 return EGL_FALSE;
543
544 {
545 struct xlib_egl_surface *xsurf = lookup_surface(draw);
546 struct pipe_winsys *pws = xsurf->winsys;
547 struct pipe_surface *psurf =
548 st_get_framebuffer_surface(xsurf->Framebuffer, ST_SURFACE_BACK_LEFT);
549
550 st_notify_swapbuffers(xsurf->Framebuffer);
551
552 display_surface(pws, psurf, xsurf);
553
554 check_and_update_buffer_size(xsurf);
555 }
556
557 return EGL_TRUE;
558 }
559
560
561 /**
562 * This is the main entrypoint into the driver.
563 * Called by libEGL to instantiate an _EGLDriver object.
564 */
565 _EGLDriver *
566 _eglMain(_EGLDisplay *dpy, const char *args)
567 {
568 struct xlib_egl_driver *xdrv;
569
570 _eglLog(_EGL_INFO, "Entering EGL/Xlib _eglMain(%s)", args);
571
572 xdrv = CALLOC_STRUCT(xlib_egl_driver);
573 if (!xdrv)
574 return NULL;
575
576 if (!dpy->Xdpy) {
577 dpy->Xdpy = XOpenDisplay(NULL);
578 }
579
580 _eglInitDriverFallbacks(&xdrv->Base);
581 xdrv->Base.API.Initialize = xlib_eglInitialize;
582 xdrv->Base.API.Terminate = xlib_eglTerminate;
583 xdrv->Base.API.GetProcAddress = xlib_eglGetProcAddress;
584 xdrv->Base.API.CreateContext = xlib_eglCreateContext;
585 xdrv->Base.API.DestroyContext = xlib_eglDestroyContext;
586 xdrv->Base.API.CreateWindowSurface = xlib_eglCreateWindowSurface;
587 xdrv->Base.API.DestroySurface = xlib_eglDestroySurface;
588 xdrv->Base.API.MakeCurrent = xlib_eglMakeCurrent;
589 xdrv->Base.API.SwapBuffers = xlib_eglSwapBuffers;
590
591 xdrv->Base.ClientAPIsMask = EGL_OPENGL_BIT /*| EGL_OPENGL_ES_BIT*/;
592
593 xdrv->Base.Name = "Xlib/softpipe";
594
595 /* create one winsys and use it for all contexts/surfaces */
596 xdrv->winsys = create_sw_winsys();
597 xdrv->winsys->flush_frontbuffer = flush_frontbuffer;
598
599 xdrv->screen = softpipe_create_screen(xdrv->winsys);
600
601 return &xdrv->Base;
602 }
603