pmaports/hybris/libhybris/0003-Implement-X11-EGL-platform-based-on-wayland-code.patch

1691 lines
54 KiB
Diff

From ae11619430c59ba4a23acd8659157f43b863d2ed Mon Sep 17 00:00:00 2001
From: NeKit <nekit1000@gmail.com>
Date: Wed, 18 Oct 2017 23:12:51 +0300
Subject: [PATCH 3/3] Implement X11 EGL platform based on wayland code.
* 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
---
hybris/configure.ac | 1 +
hybris/egl/egl.c | 13 +-
hybris/egl/platforms/Makefile.am | 2 +-
.../platforms/common/eglplatformcommon.cpp | 2 +-
hybris/egl/platforms/x11/Makefile.am | 43 +
hybris/egl/platforms/x11/eglplatform_x11.cpp | 235 ++++++
hybris/egl/platforms/x11/x11_window.cpp | 742 ++++++++++++++++++
hybris/egl/platforms/x11/x11_window.h | 206 +++++
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 +
12 files changed, 1541 insertions(+), 3 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 dac8bc9..526567a 100644
--- a/hybris/configure.ac
+++ b/hybris/configure.ac
@@ -254,6 +254,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/common/eglplatformcommon.cpp b/hybris/egl/platforms/common/eglplatformcommon.cpp
index b512dc0..04aed79 100644
--- a/hybris/egl/platforms/common/eglplatformcommon.cpp
+++ b/hybris/egl/platforms/common/eglplatformcommon.cpp
@@ -74,7 +74,7 @@ extern "C" void hybris_dump_buffer_to_file(ANativeWindowBuffer *buf)
char b[1024];
int bytes_pp = 0;
- if (buf->format == HAL_PIXEL_FORMAT_RGBA_8888)
+ if (buf->format == HAL_PIXEL_FORMAT_RGBA_8888 || buf->format == HAL_PIXEL_FORMAT_BGRA_8888)
bytes_pp = 4;
else if (buf->format == HAL_PIXEL_FORMAT_RGB_565)
bytes_pp = 2;
diff --git a/hybris/egl/platforms/x11/Makefile.am b/hybris/egl/platforms/x11/Makefile.am
new file mode 100644
index 0000000..22eac5e
--- /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)/hardware/libhardware.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..001b733
--- /dev/null
+++ b/hybris/egl/platforms/x11/eglplatform_x11.cpp
@@ -0,0 +1,235 @@
+/****************************************************************************************
+**
+** 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 "x11_window.h"
+#include "logging.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+static gralloc_module_t *gralloc = 0;
+static alloc_device_t *alloc = 0;
+
+
+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)
+{
+ int err;
+ hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const hw_module_t **) &gralloc);
+ err = gralloc_open((const hw_module_t *) gralloc, &alloc);
+ TRACE("++ %lu x11: got gralloc %p err:%s", pthread_self(), gralloc, strerror(-err));
+ eglplatformcommon_init(egl_iface, gralloc, alloc);
+}
+
+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, alloc, gralloc);
+ 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..26e8844
--- /dev/null
+++ b/hybris/egl/platforms/x11/x11_window.cpp
@@ -0,0 +1,742 @@
+/****************************************************************************************
+ **
+ ** 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, alloc_device_t* alloc, gralloc_module_t* gralloc)
+{
+ 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;
+
+ this->m_alloc = alloc;
+ m_gralloc = gralloc;
+
+ 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_alloc, 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 = m_gralloc->lock(m_gralloc, 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);
+ m_gralloc->unlock(m_gralloc, 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);
+ m_gralloc->unlock(m_gralloc, 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..e5be070
--- /dev/null
+++ b/hybris/egl/platforms/x11/x11_window.h
@@ -0,0 +1,206 @@
+/****************************************************************************************
+ **
+ ** 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 <hardware/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()
+ : m_alloc(0)
+ {}
+
+ ClientX11Buffer(alloc_device_t* alloc_device,
+ 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;
+ this->m_alloc = alloc_device;
+ int alloc_ok = this->m_alloc->alloc(this->m_alloc,
+ this->width ? this->width : 1, this->height ? this->height : 1,
+ this->format, this->usage,
+ &this->handle, &this->stride);
+ assert(alloc_ok == 0);
+ this->youngest = 0;
+ this->common.incRef(&this->common);
+
+ this->windowDepth = windowDepth;
+ this->pixmap = 0;
+ }
+
+ ~ClientX11Buffer()
+ {
+ if (this->m_alloc)
+ m_alloc->free(m_alloc, this->handle);
+ }
+
+protected:
+ void* vaddr;
+ alloc_device_t* m_alloc;
+
+public:
+
+};
+
+class X11NativeWindow : public BaseNativeWindow {
+public:
+ X11NativeWindow(Display* xl_display, Window xl_window, alloc_device_t* alloc, gralloc_module_t* gralloc);
+ ~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;
+
+ alloc_device_t* m_alloc;
+ 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;
+ gralloc_module_t *m_gralloc;
+};
+
+#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.17.0