Merge branch 'mesa_7_7_branch'
[mesa.git] / src / egl / drivers / xdri / egl_xdri.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 /**
30 * Code to interface a DRI driver to libEGL.
31 * Note that unlike previous DRI/EGL interfaces, this one is meant to
32 * be used _with_ X. Applications will use eglCreateWindowSurface()
33 * to render into X-created windows.
34 *
35 * This is an EGL driver that, in turn, loads a regular DRI driver.
36 * There are some dependencies on code in libGL, but those could be
37 * removed with some effort.
38 *
39 * Authors: Brian Paul
40 */
41
42 #include <assert.h>
43 #include <stdlib.h>
44 #include <X11/Xlib.h>
45
46 #include "glxinit.h"
47 #include "driinit.h"
48 #include "glapi/glapi.h" /* for glapi functions */
49
50 #include "eglconfig.h"
51 #include "eglconfigutil.h"
52 #include "eglcontext.h"
53 #include "egldisplay.h"
54 #include "egldriver.h"
55 #include "eglglobals.h"
56 #include "egllog.h"
57 #include "eglsurface.h"
58
59 #define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
60
61 /** subclass of _EGLDriver */
62 struct xdri_egl_driver
63 {
64 _EGLDriver Base; /**< base class */
65 void (*FlushCurrentContext)(void);
66 };
67
68
69 /** driver data of _EGLDisplay */
70 struct xdri_egl_display
71 {
72 Display *dpy;
73 __GLXdisplayPrivate *dpyPriv;
74 __GLXDRIdisplay *driDisplay;
75 int driVersion;
76
77 __GLXscreenConfigs *psc;
78 EGLint scr;
79 };
80
81
82 /** subclass of _EGLContext */
83 struct xdri_egl_context
84 {
85 _EGLContext Base; /**< base class */
86
87 /* just enough info to create dri contexts */
88 GLXContext dummy_gc;
89
90 __GLXDRIcontext *driContext;
91 };
92
93
94 /** subclass of _EGLSurface */
95 struct xdri_egl_surface
96 {
97 _EGLSurface Base; /**< base class */
98
99 Drawable drawable;
100 __GLXDRIdrawable *driDrawable;
101 };
102
103
104 /** subclass of _EGLConfig */
105 struct xdri_egl_config
106 {
107 _EGLConfig Base; /**< base class */
108
109 const __GLcontextModes *mode; /**< corresponding GLX mode */
110 EGLint window_render_buffer;
111 };
112
113
114
115 /** cast wrapper */
116 static INLINE struct xdri_egl_driver *
117 xdri_egl_driver(_EGLDriver *drv)
118 {
119 return (struct xdri_egl_driver *) drv;
120 }
121
122
123 static INLINE struct xdri_egl_display *
124 lookup_display(_EGLDisplay *dpy)
125 {
126 return (struct xdri_egl_display *) dpy->DriverData;
127 }
128
129
130 /** Map EGLSurface handle to xdri_egl_surface object */
131 static INLINE struct xdri_egl_surface *
132 lookup_surface(_EGLSurface *surface)
133 {
134 return (struct xdri_egl_surface *) surface;
135 }
136
137
138 /** Map EGLContext handle to xdri_egl_context object */
139 static INLINE struct xdri_egl_context *
140 lookup_context(_EGLContext *context)
141 {
142 return (struct xdri_egl_context *) context;
143 }
144
145
146 /** Map EGLConfig handle to xdri_egl_config object */
147 static INLINE struct xdri_egl_config *
148 lookup_config(_EGLConfig *conf)
149 {
150 return (struct xdri_egl_config *) conf;
151 }
152
153
154 /** Get size of given window */
155 static Status
156 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
157 {
158 Window root;
159 Status stat;
160 int xpos, ypos;
161 unsigned int w, h, bw, depth;
162 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
163 *width = w;
164 *height = h;
165 return stat;
166 }
167
168
169 static EGLBoolean
170 convert_config(_EGLConfig *conf, EGLint id, const __GLcontextModes *m)
171 {
172 EGLint val;
173
174 _eglInitConfig(conf, id);
175 if (!_eglConfigFromContextModesRec(conf, m, EGL_OPENGL_BIT, EGL_OPENGL_BIT))
176 return EGL_FALSE;
177
178 if (m->doubleBufferMode) {
179 /* pixmap and pbuffer surfaces are always single-buffered */
180 val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
181 val &= ~(EGL_PIXMAP_BIT | EGL_PBUFFER_BIT);
182 SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, val);
183 }
184 else {
185 /* EGL requires OpenGL ES context to be double-buffered */
186 val = GET_CONFIG_ATTRIB(conf, EGL_RENDERABLE_TYPE);
187 val &= ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT);
188 SET_CONFIG_ATTRIB(conf, EGL_RENDERABLE_TYPE, val);
189 }
190 /* skip "empty" config */
191 if (!val)
192 return EGL_FALSE;
193
194 val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
195 if (!(val & EGL_PBUFFER_BIT)) {
196 /* bind-to-texture cannot be EGL_TRUE without pbuffer bit */
197 SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE);
198 SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE);
199 }
200
201 /* EGL_NATIVE_RENDERABLE is a boolean */
202 val = GET_CONFIG_ATTRIB(conf, EGL_NATIVE_RENDERABLE);
203 if (val != EGL_TRUE)
204 SET_CONFIG_ATTRIB(conf, EGL_NATIVE_RENDERABLE, EGL_FALSE);
205
206 return _eglValidateConfig(conf, EGL_FALSE);
207 }
208
209
210 /**
211 * Produce a set of EGL configs.
212 */
213 static EGLint
214 create_configs(_EGLDisplay *disp, const __GLcontextModes *m, EGLint first_id)
215 {
216 struct xdri_egl_display *xdri_dpy = lookup_display(disp);
217 int id = first_id;
218
219 for (; m; m = m->next) {
220 struct xdri_egl_config *xdri_conf;
221 _EGLConfig conf;
222 EGLint rb;
223
224 if (!convert_config(&conf, id, m))
225 continue;
226 if (m->doubleBufferMode) {
227 rb = EGL_BACK_BUFFER;
228 }
229 else {
230 /* ignore single-buffered mode for DRISW */
231 if (xdri_dpy->driVersion == 0)
232 continue;
233 rb = EGL_SINGLE_BUFFER;
234 }
235
236 xdri_conf = CALLOC_STRUCT(xdri_egl_config);
237 if (xdri_conf) {
238 memcpy(&xdri_conf->Base, &conf, sizeof(conf));
239 xdri_conf->mode = m;
240 xdri_conf->window_render_buffer = rb;
241 _eglAddConfig(disp, &xdri_conf->Base);
242 id++;
243 }
244 }
245
246 return id;
247 }
248
249
250 /**
251 * Called via eglInitialize(), xdri_dpy->API.Initialize().
252 */
253 static EGLBoolean
254 xdri_eglInitialize(_EGLDriver *drv, _EGLDisplay *dpy,
255 EGLint *minor, EGLint *major)
256 {
257 struct xdri_egl_display *xdri_dpy;
258 __GLXdisplayPrivate *dpyPriv;
259 __GLXDRIdisplay *driDisplay;
260 __GLXscreenConfigs *psc;
261 EGLint first_id = 1;
262 int scr;
263
264 xdri_dpy = CALLOC_STRUCT(xdri_egl_display);
265 if (!xdri_dpy)
266 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
267
268 xdri_dpy->dpy = (Display *) dpy->NativeDisplay;
269 if (!xdri_dpy->dpy) {
270 xdri_dpy->dpy = XOpenDisplay(NULL);
271 if (!xdri_dpy->dpy) {
272 free(xdri_dpy);
273 return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
274 }
275 }
276
277 dpyPriv = __glXInitialize(xdri_dpy->dpy);
278 if (!dpyPriv) {
279 _eglLog(_EGL_WARNING, "failed to create GLX display");
280 free(xdri_dpy);
281 return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
282 }
283
284 driDisplay = __driCreateDisplay(dpyPriv, &xdri_dpy->driVersion);
285 if (!driDisplay) {
286 _eglLog(_EGL_WARNING, "failed to create DRI display");
287 free(xdri_dpy);
288 return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
289 }
290
291 scr = DefaultScreen(xdri_dpy->dpy);
292 psc = &dpyPriv->screenConfigs[scr];
293
294 xdri_dpy->dpyPriv = dpyPriv;
295 xdri_dpy->driDisplay = driDisplay;
296 xdri_dpy->psc = psc;
297 xdri_dpy->scr = scr;
298
299 psc->driScreen = driDisplay->createScreen(psc, scr, dpyPriv);
300 if (!psc->driScreen) {
301 _eglLog(_EGL_WARNING, "failed to create DRI screen #%d", scr);
302 free(xdri_dpy);
303 return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
304 }
305
306 dpy->DriverData = xdri_dpy;
307 dpy->ClientAPIsMask = EGL_OPENGL_BIT;
308
309 /* add visuals and fbconfigs */
310 first_id = create_configs(dpy, psc->visuals, first_id);
311 create_configs(dpy, psc->configs, first_id);
312
313 /* we're supporting EGL 1.4 */
314 *minor = 1;
315 *major = 4;
316
317 return EGL_TRUE;
318 }
319
320
321 /**
322 * Called via eglTerminate(), drv->API.Terminate().
323 */
324 static EGLBoolean
325 xdri_eglTerminate(_EGLDriver *drv, _EGLDisplay *dpy)
326 {
327 struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
328 __GLXscreenConfigs *psc;
329
330 _eglReleaseDisplayResources(drv, dpy);
331 _eglCleanupDisplay(dpy);
332
333 psc = xdri_dpy->psc;
334 if (psc->driver_configs) {
335 unsigned int i;
336 for (i = 0; psc->driver_configs[i]; i++)
337 free((__DRIconfig *) psc->driver_configs[i]);
338 free(psc->driver_configs);
339 psc->driver_configs = NULL;
340 }
341 if (psc->driScreen) {
342 psc->driScreen->destroyScreen(psc);
343 free(psc->driScreen);
344 psc->driScreen = NULL;
345 }
346
347 xdri_dpy->driDisplay->destroyDisplay(xdri_dpy->driDisplay);
348
349 free(xdri_dpy);
350 dpy->DriverData = NULL;
351
352 return EGL_TRUE;
353 }
354
355
356 /*
357 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
358 */
359 static _EGLProc
360 xdri_eglGetProcAddress(_EGLDriver *drv, const char *procname)
361 {
362 /* the symbol is defined in libGL.so */
363 return (_EGLProc) _glapi_get_proc_address(procname);
364 }
365
366
367 /**
368 * Called via eglCreateContext(), drv->API.CreateContext().
369 */
370 static _EGLContext *
371 xdri_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
372 _EGLContext *share_list, const EGLint *attrib_list)
373 {
374 struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
375 struct xdri_egl_config *xdri_config = lookup_config(conf);
376 struct xdri_egl_context *shared = lookup_context(share_list);
377 __GLXscreenConfigs *psc = xdri_dpy->psc;
378 int renderType = GLX_RGBA_BIT;
379 struct xdri_egl_context *xdri_ctx;
380
381 xdri_ctx = CALLOC_STRUCT(xdri_egl_context);
382 if (!xdri_ctx) {
383 _eglError(EGL_BAD_ALLOC, "eglCreateContext");
384 return NULL;
385 }
386
387 xdri_ctx->dummy_gc = CALLOC_STRUCT(__GLXcontextRec);
388 if (!xdri_ctx->dummy_gc) {
389 _eglError(EGL_BAD_ALLOC, "eglCreateContext");
390 free(xdri_ctx);
391 return NULL;
392 }
393
394 if (!_eglInitContext(drv, &xdri_ctx->Base, &xdri_config->Base, attrib_list)) {
395 free(xdri_ctx->dummy_gc);
396 free(xdri_ctx);
397 return NULL;
398 }
399
400 /* the config decides the render buffer for the context */
401 xdri_ctx->Base.WindowRenderBuffer = xdri_config->window_render_buffer;
402
403 xdri_ctx->driContext =
404 psc->driScreen->createContext(psc,
405 xdri_config->mode,
406 xdri_ctx->dummy_gc,
407 (shared) ? shared->dummy_gc : NULL,
408 renderType);
409 if (!xdri_ctx->driContext) {
410 free(xdri_ctx->dummy_gc);
411 free(xdri_ctx);
412 return NULL;
413 }
414
415 /* fill in the required field */
416 xdri_ctx->dummy_gc->driContext = xdri_ctx->driContext;
417
418 return &xdri_ctx->Base;
419 }
420
421
422 static EGLBoolean
423 xdri_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
424 {
425 struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
426 struct xdri_egl_context *xdri_ctx = lookup_context(ctx);
427
428 if (!_eglIsContextBound(ctx)) {
429 xdri_ctx->driContext->destroyContext(xdri_ctx->driContext,
430 xdri_dpy->psc, xdri_dpy->dpy);
431 free(xdri_ctx->dummy_gc);
432 free(xdri_ctx);
433 }
434
435 return EGL_TRUE;
436 }
437
438
439 /**
440 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
441 */
442 static EGLBoolean
443 xdri_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *d,
444 _EGLSurface *r, _EGLContext *context)
445 {
446 struct xdri_egl_driver *xdri_driver = xdri_egl_driver(drv);
447 struct xdri_egl_context *xdri_ctx = lookup_context(context);
448 struct xdri_egl_surface *draw = lookup_surface(d);
449 struct xdri_egl_surface *read = lookup_surface(r);
450 _EGLContext *old = _eglGetCurrentContext();
451
452 /* an unlinked context will be invalid after context switch */
453 if (!_eglIsContextLinked(old))
454 old = NULL;
455
456 if (!_eglMakeCurrent(drv, dpy, d, r, context))
457 return EGL_FALSE;
458
459 /* flush before context switch */
460 if (old && old != context && xdri_driver->FlushCurrentContext)
461 xdri_driver->FlushCurrentContext();
462
463 /* the symbol is defined in libGL.so */
464 _glapi_check_multithread();
465
466 if (xdri_ctx) {
467 if (!xdri_ctx->driContext->bindContext(xdri_ctx->driContext,
468 draw->driDrawable,
469 read->driDrawable)) {
470 return EGL_FALSE;
471 }
472 }
473 else if (old) {
474 xdri_ctx = lookup_context(old);
475 xdri_ctx->driContext->unbindContext(xdri_ctx->driContext);
476 }
477
478 return EGL_TRUE;
479 }
480
481
482 /**
483 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
484 */
485 static _EGLSurface *
486 xdri_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
487 EGLNativeWindowType window,
488 const EGLint *attrib_list)
489 {
490 struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
491 struct xdri_egl_config *xdri_config = lookup_config(conf);
492 struct xdri_egl_surface *xdri_surf;
493 uint width, height;
494
495 xdri_surf = CALLOC_STRUCT(xdri_egl_surface);
496 if (!xdri_surf) {
497 _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
498 return NULL;
499 }
500
501 if (!_eglInitSurface(drv, &xdri_surf->Base, EGL_WINDOW_BIT,
502 &xdri_config->Base, attrib_list)) {
503 free(xdri_surf);
504 return NULL;
505 }
506
507 xdri_surf->driDrawable =
508 xdri_dpy->psc->driScreen->createDrawable(xdri_dpy->psc,
509 (XID) window,
510 (GLXDrawable) window,
511 xdri_config->mode);
512 if (!xdri_surf->driDrawable) {
513 free(xdri_surf);
514 return NULL;
515 }
516
517 xdri_surf->drawable = (Drawable) window;
518
519 get_drawable_size(xdri_dpy->dpy, window, &width, &height);
520 xdri_surf->Base.Width = width;
521 xdri_surf->Base.Height = height;
522
523 return &xdri_surf->Base;
524 }
525
526
527 /**
528 * Called via eglCreatePbufferSurface(), drv->API.CreatePbufferSurface().
529 */
530 static _EGLSurface *
531 xdri_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
532 const EGLint *attrib_list)
533 {
534 return NULL;
535 }
536
537
538
539 static EGLBoolean
540 xdri_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface)
541 {
542 struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
543
544 if (!_eglIsSurfaceBound(&xdri_surf->Base)) {
545 xdri_surf->driDrawable->destroyDrawable(xdri_surf->driDrawable);
546 free(xdri_surf);
547 }
548
549 return EGL_TRUE;
550 }
551
552
553 static EGLBoolean
554 xdri_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
555 EGLint buffer)
556 {
557 return EGL_FALSE;
558 }
559
560
561 static EGLBoolean
562 xdri_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
563 EGLint buffer)
564 {
565 return EGL_FALSE;
566 }
567
568
569 static EGLBoolean
570 xdri_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw)
571 {
572 struct xdri_egl_driver *xdri_driver = xdri_egl_driver(drv);
573 struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
574 struct xdri_egl_surface *xdri_surf = lookup_surface(draw);
575
576 /* swapBuffers does not flush commands */
577 if (draw->Binding && xdri_driver->FlushCurrentContext)
578 xdri_driver->FlushCurrentContext();
579
580 xdri_dpy->psc->driScreen->swapBuffers(xdri_surf->driDrawable, 0, 0, 0);
581
582 return EGL_TRUE;
583 }
584
585
586 static void
587 xdri_Unload(_EGLDriver *drv)
588 {
589 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
590 free(xdri_drv);
591 }
592
593
594 /**
595 * This is the main entrypoint into the driver, called by libEGL.
596 * Create a new _EGLDriver object and init its dispatch table.
597 */
598 _EGLDriver *
599 _eglMain(const char *args)
600 {
601 struct xdri_egl_driver *xdri_drv = CALLOC_STRUCT(xdri_egl_driver);
602 if (!xdri_drv)
603 return NULL;
604
605 _eglInitDriverFallbacks(&xdri_drv->Base);
606 xdri_drv->Base.API.Initialize = xdri_eglInitialize;
607 xdri_drv->Base.API.Terminate = xdri_eglTerminate;
608
609 xdri_drv->Base.API.GetProcAddress = xdri_eglGetProcAddress;
610
611 xdri_drv->Base.API.CreateContext = xdri_eglCreateContext;
612 xdri_drv->Base.API.DestroyContext = xdri_eglDestroyContext;
613 xdri_drv->Base.API.MakeCurrent = xdri_eglMakeCurrent;
614 xdri_drv->Base.API.CreateWindowSurface = xdri_eglCreateWindowSurface;
615 xdri_drv->Base.API.CreatePbufferSurface = xdri_eglCreatePbufferSurface;
616 xdri_drv->Base.API.DestroySurface = xdri_eglDestroySurface;
617 xdri_drv->Base.API.BindTexImage = xdri_eglBindTexImage;
618 xdri_drv->Base.API.ReleaseTexImage = xdri_eglReleaseTexImage;
619 xdri_drv->Base.API.SwapBuffers = xdri_eglSwapBuffers;
620
621 xdri_drv->Base.Name = "X/DRI";
622 xdri_drv->Base.Unload = xdri_Unload;
623
624 /* we need a way to flush commands */
625 xdri_drv->FlushCurrentContext =
626 (void (*)(void)) xdri_eglGetProcAddress(&xdri_drv->Base, "glFlush");
627
628 return &xdri_drv->Base;
629 }