egl: fix-up window resizes
[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 void
180 get_drawable_visual_info(Display *dpy, Drawable d, XVisualInfo *visInfo)
181 {
182 XWindowAttributes attr;
183 XVisualInfo visTemp, *vis;
184 int num_visuals;
185
186 XGetWindowAttributes(dpy, d, &attr);
187
188 visTemp.screen = DefaultScreen(dpy);
189 visTemp.visualid = attr.visual->visualid;
190 vis = XGetVisualInfo(dpy,
191 (VisualScreenMask | VisualIDMask),
192 &visTemp, &num_visuals);
193 if (vis)
194 *visInfo = *vis;
195
196 XFree(vis);
197 }
198
199
200
201 /** Get size of given window */
202 static Status
203 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
204 {
205 Window root;
206 Status stat;
207 int xpos, ypos;
208 unsigned int w, h, bw, depth;
209 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
210 *width = w;
211 *height = h;
212 return stat;
213 }
214
215
216 static void
217 check_and_update_buffer_size(struct xlib_egl_surface *surface)
218 {
219 uint width, height;
220 get_drawable_size(surface->Dpy, surface->Win, &width, &height);
221 st_resize_framebuffer(surface->Framebuffer, width, height);
222 surface->Base.Width = width;
223 surface->Base.Height = height;
224 }
225
226
227
228 static void
229 display_surface(struct pipe_winsys *pws,
230 struct pipe_surface *psurf,
231 struct xlib_egl_surface *xsurf)
232 {
233 XImage *ximage;
234 void *data;
235
236 ximage = XCreateImage(xsurf->Dpy,
237 xsurf->VisInfo.visual,
238 xsurf->VisInfo.depth,
239 ZPixmap, 0, /* format, offset */
240 NULL, /* data */
241 0, 0, /* size */
242 32, /* bitmap_pad */
243 0); /* bytes_per_line */
244
245
246 assert(ximage->format);
247 assert(ximage->bitmap_unit);
248
249 data = pws->buffer_map(pws, psurf->buffer, 0);
250
251 /* update XImage's fields */
252 ximage->data = data;
253 ximage->width = psurf->width;
254 ximage->height = psurf->height;
255 ximage->bytes_per_line = psurf->pitch * psurf->cpp;
256
257 XPutImage(xsurf->Dpy, xsurf->Win, xsurf->Gc,
258 ximage, 0, 0, 0, 0, psurf->width, psurf->height);
259
260 XSync(xsurf->Dpy, 0);
261
262 ximage->data = NULL;
263 XDestroyImage(ximage);
264
265 pws->buffer_unmap(pws, psurf->buffer);
266 }
267
268
269
270 /** Display gallium surface in X window */
271 static void
272 flush_frontbuffer(struct pipe_winsys *pws,
273 struct pipe_surface *psurf,
274 void *context_private)
275 {
276 struct xlib_egl_surface *xsurf = (struct xlib_egl_surface *) context_private;
277 display_surface(pws, psurf, xsurf);
278 }
279
280
281
282 /**
283 * Called via eglCreateContext(), drv->API.CreateContext().
284 */
285 static EGLContext
286 xlib_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
287 EGLContext share_list, const EGLint *attrib_list)
288 {
289 struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
290 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
291 struct xlib_egl_context *ctx;
292 struct st_context *share_ctx = NULL; /* XXX fix */
293 __GLcontextModes visual;
294
295 ctx = CALLOC_STRUCT(xlib_egl_context);
296 if (!ctx)
297 return EGL_NO_CONTEXT;
298
299 /* let EGL lib init the common stuff */
300 if (!_eglInitContext(drv, dpy, &ctx->Base, config, attrib_list)) {
301 free(ctx);
302 return EGL_NO_CONTEXT;
303 }
304
305 /* create a softpipe context */
306 ctx->pipe = softpipe_create(xdrv->screen, xdrv->winsys, NULL);
307
308 /* Now do xlib / state tracker inits here */
309 _eglConfigToContextModesRec(conf, &visual);
310 ctx->Context = st_create_context(ctx->pipe, &visual, share_ctx);
311
312
313 return _eglGetContextHandle(&ctx->Base);
314 }
315
316
317 static EGLBoolean
318 xlib_eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx)
319 {
320 struct xlib_egl_context *context = lookup_context(ctx);
321 if (context) {
322 if (context->Base.IsBound) {
323 context->Base.DeletePending = EGL_TRUE;
324 }
325 else {
326 st_destroy_context(context->Context);
327 free(context);
328 }
329 return EGL_TRUE;
330 }
331 else {
332 _eglError(EGL_BAD_CONTEXT, "eglDestroyContext");
333 return EGL_TRUE;
334 }
335 }
336
337
338 /**
339 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
340 */
341 static EGLBoolean
342 xlib_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy,
343 EGLSurface draw, EGLSurface read, EGLContext ctx)
344 {
345 struct xlib_egl_context *context = lookup_context(ctx);
346 struct xlib_egl_surface *draw_surf = lookup_surface(draw);
347 struct xlib_egl_surface *read_surf = lookup_surface(read);
348
349 if (!_eglMakeCurrent(drv, dpy, draw, read, context))
350 return EGL_FALSE;
351
352 st_make_current((context ? context->Context : NULL),
353 (draw_surf ? draw_surf->Framebuffer : NULL),
354 (read_surf ? read_surf->Framebuffer : NULL));
355
356 check_and_update_buffer_size(draw_surf);
357
358 return EGL_TRUE;
359 }
360
361
362 static enum pipe_format
363 choose_color_format(const __GLcontextModes *visual)
364 {
365 if (visual->redBits == 8 &&
366 visual->greenBits == 8 &&
367 visual->blueBits == 8 &&
368 visual->alphaBits == 8) {
369 /* XXX this really also depends on the ordering of R,G,B,A */
370 return PIPE_FORMAT_A8R8G8B8_UNORM;
371 }
372 else {
373 assert(0);
374 return PIPE_FORMAT_NONE;
375 }
376 }
377
378
379 static enum pipe_format
380 choose_depth_format(const __GLcontextModes *visual)
381 {
382 if (visual->depthBits > 0)
383 return PIPE_FORMAT_S8Z24_UNORM;
384 else
385 return PIPE_FORMAT_NONE;
386 }
387
388
389 static enum pipe_format
390 choose_stencil_format(const __GLcontextModes *visual)
391 {
392 if (visual->stencilBits > 0)
393 return PIPE_FORMAT_S8Z24_UNORM;
394 else
395 return PIPE_FORMAT_NONE;
396 }
397
398
399 /**
400 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
401 */
402 static EGLSurface
403 xlib_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
404 NativeWindowType window, const EGLint *attrib_list)
405 {
406 struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
407 _EGLDisplay *disp = _eglLookupDisplay(dpy);
408 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
409
410 struct xlib_egl_surface *surf;
411 __GLcontextModes visual;
412 uint width, height;
413
414 surf = CALLOC_STRUCT(xlib_egl_surface);
415 if (!surf)
416 return EGL_NO_SURFACE;
417
418 /* Let EGL lib init the common stuff */
419 if (!_eglInitSurface(drv, dpy, &surf->Base, EGL_WINDOW_BIT,
420 config, attrib_list)) {
421 free(surf);
422 return EGL_NO_SURFACE;
423 }
424
425 _eglSaveSurface(&surf->Base);
426
427 /*
428 * Now init the Xlib and gallium stuff
429 */
430 surf->Win = (Window) window; /* The X window ID */
431 surf->Dpy = disp->Xdpy; /* The X display */
432 surf->Gc = XCreateGC(surf->Dpy, surf->Win, 0, NULL);
433
434 surf->winsys = xdrv->winsys;
435
436 _eglConfigToContextModesRec(conf, &visual);
437 get_drawable_size(surf->Dpy, surf->Win, &width, &height);
438 get_drawable_visual_info(surf->Dpy, surf->Win, &surf->VisInfo);
439
440 surf->Base.Width = width;
441 surf->Base.Height = height;
442
443 /* Create GL statetracker framebuffer */
444 surf->Framebuffer = st_create_framebuffer(&visual,
445 choose_color_format(&visual),
446 choose_depth_format(&visual),
447 choose_stencil_format(&visual),
448 width, height,
449 (void *) surf);
450
451 st_resize_framebuffer(surf->Framebuffer, width, height);
452
453 return _eglGetSurfaceHandle(&surf->Base);
454 }
455
456
457 static EGLBoolean
458 xlib_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
459 {
460 /* error checking step: */
461 if (!_eglSwapBuffers(drv, dpy, draw))
462 return EGL_FALSE;
463
464 {
465 struct xlib_egl_surface *xsurf = lookup_surface(draw);
466 struct pipe_winsys *pws = xsurf->winsys;
467 struct pipe_surface *psurf =
468 st_get_framebuffer_surface(xsurf->Framebuffer, ST_SURFACE_BACK_LEFT);
469
470 st_notify_swapbuffers(xsurf->Framebuffer);
471
472 display_surface(pws, psurf, xsurf);
473
474 check_and_update_buffer_size(xsurf);
475 }
476
477 return EGL_TRUE;
478 }
479
480
481 /**
482 * This is the main entrypoint into the driver.
483 * Called by libEGL to instantiate an _EGLDriver object.
484 */
485 _EGLDriver *
486 _eglMain(_EGLDisplay *dpy, const char *args)
487 {
488 struct xlib_egl_driver *xdrv;
489
490 _eglLog(_EGL_INFO, "Entering EGL/Xlib _eglMain(%s)", args);
491
492 xdrv = CALLOC_STRUCT(xlib_egl_driver);
493 if (!xdrv)
494 return NULL;
495
496 _eglInitDriverFallbacks(&xdrv->Base);
497 xdrv->Base.API.Initialize = xlib_eglInitialize;
498 xdrv->Base.API.Terminate = xlib_eglTerminate;
499 xdrv->Base.API.CreateContext = xlib_eglCreateContext;
500 xdrv->Base.API.DestroyContext = xlib_eglDestroyContext;
501 xdrv->Base.API.CreateWindowSurface = xlib_eglCreateWindowSurface;
502 xdrv->Base.API.MakeCurrent = xlib_eglMakeCurrent;
503 xdrv->Base.API.SwapBuffers = xlib_eglSwapBuffers;
504
505
506 xdrv->Base.ClientAPIs = "OpenGL"; /* "OpenGL_ES" */
507 xdrv->Base.Name = "Xlib/softpipe";
508
509 /* create one winsys and use it for all contexts/surfaces */
510 xdrv->winsys = create_sw_winsys();
511 xdrv->winsys->flush_frontbuffer = flush_frontbuffer;
512
513 xdrv->screen = softpipe_create_screen(xdrv->winsys);
514
515
516 return &xdrv->Base;
517 }
518