This patch adds MESA_screen_surface support to the egl_glx EGL->GLX wrapper and egl_xlib Gallium state tracker.
With this patch applied, you should be able to just run eglgears from an X11 terminal and get a maximized hardware accelerated gears window. Screen surfaces are window surfaces where the X11 window is created by the EGL driver. Showing a screen surface calls XMapWindow on it. The window is automatically made maximized or fullscreen if the size makes it necessary. A single screen mode is advertised, which sized by default like the size of the client area of a maximized window. The EGL_FULLSCREEN=[WxH[xRATE]] and EGL_WINDOW=WxH options can be used to force fullscreen or a window with the appropriate dimensions. It also changes the default EGL driver for X11 to be egl_glx rather than egl_softpipe, as this gives a good chance of being able to use hardware acceleration. The core X11 code is in src/egl/main/eglx11.[ch] and it is called both by egl_x11 and Gallium egl_xlib. It uses the WM protocol to determine work area and frame sizes and (try to) compute the size of a maximized window and xrandr to change fullscreen mode. --- configure.ac | 6 +- src/egl/drivers/glx/egl_glx.c | 157 +++++++++- src/egl/main/Makefile | 6 +- src/egl/main/eglconfig.c | 1 + src/egl/main/eglconfigutil.c | 2 +- src/egl/main/egldriver.c | 2 +- src/egl/main/eglsurface.c | 2 +- src/egl/main/eglx11.c | 537 ++++++++++++++++++++++++++++++++ src/egl/main/eglx11.h | 21 ++ src/gallium/winsys/egl_xlib/Makefile | 13 +- src/gallium/winsys/egl_xlib/egl_xlib.c | 95 ++++++- 11 files changed, 815 insertions(+), 27 deletions(-) create mode 100644 src/egl/main/eglx11.c create mode 100644 src/egl/main/eglx11.h diff --git a/configure.ac b/configure.ac index d83dd43..83b14b5 100644 --- a/configure.ac +++ b/configure.ac @@ -890,11 +890,11 @@ if test "x$enable_egl" = xyes; then SRC_DIRS="$SRC_DIRS egl" if test "$x11_pkgconfig" = yes; then - PKG_CHECK_MODULES([EGL], [x11]) + PKG_CHECK_MODULES([EGL], [x11 xrandr]) EGL_LIB_DEPS="$EGL_LIBS" else # should check these... - EGL_LIB_DEPS="$X_LIBS -lX11" + EGL_LIB_DEPS="$X_LIBS -lX11 -lXrandr" fi EGL_LIB_DEPS="$EGL_LIB_DEPS $DLOPEN_LIBS" fi diff --git a/src/egl/drivers/glx/egl_glx.c b/src/egl/drivers/glx/egl_glx.c index 96292b0..55f99b5 100644 --- a/src/egl/drivers/glx/egl_glx.c +++ b/src/egl/drivers/glx/egl_glx.c @@ -33,10 +33,13 @@ * Authors: Alan Hourihane <al...@tungstengraphics.com> */ +#define GLX_GLXEXT_PROTOTYPES #include <stdlib.h> #include <string.h> +#include <errno.h> #include <X11/Xlib.h> #include <GL/glx.h> +#include <GL/glxext.h> #include "eglconfigutil.h" #include "eglconfig.h" @@ -46,6 +49,9 @@ #include "eglglobals.h" #include "egllog.h" #include "eglsurface.h" +#include "eglscreen.h" +#include "eglmode.h" +#include "eglx11.h" #define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T)) #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) @@ -67,6 +73,7 @@ struct GLX_egl_driver _EGLDriver Base; /**< base class */ }; +struct GLX_egl_surface; /** driver data of _EGLDisplay */ struct GLX_egl_display @@ -91,6 +98,9 @@ struct GLX_egl_display EGLBoolean single_buffered_quirk; EGLBoolean glx_window_quirk; + _EGLX11Screen* x11; + + struct GLX_egl_surface* screen_surface; }; @@ -200,7 +210,7 @@ static const struct { static EGLBoolean convert_fbconfig(Display *dpy, GLXFBConfig fbconfig, - struct GLX_egl_config *GLX_conf) + struct GLX_egl_config *GLX_conf, int force_rgba) { __GLcontextModes mode; int err = 0, attr, val, i; @@ -223,10 +233,17 @@ convert_fbconfig(Display *dpy, GLXFBConfig fbconfig, if (err) return EGL_FALSE; + if(force_rgba) + mode.renderType = GLX_RGBA_BIT; + /* must have rgba bit */ if (!(mode.renderType & GLX_RGBA_BIT)) return EGL_FALSE; + /* EGL doesn't support accumulation buffers and we don't want them as their mode are marked "Slow" */ + if(mode.accumRedBits || mode.accumGreenBits || mode.accumBlueBits || mode.accumAlphaBits) + return EGL_FALSE; + /* pixmap and pbuffer surfaces must be single-buffered in EGL */ if (mode.doubleBufferMode) { mode.drawableType &= ~(GLX_PIXMAP_BIT | GLX_PBUFFER_BIT); @@ -377,7 +394,7 @@ fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf) surface_type = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE); if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) { /* some GLX impls do not like single-buffered window surface */ - surface_type &= ~EGL_WINDOW_BIT; + surface_type &= ~(EGL_WINDOW_BIT | EGL_SCREEN_BIT_MESA); /* pbuffer bit is usually not set */ if (GLX_dpy->have_pbuffer) surface_type |= EGL_PBUFFER_BIT; @@ -405,23 +422,47 @@ create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy, { EGLint num_configs = 0, i; EGLint id = 1; + int force_rgba = 0; + int db; if (GLX_dpy->have_fbconfig) { GLX_dpy->fbconfigs = glXGetFBConfigs(GLX_dpy->dpy, screen, &num_configs); + + if (!num_configs) + return EGL_FALSE; + + GLX_dpy->visuals = calloc(sizeof(XVisualInfo), num_configs); + for(i = 0; i < num_configs; ++i) + { + XVisualInfo* vinfo; + vinfo = glXGetVisualFromFBConfig(GLX_dpy->dpy, GLX_dpy->fbconfigs[i]); + if(vinfo) + { + memcpy(GLX_dpy->visuals + i, vinfo, sizeof(XVisualInfo)); + XFree(vinfo); + } + } } else { XVisualInfo vinfo_template; long mask; + XVisualInfo* vinfo; vinfo_template.screen = screen; mask = VisualScreenMask; - GLX_dpy->visuals = XGetVisualInfo(GLX_dpy->dpy, mask, &vinfo_template, + vinfo = XGetVisualInfo(GLX_dpy->dpy, mask, &vinfo_template, &num_configs); - } - if (!num_configs) - return EGL_FALSE; + if (!num_configs) + return EGL_FALSE; + + GLX_dpy->visuals = malloc(sizeof(XVisualInfo) * num_configs); + memcpy(GLX_dpy->visuals, vinfo, sizeof(XVisualInfo) * num_configs); + XFree(vinfo); + } +retry: + for(db = 1; db >= 0; --db) { for (i = 0; i < num_configs; i++) { struct GLX_egl_config *GLX_conf, template; EGLBoolean ok; @@ -429,7 +470,7 @@ create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy, memset(&template, 0, sizeof(template)); _eglInitConfig(&template.Base, id); if (GLX_dpy->have_fbconfig) - ok = convert_fbconfig(GLX_dpy->dpy, GLX_dpy->fbconfigs[i], &template); + ok = convert_fbconfig(GLX_dpy->dpy, GLX_dpy->fbconfigs[i], &template, force_rgba); else ok = convert_visual(GLX_dpy->dpy, &GLX_dpy->visuals[i], &template); if (!ok) @@ -441,6 +482,8 @@ create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy, continue; } + if(template.double_buffered == db) + { GLX_conf = CALLOC_STRUCT(GLX_egl_config); if (GLX_conf) { memcpy(GLX_conf, &template, sizeof(template)); @@ -449,6 +492,15 @@ create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy, _eglAddConfig(dpy, &GLX_conf->Base); id++; } + } + } + } + + if(id == 1 && !force_rgba) + { + /* nVidia GLX server + Mesa GLX library mistakenly reports all FBConfigs as being color-indexed */ + force_rgba = 1; + goto retry; } return EGL_TRUE; @@ -558,9 +610,14 @@ GLX_eglInitialize(_EGLDriver *drv, _EGLDisplay *disp, return EGL_FALSE; } + /* TODO: support other screens */ + GLX_dpy->x11 = _eglX11AddScreen(disp, GLX_dpy->dpy, DefaultScreen(GLX_dpy->dpy)); + disp->DriverData = (void *) GLX_dpy; disp->ClientAPIsMask = GLX_EGL_APIS; + disp->Extensions.MESA_screen_surface = EGL_TRUE; + /* we're supporting EGL 1.4 */ *major = 1; *minor = 4; @@ -580,10 +637,12 @@ GLX_eglTerminate(_EGLDriver *drv, _EGLDisplay *disp) _eglCleanupDisplay(disp); if (GLX_dpy->visuals) - XFree(GLX_dpy->visuals); + free(GLX_dpy->visuals); if (GLX_dpy->fbconfigs) XFree(GLX_dpy->fbconfigs); + _eglX11TerminateScreen(GLX_dpy->x11); + if (!disp->NativeDisplay) XCloseDisplay(GLX_dpy->dpy); free(GLX_dpy); @@ -841,6 +900,77 @@ GLX_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *disp, return &GLX_surf->Base; } +static EGLSurface +GLX_eglCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay disp, EGLConfig conf, + const EGLint *attrib_list) +{ + struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); + struct GLX_egl_surface *GLX_surf; + XVisualInfo* vinfo; + + vinfo = &GLX_dpy->visuals[GLX_egl_config_index(conf)]; + if(!vinfo->visual) + return NULL; + + GLX_surf = CALLOC_STRUCT(GLX_egl_surface); + if (!GLX_surf) { + _eglError(EGL_BAD_ALLOC, "eglCreateScreenSurfaceMESA"); + return NULL; + } + + if (!_eglInitSurface(drv, &GLX_surf->Base, EGL_SCREEN_BIT_MESA, + conf, attrib_list)) { + free(GLX_surf); + return NULL; + } + + GLX_surf->drawable = _eglX11CreateWindow(GLX_dpy->x11, &GLX_surf->Base, vinfo); + + if (GLX_dpy->have_1_3 && !GLX_dpy->glx_window_quirk) + GLX_surf->glx_drawable = + glXCreateWindow(GLX_dpy->dpy, + GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], + GLX_surf->drawable, NULL); + else + GLX_surf->glx_drawable = GLX_surf->drawable; + + if (!GLX_surf->glx_drawable) { + free(GLX_surf); + XDestroyWindow(GLX_dpy->dpy, GLX_surf->drawable); + return NULL; + } + + return &GLX_surf->Base; +} + +/** + * Show the given surface on the named screen. + * If surface is EGL_NO_SURFACE, disable the screen's output. + * Called via eglShowSurfaceMESA(). + */ +static EGLBoolean +GLX_eglShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay disp, + EGLScreenMESA screen, + EGLSurface surf, EGLModeMESA m) +{ + /* TODO: possibly resize window to support multiple modes */ + struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); + + if(GLX_dpy->screen_surface) + XUnmapWindow(GLX_dpy->dpy, GLX_dpy->screen_surface->drawable); + + if(surf == EGL_NO_SURFACE) + GLX_dpy->screen_surface = 0; + else + { + struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf); + GLX_dpy->screen_surface = GLX_surf; + _eglX11MapWindow(GLX_dpy->x11, surf, GLX_surf->drawable); + } + + return EGL_TRUE; +} + static EGLBoolean GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) { @@ -851,6 +981,7 @@ GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) if (GLX_dpy->have_1_3) { switch (surf->Type) { case EGL_WINDOW_BIT: + case EGL_SCREEN_BIT_MESA: if (!GLX_dpy->glx_window_quirk) glXDestroyWindow(GLX_dpy->dpy, GLX_surf->glx_drawable); break; @@ -877,6 +1008,14 @@ GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) break; } } + + if(surf->Type == EGL_SCREEN_BIT_MESA) + { + if(GLX_dpy->screen_surface == GLX_surf) + GLX_dpy->screen_surface = 0; + XDestroyWindow(GLX_dpy->dpy, GLX_surf->drawable); + } + free(surf); } @@ -953,6 +1092,8 @@ _eglMain(const char *args) GLX_drv->Base.API.GetProcAddress = GLX_eglGetProcAddress; GLX_drv->Base.API.WaitClient = GLX_eglWaitClient; GLX_drv->Base.API.WaitNative = GLX_eglWaitNative; + GLX_drv->Base.API.CreateScreenSurfaceMESA = GLX_eglCreateScreenSurfaceMESA; + GLX_drv->Base.API.ShowScreenSurfaceMESA = GLX_eglShowScreenSurfaceMESA; GLX_drv->Base.Name = "GLX"; GLX_drv->Base.Unload = GLX_Unload; diff --git a/src/egl/main/Makefile b/src/egl/main/Makefile index c951b07..202bf20 100644 --- a/src/egl/main/Makefile +++ b/src/egl/main/Makefile @@ -22,7 +22,8 @@ HEADERS = \ eglmutex.h \ eglscreen.h \ eglstring.h \ - eglsurface.h + eglsurface.h \ + eglx11.h SOURCES = \ eglapi.c \ @@ -38,7 +39,8 @@ SOURCES = \ eglmode.c \ eglscreen.c \ eglstring.c \ - eglsurface.c + eglsurface.c \ + eglx11.c OBJECTS = $(SOURCES:.c=.o) diff --git a/src/egl/main/eglconfig.c b/src/egl/main/eglconfig.c index 31d69a7..6580d44 100644 --- a/src/egl/main/eglconfig.c +++ b/src/egl/main/eglconfig.c @@ -324,6 +324,7 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) mask = EGL_PBUFFER_BIT | EGL_PIXMAP_BIT | EGL_WINDOW_BIT | + EGL_SCREEN_BIT_MESA | EGL_VG_COLORSPACE_LINEAR_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT | EGL_MULTISAMPLE_RESOLVE_BOX_BIT | diff --git a/src/egl/main/eglconfigutil.c b/src/egl/main/eglconfigutil.c index 36e94f0..a421cad 100644 --- a/src/egl/main/eglconfigutil.c +++ b/src/egl/main/eglconfigutil.c @@ -76,7 +76,7 @@ _eglConfigFromContextModesRec(_EGLConfig *conf, const __GLcontextModes *m, surface_type = 0; if (m->drawableType & GLX_WINDOW_BIT) - surface_type |= EGL_WINDOW_BIT; + surface_type |= EGL_WINDOW_BIT | EGL_SCREEN_BIT_MESA; if (m->drawableType & GLX_PIXMAP_BIT) surface_type |= EGL_PIXMAP_BIT; if (m->drawableType & GLX_PBUFFER_BIT) diff --git a/src/egl/main/egldriver.c b/src/egl/main/egldriver.c index 018b06d..f9f0b43 100644 --- a/src/egl/main/egldriver.c +++ b/src/egl/main/egldriver.c @@ -52,7 +52,7 @@ close_library(HMODULE lib) #elif defined(_EGL_PLATFORM_X) -static const char DefaultDriverName[] = "egl_softpipe"; +static const char DefaultDriverName[] = "egl_glx"; typedef void * lib_handle; diff --git a/src/egl/main/eglsurface.c b/src/egl/main/eglsurface.c index 940a1b7..fcee87f 100644 --- a/src/egl/main/eglsurface.c +++ b/src/egl/main/eglsurface.c @@ -63,7 +63,7 @@ _eglInitSurface(_EGLDriver *drv, _EGLSurface *surf, EGLint type, break; case EGL_SCREEN_BIT_MESA: func = "eglCreateScreenSurface"; - renderBuffer = EGL_SINGLE_BUFFER; /* XXX correct? */ + //renderBuffer = EGL_SINGLE_BUFFER; /* XXX correct? No! */ break; default: _eglLog(_EGL_WARNING, "Bad type in _eglInitSurface"); diff --git a/src/egl/main/eglx11.c b/src/egl/main/eglx11.c new file mode 100644 index 0000000..9e045ed --- /dev/null +++ b/src/egl/main/eglx11.c @@ -0,0 +1,537 @@ +#include <stdlib.h> +#include <memory.h> +#include <errno.h> +#include <ctype.h> +#include <limits.h> +#include <X11/Xproto.h> +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/extensions/Xrandr.h> +#include <sys/poll.h> +#include <sys/time.h> +#include "eglx11.h" +#include "eglscreen.h" +#include "eglmode.h" + +struct _EGLX11Screen +{ + Display* dpy; + int screen; + unsigned width; + unsigned height; + unsigned work_x; + unsigned work_y; + unsigned work_width; + unsigned work_height; + unsigned frame_left; + unsigned frame_right; + unsigned frame_top; + unsigned frame_bottom; + unsigned client_width; + unsigned client_height; + unsigned max_width; + unsigned max_height; + + int def_fullscreen; + unsigned def_width; + unsigned def_height; + unsigned def_rate; + + int orig_size; + int orig_rate; +}; + +static int _eglX11GetWorkArea(_EGLX11Screen* x11, CARD32* area) +{ + Atom _NET_WORKAREA = XInternAtom(x11->dpy, "_NET_WORKAREA", False); + Atom type; + int format; + unsigned long nitems, bytes_after; + unsigned char *data; + + if(XGetWindowProperty(x11->dpy, RootWindow(x11->dpy, x11->screen), _NET_WORKAREA, 0L, 0x7fffffff, False, XA_CARDINAL, &type, &format, &nitems, &bytes_after, (unsigned char**)&data) == Success) + { + if ((type == XA_CARDINAL) && (format == 32) && (nitems >= 4) && data) + { + memcpy(area, data, sizeof(CARD32) * 4); + XFree(data); + return 1; + } + XFree(data); + } + return 0; +} + +struct x11_property_notify_criteria +{ + Window window; + Atom atom; +}; + +static Bool +x11_property_notify_predicate (Display *xdisplay __attribute__((unused)), + XEvent *event, + XPointer arg) +{ + struct x11_property_notify_criteria *criteria = (struct x11_property_notify_criteria*)arg; + + if (event->xany.type == PropertyNotify + && event->xany.window == criteria->window + && event->xproperty.atom == criteria->atom) + return True; + else + return False; +} + +static int _eglX11WaitEventUntil(_EGLX11Screen* x11, struct timeval* deadline) +{ + int fd = ConnectionNumber(x11->dpy); + struct pollfd pfd; + struct timeval now; + + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + gettimeofday(&now, 0); + if(now.tv_sec > deadline->tv_sec) + return 0; + + return poll(&pfd, 1, (int)(deadline->tv_sec - now.tv_sec) * 1000 + (int)(deadline->tv_usec - now.tv_usec + 999) / 1000); +} + +static int _eglX11SetWindowState(_EGLX11Screen* x11, Window win, const char* name1, const char* name2) +{ + Atom _NET_WM_STATE = XInternAtom(x11->dpy, "_NET_WM_STATE", 0); + Atom _NET_WM_STATE_MAXIMIZED_HORZ = name1 ? XInternAtom(x11->dpy, name1, 0) : 0; + Atom _NET_WM_STATE_MAXIMIZED_VERT = name2 ? XInternAtom(x11->dpy, name2, 0) : 0; + XEvent xevent; + struct x11_property_notify_criteria criteria; + struct timeval deadline; + + criteria.window = win; + criteria.atom = _NET_WM_STATE; + + while(XCheckIfEvent(x11->dpy, &xevent, x11_property_notify_predicate, (XPointer) &criteria)); + + xevent.xany.type = ClientMessage; + xevent.xany.window = win; + xevent.xclient.message_type = _NET_WM_STATE; + xevent.xclient.format = 32; + xevent.xclient.data.l[0] = 1; + xevent.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT; + xevent.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ; + xevent.xclient.data.l[3] = 2; + xevent.xclient.data.l[4] = 0; + + XSendEvent (x11->dpy, RootWindow(x11->dpy, x11->screen), False, + (SubstructureRedirectMask | SubstructureNotifyMask), + &xevent); + + gettimeofday(&deadline, 0); + ++deadline.tv_sec; + while(!XCheckIfEvent(x11->dpy, &xevent, x11_property_notify_predicate, (XPointer) &criteria)) + { + if(!_eglX11WaitEventUntil(x11, &deadline)) + return 0; + } + + return 1; +} + +static int _eglX11MaximizeWindow(_EGLX11Screen* x11, Window win) +{ + return _eglX11SetWindowState(x11, win, "_NET_WM_STATE_MAXIMIZED_HORZ", "_NET_WM_STATE_MAXIMIZED_VERT"); +} + +static int _eglX11MakeWindowFullscreen(_EGLX11Screen* x11, Window win) +{ + return _eglX11SetWindowState(x11, win, "_NET_WM_STATE_FULLSCREEN", 0); +} + +static int _eglX11GetFrameExtents(_EGLX11Screen* x11, CARD32* extents) +{ + Atom _NET_REQUEST_FRAME_EXTENTS = XInternAtom(x11->dpy, "_NET_REQUEST_FRAME_EXTENTS", 0); + Atom _NET_FRAME_EXTENTS = XInternAtom(x11->dpy, "_NET_FRAME_EXTENTS", 0); + + XEvent xevent; + Window root = RootWindow(x11->dpy, x11->screen); + Window win; + XSetWindowAttributes attrs; + Atom type; + int format; + unsigned long nitems, bytes_after; + unsigned char *data; + int ret = 0; + unsigned mask; + struct x11_property_notify_criteria criteria; + + attrs.background_pixel = 0; + attrs.border_pixel = 0; + attrs.colormap = XCreateColormap(x11->dpy, root, DefaultVisual(x11->dpy, x11->screen), AllocNone); + attrs.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask | PropertyChangeMask; + attrs.override_redirect = 0; + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect; + + win = XCreateWindow(x11->dpy, root, 0, 0, 64, 64, + 0, CopyFromParent, InputOutput, + CopyFromParent, mask, &attrs); + + if(!win) + return 0; + + criteria.window = win; + criteria.atom = _NET_FRAME_EXTENTS; + + while(XCheckIfEvent(x11->dpy, &xevent, x11_property_notify_predicate, (XPointer) &criteria)); + + xevent.xclient.type = ClientMessage; + xevent.xclient.message_type = _NET_REQUEST_FRAME_EXTENTS; + xevent.xclient.display = x11->dpy; + xevent.xclient.window = win; + xevent.xclient.format = 32; + xevent.xclient.data.l[0] = 0; + xevent.xclient.data.l[1] = 0; + xevent.xclient.data.l[2] = 0; + xevent.xclient.data.l[3] = 0; + xevent.xclient.data.l[4] = 0; + + XSendEvent (x11->dpy, root, False, + (SubstructureRedirectMask | SubstructureNotifyMask), + &xevent); + + XFlush(x11->dpy); + + XIfEvent(x11->dpy, &xevent, x11_property_notify_predicate, (XPointer) &criteria); + + if (XGetWindowProperty(x11->dpy, win, _NET_FRAME_EXTENTS, 0l, + sizeof (unsigned long) * 4, False, XA_CARDINAL, &type, + &format, &nitems, &bytes_after, &data) == Success) + { + if ((type == XA_CARDINAL) && (format == 32) && (nitems >= 4) && (data)) + { + memcpy(extents, data, 4 * sizeof(long)); + ret = 1; + } + XFree(data); + } + + XDestroyWindow(x11->dpy, win); + return ret; +} + +_EGLX11Screen* _eglX11AddScreen(_EGLDisplay *disp, Display* dpy, int screen) +{ + _EGLX11Screen* x11; + CARD32 data[4]; + _EGLScreen *scrn; + + x11 = (_EGLX11Screen*)malloc(sizeof(_EGLX11Screen)); + x11->dpy = dpy; + x11->screen = screen; + + x11->width = DisplayWidth(x11->dpy, x11->screen); + x11->height = DisplayHeight(x11->dpy, x11->screen); + + if(_eglX11GetWorkArea(x11, data)) + { + x11->work_x = data[0]; + x11->work_y = data[1]; + x11->work_width = data[2]; + x11->work_height = data[3]; + } + else + { + x11->work_x = 0; + x11->work_y = 0; + x11->work_width = x11->width; + x11->work_height = x11->height; + } + + if(_eglX11GetFrameExtents(x11, data)) + { + x11->frame_left = data[0]; + x11->frame_right = data[1]; + x11->frame_top = data[2]; + x11->frame_bottom = data[3]; + } + else + { + x11->frame_left = 0; + x11->frame_right = 0; + x11->frame_top = 0; + x11->frame_bottom = 0; + } + + x11->client_width = x11->work_width - x11->frame_left - x11->frame_right; + x11->client_height = x11->work_height - x11->frame_top - x11->frame_bottom; + + // XXX: this is true for my system, but possibly not elsewhere + // unfortunately, Metacity doesn't seem to allow to maximize unmapped windows, so it's not clear how to do this properly + x11->max_width = x11->work_width; + x11->max_height = x11->work_height - x11->frame_top - 1; + + x11->orig_size = -1; + x11->orig_rate = -1; + + { + char* p; + + x11->def_fullscreen = 0; + x11->def_width = 0; + x11->def_height = 0; + x11->def_rate = 0; + + if((p = getenv("EGL_WINDOW"))) + { + int w, h; + + w = strtoul(p, &p, 10); + while(*p && !isdigit(*p)) + ++p; + h = strtoul(p, &p, 10); + if(w) + x11->def_width = w; + if(h) + x11->def_height = h; + } + + if((p = getenv("EGL_FULLSCREEN"))) + { + int w, h; + x11->def_fullscreen = 1; + + w = strtoul(p, &p, 10); + while(*p && !isdigit(*p)) + ++p; + h = strtoul(p, &p, 10); + while(*p && !isdigit(*p)) + ++p; + x11->def_rate = strtoul(p, &p, 10); + + if(w) + x11->def_width = w; + if(h) + x11->def_height = h; + } + + if(!x11->def_width) + x11->def_width = x11->def_fullscreen ? x11->width : x11->max_width; + + if(!x11->def_height) + x11->def_height = x11->def_fullscreen ? x11->height : x11->max_height; + + if(!x11->def_rate) + { + XRRScreenConfiguration* rrcfg; + x11->def_rate = 60; + rrcfg = XRRGetScreenInfo(x11->dpy, RootWindow(x11->dpy, x11->screen)); + if(rrcfg) + x11->def_rate = XRRConfigCurrentRate(rrcfg); + XRRFreeScreenConfigInfo(rrcfg); + } + } + + /* Create a screen */ + scrn = calloc(1, sizeof(*scrn)); + _eglAddScreen(disp, scrn); + + _eglAddNewMode(scrn, x11->def_width, x11->def_height, x11->def_rate * 1000, "x11"); + + return x11; +} + +static int _eglX11PlaceWindow(_EGLX11Screen* x11, int* x, int* y, int* w, int* h) +{ + if (!*w || !*h) + { + if(!*w) + *w = x11->def_width; + if (!*h) + *h = x11->def_height; + } + + if(!x11->def_fullscreen && *w <= x11->client_width && *h <= x11->client_height) + { + *x = x11->work_x + ((int)(x11->client_width - *w) >> 1); + *y = x11->work_y + ((int)(x11->client_height - *h) >> 1); + return 0; + } + else if(!x11->def_fullscreen && *w <= x11->max_width && *h <= x11->max_height) + { + *x = x11->work_x + ((int)(x11->max_width - *w) >> 1); + *y = x11->work_y + ((int)(x11->max_height - *h) >> 1); + return 1; + } + /* + else if(*w <= x11->work_width && *h <= x11->work_height) + { + *x = x11->work_x + ((int)(x11->work_width - *w) >> 1); + *y = x11->work_y + ((int)(x11->work_height - *h) >> 1); + return 2; + } + */ + else + { + *x = (int)(x11->width - *w) >> 1; + *y = (int)(x11->height - *h) >> 1; + return 2; + } +} + +Window _eglX11CreateWindow(_EGLX11Screen* x11, _EGLSurface* surf, XVisualInfo* vinfo) +{ + Window win; + Window root; + XSetWindowAttributes attrs; + int x, y; + unsigned mask; + const char* name; + + _eglX11PlaceWindow(x11, &x, &y, &surf->Width, &surf->Height); + + root = RootWindow(x11->dpy, vinfo->screen); + + attrs.background_pixel = 0; + attrs.border_pixel = 0; + attrs.colormap = XCreateColormap(x11->dpy, root, vinfo->visual, AllocNone); + attrs.event_mask = PropertyChangeMask; //StructureNotifyMask | ExposureMask | KeyPressMask; + attrs.override_redirect = 0; + + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect; +#ifdef __GLIBC__ + name = program_invocation_short_name; +#else + name = "EGL application"; +#endif + + win = XCreateWindow(x11->dpy, root, x, y, surf->Width, surf->Height, + 0, vinfo->depth, InputOutput, + vinfo->visual, mask, &attrs); + + { + XSizeHints sizehints; + sizehints.x = x; + sizehints.y = y; + sizehints.width = surf->Width; + sizehints.height = surf->Height; + sizehints.flags = USSize | USPosition; + XSetNormalHints(x11->dpy, win, &sizehints); + XSetStandardProperties(x11->dpy, win, name, name, + None, (char **)NULL, 0, &sizehints); + } + + return win; +} + +static void _eglX11SetFullScreenMode(_EGLX11Screen* x11, int width, int height, int rate) +{ + XRRScreenConfiguration* rrcfg; + Time last_change; // to make Xrandr happy + Time cur; + XRRScreenSize* sizes; + int cur_size; + Rotation cur_rot; + int cur_rate; + int nsizes; + int size = -1; + int size_area = INT_MAX; + +retry: + rrcfg = XRRGetScreenInfo(x11->dpy, RootWindow(x11->dpy, x11->screen)); + if(!rrcfg) + return; + + cur = XRRConfigTimes(rrcfg, &last_change); + cur_size = XRRConfigCurrentConfiguration(rrcfg, &cur_rot); + cur_rate = XRRConfigCurrentRate(rrcfg); + + if(width < 0) + size = height; + else + { + sizes = XRRConfigSizes(rrcfg, &nsizes); + for(int i = 0; i < nsizes; ++i) + { + if(x11->def_width <= sizes[i].width && x11->def_height <= sizes[i].height) + { + int area = sizes[i].width * sizes[i].height; + if(area < size_area) + { + size = i; + size_area = area; + } + } + } + } + + if(size >= 0 && size != cur_size) + { + Status status = BadValue; + status = XRRSetScreenConfigAndRate(x11->dpy, rrcfg, RootWindow(x11->dpy, x11->screen), size, cur_rot, rate, cur); + if(status != Success && status != RRSetConfigInvalidTime) + status = XRRSetScreenConfig(x11->dpy, rrcfg, RootWindow(x11->dpy, x11->screen), size, cur_rot, cur); + if(status == RRSetConfigInvalidTime) + { + XRRFreeScreenConfigInfo(rrcfg); + goto retry; + } + if(status == Success) + { + if(x11->orig_size < 0) + x11->orig_size = cur_size; + if(x11->orig_rate < 0) + x11->orig_rate = cur_rate; + } + } + XRRFreeScreenConfigInfo(rrcfg); +} + +void _eglX11MapWindow(_EGLX11Screen* x11, _EGLSurface* surf, Window win) +{ + int x, y; + int type = _eglX11PlaceWindow(x11, &x, &y, &surf->Width, &surf->Height); + int res; + + if(x11->def_fullscreen) + _eglX11SetFullScreenMode(x11, surf->Width, surf->Height, x11->def_rate); + + XMapWindow(x11->dpy, win); + + if(type == 2) + res = _eglX11MakeWindowFullscreen(x11, win); + else if(type == 1) + res = _eglX11MaximizeWindow(x11, win); + else + res = 1; + + if(!res) + { + /* the window manager ignored our request */ + /* but we already promised the maximized size to the application */ + /* so we bypass the window manager */ + XSetWindowAttributes attrs; + attrs.override_redirect = 1; + XUnmapWindow(x11->dpy, win); + XChangeWindowAttributes(x11->dpy, win, CWOverrideRedirect, &attrs); + y = x11->work_height - surf->Height; + if(y < 0) + y = 0; + else + y += x11->work_y; + + XMoveResizeWindow(x11->dpy, win, x, y, surf->Width, surf->Height); + XMapWindow(x11->dpy, win); + } +} + +void _eglX11TerminateScreen(_EGLX11Screen* x11) +{ + if(x11->orig_size >= 0) + { + _eglX11SetFullScreenMode(x11, -1, x11->orig_size, x11->orig_rate); + x11->orig_size = -1; + x11->orig_rate = -1; + } + free(x11); +} + diff --git a/src/egl/main/eglx11.h b/src/egl/main/eglx11.h new file mode 100644 index 0000000..f80e9ee --- /dev/null +++ b/src/egl/main/eglx11.h @@ -0,0 +1,21 @@ +#ifndef EGLX11_INCLUDED +#define EGLX11_INCLUDED + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include "eglconfig.h" +#include "egldisplay.h" +#include "egldriver.h" +#include "eglsurface.h" + +struct _EGLX11Screen; +typedef struct _EGLX11Screen _EGLX11Screen; + +_EGLX11Screen* _eglX11AddScreen(_EGLDisplay *disp, Display* dpy, int screen); +void _eglX11TerminateScreen(_EGLX11Screen* x11); + +Window _eglX11CreateWindow(_EGLX11Screen* x11, _EGLSurface* surf, XVisualInfo* vinfo); +void _eglX11MapWindow(_EGLX11Screen* x11, _EGLSurface* surf, Window win); + +#endif /* EGLX11_INCLUDED */ diff --git a/src/gallium/winsys/egl_xlib/Makefile b/src/gallium/winsys/egl_xlib/Makefile index 3efb7ed..5a50c8b 100644 --- a/src/gallium/winsys/egl_xlib/Makefile +++ b/src/gallium/winsys/egl_xlib/Makefile @@ -26,16 +26,9 @@ WINSYS_SOURCES = \ WINSYS_OBJECTS = $(WINSYS_SOURCES:.c=.o) -LIBS = \ - $(GALLIUM_DRIVERS) \ - $(GALLIUM_AUXILIARIES) - -# XXX temporary (should create a separate lib with the GL API funcs and -# mesa code, as done for ES 1.x, 2.x, OpenVG, etc) -UNUSED_LIBS = \ - $(TOP)/src/mesa/libglapi.a \ - $(TOP)/src/mesa/libmesagallium.a \ - +LIBS = $(GALLIUM_AUXILIARIES) \ + $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \ + $(TOP)/src/mesa/libmesagallium.a LOCAL_CFLAGS = diff --git a/src/gallium/winsys/egl_xlib/egl_xlib.c b/src/gallium/winsys/egl_xlib/egl_xlib.c index 599973c..25ca31c 100644 --- a/src/gallium/winsys/egl_xlib/egl_xlib.c +++ b/src/gallium/winsys/egl_xlib/egl_xlib.c @@ -53,6 +53,7 @@ #include "eglglobals.h" #include "egllog.h" #include "eglsurface.h" +#include "eglx11.h" #include "state_tracker/st_public.h" @@ -66,6 +67,7 @@ struct xlib_egl_driver EGLint apis; }; +struct xlib_egl_surface; /** driver data of _EGLDisplay */ struct xlib_egl_display @@ -74,6 +76,9 @@ struct xlib_egl_display struct pipe_winsys *winsys; struct pipe_screen *screen; + + _EGLX11Screen* x11; + struct xlib_egl_surface* screen_surface; }; @@ -190,7 +195,7 @@ create_configs(struct xlib_egl_display *xdpy, _EGLDisplay *disp) SET_CONFIG_ATTRIB(config, EGL_NATIVE_RENDERABLE, EGL_FALSE); SET_CONFIG_ATTRIB(config, EGL_CONFORMANT, all_apis); SET_CONFIG_ATTRIB(config, EGL_RENDERABLE_TYPE, all_apis); - SET_CONFIG_ATTRIB(config, EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); + SET_CONFIG_ATTRIB(config, EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT | EGL_SCREEN_BIT_MESA); SET_CONFIG_ATTRIB(config, EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); SET_CONFIG_ATTRIB(config, EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); @@ -243,6 +248,8 @@ xlib_eglInitialize(_EGLDriver *drv, _EGLDisplay *dpy, create_configs(xdpy, dpy); + xdpy->x11 = _eglX11AddScreen(dpy, xdpy->Dpy, DefaultScreen(xdpy->Dpy)); + /* we're supporting EGL 1.4 */ *major = 1; *minor = 4; @@ -259,6 +266,8 @@ xlib_eglTerminate(_EGLDriver *drv, _EGLDisplay *dpy) { struct xlib_egl_display *xdpy = xlib_egl_display(dpy); + _eglX11TerminateScreen(xdpy->x11); + _eglReleaseDisplayResources(drv, dpy); _eglCleanupDisplay(dpy); @@ -646,6 +655,88 @@ xlib_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *con choose_color_format(&visual), choose_depth_format(&visual), choose_stencil_format(&visual), +/** + * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). + */ +static _EGLSurface * +xlib_eglCreateScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, + const EGLint *attrib_list) +{ + struct xlib_egl_display *xdpy = xlib_egl_display(disp); + struct xlib_egl_surface *surf; + __GLcontextModes visual; + XVisualInfo vinfo_template; + int nvinfo; + XVisualInfo* vinfo; + + surf = CALLOC_STRUCT(xlib_egl_surface); + if (!surf) + return NULL; + + /* Let EGL lib init the common stuff */ + if (!_eglInitSurface(drv, &surf->Base, EGL_SCREEN_BIT_MESA, + conf, attrib_list)) { + free(surf); + return NULL; + } + + vinfo_template.visualid = GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID); + vinfo = XGetVisualInfo(xdpy->Dpy, VisualIDMask, &vinfo_template, &nvinfo); + if(!vinfo || !nvinfo) + { + free(surf); + return NULL; + } + + memcpy(&surf->VisInfo, vinfo, sizeof(*vinfo)); + XFree(vinfo); + + /* + * Now init the Xlib and gallium stuff + */ + surf->Dpy = xdpy->Dpy; /* The X display */ + surf->Win = _eglX11CreateWindow(xdpy->x11, &surf->Base, &surf->VisInfo); + surf->Gc = XCreateGC(surf->Dpy, surf->Win, 0, NULL); + surf->winsys = xdpy->winsys; + + _eglConfigToContextModesRec(conf, &visual); + /* Create GL statetracker framebuffer */ + surf->Framebuffer = st_create_framebuffer(&visual, + choose_color_format(&visual), + choose_depth_format(&visual), + choose_stencil_format(&visual), + surf->Base.Width, surf->Base.Height, + (void *) surf); + + return &surf->Base; +} + +/** + * Show the given surface on the named screen. + * If surface is EGL_NO_SURFACE, disable the screen's output. + * Called via eglShowSurfaceMESA(). + */ +static EGLBoolean +xlib_eglShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay disp, + EGLScreenMESA screen, + EGLSurface surf, EGLModeMESA m) +{ + struct xlib_egl_display *xdpy = xlib_egl_display(disp); + + if(xdpy->screen_surface) + XUnmapWindow(xdpy->Dpy, xdpy->screen_surface->Win); + + if(surf == EGL_NO_SURFACE) + xdpy->screen_surface = 0; + else + { + struct xlib_egl_surface *xsurf = lookup_surface(surf); + xdpy->screen_surface = xsurf; + _eglX11MapWindow(xdpy->x11, surf, xsurf->Win); + } + + return EGL_TRUE; +} width, height, (void *) surf); st_resize_framebuffer(surf->Framebuffer, width, height); @@ -842,6 +933,8 @@ _eglMain(const char *args) xdrv->Base.API.ReleaseTexImage = xlib_eglReleaseTexImage; xdrv->Base.API.MakeCurrent = xlib_eglMakeCurrent; xdrv->Base.API.SwapBuffers = xlib_eglSwapBuffers; + xdrv->Base.API.CreateScreenSurfaceMESA = xlib_eglCreateScreenSurfaceMESA; + xdrv->Base.API.ShowScreenSurfaceMESA = xlib_eglShowScreenSurfaceMESA; xdrv->apis = find_supported_apis(); if (xdrv->apis == 0x0) { -- 1.6.3.3 ------------------------------------------------------------------------------ This SF.Net email is sponsored by the Verizon Developer Community Take advantage of Verizon's best-in-class app development support A streamlined, 14 day to market process makes app distribution fast and easy Join now and get one step closer to millions of Verizon customers http://p.sf.net/sfu/verizon-dev2dev _______________________________________________ Mesa3d-dev mailing list Mesa3d-dev@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mesa3d-dev