From d3fece21813f0a0e00e751703a8998b40f8dad73 Mon Sep 17 00:00:00 2001 From: Danct12 Date: Sat, 8 Jun 2019 16:56:10 +0700 Subject: [PATCH] [PATCH v2] Implement X11 EGL platform based on wayland code. Original patch by NeKit Patched up for compatibility with libhybris gralloc support by Danct12 * Allow window system to hook eglGetConfigAttrib (needed for X11 EGL_NATIVE_VISUAL_ID) * Use custom DRIHYBRIS Xorg extension for buffer sharing to Xorg/glamor when possible Gives huge speedup over XShmPutImage, but requires patched Glamor and DDX driver to utilize it * Check for window resizes using Present extension when possible * x11nativewindow: use same depth as target window for pixmap. Call xcb_present_pixmap instead of xcb_copy_area to present pixmap Signed-off-by: Danct12 --- hybris/configure.ac | 1 + hybris/egl/egl.c | 13 +- hybris/egl/platforms/Makefile.am | 2 +- hybris/egl/platforms/x11/Makefile.am | 43 ++ hybris/egl/platforms/x11/eglplatform_x11.cpp | 229 ++++++ hybris/egl/platforms/x11/x11_window.cpp | 739 +++++++++++++++++++ hybris/egl/platforms/x11/x11_window.h | 195 +++++ hybris/egl/platforms/x11/xcb_drihybris.c | 167 +++++ hybris/egl/platforms/x11/xcb_drihybris.h | 122 +++ hybris/egl/ws.c | 9 + hybris/egl/ws.h | 2 + 11 files changed, 1520 insertions(+), 2 deletions(-) create mode 100644 hybris/egl/platforms/x11/Makefile.am create mode 100644 hybris/egl/platforms/x11/eglplatform_x11.cpp create mode 100644 hybris/egl/platforms/x11/x11_window.cpp create mode 100644 hybris/egl/platforms/x11/x11_window.h create mode 100644 hybris/egl/platforms/x11/xcb_drihybris.c create mode 100644 hybris/egl/platforms/x11/xcb_drihybris.h diff --git a/hybris/configure.ac b/hybris/configure.ac index b3ddc50..7d20c34 100644 --- a/hybris/configure.ac +++ b/hybris/configure.ac @@ -264,6 +264,7 @@ AC_CONFIG_FILES([ egl/platforms/null/Makefile egl/platforms/fbdev/Makefile egl/platforms/wayland/Makefile + egl/platforms/x11/Makefile egl/platforms/hwcomposer/Makefile egl/platforms/hwcomposer/hwcomposer-egl.pc glesv1/glesv1_cm.pc diff --git a/hybris/egl/egl.c b/hybris/egl/egl.c index f6dcd09..4c02ebf 100644 --- a/hybris/egl/egl.c +++ b/hybris/egl/egl.c @@ -228,7 +228,6 @@ const char * eglQueryString(EGLDisplay dpy, EGLint name) HYBRIS_IMPLEMENT_FUNCTION4(egl, EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig *, EGLint, EGLint *); HYBRIS_IMPLEMENT_FUNCTION5(egl, EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *); -HYBRIS_IMPLEMENT_FUNCTION4(egl, EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint *); EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, @@ -461,4 +460,16 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) return ret; } +EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) +{ + HYBRIS_DLSYSM(egl, &_eglGetConfigAttrib, "eglGetConfigAttrib"); + struct _EGLDisplay *display = hybris_egl_display_get_mapping(dpy); + + EGLBoolean ret = ws_eglGetConfigAttrib(display, config, attribute, value); + if (ret == EGL_FALSE) { + return (*_eglGetConfigAttrib)(dpy, config, attribute, value); + } + return ret; +} + // vim:ts=4:sw=4:noexpandtab diff --git a/hybris/egl/platforms/Makefile.am b/hybris/egl/platforms/Makefile.am index 4126752..c52de15 100644 --- a/hybris/egl/platforms/Makefile.am +++ b/hybris/egl/platforms/Makefile.am @@ -11,4 +11,4 @@ if WANT_WAYLAND SUBDIRS += wayland endif - +SUBDIRS += x11 diff --git a/hybris/egl/platforms/x11/Makefile.am b/hybris/egl/platforms/x11/Makefile.am new file mode 100644 index 0000000..4ab00f2 --- /dev/null +++ b/hybris/egl/platforms/x11/Makefile.am @@ -0,0 +1,43 @@ +pkglib_LTLIBRARIES = eglplatform_x11.la + +eglplatform_x11_la_SOURCES = eglplatform_x11.cpp x11_window.cpp xcb_drihybris.c +eglplatform_x11_la_CXXFLAGS = \ + -I$(top_srcdir)/common \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/egl \ + -I$(top_srcdir)/egl/platforms/common \ + $(ANDROID_HEADERS_CFLAGS) \ + $(WAYLAND_CLIENT_CFLAGS) + +if WANT_DEBUG +eglplatform_x11_la_CXXFLAGS += -I$(top_srcdir)/common +endif + +if WANT_TRACE +eglplatform_x11_la_CXXFLAGS += -DDEBUG +endif + +if WANT_DEBUG +eglplatform_x11_la_CXXFLAGS += -ggdb -O0 +endif + +if !WANT_WL_SERVERSIDE_BUFFERS +eglplatform_x11_la_CXXFLAGS += -DHYBRIS_NO_SERVER_SIDE_BUFFERS +endif + + + +eglplatform_x11_la_LDFLAGS = \ + -avoid-version -module -shared -export-dynamic \ + $(top_builddir)/egl/platforms/common/libhybris-eglplatformcommon.la \ + $(top_builddir)/gralloc/libgralloc.la \ + -lXext -lxcb -lX11-xcb -lxcb-present + +if HAS_ANDROID_4_2_0 +eglplatform_x11_la_LDFLAGS += $(top_builddir)/libsync/libsync.la +endif + +if HAS_ANDROID_5_0_0 +eglplatform_x11_la_LDFLAGS += $(top_builddir)/libsync/libsync.la +endif + diff --git a/hybris/egl/platforms/x11/eglplatform_x11.cpp b/hybris/egl/platforms/x11/eglplatform_x11.cpp new file mode 100644 index 0000000..3a1ac4f --- /dev/null +++ b/hybris/egl/platforms/x11/eglplatform_x11.cpp @@ -0,0 +1,229 @@ +/**************************************************************************************** +** +** Copyright (C) 2013 Jolla Ltd. +** Contact: Carsten Munk +** 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +extern "C" { +#include +}; +#include + +#include + +extern "C" { +#include +#include +} + +#include +#include "x11_window.h" +#include "logging.h" + +#include +#include + +static const char * (*_eglQueryString)(EGLDisplay dpy, EGLint name) = NULL; +static __eglMustCastToProperFunctionPointerType (*_eglGetProcAddress)(const char *procname) = NULL; +static EGLSyncKHR (*_eglCreateSyncKHR)(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) = NULL; +static EGLBoolean (*_eglDestroySyncKHR)(EGLDisplay dpy, EGLSyncKHR sync) = NULL; +static EGLint (*_eglClientWaitSyncKHR)(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) = NULL; + +struct X11Display { + _EGLDisplay base; + Display *xl_display; +}; + +extern "C" void x11ws_init_module(struct ws_egl_interface *egl_iface) +{ + hybris_gralloc_initialize(0); + eglplatformcommon_init(egl_iface); +} + +static void _init_egl_funcs(EGLDisplay display) +{ + if (_eglQueryString != NULL) + return; + + _eglQueryString = (const char * (*)(void*, int)) + hybris_android_egl_dlsym("eglQueryString"); + assert(_eglQueryString); + _eglGetProcAddress = (__eglMustCastToProperFunctionPointerType (*)(const char *)) + hybris_android_egl_dlsym("eglGetProcAddress"); + assert(_eglGetProcAddress); + + const char *extensions = (*_eglQueryString)(display, EGL_EXTENSIONS); + + if (strstr(extensions, "EGL_KHR_fence_sync")) { + _eglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) + (*_eglGetProcAddress)("eglCreateSyncKHR"); + assert(_eglCreateSyncKHR); + _eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) + (*_eglGetProcAddress)("eglDestroySyncKHR"); + assert(_eglDestroySyncKHR); + _eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) + (*_eglGetProcAddress)("eglClientWaitSyncKHR"); + assert(_eglClientWaitSyncKHR); + } +} + +extern "C" _EGLDisplay *x11ws_GetDisplay(EGLNativeDisplayType display) +{ + X11Display *xdpy = new X11Display; + xdpy->xl_display = (Display *)display; + + return &xdpy->base; +} + +extern "C" void x11ws_Terminate(_EGLDisplay *dpy) +{ + X11Display *xdpy = (X11Display *)dpy; + int ret = 0; + delete xdpy; +} + +extern "C" EGLNativeWindowType x11ws_CreateWindow(EGLNativeWindowType win, _EGLDisplay *display) +{ + Window xlib_window = (Window) win; + X11Display *xdpy = (X11Display *)display; + + if (win == 0 || xdpy->xl_display == 0) { + HYBRIS_ERROR("Running with EGL_PLATFORM=x11 without X server is not possible"); + HYBRIS_ERROR("If you want to run a standlone EGL client do it like this:"); + HYBRIS_ERROR(" $ export EGL_PLATFORM=null"); + HYBRIS_ERROR(" $ test_glevs2"); + abort(); + } + + X11NativeWindow *window = new X11NativeWindow(xdpy->xl_display, xlib_window); + window->common.incRef(&window->common); + return (EGLNativeWindowType) static_cast(window); +} + +extern "C" void x11ws_DestroyWindow(EGLNativeWindowType win) +{ + X11NativeWindow *window = static_cast((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((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((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((struct ANativeWindow *)win); + window->setSwapInterval(interval); +} + +extern "C" EGLBoolean x11ws_eglGetConfigAttrib(struct _EGLDisplay *display, EGLConfig config, EGLint attribute, EGLint *value) +{ + TRACE("attribute:%i", attribute); + if (attribute == EGL_NATIVE_VISUAL_ID) + { + X11Display *xdpy = (X11Display *)display; + XVisualInfo visinfo_template; + XVisualInfo *visinfo = NULL; + int visinfos_count = 0; + + visinfo_template.depth = 32; + visinfo = XGetVisualInfo (xdpy->xl_display, + VisualDepthMask, + &visinfo_template, + &visinfos_count); + + if (visinfos_count) + { + TRACE("visinfo.visualid:%i", attribute); + *value = visinfo->visualid; + return EGL_TRUE; + } + + } + return EGL_FALSE; +} + +struct ws_module ws_module_info = { + x11ws_init_module, + x11ws_GetDisplay, + x11ws_Terminate, + x11ws_CreateWindow, + x11ws_DestroyWindow, + x11ws_eglGetProcAddress, + x11ws_passthroughImageKHR, + x11ws_eglQueryString, + x11ws_prepareSwap, + x11ws_finishSwap, + x11ws_setSwapInterval, + x11ws_eglGetConfigAttrib +}; diff --git a/hybris/egl/platforms/x11/x11_window.cpp b/hybris/egl/platforms/x11/x11_window.cpp new file mode 100644 index 0000000..6eea75b --- /dev/null +++ b/hybris/egl/platforms/x11/x11_window.cpp @@ -0,0 +1,739 @@ +/**************************************************************************************** + ** + ** Copyright (C) 2013 Jolla Ltd. + ** Contact: Carsten Munk + ** 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 +#include "x11_window.h" +#include +#include +#include +#include + +#include "logging.h" +#include +#include "xcb_drihybris.h" + +#if ANDROID_VERSION_MAJOR>=4 && ANDROID_VERSION_MINOR>=2 || ANDROID_VERSION_MAJOR>=5 +extern "C" { +#include +} +#endif + +void X11NativeWindow::resize(unsigned int width, unsigned int height) +{ + lock(); + this->m_defaultWidth = this->m_width = width; + this->m_defaultHeight = this->m_height = height; + unlock(); +} + +void X11NativeWindow::lock() +{ + pthread_mutex_lock(&this->mutex); +} + +void X11NativeWindow::unlock() +{ + pthread_mutex_unlock(&this->mutex); +} + +X11NativeWindow::X11NativeWindow(Display* xl_display, Window xl_window) +{ + int wayland_ok; + + HYBRIS_TRACE_BEGIN("x11-platform", "create_window", ""); + this->m_window = xl_window; + this->m_display = xl_display; + this->m_connection = XGetXCBConnection(xl_display); + this->m_image = 0; + this->m_useShm = true; + this->m_format = HAL_PIXEL_FORMAT_RGBA_8888; + + const_cast(ANativeWindow::minSwapInterval) = 0; + const_cast(ANativeWindow::maxSwapInterval) = 1; + // This is the default as per the EGL documentation + this->m_swap_interval = 1; + + TRACE("getting X11 window information"); + + XWindowAttributes window_attributes; + XGetWindowAttributes(m_display, m_window, &window_attributes); + + TRACE("window x=%d y=%d width=%d height=%d depth=%d", + window_attributes.x, + window_attributes.y, + window_attributes.width, + window_attributes.height, + window_attributes.depth); + + m_width = window_attributes.width; + m_height = window_attributes.height; + m_depth = window_attributes.depth; + + const char *env = getenv("HYBRIS_X11_FORCE_WIDTH"); + if (env != NULL) + { + m_width = atoi(env); + TRACE("forced width=%d", m_width); + } + + env = getenv("HYBRIS_X11_FORCE_HEIGHT"); + if (env != NULL) + { + m_height = atoi(env); + TRACE("forced height=%d", m_height); + } + + m_defaultWidth = m_width; + m_defaultHeight = m_height; + + env = getenv("HYBRIS_X11_DISABLE_SHM"); + if (env != NULL) + { + m_useShm = false; + TRACE("won't use MIT-SHM"); + } + + XGCValues gcvalues; + m_gc = XCreateGC(m_display, m_window, 0, &gcvalues); + + m_xcb_gc = xcb_generate_id(m_connection); + xcb_create_gc(m_connection, m_xcb_gc, m_window, 0, 0); + + m_specialEvent = 0; + m_haveDRIHybris = false; + tryEnableDRIHybris(); + + m_usage=GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN; + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cond, NULL); + m_queueReads = 0; + m_freeBufs = 0; + m_damage_rects = NULL; + m_damage_n_rects = 0; + m_lastBuffer = 0; + setBufferCount(3); + HYBRIS_TRACE_END("x11-platform", "create_window", ""); +} + +X11NativeWindow::~X11NativeWindow() +{ + std::list::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::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::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::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::iterator it = m_bufList.begin(); + for (; it!=m_bufList.end(); ++it) + { + destroyBuffer(*it); + it = m_bufList.erase(it); + } + m_bufList.clear(); + m_freeBufs = 0; +} + +X11NativeWindowBuffer *X11NativeWindow::addBuffer() { + + X11NativeWindowBuffer *wnb; + + wnb = new ClientX11Buffer(m_width, m_height, m_format, m_usage, m_depth); + m_bufList.push_back(wnb); + ++m_freeBufs; + + TRACE("wnb:%p width:%i height:%i format:x%x usage:x%x", + wnb, wnb->width, wnb->height, wnb->format, wnb->usage); + + return wnb; +} + +int X11NativeWindow::setBufferCount(int cnt) { + int start = 0; + + TRACE("cnt:%d", cnt); + + if (m_bufList.size() == cnt) + return NO_ERROR; + + lock(); + + if (m_bufList.size() > cnt) { + /* Decreasing buffer count, remove from beginning */ + std::list::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::iterator it; + + ret = hybris_gralloc_lock(wnb->handle, wnb->usage, 0, 0, wnb->width, wnb->height, &vaddr); + TRACE("wnb:%p gralloc lock returns %i", wnb, ret); + TRACE("wnb:%p lock to vaddr %p", wnb, vaddr); + TRACE("wnb:%p width=%d stride=%d height=%d format=%d", wnb, wnb->width, wnb->stride, wnb->height, wnb->format); + + if (!m_image) + { + if (m_useShm) + { + m_image = XShmCreateImage(m_display, + CopyFromParent, + 32, + ZPixmap, 0, &m_shminfo, wnb->stride, wnb->height); + + m_shminfo.shmid = shmget(IPC_PRIVATE, + m_image->bytes_per_line * m_image->height, + IPC_CREAT|0777); + + m_shminfo.shmaddr = m_image->data = (char *)shmat(m_shminfo.shmid, 0, 0); + m_shminfo.readOnly = 0; + + TRACE("m_shminfo.shmaddr %p", m_shminfo.shmaddr); + + XShmAttach(m_display, &m_shminfo); + } + else + { + m_image = XCreateImage(m_display, + CopyFromParent, + 32, + ZPixmap, 0, (char *)vaddr, wnb->stride, wnb->height, 32, 0); + } + } + + + if (m_useShm) + { + memcpy(m_image->data, vaddr, m_image->bytes_per_line * m_image->height); + hybris_gralloc_unlock(wnb->handle); + XShmPutImage(m_display, m_window, m_gc, m_image, 0, 0, 0, 0, m_width, m_height, 0); + } + else + { + m_image->data = (char *)vaddr; + XPutImage(m_display, m_window, m_gc, m_image, 0, 0, 0, 0, m_width, m_height); + hybris_gralloc_unlock(wnb->handle); + } + + lock(); + + ++m_freeBufs; + HYBRIS_TRACE_COUNTER("x11-platform", "m_freeBufs", "%i", m_freeBufs); + for (it = m_bufList.begin(); it != m_bufList.end(); it++) + { + (*it)->youngest = 0; + } + wnb->youngest = 1; + wnb->busy = 0; + + unlock(); +} + +void X11NativeWindow::tryEnableDRIHybris() +{ + const xcb_query_extension_reply_t *extension; + xcb_void_cookie_t cookie; + xcb_generic_error_t *error; + + xcb_prefetch_extension_data (m_connection, &xcb_drihybris_id); + xcb_prefetch_extension_data (m_connection, &xcb_present_id); + + extension = xcb_get_extension_data(m_connection, &xcb_drihybris_id); + if (!(extension && extension->present)) + return; + + extension = xcb_get_extension_data(m_connection, &xcb_present_id); + if (!(extension && extension->present)) + return; + + m_specialEventId = xcb_generate_id(m_connection); + m_specialEvent = xcb_register_for_special_xge(m_connection, + &xcb_present_id, m_specialEventId, NULL); + + cookie = xcb_present_select_input_checked(m_connection, + m_specialEventId, m_window, + XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY | + XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY); + + error = xcb_request_check(m_connection, cookie); + if (error) { + return; + } + + m_haveDRIHybris = true; + // HYBRIS_PIXEL_FORMAT_RGBA_8888 is used in glamor for buffer import + m_format = HAL_PIXEL_FORMAT_RGBA_8888; +} + +void X11NativeWindow::handlePresentEvent(xcb_present_generic_event_t *ge) +{ + switch (ge->evtype) { + case XCB_PRESENT_CONFIGURE_NOTIFY: { + xcb_present_configure_notify_event_t *ce = (xcb_present_configure_notify_event_t *) ge; + printf("XCB_PRESENT_CONFIGURE_NOTIFY: %dx%d\n", ce->width, ce->height); + resize(ce->width, ce->height); + break; + } + } +} + +void X11NativeWindowBuffer::pixmap_from_buffer(xcb_connection_t *connection, xcb_drawable_t drawable) +{ + int32_t * fds; + fds = (int32_t *)calloc(handle->numFds, sizeof(int)); + for (int i = 0; i < handle->numFds; i++) { + fds[i] = dup(handle->data[i]); + } + + xcb_drihybris_pixmap_from_buffer_checked(connection, + (pixmap = xcb_generate_id(connection)), + drawable, + stride * height * 4, + this->width, height, stride, + windowDepth, 32, + handle->numInts, + handle->numFds, + (const uint32_t *)(handle->data + handle->numFds), + (const int32_t *)fds); + xcb_flush(connection); + free(fds); +} + +// vim: noai:ts=4:sw=4:ss=4:expandtab diff --git a/hybris/egl/platforms/x11/x11_window.h b/hybris/egl/platforms/x11/x11_window.h new file mode 100644 index 0000000..e4464db --- /dev/null +++ b/hybris/egl/platforms/x11/x11_window.h @@ -0,0 +1,195 @@ +/**************************************************************************************** + ** + ** Copyright (C) 2013 Jolla Ltd. + ** Contact: Carsten Munk + ** 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 +#include +extern "C" { +#include +#include +#include +#include +#include +} +#include +#include + +class X11NativeWindowBuffer : public BaseNativeWindowBuffer +{ +public: + X11NativeWindowBuffer() : busy(0), youngest(0), other(0) {} + X11NativeWindowBuffer(ANativeWindowBuffer *other) + { + ANativeWindowBuffer::width = other->width; + ANativeWindowBuffer::height = other->height; + ANativeWindowBuffer::format = other->format; + ANativeWindowBuffer::usage = other->usage; + ANativeWindowBuffer::handle = other->handle; + ANativeWindowBuffer::stride = other->stride; + + this->busy = 0; + this->other = other; + this->youngest = 0; + this->pixmap = 0; + } + + int busy; + int youngest; + ANativeWindowBuffer *other; + int windowDepth; + xcb_pixmap_t pixmap; + + void pixmap_from_buffer(xcb_connection_t *connection, xcb_drawable_t drawable); +}; + +class ClientX11Buffer : public X11NativeWindowBuffer +{ +friend class X11NativeWindow; +protected: + ClientX11Buffer( unsigned int width, + unsigned int height, + unsigned int format, + unsigned int usage, + unsigned int windowDepth) + { + // Base members + ANativeWindowBuffer::width = width; + ANativeWindowBuffer::height = height; + ANativeWindowBuffer::format = format; + ANativeWindowBuffer::usage = usage; + + this->busy = 0; + this->other = NULL; + int alloc_ok = hybris_gralloc_allocate(this->width ? this->width : 1, this->height ? this->height : 1, + this->format, this->usage, + &this->handle, (uint32_t*)&this->stride); + assert(alloc_ok == 0); + this->youngest = 0; + this->common.incRef(&this->common); + + this->windowDepth = windowDepth; + this->pixmap = 0; + } + + ~ClientX11Buffer() + { + hybris_gralloc_release(this->handle, 1); + } + +protected: + void* vaddr; + +public: + +}; + +class X11NativeWindow : public BaseNativeWindow { +public: + X11NativeWindow(Display* xl_display, Window xl_window); + ~X11NativeWindow(); + + void lock(); + void unlock(); + void frame(); + void resize(unsigned int width, unsigned int height); + void releaseBuffer(struct wl_buffer *buffer); + + virtual int setSwapInterval(int interval); + void prepareSwap(EGLint *damage_rects, EGLint damage_n_rects); + void finishSwap(); + +protected: + // overloads from BaseNativeWindow + virtual int dequeueBuffer(BaseNativeWindowBuffer **buffer, int *fenceFd); + virtual int lockBuffer(BaseNativeWindowBuffer* buffer); + virtual int queueBuffer(BaseNativeWindowBuffer* buffer, int fenceFd); + virtual int cancelBuffer(BaseNativeWindowBuffer* buffer, int fenceFd); + virtual unsigned int type() const; + virtual unsigned int width() const; + virtual unsigned int height() const; + virtual unsigned int format() const; + virtual unsigned int defaultWidth() const; + virtual unsigned int defaultHeight() const; + virtual unsigned int queueLength() const; + virtual unsigned int transformHint() const; + virtual unsigned int getUsage() const; + // perform calls + virtual int setUsage(int usage); + virtual int setBuffersFormat(int format); + virtual int setBuffersDimensions(int width, int height); + virtual int setBufferCount(int cnt); + +private: + X11NativeWindowBuffer *addBuffer(); + void destroyBuffer(X11NativeWindowBuffer *); + void destroyBuffers(); + int readQueue(bool block); + + void copyToX11(X11NativeWindowBuffer *wnb); + void tryEnableDRIHybris(); + void handlePresentEvent(xcb_present_generic_event_t *ge); + + std::list m_bufList; + std::list fronted; + std::list posted; + std::list post_registered; + std::deque queue; + + Display* m_display; + Window m_window; + XImage *m_image; + XShmSegmentInfo m_shminfo; + GC m_gc; + + xcb_connection_t *m_connection; + xcb_gcontext_t m_xcb_gc; + xcb_present_event_t m_specialEventId; + xcb_special_event_t *m_specialEvent; + + bool m_useShm; + bool m_haveDRIHybris; + + X11NativeWindowBuffer *m_lastBuffer; + unsigned int m_width; + unsigned int m_height; + unsigned int m_depth; + unsigned int m_format; + unsigned int m_defaultWidth; + unsigned int m_defaultHeight; + unsigned int m_usage; + + pthread_mutex_t mutex; + pthread_cond_t cond; + int m_queueReads; + int m_freeBufs; + EGLint *m_damage_rects, m_damage_n_rects; + int m_swap_interval; +}; + +#endif +// vim: noai:ts=4:sw=4:ss=4:expandtab diff --git a/hybris/egl/platforms/x11/xcb_drihybris.c b/hybris/egl/platforms/x11/xcb_drihybris.c new file mode 100644 index 0000000..bec3722 --- /dev/null +++ b/hybris/egl/platforms/x11/xcb_drihybris.c @@ -0,0 +1,167 @@ +/* + * This file generated automatically from drihybris.xml by c_client.py. + * Edit at your peril. + */ + +#include "xcb_drihybris.h" +#include /* 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 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define XCB_DRIHYBRIS_MAJOR_VERSION 1 +#define XCB_DRIHYBRIS_MINOR_VERSION 0 + +extern xcb_extension_t xcb_drihybris_id; + +/** Opcode for xcb_drihybris_pixmap_from_buffer. */ +#define XCB_DRIHYBRIS_PIXMAP_FROM_BUFFER 1 + +/** + * @brief xcb_drihybris_pixmap_from_buffer_request_t + **/ +typedef struct xcb_drihybris_pixmap_from_buffer_request_t { + uint8_t major_opcode; + uint8_t minor_opcode; + uint16_t length; + xcb_pixmap_t pixmap; + xcb_drawable_t drawable; + uint32_t size; + uint16_t width; + uint16_t height; + uint16_t stride; + uint8_t depth; + uint8_t bpp; + uint16_t num_ints; + uint16_t num_fds; +} xcb_drihybris_pixmap_from_buffer_request_t; + +/** + * @brief xcb_drihybris_buffer_from_pixmap_cookie_t + **/ +typedef struct xcb_drihybris_buffer_from_pixmap_cookie_t { + unsigned int sequence; +} xcb_drihybris_buffer_from_pixmap_cookie_t; + +int +xcb_drihybris_pixmap_from_buffer_sizeof (const void *_buffer, + int32_t pixmap_fd); + +/** + * + * @param c The connection + * @return A cookie + * + * Delivers a request to the X server. + * + * This form can be used only if the request will not cause + * a reply to be generated. Any returned error will be + * saved for handling by xcb_request_check(). + */ +xcb_void_cookie_t +xcb_drihybris_pixmap_from_buffer_checked (xcb_connection_t *c, + xcb_pixmap_t pixmap, + xcb_drawable_t drawable, + uint32_t size, + uint16_t width, + uint16_t height, + uint16_t stride, + uint8_t depth, + uint8_t bpp, + uint16_t num_ints, + uint16_t num_fds, + const uint32_t *ints, + const int32_t *fds); + +/** + * + * @param c The connection + * @return A cookie + * + * Delivers a request to the X server. + * + */ +xcb_void_cookie_t +xcb_drihybris_pixmap_from_buffer (xcb_connection_t *c, + xcb_pixmap_t pixmap, + xcb_drawable_t drawable, + uint32_t size, + uint16_t width, + uint16_t height, + uint16_t stride, + uint8_t depth, + uint8_t bpp, + uint16_t num_ints, + uint16_t num_fds, + const uint32_t *ints, + const int32_t *fds); + +uint32_t * +xcb_drihybris_pixmap_from_buffer_ints (const xcb_drihybris_pixmap_from_buffer_request_t *R); + +int +xcb_drihybris_pixmap_from_buffer_ints_length (const xcb_drihybris_pixmap_from_buffer_request_t *R); + +xcb_generic_iterator_t +xcb_drihybris_pixmap_from_buffer_ints_end (const xcb_drihybris_pixmap_from_buffer_request_t *R); + +#ifdef __cplusplus +} +#endif + +#endif //DRIHYBRIS_PROTO_H diff --git a/hybris/egl/ws.c b/hybris/egl/ws.c index b10c704..36bc180 100644 --- a/hybris/egl/ws.c +++ b/hybris/egl/ws.c @@ -118,4 +118,13 @@ void ws_setSwapInterval(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval ws->setSwapInterval(dpy, win, interval); } +EGLBoolean ws_eglGetConfigAttrib(struct _EGLDisplay *display, EGLConfig config, EGLint attribute, EGLint *value) +{ + _init_ws(); + if (ws->eglGetConfigAttrib) + return ws->eglGetConfigAttrib(display, config, attribute, value); + else + return EGL_FALSE; +} + // vim:ts=4:sw=4:noexpandtab diff --git a/hybris/egl/ws.h b/hybris/egl/ws.h index c4811c0..92b221a 100644 --- a/hybris/egl/ws.h +++ b/hybris/egl/ws.h @@ -37,6 +37,7 @@ struct ws_module { void (*prepareSwap)(EGLDisplay dpy, EGLNativeWindowType win, EGLint *damage_rects, EGLint damage_n_rects); void (*finishSwap)(EGLDisplay dpy, EGLNativeWindowType win); void (*setSwapInterval)(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval); + EGLBoolean (*eglGetConfigAttrib)(struct _EGLDisplay *display, EGLConfig config, EGLint attribute, EGLint *value); }; struct _EGLDisplay *ws_GetDisplay(EGLNativeDisplayType native); @@ -49,5 +50,6 @@ const char *ws_eglQueryString(EGLDisplay dpy, EGLint name, const char *(*real_eg void ws_prepareSwap(EGLDisplay dpy, EGLNativeWindowType win, EGLint *damage_rects, EGLint damage_n_rects); void ws_finishSwap(EGLDisplay dpy, EGLNativeWindowType win); void ws_setSwapInterval(EGLDisplay dpy, EGLNativeWindowType win, EGLint interval); +EGLBoolean ws_eglGetConfigAttrib(struct _EGLDisplay *display, EGLConfig config, EGLint attribute, EGLint *value); #endif -- 2.21.0