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 <[email protected]>
*/
+#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
[email protected]
https://lists.sourceforge.net/lists/listinfo/mesa3d-dev