From d3fece21813f0a0e00e751703a8998b40f8dad73 Mon Sep 17 00:00:00 2001
From: Danct12 <danct12@disroot.org>
Date: Sat, 8 Jun 2019 16:56:10 +0700
Subject: [PATCH] [PATCH v2] Implement X11 EGL platform based on wayland code.

Original patch by NeKit <nekit1000@gmail.com>
Patched up for compatibility with libhybris gralloc support by Danct12 <danct12@disroot.org>

* Allow window system to hook eglGetConfigAttrib (needed for X11 EGL_NATIVE_VISUAL_ID)

* Use custom DRIHYBRIS Xorg extension for buffer sharing to Xorg/glamor when possible
  Gives huge speedup over XShmPutImage, but requires patched Glamor and DDX driver to
  utilize it

* Check for window resizes using Present extension when possible

* x11nativewindow: use same depth as target window for pixmap.
  Call xcb_present_pixmap instead of xcb_copy_area to present pixmap

Signed-off-by: Danct12 <danct12@disroot.org>
---
 hybris/configure.ac                          |   1 +
 hybris/egl/egl.c                             |  13 +-
 hybris/egl/platforms/Makefile.am             |   2 +-
 hybris/egl/platforms/x11/Makefile.am         |  43 ++
 hybris/egl/platforms/x11/eglplatform_x11.cpp | 229 ++++++
 hybris/egl/platforms/x11/x11_window.cpp      | 739 +++++++++++++++++++
 hybris/egl/platforms/x11/x11_window.h        | 195 +++++
 hybris/egl/platforms/x11/xcb_drihybris.c     | 167 +++++
 hybris/egl/platforms/x11/xcb_drihybris.h     | 122 +++
 hybris/egl/ws.c                              |   9 +
 hybris/egl/ws.h                              |   2 +
 11 files changed, 1520 insertions(+), 2 deletions(-)
 create mode 100644 hybris/egl/platforms/x11/Makefile.am
 create mode 100644 hybris/egl/platforms/x11/eglplatform_x11.cpp
 create mode 100644 hybris/egl/platforms/x11/x11_window.cpp
 create mode 100644 hybris/egl/platforms/x11/x11_window.h
 create mode 100644 hybris/egl/platforms/x11/xcb_drihybris.c
 create mode 100644 hybris/egl/platforms/x11/xcb_drihybris.h

diff --git a/hybris/configure.ac b/hybris/configure.ac
index b3ddc50..7d20c34 100644
--- a/hybris/configure.ac
+++ b/hybris/configure.ac
@@ -264,6 +264,7 @@ AC_CONFIG_FILES([
 	egl/platforms/null/Makefile
 	egl/platforms/fbdev/Makefile
 	egl/platforms/wayland/Makefile
+	egl/platforms/x11/Makefile
 	egl/platforms/hwcomposer/Makefile
 	egl/platforms/hwcomposer/hwcomposer-egl.pc
 	glesv1/glesv1_cm.pc
diff --git a/hybris/egl/egl.c b/hybris/egl/egl.c
index f6dcd09..4c02ebf 100644
--- a/hybris/egl/egl.c
+++ b/hybris/egl/egl.c
@@ -228,7 +228,6 @@ const char * eglQueryString(EGLDisplay dpy, EGLint name)
 
 HYBRIS_IMPLEMENT_FUNCTION4(egl, EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig *, EGLint, EGLint *);
 HYBRIS_IMPLEMENT_FUNCTION5(egl, EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *);
-HYBRIS_IMPLEMENT_FUNCTION4(egl, EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint *);
 
 EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
 		EGLNativeWindowType win,
@@ -461,4 +460,16 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
 	return ret;
 }
 
+EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
+{
+	HYBRIS_DLSYSM(egl, &_eglGetConfigAttrib, "eglGetConfigAttrib");
+	struct _EGLDisplay *display = hybris_egl_display_get_mapping(dpy);
+
+    EGLBoolean ret = ws_eglGetConfigAttrib(display, config, attribute, value);
+    if (ret == EGL_FALSE) {
+        return (*_eglGetConfigAttrib)(dpy, config, attribute, value);
+    }
+    return ret;
+}
+
 // vim:ts=4:sw=4:noexpandtab
diff --git a/hybris/egl/platforms/Makefile.am b/hybris/egl/platforms/Makefile.am
index 4126752..c52de15 100644
--- a/hybris/egl/platforms/Makefile.am
+++ b/hybris/egl/platforms/Makefile.am
@@ -11,4 +11,4 @@ if WANT_WAYLAND
 SUBDIRS += wayland
 endif
 
-
+SUBDIRS += x11
diff --git a/hybris/egl/platforms/x11/Makefile.am b/hybris/egl/platforms/x11/Makefile.am
new file mode 100644
index 0000000..4ab00f2
--- /dev/null
+++ b/hybris/egl/platforms/x11/Makefile.am
@@ -0,0 +1,43 @@
+pkglib_LTLIBRARIES = eglplatform_x11.la
+
+eglplatform_x11_la_SOURCES = eglplatform_x11.cpp x11_window.cpp xcb_drihybris.c
+eglplatform_x11_la_CXXFLAGS = \
+	-I$(top_srcdir)/common \
+	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/egl \
+	-I$(top_srcdir)/egl/platforms/common \
+	$(ANDROID_HEADERS_CFLAGS) \
+	$(WAYLAND_CLIENT_CFLAGS)
+
+if WANT_DEBUG
+eglplatform_x11_la_CXXFLAGS += -I$(top_srcdir)/common
+endif
+
+if WANT_TRACE
+eglplatform_x11_la_CXXFLAGS += -DDEBUG
+endif
+
+if WANT_DEBUG
+eglplatform_x11_la_CXXFLAGS += -ggdb -O0
+endif
+
+if !WANT_WL_SERVERSIDE_BUFFERS
+eglplatform_x11_la_CXXFLAGS += -DHYBRIS_NO_SERVER_SIDE_BUFFERS
+endif
+
+
+
+eglplatform_x11_la_LDFLAGS = \
+	-avoid-version -module -shared -export-dynamic \
+	$(top_builddir)/egl/platforms/common/libhybris-eglplatformcommon.la \
+	$(top_builddir)/gralloc/libgralloc.la \
+	-lXext -lxcb -lX11-xcb -lxcb-present
+
+if HAS_ANDROID_4_2_0
+eglplatform_x11_la_LDFLAGS += $(top_builddir)/libsync/libsync.la
+endif
+
+if HAS_ANDROID_5_0_0
+eglplatform_x11_la_LDFLAGS += $(top_builddir)/libsync/libsync.la
+endif
+
diff --git a/hybris/egl/platforms/x11/eglplatform_x11.cpp b/hybris/egl/platforms/x11/eglplatform_x11.cpp
new file mode 100644
index 0000000..3a1ac4f
--- /dev/null
+++ b/hybris/egl/platforms/x11/eglplatform_x11.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************************
+**
+** Copyright (C) 2013 Jolla Ltd.
+** Contact: Carsten Munk <carsten.munk@jollamobile.com>
+** All rights reserved.
+**
+** This file is part of X11 enablement for libhybris
+**
+** You may use this file under the terms of the GNU Lesser General
+** Public License version 2.1 as published by the Free Software Foundation
+** and appearing in the file license.lgpl included in the packaging
+** of this file.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation
+** and appearing in the file license.lgpl included in the packaging
+** of this file.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Lesser General Public License for more details.
+**
+****************************************************************************************/
+
+#include <android-config.h>
+#include <ws.h>
+#include <malloc.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdlib.h>
+extern "C" {
+#include <eglplatformcommon.h>
+};
+#include <eglhybris.h>
+
+#include <EGL/eglext.h>
+
+extern "C" {
+#include <wayland-client.h>
+#include <wayland-egl.h>
+}
+
+#include <hybris/gralloc/gralloc.h>
+#include "x11_window.h"
+#include "logging.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+static const char *  (*_eglQueryString)(EGLDisplay dpy, EGLint name) = NULL;
+static __eglMustCastToProperFunctionPointerType (*_eglGetProcAddress)(const char *procname) = NULL;
+static EGLSyncKHR (*_eglCreateSyncKHR)(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) = NULL;
+static EGLBoolean (*_eglDestroySyncKHR)(EGLDisplay dpy, EGLSyncKHR sync) = NULL;
+static EGLint (*_eglClientWaitSyncKHR)(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) = NULL;
+
+struct X11Display {
+	_EGLDisplay base;
+	Display *xl_display;
+};
+
+extern "C" void x11ws_init_module(struct ws_egl_interface *egl_iface)
+{
+	hybris_gralloc_initialize(0);
+	eglplatformcommon_init(egl_iface);
+}
+
+static void _init_egl_funcs(EGLDisplay display)
+{
+	if (_eglQueryString != NULL)
+		return;
+
+	_eglQueryString = (const char * (*)(void*, int))
+			hybris_android_egl_dlsym("eglQueryString");
+	assert(_eglQueryString);
+	_eglGetProcAddress = (__eglMustCastToProperFunctionPointerType (*)(const char *))
+			hybris_android_egl_dlsym("eglGetProcAddress");
+	assert(_eglGetProcAddress);
+
+	const char *extensions = (*_eglQueryString)(display, EGL_EXTENSIONS);
+
+	if (strstr(extensions, "EGL_KHR_fence_sync")) {
+		_eglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC)
+				(*_eglGetProcAddress)("eglCreateSyncKHR");
+		assert(_eglCreateSyncKHR);
+		_eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)
+				(*_eglGetProcAddress)("eglDestroySyncKHR");
+		assert(_eglDestroySyncKHR);
+		_eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)
+				(*_eglGetProcAddress)("eglClientWaitSyncKHR");
+		assert(_eglClientWaitSyncKHR);
+	}
+}
+
+extern "C" _EGLDisplay *x11ws_GetDisplay(EGLNativeDisplayType display)
+{
+	X11Display *xdpy = new X11Display;
+	xdpy->xl_display = (Display *)display;
+
+	return &xdpy->base;
+}
+
+extern "C" void x11ws_Terminate(_EGLDisplay *dpy)
+{
+	X11Display *xdpy = (X11Display *)dpy;
+	int ret = 0;
+	delete xdpy;
+}
+
+extern "C" EGLNativeWindowType x11ws_CreateWindow(EGLNativeWindowType win, _EGLDisplay *display)
+{
+	Window xlib_window = (Window) win;
+	X11Display *xdpy = (X11Display *)display;
+
+	if (win == 0 || xdpy->xl_display == 0) {
+		HYBRIS_ERROR("Running with EGL_PLATFORM=x11 without X server is not possible");
+		HYBRIS_ERROR("If you want to run a standlone EGL client do it like this:");
+		HYBRIS_ERROR(" $ export EGL_PLATFORM=null");
+		HYBRIS_ERROR(" $ test_glevs2");
+		abort();
+	}
+
+	X11NativeWindow *window = new X11NativeWindow(xdpy->xl_display, xlib_window);
+	window->common.incRef(&window->common);
+	return (EGLNativeWindowType) static_cast<struct ANativeWindow *>(window);
+}
+
+extern "C" void x11ws_DestroyWindow(EGLNativeWindowType win)
+{
+	X11NativeWindow *window = static_cast<X11NativeWindow *>((struct ANativeWindow *)win);
+	window->common.decRef(&window->common);
+}
+
+extern "C" __eglMustCastToProperFunctionPointerType x11ws_eglGetProcAddress(const char *procname)
+{
+	return eglplatformcommon_eglGetProcAddress(procname);
+}
+
+extern "C" void x11ws_passthroughImageKHR(EGLContext *ctx, EGLenum *target, EGLClientBuffer *buffer, const EGLint **attrib_list)
+{
+	eglplatformcommon_passthroughImageKHR(ctx, target, buffer, attrib_list);
+}
+
+extern "C" const char *x11ws_eglQueryString(EGLDisplay dpy, EGLint name, const char *(*real_eglQueryString)(EGLDisplay dpy, EGLint name))
+{
+	const char *ret = eglplatformcommon_eglQueryString(dpy, name, real_eglQueryString);
+	if (ret && name == EGL_EXTENSIONS)
+	{
+		static char eglextensionsbuf[1024];
+		snprintf(eglextensionsbuf, 1022, "%s %s", ret,
+			"EGL_EXT_swap_buffers_with_damage EGL_WL_create_x11_buffer_from_image"
+		);
+		ret = eglextensionsbuf;
+	}
+	return ret;
+}
+
+extern "C" void x11ws_prepareSwap(EGLDisplay dpy, EGLNativeWindowType win, EGLint *damage_rects, EGLint damage_n_rects)
+{
+	X11NativeWindow *window = static_cast<X11NativeWindow *>((struct ANativeWindow *)win);
+	window->prepareSwap(damage_rects, damage_n_rects);
+}
+
+extern "C" void x11ws_finishSwap(EGLDisplay dpy, EGLNativeWindowType win)
+{
+	_init_egl_funcs(dpy);
+	X11NativeWindow *window = static_cast<X11NativeWindow *>((struct ANativeWindow *)win);
+	if (_eglCreateSyncKHR) {
+		EGLSyncKHR sync = (*_eglCreateSyncKHR)(dpy, EGL_SYNC_FENCE_KHR, NULL);
+		(*_eglClientWaitSyncKHR)(dpy, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
+		(*_eglDestroySyncKHR)(dpy, sync);
+	}
+	window->finishSwap();
+}
+
+extern "C" void x11ws_setSwapInterval(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval)
+{
+	X11NativeWindow *window = static_cast<X11NativeWindow *>((struct ANativeWindow *)win);
+	window->setSwapInterval(interval);
+}
+
+extern "C" EGLBoolean x11ws_eglGetConfigAttrib(struct _EGLDisplay *display, EGLConfig config, EGLint attribute, EGLint *value)
+{
+    TRACE("attribute:%i", attribute);
+    if (attribute == EGL_NATIVE_VISUAL_ID)
+    {
+        X11Display *xdpy = (X11Display *)display;
+        XVisualInfo visinfo_template;
+        XVisualInfo *visinfo = NULL;
+        int visinfos_count = 0;
+
+        visinfo_template.depth = 32;
+        visinfo = XGetVisualInfo (xdpy->xl_display,
+                            VisualDepthMask,
+                            &visinfo_template,
+                            &visinfos_count);
+
+        if (visinfos_count)
+        {
+            TRACE("visinfo.visualid:%i", attribute);
+            *value = visinfo->visualid;
+            return EGL_TRUE;
+        }
+
+    }
+    return EGL_FALSE;
+}
+
+struct ws_module ws_module_info = {
+	x11ws_init_module,
+	x11ws_GetDisplay,
+	x11ws_Terminate,
+	x11ws_CreateWindow,
+	x11ws_DestroyWindow,
+	x11ws_eglGetProcAddress,
+	x11ws_passthroughImageKHR,
+	x11ws_eglQueryString,
+	x11ws_prepareSwap,
+	x11ws_finishSwap,
+	x11ws_setSwapInterval,
+    x11ws_eglGetConfigAttrib
+};
diff --git a/hybris/egl/platforms/x11/x11_window.cpp b/hybris/egl/platforms/x11/x11_window.cpp
new file mode 100644
index 0000000..6eea75b
--- /dev/null
+++ b/hybris/egl/platforms/x11/x11_window.cpp
@@ -0,0 +1,739 @@
+/****************************************************************************************
+ **
+ ** Copyright (C) 2013 Jolla Ltd.
+ ** Contact: Carsten Munk <carsten.munk@jollamobile.com>
+ ** All rights reserved.
+ **
+ ** This file is part of Wayland enablement for libhybris
+ **
+ ** You may use this file under the terms of the GNU Lesser General
+ ** Public License version 2.1 as published by the Free Software Foundation
+ ** and appearing in the file license.lgpl included in the packaging
+ ** of this file.
+ **
+ ** This library is free software; you can redistribute it and/or
+ ** modify it under the terms of the GNU Lesser General Public
+ ** License version 2.1 as published by the Free Software Foundation
+ ** and appearing in the file license.lgpl included in the packaging
+ ** of this file.
+ **
+ ** This library is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ** Lesser General Public License for more details.
+ **
+ ****************************************************************************************/
+
+#include <android-config.h>
+#include "x11_window.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "logging.h"
+#include <eglhybris.h>
+#include "xcb_drihybris.h"
+
+#if ANDROID_VERSION_MAJOR>=4 && ANDROID_VERSION_MINOR>=2 || ANDROID_VERSION_MAJOR>=5
+extern "C" {
+#include <sync/sync.h>
+}
+#endif
+
+void X11NativeWindow::resize(unsigned int width, unsigned int height)
+{
+    lock();
+    this->m_defaultWidth = this->m_width = width;
+    this->m_defaultHeight = this->m_height = height;
+    unlock();
+}
+
+void X11NativeWindow::lock()
+{
+    pthread_mutex_lock(&this->mutex);
+}
+
+void X11NativeWindow::unlock()
+{
+    pthread_mutex_unlock(&this->mutex);
+}
+
+X11NativeWindow::X11NativeWindow(Display* xl_display, Window xl_window)
+{
+    int wayland_ok;
+
+    HYBRIS_TRACE_BEGIN("x11-platform", "create_window", "");
+    this->m_window = xl_window;
+    this->m_display = xl_display;
+    this->m_connection = XGetXCBConnection(xl_display);
+    this->m_image = 0;
+    this->m_useShm = true;
+    this->m_format = HAL_PIXEL_FORMAT_RGBA_8888;
+
+    const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
+    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
+    // This is the default as per the EGL documentation
+    this->m_swap_interval = 1;
+
+    TRACE("getting X11 window information");
+
+    XWindowAttributes window_attributes;
+    XGetWindowAttributes(m_display, m_window, &window_attributes);
+
+    TRACE("window x=%d y=%d width=%d height=%d depth=%d",
+        window_attributes.x,
+        window_attributes.y,
+        window_attributes.width,
+        window_attributes.height,
+        window_attributes.depth);
+
+    m_width = window_attributes.width;
+    m_height = window_attributes.height;
+    m_depth = window_attributes.depth;
+
+    const char *env = getenv("HYBRIS_X11_FORCE_WIDTH");
+    if (env != NULL)
+    {
+        m_width = atoi(env);
+        TRACE("forced width=%d", m_width);
+    }
+
+    env = getenv("HYBRIS_X11_FORCE_HEIGHT");
+    if (env != NULL)
+    {
+        m_height = atoi(env);
+        TRACE("forced height=%d", m_height);
+    }
+
+    m_defaultWidth = m_width;
+    m_defaultHeight = m_height;
+
+    env = getenv("HYBRIS_X11_DISABLE_SHM");
+    if (env != NULL)
+    {
+        m_useShm = false;
+        TRACE("won't use MIT-SHM");
+    }
+
+    XGCValues gcvalues;
+    m_gc = XCreateGC(m_display, m_window, 0, &gcvalues);
+
+    m_xcb_gc = xcb_generate_id(m_connection);
+    xcb_create_gc(m_connection, m_xcb_gc, m_window, 0, 0);
+
+    m_specialEvent = 0;
+    m_haveDRIHybris = false;
+    tryEnableDRIHybris();
+
+    m_usage=GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN;
+    pthread_mutex_init(&mutex, NULL);
+    pthread_cond_init(&cond, NULL);
+    m_queueReads = 0;
+    m_freeBufs = 0;
+    m_damage_rects = NULL;
+    m_damage_n_rects = 0;
+    m_lastBuffer = 0;
+    setBufferCount(3);
+    HYBRIS_TRACE_END("x11-platform", "create_window", "");
+}
+
+X11NativeWindow::~X11NativeWindow()
+{
+    std::list<X11NativeWindowBuffer *>::iterator it = m_bufList.begin();
+    destroyBuffers();
+}
+
+// overloads from BaseNativeWindow
+int X11NativeWindow::setSwapInterval(int interval) {
+    TRACE("interval:%i", interval);
+
+    if (interval < 0)
+        interval = 0;
+    if (interval > 1)
+        interval = 1;
+
+    HYBRIS_TRACE_BEGIN("x11-platform", "swap_interval", "=%d", interval);
+
+    lock();
+    m_swap_interval = interval;
+    unlock();
+
+    HYBRIS_TRACE_END("x11-platform", "swap_interval", "");
+
+    return 0;
+}
+
+int X11NativeWindow::dequeueBuffer(BaseNativeWindowBuffer **buffer, int *fenceFd){
+    HYBRIS_TRACE_BEGIN("x11-platform", "dequeueBuffer", "");
+
+    X11NativeWindowBuffer *wnb=NULL;
+    TRACE("%p", buffer);
+
+    readQueue(false);
+
+    HYBRIS_TRACE_BEGIN("x11-platform", "dequeueBuffer_wait_for_buffer", "");
+
+    HYBRIS_TRACE_COUNTER("x11-platform", "m_freeBufs", "%i", m_freeBufs);
+
+    while (m_freeBufs == 0) {
+        HYBRIS_TRACE_COUNTER("x11-platform", "m_freeBufs", "%i", m_freeBufs);
+        readQueue(true);
+    }
+
+    lock();
+
+    std::list<X11NativeWindowBuffer *>::iterator it = m_bufList.begin();
+    for (; it != m_bufList.end(); it++)
+    {
+        if ((*it)->busy)
+            continue;
+        if ((*it)->youngest == 1)
+            continue;
+        break;
+    }
+
+    if (it==m_bufList.end()) {
+        HYBRIS_TRACE_BEGIN("x11-platform", "dequeueBuffer_worst_case_scenario", "");
+        HYBRIS_TRACE_END("x11-platform", "dequeueBuffer_worst_case_scenario", "");
+
+        it = m_bufList.begin();
+        for (; it != m_bufList.end() && (*it)->busy; it++)
+        {}
+
+    }
+    if (it==m_bufList.end()) {
+        unlock();
+        HYBRIS_TRACE_BEGIN("x11-platform", "dequeueBuffer_no_free_buffers", "");
+        HYBRIS_TRACE_END("x11-platform", "dequeueBuffer_no_free_buffers", "");
+        TRACE("%p: no free buffers", buffer);
+        return NO_ERROR;
+    }
+
+    wnb = *it;
+    assert(wnb!=NULL);
+    HYBRIS_TRACE_END("x11-platform", "dequeueBuffer_wait_for_buffer", "");
+
+    /* If the buffer doesn't match the window anymore, re-allocate */
+    if (wnb->width != m_width || wnb->height != m_height
+        || wnb->format != m_format || wnb->usage != m_usage)
+    {
+        TRACE("wnb:%p,win:%p %i,%i %i,%i x%x,x%x x%x,x%x",
+            wnb,m_window,
+            wnb->width,m_width, wnb->height,m_height,
+            wnb->format,m_format, wnb->usage,m_usage);
+        destroyBuffer(wnb);
+        m_bufList.erase(it);
+        wnb = addBuffer();
+    }
+
+    wnb->busy = 1;
+    *buffer = wnb;
+    queue.push_back(wnb);
+    --m_freeBufs;
+
+    HYBRIS_TRACE_COUNTER("x11-platform", "m_freeBufs", "%i", m_freeBufs);
+    HYBRIS_TRACE_BEGIN("x11-platform", "dequeueBuffer_gotBuffer", "-%p", wnb);
+    HYBRIS_TRACE_END("x11-platform", "dequeueBuffer_gotBuffer", "-%p", wnb);
+    HYBRIS_TRACE_END("x11-platform", "dequeueBuffer_wait_for_buffer", "");
+
+    unlock();
+    return NO_ERROR;
+}
+
+int X11NativeWindow::lockBuffer(BaseNativeWindowBuffer* buffer){
+    X11NativeWindowBuffer *wnb = (X11NativeWindowBuffer*) buffer;
+    HYBRIS_TRACE_BEGIN("x11-platform", "lockBuffer", "-%p", wnb);
+    HYBRIS_TRACE_END("x11-platform", "lockBuffer", "-%p", wnb);
+    return NO_ERROR;
+}
+
+int X11NativeWindow::readQueue(bool block)
+{
+    int ret = 0;
+
+    if (++m_queueReads == 1) {
+        if (m_specialEvent) {
+            xcb_generic_event_t    *ev;
+
+            if (!block)
+            {
+                while ((ev = xcb_poll_for_special_event(m_connection,
+                                                        m_specialEvent)) != NULL) {
+                    xcb_present_generic_event_t *ge = (xcb_present_generic_event_t *) ev;
+                    handlePresentEvent(ge);
+                }
+            }
+        }
+
+        // all threads waiting on the false branch will wake and return now, so we
+        // can safely set m_queueReads to 0 here instead of relying on every thread
+        // to decrement it. This prevents a race condition when a thread enters readQueue()
+        // before the one in this thread returns.
+        // The new thread would go in the false branch, and there would be no thread in the
+        // true branch, blocking the new thread and any other that will call readQueue in
+        // the future.
+        m_queueReads = 0;
+
+        pthread_cond_broadcast(&cond);
+
+    } else if (block) {
+        while (m_queueReads > 0) {
+            pthread_cond_wait(&cond, &mutex);
+        }
+    }
+
+    return ret;
+}
+
+void X11NativeWindow::prepareSwap(EGLint *damage_rects, EGLint damage_n_rects)
+{
+    lock();
+    m_damage_rects = damage_rects;
+    m_damage_n_rects = damage_n_rects;
+    unlock();
+}
+
+void X11NativeWindow::finishSwap()
+{
+    static int serial = 0;
+    int ret = 0;
+    lock();
+
+    X11NativeWindowBuffer *wnb = queue.front();
+    if (!wnb) {
+        wnb = m_lastBuffer;
+    } else {
+        queue.pop_front();
+    }
+    assert(wnb);
+    m_lastBuffer = wnb;
+    wnb->busy = 1;
+
+    // fronted.push_back(wnb);
+
+    m_damage_rects = NULL;
+    m_damage_n_rects = 0;
+    unlock();
+
+    if (m_haveDRIHybris) {
+        if (wnb->pixmap == 0)
+            wnb->pixmap_from_buffer(m_connection, m_window);
+
+        xcb_present_pixmap(m_connection,
+                            m_window,
+                            wnb->pixmap,
+                            (uint32_t) serial++,
+                            0,                                    /* valid */
+                            0,                                    /* update */
+                            0,                                    /* x_off */
+                            0,                                    /* y_off */
+                            None,                                 /* target_crtc */
+                            None,
+                            NULL,
+                            XCB_PRESENT_OPTION_NONE,
+                            0,
+                            0,
+                            0, 0, NULL);
+        xcb_flush(m_connection);
+
+        lock();
+
+        ++m_freeBufs;
+        HYBRIS_TRACE_COUNTER("x11-platform", "m_freeBufs", "%i", m_freeBufs);
+
+        std::list<X11NativeWindowBuffer *>::iterator it;
+        for (it = m_bufList.begin(); it != m_bufList.end(); it++)
+        {
+            (*it)->youngest = 0;
+        }
+        wnb->youngest = 1;
+        wnb->busy = 0;
+
+        unlock();
+    } else {
+        copyToX11(wnb);
+    }
+}
+
+static int debugenvchecked = 0;
+
+int X11NativeWindow::queueBuffer(BaseNativeWindowBuffer* buffer, int fenceFd)
+{
+    X11NativeWindowBuffer *wnb = (X11NativeWindowBuffer*) buffer;
+    int ret = 0;
+
+    HYBRIS_TRACE_BEGIN("x11-platform", "queueBuffer", "-%p", wnb);
+    lock();
+
+    if (debugenvchecked == 0)
+    {
+        if (getenv("HYBRIS_WAYLAND_DUMP_BUFFERS") != NULL)
+            debugenvchecked = 2;
+        else
+            debugenvchecked = 1;
+    }
+    if (debugenvchecked == 2)
+    {
+        HYBRIS_TRACE_BEGIN("x11-platform", "queueBuffer_dumping_buffer", "-%p", wnb);
+        hybris_dump_buffer_to_file(wnb->getNativeBuffer());
+        HYBRIS_TRACE_END("x11-platform", "queueBuffer_dumping_buffer", "-%p", wnb);
+
+    }
+
+#if ANDROID_VERSION_MAJOR>=4 && ANDROID_VERSION_MINOR>=2 || ANDROID_VERSION_MAJOR>=5
+    HYBRIS_TRACE_BEGIN("x11-platform", "queueBuffer_waiting_for_fence", "-%p", wnb);
+    if (fenceFd >= 0)
+    {
+        sync_wait(fenceFd, -1);
+        close(fenceFd);
+    }
+    HYBRIS_TRACE_END("x11-platform", "queueBuffer_waiting_for_fence", "-%p", wnb);
+#endif
+
+    HYBRIS_TRACE_COUNTER("x11-platform", "fronted.size", "%i", fronted.size());
+    HYBRIS_TRACE_END("x11-platform", "queueBuffer", "-%p", wnb);
+
+    unlock();
+
+    return NO_ERROR;
+}
+
+int X11NativeWindow::cancelBuffer(BaseNativeWindowBuffer* buffer, int fenceFd){
+    std::list<X11NativeWindowBuffer *>::iterator it;
+    X11NativeWindowBuffer *wnb = (X11NativeWindowBuffer*) buffer;
+
+    lock();
+    HYBRIS_TRACE_BEGIN("x11-platform", "cancelBuffer", "-%p", wnb);
+
+    /* Check first that it really is our buffer */
+    for (it = m_bufList.begin(); it != m_bufList.end(); it++)
+    {
+        if ((*it) == wnb)
+            break;
+    }
+    assert(it != m_bufList.end());
+
+    wnb->busy = 0;
+    ++m_freeBufs;
+    HYBRIS_TRACE_COUNTER("x11-platform", "m_freeBufs", "%i", m_freeBufs);
+
+    for (it = m_bufList.begin(); it != m_bufList.end(); it++)
+    {
+        (*it)->youngest = 0;
+    }
+    wnb->youngest = 1;
+
+    if (m_queueReads != 0) {
+        // Some thread is waiting on wl_display_dispatch_queue(), possibly waiting for a wl_buffer.release
+        // event. Since we have now cancelled a buffer push an artificial event so that the dispatch returns
+        // and the thread can notice the cancelled buffer. This means there is a delay of one roundtrip,
+        // but I don't see other solution except having one dedicated thread for calling wl_display_dispatch_queue().
+        //wl_callback_destroy(wl_display_sync(m_display));
+    }
+
+    HYBRIS_TRACE_END("x11-platform", "cancelBuffer", "-%p", wnb);
+    unlock();
+
+    return 0;
+}
+
+unsigned int X11NativeWindow::width() const {
+    TRACE("value:%i", m_width);
+    return m_width;
+}
+
+unsigned int X11NativeWindow::height() const {
+    TRACE("value:%i", m_height);
+    return m_height;
+}
+
+unsigned int X11NativeWindow::format() const {
+    TRACE("value:%i", m_format);
+    return m_format;
+}
+
+unsigned int X11NativeWindow::defaultWidth() const {
+    TRACE("value:%i", m_defaultWidth);
+    return m_defaultWidth;
+}
+
+unsigned int X11NativeWindow::defaultHeight() const {
+    TRACE("value:%i", m_defaultHeight);
+    return m_defaultHeight;
+}
+
+unsigned int X11NativeWindow::queueLength() const {
+    TRACE("WARN: stub");
+    return 1;
+}
+
+unsigned int X11NativeWindow::type() const {
+    TRACE("");
+#if ANDROID_VERSION_MAJOR>=4 && ANDROID_VERSION_MINOR>=3 || ANDROID_VERSION_MAJOR>=5
+    /* https://android.googlesource.com/platform/system/core/+/bcfa910611b42018db580b3459101c564f802552%5E!/ */
+    return NATIVE_WINDOW_SURFACE;
+#else
+    return NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
+#endif
+}
+
+unsigned int X11NativeWindow::transformHint() const {
+    TRACE("WARN: stub");
+    return 0;
+}
+
+/*
+ * returns the current usage of this window
+ */
+unsigned int X11NativeWindow::getUsage() const {
+    return m_usage;
+}
+
+int X11NativeWindow::setBuffersFormat(int format) {
+    if (format != m_format)
+    {
+        TRACE("old-format:x%x new-format:x%x", m_format, format);
+        m_format = format;
+        /* Buffers will be re-allocated when dequeued */
+    } else {
+        TRACE("format:x%x", format);
+    }
+    return NO_ERROR;
+}
+
+void X11NativeWindow::destroyBuffer(X11NativeWindowBuffer* wnb)
+{
+    TRACE("wnb:%p", wnb);
+
+    assert(wnb != NULL);
+
+    int ret = 0;
+
+    wnb->common.decRef(&wnb->common);
+    m_freeBufs--;
+}
+
+void X11NativeWindow::destroyBuffers()
+{
+    TRACE("");
+
+    std::list<X11NativeWindowBuffer*>::iterator it = m_bufList.begin();
+    for (; it!=m_bufList.end(); ++it)
+    {
+        destroyBuffer(*it);
+        it = m_bufList.erase(it);
+    }
+    m_bufList.clear();
+    m_freeBufs = 0;
+}
+
+X11NativeWindowBuffer *X11NativeWindow::addBuffer() {
+
+    X11NativeWindowBuffer *wnb;
+
+    wnb = new ClientX11Buffer(m_width, m_height, m_format, m_usage, m_depth);
+    m_bufList.push_back(wnb);
+    ++m_freeBufs;
+
+    TRACE("wnb:%p width:%i height:%i format:x%x usage:x%x",
+        wnb, wnb->width, wnb->height, wnb->format, wnb->usage);
+
+    return wnb;
+}
+
+int X11NativeWindow::setBufferCount(int cnt) {
+    int start = 0;
+
+    TRACE("cnt:%d", cnt);
+
+    if (m_bufList.size() == cnt)
+        return NO_ERROR;
+
+    lock();
+
+    if (m_bufList.size() > cnt) {
+        /* Decreasing buffer count, remove from beginning */
+        std::list<X11NativeWindowBuffer*>::iterator it = m_bufList.begin();
+        for (int i = 0; i <= m_bufList.size() - cnt; i++ )
+        {
+            destroyBuffer(*it);
+            ++it;
+            m_bufList.pop_front();
+        }
+
+    } else {
+        /* Increasing buffer count, start from current size */
+        for (int i = m_bufList.size(); i < cnt; i++)
+            X11NativeWindowBuffer *unused = addBuffer();
+
+    }
+
+    unlock();
+
+    return NO_ERROR;
+}
+
+int X11NativeWindow::setBuffersDimensions(int width, int height) {
+    if (m_width != width || m_height != height)
+    {
+        TRACE("old-size:%ix%i new-size:%ix%i", m_width, m_height, width, height);
+        m_width = width;
+        m_height = height;
+        /* Buffers will be re-allocated when dequeued */
+    } else {
+        TRACE("size:%ix%i", width, height);
+    }
+    return NO_ERROR;
+}
+
+int X11NativeWindow::setUsage(int usage) {
+//     if ((usage | GRALLOC_USAGE_HW_TEXTURE) != m_usage)
+//     {
+//         TRACE("old-usage:x%x new-usage:x%x", m_usage, usage);
+//         m_usage = usage | GRALLOC_USAGE_HW_TEXTURE;
+//         /* Buffers will be re-allocated when dequeued */
+//     } else {
+//         TRACE("usage:x%x", usage);
+//     }
+    return NO_ERROR;
+}
+
+void X11NativeWindow::copyToX11(X11NativeWindowBuffer *wnb) {
+    int ret;
+    void *vaddr;
+    std::list<X11NativeWindowBuffer *>::iterator it;
+
+    ret = hybris_gralloc_lock(wnb->handle, wnb->usage, 0, 0, wnb->width, wnb->height, &vaddr);
+    TRACE("wnb:%p gralloc lock returns %i", wnb, ret);
+    TRACE("wnb:%p lock to vaddr %p", wnb, vaddr);
+    TRACE("wnb:%p width=%d stride=%d height=%d format=%d", wnb, wnb->width, wnb->stride, wnb->height, wnb->format);
+
+    if (!m_image)
+    {
+        if (m_useShm)
+        {
+            m_image = XShmCreateImage(m_display,
+                        CopyFromParent,
+                        32,
+                        ZPixmap, 0, &m_shminfo, wnb->stride, wnb->height);
+
+            m_shminfo.shmid = shmget(IPC_PRIVATE,
+                m_image->bytes_per_line * m_image->height,
+                IPC_CREAT|0777);
+
+            m_shminfo.shmaddr = m_image->data = (char *)shmat(m_shminfo.shmid, 0, 0);
+            m_shminfo.readOnly = 0;
+
+            TRACE("m_shminfo.shmaddr %p", m_shminfo.shmaddr);
+
+            XShmAttach(m_display, &m_shminfo);
+        }
+        else
+        {
+            m_image = XCreateImage(m_display,
+                                CopyFromParent,
+                                32,
+                                ZPixmap, 0, (char *)vaddr, wnb->stride, wnb->height, 32, 0);
+        }
+    }
+
+
+    if (m_useShm)
+    {
+        memcpy(m_image->data, vaddr, m_image->bytes_per_line * m_image->height);
+        hybris_gralloc_unlock(wnb->handle);
+        XShmPutImage(m_display, m_window, m_gc, m_image, 0, 0, 0, 0, m_width, m_height, 0);
+    }
+    else
+    {
+        m_image->data = (char *)vaddr;
+        XPutImage(m_display, m_window, m_gc, m_image, 0, 0, 0, 0, m_width, m_height);
+        hybris_gralloc_unlock(wnb->handle);
+    }
+
+    lock();
+
+    ++m_freeBufs;
+    HYBRIS_TRACE_COUNTER("x11-platform", "m_freeBufs", "%i", m_freeBufs);
+    for (it = m_bufList.begin(); it != m_bufList.end(); it++)
+    {
+        (*it)->youngest = 0;
+    }
+    wnb->youngest = 1;
+    wnb->busy = 0;
+
+    unlock();
+}
+
+void X11NativeWindow::tryEnableDRIHybris()
+{
+    const xcb_query_extension_reply_t *extension;
+    xcb_void_cookie_t cookie;
+    xcb_generic_error_t *error;
+
+    xcb_prefetch_extension_data (m_connection, &xcb_drihybris_id);
+    xcb_prefetch_extension_data (m_connection, &xcb_present_id);
+
+    extension = xcb_get_extension_data(m_connection, &xcb_drihybris_id);
+    if (!(extension && extension->present))
+        return;
+
+    extension = xcb_get_extension_data(m_connection, &xcb_present_id);
+    if (!(extension && extension->present))
+        return;
+
+    m_specialEventId = xcb_generate_id(m_connection);
+    m_specialEvent = xcb_register_for_special_xge(m_connection,
+                            &xcb_present_id, m_specialEventId, NULL);
+
+    cookie = xcb_present_select_input_checked(m_connection,
+            m_specialEventId, m_window,
+            XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY |
+            XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY);
+
+    error = xcb_request_check(m_connection, cookie);
+    if (error) {
+        return;
+    }
+
+    m_haveDRIHybris = true;
+    // HYBRIS_PIXEL_FORMAT_RGBA_8888 is used in glamor for buffer import
+    m_format = HAL_PIXEL_FORMAT_RGBA_8888;
+}
+
+void X11NativeWindow::handlePresentEvent(xcb_present_generic_event_t *ge)
+{
+    switch (ge->evtype) {
+    case XCB_PRESENT_CONFIGURE_NOTIFY: {
+        xcb_present_configure_notify_event_t *ce = (xcb_present_configure_notify_event_t *) ge;
+        printf("XCB_PRESENT_CONFIGURE_NOTIFY: %dx%d\n", ce->width, ce->height);
+        resize(ce->width, ce->height);
+        break;
+    }
+    }
+}
+
+void X11NativeWindowBuffer::pixmap_from_buffer(xcb_connection_t *connection, xcb_drawable_t drawable)
+{
+    int32_t * fds;
+    fds = (int32_t *)calloc(handle->numFds, sizeof(int));
+    for (int i = 0; i < handle->numFds; i++) {
+        fds[i] = dup(handle->data[i]);
+    }
+
+    xcb_drihybris_pixmap_from_buffer_checked(connection,
+                               (pixmap = xcb_generate_id(connection)),
+                               drawable,
+                               stride * height * 4,
+                               this->width, height, stride,
+                               windowDepth, 32,
+                               handle->numInts,
+                               handle->numFds,
+                               (const uint32_t *)(handle->data + handle->numFds),
+                               (const int32_t *)fds);
+    xcb_flush(connection);
+    free(fds);
+}
+
+// vim: noai:ts=4:sw=4:ss=4:expandtab
diff --git a/hybris/egl/platforms/x11/x11_window.h b/hybris/egl/platforms/x11/x11_window.h
new file mode 100644
index 0000000..e4464db
--- /dev/null
+++ b/hybris/egl/platforms/x11/x11_window.h
@@ -0,0 +1,195 @@
+/****************************************************************************************
+ **
+ ** Copyright (C) 2013 Jolla Ltd.
+ ** Contact: Carsten Munk <carsten.munk@jollamobile.com>
+ ** All rights reserved.
+ **
+ ** This file is part of Wayland enablement for libhybris
+ **
+ ** You may use this file under the terms of the GNU Lesser General
+ ** Public License version 2.1 as published by the Free Software Foundation
+ ** and appearing in the file license.lgpl included in the packaging
+ ** of this file.
+ **
+ ** This library is free software; you can redistribute it and/or
+ ** modify it under the terms of the GNU Lesser General Public
+ ** License version 2.1 as published by the Free Software Foundation
+ ** and appearing in the file license.lgpl included in the packaging
+ ** of this file.
+ **
+ ** This library is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ** Lesser General Public License for more details.
+ **
+ ****************************************************************************************/
+
+#ifndef X11_WINDOW_H
+#define X11_WINDOW_H
+#include "nativewindowbase.h"
+#include <linux/fb.h>
+#include <hybris/gralloc/gralloc.h>
+extern "C" {
+#include <X11/Xlib-xcb.h>
+#include <xcb/present.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+#include <pthread.h>
+}
+#include <list>
+#include <deque>
+
+class X11NativeWindowBuffer : public BaseNativeWindowBuffer
+{
+public:
+    X11NativeWindowBuffer() : busy(0), youngest(0), other(0) {}
+    X11NativeWindowBuffer(ANativeWindowBuffer *other)
+    {
+        ANativeWindowBuffer::width = other->width;
+        ANativeWindowBuffer::height = other->height;
+        ANativeWindowBuffer::format = other->format;
+        ANativeWindowBuffer::usage = other->usage;
+        ANativeWindowBuffer::handle = other->handle;
+        ANativeWindowBuffer::stride = other->stride;
+
+        this->busy = 0;
+        this->other = other;
+        this->youngest = 0;
+        this->pixmap = 0;
+    }
+
+    int busy;
+    int youngest;
+    ANativeWindowBuffer *other;
+    int windowDepth;
+    xcb_pixmap_t pixmap;
+
+    void pixmap_from_buffer(xcb_connection_t *connection, xcb_drawable_t drawable);
+};
+
+class ClientX11Buffer : public X11NativeWindowBuffer
+{
+friend class X11NativeWindow;
+protected:
+    ClientX11Buffer(        unsigned int width,
+                            unsigned int height,
+                            unsigned int format,
+                            unsigned int usage,
+                            unsigned int windowDepth)
+    {
+        // Base members
+        ANativeWindowBuffer::width = width;
+        ANativeWindowBuffer::height = height;
+        ANativeWindowBuffer::format = format;
+        ANativeWindowBuffer::usage = usage;
+
+        this->busy = 0;
+        this->other = NULL;
+        int alloc_ok = hybris_gralloc_allocate(this->width ? this->width : 1, this->height ? this->height : 1,
+                this->format, this->usage,
+                &this->handle, (uint32_t*)&this->stride);
+        assert(alloc_ok == 0);
+        this->youngest = 0;
+        this->common.incRef(&this->common);
+
+        this->windowDepth = windowDepth;
+        this->pixmap = 0;
+    }
+
+    ~ClientX11Buffer()
+    {
+        hybris_gralloc_release(this->handle, 1);
+    }
+
+protected:
+    void* vaddr;
+
+public:
+
+};
+
+class X11NativeWindow : public BaseNativeWindow {
+public:
+    X11NativeWindow(Display* xl_display, Window xl_window);
+    ~X11NativeWindow();
+
+    void lock();
+    void unlock();
+    void frame();
+    void resize(unsigned int width, unsigned int height);
+    void releaseBuffer(struct wl_buffer *buffer);
+
+    virtual int setSwapInterval(int interval);
+    void prepareSwap(EGLint *damage_rects, EGLint damage_n_rects);
+    void finishSwap();
+
+protected:
+    // overloads from BaseNativeWindow
+    virtual int dequeueBuffer(BaseNativeWindowBuffer **buffer, int *fenceFd);
+    virtual int lockBuffer(BaseNativeWindowBuffer* buffer);
+    virtual int queueBuffer(BaseNativeWindowBuffer* buffer, int fenceFd);
+    virtual int cancelBuffer(BaseNativeWindowBuffer* buffer, int fenceFd);
+    virtual unsigned int type() const;
+    virtual unsigned int width() const;
+    virtual unsigned int height() const;
+    virtual unsigned int format() const;
+    virtual unsigned int defaultWidth() const;
+    virtual unsigned int defaultHeight() const;
+    virtual unsigned int queueLength() const;
+    virtual unsigned int transformHint() const;
+    virtual unsigned int getUsage() const;
+    // perform calls
+    virtual int setUsage(int usage);
+    virtual int setBuffersFormat(int format);
+    virtual int setBuffersDimensions(int width, int height);
+    virtual int setBufferCount(int cnt);
+
+private:
+    X11NativeWindowBuffer *addBuffer();
+    void destroyBuffer(X11NativeWindowBuffer *);
+    void destroyBuffers();
+    int readQueue(bool block);
+
+    void copyToX11(X11NativeWindowBuffer *wnb);
+    void tryEnableDRIHybris();
+    void handlePresentEvent(xcb_present_generic_event_t *ge);
+
+    std::list<X11NativeWindowBuffer *> m_bufList;
+    std::list<X11NativeWindowBuffer *> fronted;
+    std::list<X11NativeWindowBuffer *> posted;
+    std::list<X11NativeWindowBuffer *> post_registered;
+    std::deque<X11NativeWindowBuffer *> queue;
+
+    Display* m_display;
+    Window m_window;
+    XImage *m_image;
+    XShmSegmentInfo m_shminfo;
+    GC m_gc;
+
+    xcb_connection_t *m_connection;
+    xcb_gcontext_t m_xcb_gc;
+    xcb_present_event_t m_specialEventId;
+    xcb_special_event_t *m_specialEvent;
+
+    bool m_useShm;
+    bool m_haveDRIHybris;
+    
+    X11NativeWindowBuffer *m_lastBuffer;
+    unsigned int m_width;
+    unsigned int m_height;
+    unsigned int m_depth;
+    unsigned int m_format;
+    unsigned int m_defaultWidth;
+    unsigned int m_defaultHeight;
+    unsigned int m_usage;
+
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    int m_queueReads;
+    int m_freeBufs;
+    EGLint *m_damage_rects, m_damage_n_rects;
+    int m_swap_interval;
+};
+
+#endif
+// vim: noai:ts=4:sw=4:ss=4:expandtab
diff --git a/hybris/egl/platforms/x11/xcb_drihybris.c b/hybris/egl/platforms/x11/xcb_drihybris.c
new file mode 100644
index 0000000..bec3722
--- /dev/null
+++ b/hybris/egl/platforms/x11/xcb_drihybris.c
@@ -0,0 +1,167 @@
+/*
+ * This file generated automatically from drihybris.xml by c_client.py.
+ * Edit at your peril.
+ */
+
+#include "xcb_drihybris.h"
+#include <stddef.h>  /* for offsetof() */
+
+xcb_extension_t xcb_drihybris_id = { "DRIHYBRIS", 0 };
+
+#define ALIGNOF(type) offsetof(struct { char dummy; type member; }, member)
+
+int
+xcb_drihybris_pixmap_from_buffer_sizeof (const void  *_buffer,
+                                         int32_t      pixmap_fd)
+{
+    char *xcb_tmp = (char *)_buffer;
+    const xcb_drihybris_pixmap_from_buffer_request_t *_aux = (xcb_drihybris_pixmap_from_buffer_request_t *)_buffer;
+    unsigned int xcb_buffer_len = 0;
+    unsigned int xcb_block_len = 0;
+    unsigned int xcb_pad = 0;
+    unsigned int xcb_align_to = 0;
+
+
+    xcb_block_len += sizeof(xcb_drihybris_pixmap_from_buffer_request_t);
+    xcb_tmp += xcb_block_len;
+    xcb_buffer_len += xcb_block_len;
+    xcb_block_len = 0;
+    /* ints */
+    xcb_block_len += _aux->num_ints * sizeof(uint32_t);
+    xcb_tmp += xcb_block_len;
+    xcb_align_to = ALIGNOF(uint32_t);
+    /* insert padding */
+    xcb_pad = -xcb_block_len & (xcb_align_to - 1);
+    xcb_buffer_len += xcb_block_len + xcb_pad;
+    if (0 != xcb_pad) {
+        xcb_tmp += xcb_pad;
+        xcb_pad = 0;
+    }
+    xcb_block_len = 0;
+
+    return xcb_buffer_len;
+}
+
+xcb_void_cookie_t
+xcb_drihybris_pixmap_from_buffer_checked (xcb_connection_t *c,
+                                          xcb_pixmap_t      pixmap,
+                                          xcb_drawable_t    drawable,
+                                          uint32_t          size,
+                                          uint16_t          width,
+                                          uint16_t          height,
+                                          uint16_t          stride,
+                                          uint8_t           depth,
+                                          uint8_t           bpp,
+                                          uint16_t          num_ints,
+                                          uint16_t          num_fds,
+                                          const uint32_t   *ints,
+                                          const int32_t    *fds)
+{
+    static const xcb_protocol_request_t xcb_req = {
+        .count = 4,
+        .ext = &xcb_drihybris_id,
+        .opcode = XCB_DRIHYBRIS_PIXMAP_FROM_BUFFER,
+        .isvoid = 1
+    };
+
+    struct iovec xcb_parts[6];
+    xcb_void_cookie_t xcb_ret;
+    xcb_drihybris_pixmap_from_buffer_request_t xcb_out;
+
+    xcb_out.pixmap = pixmap;
+    xcb_out.drawable = drawable;
+    xcb_out.size = size;
+    xcb_out.width = width;
+    xcb_out.height = height;
+    xcb_out.stride = stride;
+    xcb_out.depth = depth;
+    xcb_out.bpp = bpp;
+    xcb_out.num_ints = num_ints;
+    xcb_out.num_fds = num_fds;
+
+    xcb_parts[2].iov_base = (char *) &xcb_out;
+    xcb_parts[2].iov_len = sizeof(xcb_out);
+    xcb_parts[3].iov_base = 0;
+    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;
+    /* uint32_t ints */
+    xcb_parts[4].iov_base = (char *) ints;
+    xcb_parts[4].iov_len = num_ints * sizeof(uint32_t);
+    xcb_parts[5].iov_base = 0;
+    xcb_parts[5].iov_len = -xcb_parts[4].iov_len & 3;
+
+    xcb_ret.sequence = xcb_send_request_with_fds(c, XCB_REQUEST_CHECKED, xcb_parts + 2, &xcb_req, num_fds, fds);
+    return xcb_ret;
+}
+
+xcb_void_cookie_t
+xcb_drihybris_pixmap_from_buffer (xcb_connection_t *c,
+                                  xcb_pixmap_t      pixmap,
+                                  xcb_drawable_t    drawable,
+                                  uint32_t          size,
+                                  uint16_t          width,
+                                  uint16_t          height,
+                                  uint16_t          stride,
+                                  uint8_t           depth,
+                                  uint8_t           bpp,
+                                  uint16_t          num_ints,
+                                  uint16_t          num_fds,
+                                  const uint32_t   *ints,
+                                  const int32_t    *fds)
+{
+    static const xcb_protocol_request_t xcb_req = {
+        .count = 4,
+        .ext = &xcb_drihybris_id,
+        .opcode = XCB_DRIHYBRIS_PIXMAP_FROM_BUFFER,
+        .isvoid = 1
+    };
+
+    struct iovec xcb_parts[6];
+    xcb_void_cookie_t xcb_ret;
+    xcb_drihybris_pixmap_from_buffer_request_t xcb_out;
+
+    xcb_out.pixmap = pixmap;
+    xcb_out.drawable = drawable;
+    xcb_out.size = size;
+    xcb_out.width = width;
+    xcb_out.height = height;
+    xcb_out.stride = stride;
+    xcb_out.depth = depth;
+    xcb_out.bpp = bpp;
+    xcb_out.num_ints = num_ints;
+    xcb_out.num_fds = num_fds;
+
+    xcb_parts[2].iov_base = (char *) &xcb_out;
+    xcb_parts[2].iov_len = sizeof(xcb_out);
+    xcb_parts[3].iov_base = 0;
+    xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;
+    /* uint32_t ints */
+    xcb_parts[4].iov_base = (char *) ints;
+    xcb_parts[4].iov_len = num_ints * sizeof(uint32_t);
+    xcb_parts[5].iov_base = 0;
+    xcb_parts[5].iov_len = -xcb_parts[4].iov_len & 3;
+
+    xcb_ret.sequence = xcb_send_request_with_fds(c, 0, xcb_parts + 2, &xcb_req, num_fds, fds);
+    return xcb_ret;
+}
+
+uint32_t *
+xcb_drihybris_pixmap_from_buffer_ints (const xcb_drihybris_pixmap_from_buffer_request_t *R)
+{
+    return (uint32_t *) (R + 1);
+}
+
+int
+xcb_drihybris_pixmap_from_buffer_ints_length (const xcb_drihybris_pixmap_from_buffer_request_t *R)
+{
+    return R->num_ints;
+}
+
+xcb_generic_iterator_t
+xcb_drihybris_pixmap_from_buffer_ints_end (const xcb_drihybris_pixmap_from_buffer_request_t *R)
+{
+    xcb_generic_iterator_t i;
+    i.data = ((uint32_t *) (R + 1)) + (R->num_ints);
+    i.rem = 0;
+    i.index = (char *) i.data - (char *) R;
+    return i;
+}
diff --git a/hybris/egl/platforms/x11/xcb_drihybris.h b/hybris/egl/platforms/x11/xcb_drihybris.h
new file mode 100644
index 0000000..974828d
--- /dev/null
+++ b/hybris/egl/platforms/x11/xcb_drihybris.h
@@ -0,0 +1,122 @@
+/*
+ * This file generated automatically from drihybris.xml by c_client.py.
+ * Edit at your peril.
+ */
+
+/**
+ * @defgroup XCB_DRIHYBRIS_API XCB DRIHYBRIS API
+ * @brief DRIHYBRIS XCB Protocol Implementation.
+ * @{
+ **/
+
+#ifndef DRIHYBRIS_PROTO_H
+#define DRIHYBRIS_PROTO_H
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define XCB_DRIHYBRIS_MAJOR_VERSION 1
+#define XCB_DRIHYBRIS_MINOR_VERSION 0
+
+extern xcb_extension_t xcb_drihybris_id;
+
+/** Opcode for xcb_drihybris_pixmap_from_buffer. */
+#define XCB_DRIHYBRIS_PIXMAP_FROM_BUFFER 1
+
+/**
+ * @brief xcb_drihybris_pixmap_from_buffer_request_t
+ **/
+typedef struct xcb_drihybris_pixmap_from_buffer_request_t {
+    uint8_t        major_opcode;
+    uint8_t        minor_opcode;
+    uint16_t       length;
+    xcb_pixmap_t   pixmap;
+    xcb_drawable_t drawable;
+    uint32_t       size;
+    uint16_t       width;
+    uint16_t       height;
+    uint16_t       stride;
+    uint8_t        depth;
+    uint8_t        bpp;
+    uint16_t       num_ints;
+    uint16_t       num_fds;
+} xcb_drihybris_pixmap_from_buffer_request_t;
+
+/**
+ * @brief xcb_drihybris_buffer_from_pixmap_cookie_t
+ **/
+typedef struct xcb_drihybris_buffer_from_pixmap_cookie_t {
+    unsigned int sequence;
+} xcb_drihybris_buffer_from_pixmap_cookie_t;
+
+int
+xcb_drihybris_pixmap_from_buffer_sizeof (const void  *_buffer,
+                                         int32_t      pixmap_fd);
+
+/**
+ *
+ * @param c The connection
+ * @return A cookie
+ *
+ * Delivers a request to the X server.
+ *
+ * This form can be used only if the request will not cause
+ * a reply to be generated. Any returned error will be
+ * saved for handling by xcb_request_check().
+ */
+xcb_void_cookie_t
+xcb_drihybris_pixmap_from_buffer_checked (xcb_connection_t *c,
+                                          xcb_pixmap_t      pixmap,
+                                          xcb_drawable_t    drawable,
+                                          uint32_t          size,
+                                          uint16_t          width,
+                                          uint16_t          height,
+                                          uint16_t          stride,
+                                          uint8_t           depth,
+                                          uint8_t           bpp,
+                                          uint16_t          num_ints,
+                                          uint16_t          num_fds,
+                                          const uint32_t   *ints,
+                                          const int32_t    *fds);
+
+/**
+ *
+ * @param c The connection
+ * @return A cookie
+ *
+ * Delivers a request to the X server.
+ *
+ */
+xcb_void_cookie_t
+xcb_drihybris_pixmap_from_buffer (xcb_connection_t *c,
+                                  xcb_pixmap_t      pixmap,
+                                  xcb_drawable_t    drawable,
+                                  uint32_t          size,
+                                  uint16_t          width,
+                                  uint16_t          height,
+                                  uint16_t          stride,
+                                  uint8_t           depth,
+                                  uint8_t           bpp,
+                                  uint16_t          num_ints,
+                                  uint16_t          num_fds,
+                                  const uint32_t   *ints,
+                                  const int32_t    *fds);
+
+uint32_t *
+xcb_drihybris_pixmap_from_buffer_ints (const xcb_drihybris_pixmap_from_buffer_request_t *R);
+
+int
+xcb_drihybris_pixmap_from_buffer_ints_length (const xcb_drihybris_pixmap_from_buffer_request_t *R);
+
+xcb_generic_iterator_t
+xcb_drihybris_pixmap_from_buffer_ints_end (const xcb_drihybris_pixmap_from_buffer_request_t *R);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //DRIHYBRIS_PROTO_H
diff --git a/hybris/egl/ws.c b/hybris/egl/ws.c
index b10c704..36bc180 100644
--- a/hybris/egl/ws.c
+++ b/hybris/egl/ws.c
@@ -118,4 +118,13 @@ void ws_setSwapInterval(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval
 		ws->setSwapInterval(dpy, win, interval);
 }
 
+EGLBoolean ws_eglGetConfigAttrib(struct _EGLDisplay *display, EGLConfig config, EGLint attribute, EGLint *value)
+{
+	_init_ws();
+	if (ws->eglGetConfigAttrib)
+		return ws->eglGetConfigAttrib(display, config, attribute, value);
+    else
+        return EGL_FALSE;
+}
+
 // vim:ts=4:sw=4:noexpandtab
diff --git a/hybris/egl/ws.h b/hybris/egl/ws.h
index c4811c0..92b221a 100644
--- a/hybris/egl/ws.h
+++ b/hybris/egl/ws.h
@@ -37,6 +37,7 @@ struct ws_module {
 	void (*prepareSwap)(EGLDisplay dpy, EGLNativeWindowType win, EGLint *damage_rects, EGLint damage_n_rects);
 	void (*finishSwap)(EGLDisplay dpy, EGLNativeWindowType win);
 	void (*setSwapInterval)(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval);
+    EGLBoolean (*eglGetConfigAttrib)(struct _EGLDisplay *display, EGLConfig config, EGLint attribute, EGLint *value);
 };
 
 struct _EGLDisplay *ws_GetDisplay(EGLNativeDisplayType native);
@@ -49,5 +50,6 @@ const char *ws_eglQueryString(EGLDisplay dpy, EGLint name, const char *(*real_eg
 void ws_prepareSwap(EGLDisplay dpy, EGLNativeWindowType win, EGLint *damage_rects, EGLint damage_n_rects);
 void ws_finishSwap(EGLDisplay dpy, EGLNativeWindowType win);
 void ws_setSwapInterval(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval);
+EGLBoolean ws_eglGetConfigAttrib(struct _EGLDisplay *display, EGLConfig config, EGLint attribute, EGLint *value);
 
 #endif
-- 
2.21.0

