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