pmaports/hybris/libhybris/0003-Implement-X11-EGL-platform-based-on-wayland-code.patch
NotKit c9b6e30e76 Package libhybris (#1402)
As discussed in #1039, I want to split feature/hybris branch into
smaller sensible pull requests.

This is the first one that simply adds android-headers and libhybris
packaging. libhybris allows apps compiled with glibc (musl in our case)
to load Android libraries that utilize bionic libc, which is used to
load proprietary userspace drivers.

The package isn't very useful on its own and requires core (non-UI/Java)
Android services to be running in some way - either in Halium-style LXC
container or in same root as main OS with modified init (Mer/Sailfish do
it this way). Both ways are tested to work in postmarketOS.

libhybris also includes some tests, not all of them are known to be
representative, but test_vibrator and test_egl_configs are usually good
indicators if system is set up correctly.
2018-04-10 21:13:42 +00:00

1672 lines
53 KiB
Diff

From b9251827932545a455bfecea7b259eba5677c3bd 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
---
hybris/configure.ac | 1 +
hybris/egl/egl.c | 13 +-
hybris/egl/platforms/Makefile.am | 2 +-
hybris/egl/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 | 728 ++++++++++++++++++++++
hybris/egl/platforms/x11/x11_window.h | 201 ++++++
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, 1522 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..4363e80
--- /dev/null
+++ b/hybris/egl/platforms/x11/x11_window.cpp
@@ -0,0 +1,728 @@
+/****************************************************************************************
+ **
+ ** 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 = width;
+ this->m_defaultHeight = 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;
+
+ 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()
+{
+ 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_copy_area(m_connection, wnb->pixmap, m_window, m_xcb_gc,
+ 0, 0, 0, 0, /* src_x, src_y, dst_x, dst_y */
+ m_width, m_height);
+ 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_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,
+ 32, 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..cceaee5
--- /dev/null
+++ b/hybris/egl/platforms/x11/x11_window.h
@@ -0,0 +1,201 @@
+/****************************************************************************************
+ **
+ ** 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;
+ 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)
+ {
+ // 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->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_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.15.1