From 6b369c4c7cd8a52f99bbff2a57fb316b33a87495 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Mon, 21 Feb 2011 16:22:34 +0100 Subject: [PATCH] egl: Add EGL_WL_bind_wayland_display --- configure.ac | 2 +- docs/WL_bind_wayland_display.spec | 92 ++++++++ include/EGL/eglext.h | 14 ++ src/egl/Makefile | 3 +- src/egl/drivers/dri2/Makefile | 6 +- src/egl/drivers/dri2/egl_dri2.c | 94 ++++++++ src/egl/drivers/dri2/egl_dri2.h | 4 + src/egl/drivers/dri2/platform_drm.c | 56 ++++- src/egl/drivers/dri2/platform_wayland.c | 36 +++- src/egl/drivers/dri2/platform_x11.c | 45 ++-- src/egl/main/Makefile | 3 + src/egl/main/eglapi.c | 44 ++++ src/egl/main/eglapi.h | 11 + src/egl/main/egldisplay.h | 2 + src/egl/main/eglmisc.c | 2 + src/egl/wayland/Makefile | 18 +- src/egl/wayland/wayland-drm/.gitignore | 3 + src/egl/wayland/wayland-drm/Makefile | 45 ++++ .../wayland-drm/protocol/wayland-drm.xml | 38 ++++ src/egl/wayland/wayland-drm/wayland-drm.c | 203 ++++++++++++++++++ src/egl/wayland/wayland-drm/wayland-drm.h | 26 +++ src/egl/wayland/wayland-egl.c | 4 +- src/gallium/state_trackers/egl/Makefile | 1 + .../egl/wayland/native_wayland.c | 1 + 24 files changed, 729 insertions(+), 24 deletions(-) create mode 100644 docs/WL_bind_wayland_display.spec create mode 100644 src/egl/wayland/wayland-drm/.gitignore create mode 100644 src/egl/wayland/wayland-drm/Makefile create mode 100644 src/egl/wayland/wayland-drm/protocol/wayland-drm.xml create mode 100644 src/egl/wayland/wayland-drm/wayland-drm.c create mode 100644 src/egl/wayland/wayland-drm/wayland-drm.h diff --git a/configure.ac b/configure.ac index dcfddb1ed99..9fa5eeea186 100644 --- a/configure.ac +++ b/configure.ac @@ -1587,7 +1587,7 @@ yes) GALLIUM_WINSYS_DIRS="$GALLIUM_WINSYS_DIRS sw/fbdev" fi if test "$plat" = "wayland"; then - PKG_CHECK_MODULES([WAYLAND], [wayland-client],, \ + PKG_CHECK_MODULES([WAYLAND], [wayland-client wayland-server],, \ [AC_MSG_ERROR([cannot find libwayland-client])]) WAYLAND_EGL_LIB_DEPS="$WAYLAND_LIBS $LIBDRM_LIBS" fi diff --git a/docs/WL_bind_wayland_display.spec b/docs/WL_bind_wayland_display.spec new file mode 100644 index 00000000000..0ff49d6a762 --- /dev/null +++ b/docs/WL_bind_wayland_display.spec @@ -0,0 +1,92 @@ +Name + + WL_bind_wayland_display + +Name Strings + + EGL_WL_bind_wayland_display + +Contact + + Kristian Høgsberg + Benjamin Franzke + +Status + + Proposal + +Version + + Version 1, March 1, 2011 + +Number + + EGL Extension #not assigned + +Dependencies + + Reguires EGL 1.4 or later. This extension is written against the + wording of the EGL 1.4 specification. + + EGL_KHR_base_image is required. + +Overview + + This extension provides entry points for binding and unbinding the + wl_display of a Wayland compositor to an EGLDisplay. Binding a + wl_display means that the EGL implementation should provide one or + more interfaces in the Wayland protocol to allow clients to create + wl_buffer objects. On the server side, this extension also + provides a new target for eglCreateImageKHR, to create an EGLImage + from a wl_buffer + + Adding a implementation specific wayland interface, allows the + EGL implementation to define specific wayland requests and events, + needed for buffer sharing in a EGL wayland platform. + +IP Status + + Open-source; freely implementable. + +New Procedures and Functions + + EGLBoolean eglBindWaylandDisplayWL(EGLDisplay dpy, + struct wl_display *display); + + EGLBoolean eglUnbindWaylandDisplayWL(EGLDisplay dpy, + struct wl_display *display); + +New Tokens + + Accepted as in eglCreateImageKHR + + EGL_WAYLAND_BUFFER_WL 0x31D5 + +Additions to the EGL 1.4 Specification: + + To bind a server side wl_display to an EGLDisplay, call + + EGLBoolean eglBindWaylandDisplayWL(EGLDisplay dpy, + struct wl_display *display); + + To unbind a server side wl_display from an EGLDisplay, call + + EGLBoolean eglUnbindWaylandDisplayWL(EGLDisplay dpy, + struct wl_display *display); + + eglBindWaylandDisplayWL returns EGL_FALSE when there is already a + wl_display bound to EGLDisplay otherwise EGL_TRUE. + + eglUnbindWaylandDisplayWL returns EGL_FALSE when there is no + wl_display bound to the EGLDisplay currently otherwise EGL_TRUE. + + Import a wl_buffer by calling eglCreateImageKHR with + wl_buffer as EGLClientBuffer, EGL_WAYLAND_BUFFER_WL as the target, + and an empty attribute_list. + +Issues + +Revision History + + Version 1, March 1, 2011 + Initial draft (Benjamin Franzke) diff --git a/include/EGL/eglext.h b/include/EGL/eglext.h index 04603931b38..fa523a51d67 100644 --- a/include/EGL/eglext.h +++ b/include/EGL/eglext.h @@ -143,6 +143,20 @@ typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESA) (EGLDisplay dpy, con typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESA) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride); #endif +#ifndef EGL_WL_bind_wayland_display +#define EGL_WL_bind_wayland_display 1 + +#define EGL_WAYLAND_BUFFER_WL 0x31D5 /* eglCreateImageKHR target */ +struct wl_display; +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglBindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display); +EGLAPI EGLBoolean EGLAPIENTRY eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display); +#else +typedef EGLBoolean (EGLAPIENTRY PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display); +typedef EGLBoolean (EGLAPIENTRY PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display); +#endif +#endif + #if KHRONOS_SUPPORT_INT64 /* EGLTimeKHR requires 64-bit uint support */ #ifndef EGL_KHR_reusable_sync #define EGL_KHR_reusable_sync 1 diff --git a/src/egl/Makefile b/src/egl/Makefile index 52daf2efa7e..361f6889580 100644 --- a/src/egl/Makefile +++ b/src/egl/Makefile @@ -3,12 +3,13 @@ TOP = ../.. include $(TOP)/configs/current -SUBDIRS = drivers main +SUBDIRS = ifneq ($(findstring wayland, $(EGL_PLATFORMS)),) SUBDIRS += wayland endif +SUBDIRS += drivers main default: subdirs diff --git a/src/egl/drivers/dri2/Makefile b/src/egl/drivers/dri2/Makefile index 89e9dd7970a..eac599e6745 100644 --- a/src/egl/drivers/dri2/Makefile +++ b/src/egl/drivers/dri2/Makefile @@ -27,8 +27,10 @@ endif ifneq ($(findstring wayland, $(EGL_PLATFORMS)),) EGL_SOURCES += platform_wayland.c EGL_INCLUDES += -DHAVE_WAYLAND_PLATFORM $(WAYLAND_CFLAGS) \ - -I$(TOP)/src/egl/wayland -EGL_LIBS += $(WAYLAND_LIBS) + -I$(TOP)/src/egl/wayland \ + -I$(TOP)/src/egl/wayland/wayland-drm +EGL_LIBS += $(WAYLAND_LIBS) \ + $(TOP)/src/egl/wayland/wayland-drm/libwayland-drm.a endif include ../Makefile.template diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 99f87f076c1..015b801c757 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -915,6 +915,51 @@ dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx, return &dri2_img->base; } +static EGLBoolean +dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, + EGLint *name, EGLint *handle, EGLint *stride); + +static _EGLImage * +dri2_reference_drm_image(_EGLDisplay *disp, _EGLContext *ctx, + _EGLImage *image, EGLint width, EGLint height) +{ + EGLint attr_list[] = { + EGL_WIDTH, 0, + EGL_HEIGHT, 0, + EGL_DRM_BUFFER_STRIDE_MESA, 0, + EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, + EGL_NONE + }; + EGLint name, stride; + + dri2_export_drm_image_mesa(disp->Driver, disp, image, + &name, NULL, &stride); + + attr_list[1] = width; + attr_list[3] = height; + attr_list[5] = stride / 4; + + return dri2_create_image_mesa_drm_buffer(disp, ctx, + (EGLClientBuffer)(intptr_t) name, + attr_list); +} + +#ifdef HAVE_WAYLAND_PLATFORM +static _EGLImage * +dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx, + EGLClientBuffer buffer, + const EGLint *attr_list) +{ + struct wl_drm_buffer *wl_drm_buffer = (struct wl_drm_buffer *) buffer; + + (void) attr_list; + + return dri2_reference_drm_image(disp, ctx, wl_drm_buffer->image, + wl_drm_buffer->buffer.width, + wl_drm_buffer->buffer.height); +} +#endif + _EGLImage * dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx, EGLenum target, @@ -927,6 +972,10 @@ dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list); case EGL_DRM_BUFFER_MESA: return dri2_create_image_mesa_drm_buffer(disp, ctx, buffer, attr_list); +#ifdef HAVE_WAYLAND_PLATFORM + case EGL_WAYLAND_BUFFER_WL: + return dri2_create_image_wayland_wl_buffer(disp, ctx, buffer, attr_list); +#endif default: _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); return EGL_NO_IMAGE_KHR; @@ -1055,6 +1104,47 @@ dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, return EGL_TRUE; } +#ifdef HAVE_WAYLAND_PLATFORM +static EGLBoolean +dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, + struct wl_display *wl_dpy) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + (void) drv; + + if (dri2_dpy->wl_server_drm) + return EGL_FALSE; + + dri2_dpy->wl_server_drm = + wayland_drm_init(wl_dpy, disp, + dri2_dpy->authenticate, + dri2_dpy->device_name); + + if (!dri2_dpy->wl_server_drm) + return EGL_FALSE; + + return EGL_TRUE; +} + +static EGLBoolean +dri2_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, + struct wl_display *wl_dpy) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + (void) drv; + + if (!dri2_dpy->wl_server_drm) + return EGL_FALSE; + + wayland_drm_destroy(dri2_dpy->wl_server_drm); + dri2_dpy->wl_server_drm = NULL; + + return EGL_TRUE; +} +#endif + static void dri2_unload(_EGLDriver *drv) { @@ -1140,6 +1230,10 @@ _EGL_MAIN(const char *args) dri2_drv->base.API.DestroyImageKHR = dri2_destroy_image_khr; dri2_drv->base.API.CreateDRMImageMESA = dri2_create_drm_image_mesa; dri2_drv->base.API.ExportDRMImageMESA = dri2_export_drm_image_mesa; +#ifdef HAVE_WAYLAND_PLATFORM + dri2_drv->base.API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl; + dri2_drv->base.API.UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl; +#endif dri2_drv->base.Name = "DRI2"; dri2_drv->base.Unload = dri2_unload; diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 235e30df3d8..5afd3d3c9c8 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -35,6 +35,7 @@ #ifdef HAVE_WAYLAND_PLATFORM #include +#include "wayland-drm.h" #include "wayland-egl-priv.h" #endif @@ -85,7 +86,10 @@ struct dri2_egl_display const __DRIextension *extensions[3]; #ifdef HAVE_WAYLAND_PLATFORM struct wl_egl_display *wl_dpy; + struct wl_drm *wl_server_drm; #endif + + int (*authenticate) (struct dri2_egl_display *dri_dpy, uint32_t id); }; struct dri2_egl_context diff --git a/src/egl/drivers/dri2/platform_drm.c b/src/egl/drivers/dri2/platform_drm.c index 3dab899decb..bd4fa80af59 100644 --- a/src/egl/drivers/dri2/platform_drm.c +++ b/src/egl/drivers/dri2/platform_drm.c @@ -568,6 +568,39 @@ const struct dri2_driver_map driver_map[] = { { 0x10de, "nouveau", NULL, -1 }, }; +static char * +dri2_get_device_name(int fd) +{ + struct udev *udev; + struct udev_device *device; + struct stat buf; + char *device_name; + + udev = udev_new(); + if (fstat(fd, &buf) < 0) { + _eglLog(_EGL_WARNING, "EGL-DRI2: failed to stat fd %d", fd); + goto out; + } + + device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev); + if (device == NULL) { + _eglLog(_EGL_WARNING, + "EGL-DRI2: could not create udev device for fd %d", fd); + goto out; + } + + device_name = udev_device_get_devnode(device); + if (!device_name) + goto out; + device_name = strdup(device_name); + + out: + udev_device_unref(device); + udev_unref(udev); + + return device_name; +} + char * dri2_get_driver_for_fd(int fd) { @@ -629,6 +662,14 @@ dri2_get_driver_for_fd(int fd) return driver; } +static int +dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + return drmAuthMagic(dri2_dpy->fd, id); +} + EGLBoolean dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp) { @@ -648,8 +689,14 @@ dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp) if (dri2_dpy->driver_name == NULL) return _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name"); - if (!dri2_load_driver(disp)) + dri2_dpy->device_name = dri2_get_device_name(dri2_dpy->fd); + if (dri2_dpy->device_name == NULL) { + _eglError(EGL_BAD_ALLOC, "DRI2: failed to get device name"); goto cleanup_driver_name; + } + + if (!dri2_load_driver(disp)) + goto cleanup_device_name; dri2_dpy->extensions[0] = &image_lookup_extension.base; dri2_dpy->extensions[1] = &use_invalidate.base; @@ -666,6 +713,11 @@ dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp) disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE; disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE; +#ifdef HAVE_WAYLAND_PLATFORM + disp->Extensions.WL_bind_wayland_display = EGL_TRUE; +#endif + dri2_dpy->authenticate = dri2_drm_authenticate; + /* we're supporting EGL 1.4 */ disp->VersionMajor = 1; disp->VersionMinor = 4; @@ -674,6 +726,8 @@ dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp) cleanup_driver: dlclose(dri2_dpy->driver); + cleanup_device_name: + free(dri2_dpy->device_name); cleanup_driver_name: free(dri2_dpy->driver_name); diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index 21b440624ff..6ae3f6554b1 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -35,6 +35,9 @@ #include "egl_dri2.h" +#include +#include "wayland-drm-client-protocol.h" + static void sync_callback(void *data) { @@ -561,6 +564,26 @@ dri2_wayland_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, } } +static int +dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + int ret = 0; + + dri2_dpy->wl_dpy->authenticated = false; + + wl_drm_authenticate(dri2_dpy->wl_dpy->drm, id); + force_roundtrip(dri2_dpy->wl_dpy->display); + + if (!dri2_dpy->wl_dpy->authenticated) + ret = -1; + + /* reset authenticated */ + dri2_dpy->wl_dpy->authenticated = true; + + return ret; +} + /** * Called via eglTerminate(), drv->API.Terminate(). */ @@ -626,8 +649,14 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) goto cleanup_fd; } - if (!dri2_load_driver(disp)) + dri2_dpy->device_name = strdup(dri2_dpy->wl_dpy->device_name); + if (dri2_dpy->device_name == NULL) { + _eglError(EGL_BAD_ALLOC, "DRI2: failed to get device name"); goto cleanup_driver_name; + } + + if (!dri2_load_driver(disp)) + goto cleanup_device_name; dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; dri2_dpy->dri2_loader_extension.base.version = 3; @@ -654,6 +683,9 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE; disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE; + disp->Extensions.WL_bind_wayland_display = EGL_TRUE; + dri2_dpy->authenticate = dri2_wayland_authenticate; + /* we're supporting EGL 1.4 */ disp->VersionMajor = 1; disp->VersionMinor = 4; @@ -662,6 +694,8 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) cleanup_driver: dlclose(dri2_dpy->driver); + cleanup_device_name: + free(dri2_dpy->device_name); cleanup_driver_name: free(dri2_dpy->driver_name); cleanup_fd: diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c index 50310eec5a9..c7bdfa62876 100644 --- a/src/egl/drivers/dri2/platform_x11.c +++ b/src/egl/drivers/dri2/platform_x11.c @@ -543,32 +543,46 @@ dri2_connect(struct dri2_egl_display *dri2_dpy) return EGL_TRUE; } -static EGLBoolean -dri2_authenticate(struct dri2_egl_display *dri2_dpy) +static int +dri2_x11_authenticate(_EGLDisplay *disp, uint32_t id) { + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); xcb_dri2_authenticate_reply_t *authenticate; xcb_dri2_authenticate_cookie_t authenticate_cookie; xcb_screen_iterator_t s; + int ret = 0; + + s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); + authenticate_cookie = + xcb_dri2_authenticate_unchecked(dri2_dpy->conn, s.data->root, id); + authenticate = + xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL); + + if (authenticate == NULL || !authenticate->authenticated) + ret = -1; + + if (authenticate) + free(authenticate); + + return ret; +} + +static EGLBoolean +dri2_authenticate(_EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); drm_magic_t magic; if (drmGetMagic(dri2_dpy->fd, &magic)) { _eglLog(_EGL_WARNING, "DRI2: failed to get drm magic"); return EGL_FALSE; } - - s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); - authenticate_cookie = - xcb_dri2_authenticate_unchecked(dri2_dpy->conn, s.data->root, magic); - authenticate = - xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL); - if (authenticate == NULL || !authenticate->authenticated) { + + if (dri2_x11_authenticate(disp, magic) < 0) { _eglLog(_EGL_WARNING, "DRI2: failed to authenticate"); - free(authenticate); return EGL_FALSE; } - free(authenticate); - return EGL_TRUE; } @@ -977,7 +991,7 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp) } if (dri2_dpy->conn) { - if (!dri2_authenticate(dri2_dpy)) + if (!dri2_authenticate(disp)) goto cleanup_fd; } @@ -1016,6 +1030,11 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp) disp->Extensions.NOK_swap_region = EGL_TRUE; disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE; +#ifdef HAVE_WAYLAND_PLATFORM + disp->Extensions.WL_bind_wayland_display = EGL_TRUE; +#endif + dri2_dpy->authenticate = dri2_x11_authenticate; + /* we're supporting EGL 1.4 */ disp->VersionMajor = 1; disp->VersionMinor = 4; diff --git a/src/egl/main/Makefile b/src/egl/main/Makefile index a5b92995020..820788d696b 100644 --- a/src/egl/main/Makefile +++ b/src/egl/main/Makefile @@ -58,6 +58,9 @@ LOCAL_LIBS = ifeq ($(filter dri2, $(EGL_DRIVERS_DIRS)),dri2) LOCAL_CFLAGS += -D_EGL_BUILT_IN_DRIVER_DRI2 LOCAL_LIBS += $(TOP)/src/egl/drivers/dri2/libegl_dri2.a +ifneq ($(findstring wayland, $(EGL_PLATFORMS)),) +LOCAL_LIBS += $(TOP)/src/egl/wayland/wayland-drm/libwayland-drm.a +endif EGL_LIB_DEPS += $(XCB_DRI2_LIBS) $(LIBUDEV_LIBS) $(DLOPEN_LIBS) $(LIBDRM_LIB) $(WAYLAND_LIBS) endif ifeq ($(filter glx, $(EGL_DRIVERS_DIRS)),glx) diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 4e64ce6f718..19dfd574268 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -913,6 +913,10 @@ eglGetProcAddress(const char *procname) #ifdef EGL_MESA_drm_image { "eglCreateDRMImageMESA", (_EGLProc) eglCreateDRMImageMESA }, { "eglExportDRMImageMESA", (_EGLProc) eglExportDRMImageMESA }, +#endif +#ifdef EGL_WL_bind_display + { "eglBindWaylandDisplayWL", (_EGLProc) eglBindWaylandDisplayWL }, + { "eglUnbindWaylandDisplayWL", (_EGLProc) eglUnbindWaylandDisplayWL }, #endif { NULL, NULL } }; @@ -1491,3 +1495,43 @@ eglExportDRMImageMESA(EGLDisplay dpy, EGLImageKHR image, } #endif + +#ifdef EGL_WL_bind_wayland_display +struct wl_display; + +EGLBoolean EGLAPIENTRY +eglBindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLDriver *drv; + EGLBoolean ret; + + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); + assert(disp->Extensions.WL_bind_wayland_display); + + if (!display) + RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_FALSE); + + ret = drv->API.BindWaylandDisplayWL(drv, disp, display); + + RETURN_EGL_EVAL(disp, ret); +} + +EGLBoolean EGLAPIENTRY +eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLDriver *drv; + EGLBoolean ret; + + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); + assert(disp->Extensions.WL_bind_wayland_display); + + if (!display) + RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_FALSE); + + ret = drv->API.UnbindWaylandDisplayWL(drv, disp, display); + + RETURN_EGL_EVAL(disp, ret); +} +#endif diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h index 01492082f66..c9913f10a10 100644 --- a/src/egl/main/eglapi.h +++ b/src/egl/main/eglapi.h @@ -95,6 +95,12 @@ typedef _EGLImage *(*CreateDRMImageMESA_t)(_EGLDriver *drv, _EGLDisplay *disp, c typedef EGLBoolean (*ExportDRMImageMESA_t)(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, EGLint *name, EGLint *handle, EGLint *stride); #endif +#ifdef EGL_WL_bind_wayland_display +struct wl_display; +typedef EGLBoolean (*BindWaylandDisplayWL_t)(_EGLDriver *drv, _EGLDisplay *disp, struct wl_display *display); +typedef EGLBoolean (*UnbindWaylandDisplayWL_t)(_EGLDriver *drv, _EGLDisplay *disp, struct wl_display *display); +#endif + /** * The API dispatcher jumps through these functions */ @@ -169,6 +175,11 @@ struct _egl_api CreateDRMImageMESA_t CreateDRMImageMESA; ExportDRMImageMESA_t ExportDRMImageMESA; #endif + +#ifdef EGL_WL_bind_wayland_display + BindWaylandDisplayWL_t BindWaylandDisplayWL; + UnbindWaylandDisplayWL_t UnbindWaylandDisplayWL; +#endif }; #endif /* EGLAPI_INCLUDED */ diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h index ce035eb2ef1..97ae2b01ba0 100644 --- a/src/egl/main/egldisplay.h +++ b/src/egl/main/egldisplay.h @@ -58,6 +58,8 @@ struct _egl_extensions EGLBoolean MESA_drm_display; EGLBoolean MESA_drm_image; + EGLBoolean WL_bind_wayland_display; + EGLBoolean KHR_image_base; EGLBoolean KHR_image_pixmap; EGLBoolean KHR_vg_parent_image; diff --git a/src/egl/main/eglmisc.c b/src/egl/main/eglmisc.c index f8ba5f33eb9..6bb2498eef4 100644 --- a/src/egl/main/eglmisc.c +++ b/src/egl/main/eglmisc.c @@ -89,6 +89,8 @@ _eglUpdateExtensionsString(_EGLDisplay *dpy) _EGL_CHECK_EXTENSION(MESA_drm_display); _EGL_CHECK_EXTENSION(MESA_drm_image); + _EGL_CHECK_EXTENSION(WL_bind_wayland_display); + _EGL_CHECK_EXTENSION(KHR_image_base); _EGL_CHECK_EXTENSION(KHR_image_pixmap); if (dpy->Extensions.KHR_image_base && dpy->Extensions.KHR_image_pixmap) diff --git a/src/egl/wayland/Makefile b/src/egl/wayland/Makefile index 4cd036519db..3499aef0486 100644 --- a/src/egl/wayland/Makefile +++ b/src/egl/wayland/Makefile @@ -1,4 +1,4 @@ -# src/egl/main/Makefile +# src/egl/wayland/Makefile TOP = ../../.. include $(TOP)/configs/current @@ -10,14 +10,20 @@ SOURCES = wayland-egl.c OBJECTS = $(SOURCES:.c=.o) -LOCAL_CFLAGS = -I$(TOP)/include/EGL $(LIBDRM_CFLAGS) $(WAYLAND_CFLAGS) +LOCAL_CFLAGS = -I$(TOP)/include/EGL \ + -I$(TOP)/src/egl/wayland/wayland-drm \ + $(LIBDRM_CFLAGS) \ + $(WAYLAND_CFLAGS) + LOCAL_LIBS = +SUBDIRS = wayland-drm + .c.o: $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $(LOCAL_CFLAGS) $< -o $@ -default: depend library +default: depend subdirs library # wayland-egl Library library: $(TOP)/$(LIB_DIR)/$(WAYLAND_EGL_LIB_NAME) @@ -54,6 +60,12 @@ clean: -rm -f *.o -rm -f depend depend.bak +subdirs: + @for dir in $(SUBDIRS) ; do \ + if [ -d $$dir ] ; then \ + (cd $$dir && $(MAKE)) || exit 1 ; \ + fi \ + done depend: $(SOURCES) $(HEADERS) @ echo "running $(MKDEP)" diff --git a/src/egl/wayland/wayland-drm/.gitignore b/src/egl/wayland/wayland-drm/.gitignore new file mode 100644 index 00000000000..f4ed848476f --- /dev/null +++ b/src/egl/wayland/wayland-drm/.gitignore @@ -0,0 +1,3 @@ +wayland-drm-client-protocol.h +wayland-drm-server-protocol.h +wayland-drm-protocol.c diff --git a/src/egl/wayland/wayland-drm/Makefile b/src/egl/wayland/wayland-drm/Makefile new file mode 100644 index 00000000000..c232769697a --- /dev/null +++ b/src/egl/wayland/wayland-drm/Makefile @@ -0,0 +1,45 @@ +# src/egl/wayland/wayland-drm/Makefile + +TOP = ../../../.. +include $(TOP)/configs/current + +GEN_SOURCES = wayland-drm-protocol.c + +GEN_HEADERS = wayland-drm-client-protocol.h wayland-drm-server-protocol.h + +wayland_drm_SOURCES = wayland-drm.c $(GEN_SOURCES) +wayland_drm_OBJECTS = $(wayland_drm_SOURCES:.c=.o) + +wayland_drm_INCLUDES = \ + $(WAYLAND_CFLAGS) \ + -I$(TOP)/src/egl/main + +# Generate protocol sources +prefix=$(shell pkg-config --variable=prefix wayland-server) +exec_prefx=$(shell pkg-config --variable=exec_prefix wayland-server) +wayland_protocoldir = $(PWD)/protocol +wayland_scanner=$(exec_prefix)/bin/wayland-scanner + +default: depend libwayland-drm.a $(GEN_SOURCES) $(GEN_HEADERS) + +libwayland-drm.a: $(wayland_drm_OBJECTS) Makefile + $(MKLIB) -o wayland-drm -static $(wayland_drm_OBJECTS) + +depend: + rm -f depend + touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(wayland_drm_INCLUDES) $(wayland_drm_SOURCES) 2> /dev/null + +clean: + rm -rf libwayland-drm.a $(wayland_drm_OBJECTS) \ + $(GEN_SOURCES) $(GEN_HEADERS) + +install: + @echo -n "" + +$(wayland_drm_OBJECTS): %.o: %.c $(GEN_HEADERS) + $(CC) -c $(wayland_drm_INCLUDES) $(CFLAGS) $< -o $@ + +include $(prefix)/share/aclocal/wayland-scanner.mk + +sinclude depend diff --git a/src/egl/wayland/wayland-drm/protocol/wayland-drm.xml b/src/egl/wayland/wayland-drm/protocol/wayland-drm.xml new file mode 100644 index 00000000000..46725d85179 --- /dev/null +++ b/src/egl/wayland/wayland-drm/protocol/wayland-drm.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/egl/wayland/wayland-drm/wayland-drm.c b/src/egl/wayland/wayland-drm/wayland-drm.c new file mode 100644 index 00000000000..6624fbe9d4e --- /dev/null +++ b/src/egl/wayland/wayland-drm/wayland-drm.c @@ -0,0 +1,203 @@ +/* + * Copyright © 2011 Kristian Høgsberg + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Kristian Høgsberg + * Benjamin Franzke + */ + +#include +#include +#include +#include + +#include +#include "wayland-drm.h" +#include "wayland-drm-server-protocol.h" + +#include "egldisplay.h" +#include "egldriver.h" +#include "eglimage.h" +#include "egltypedefs.h" + +struct wl_drm { + struct wl_object object; + struct wl_display *display; + + _EGLDisplay *edisp; + + char *device_name; + authenticate_t authenticate; +}; + +static void +drm_buffer_damage(struct wl_buffer *buffer_base, + struct wl_surface *surface, + int32_t x, int32_t y, int32_t width, int32_t height) +{ +} + +static void +destroy_buffer(struct wl_resource *resource, struct wl_client *client) +{ + struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) resource; + _EGLDriver *drv = buffer->drm->edisp->Driver; + + drv->API.DestroyImageKHR(drv, buffer->drm->edisp, buffer->image); + free(buffer); +} + +static void +buffer_destroy(struct wl_client *client, struct wl_buffer *buffer) +{ + wl_resource_destroy(&buffer->resource, client); +} + +const static struct wl_buffer_interface buffer_interface = { + buffer_destroy +}; + +static void +drm_create_buffer(struct wl_client *client, struct wl_drm *drm, + uint32_t id, uint32_t name, int32_t width, int32_t height, + uint32_t stride, struct wl_visual *visual) +{ + struct wl_drm_buffer *buffer; + EGLint attribs[] = { + EGL_WIDTH, 0, + EGL_HEIGHT, 0, + EGL_DRM_BUFFER_STRIDE_MESA, 0, + EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, + EGL_NONE + }; + _EGLDriver *drv = drm->edisp->Driver; + + buffer = malloc(sizeof *buffer); + if (buffer == NULL) { + wl_client_post_no_memory(client); + return; + } + + buffer->drm = drm; + buffer->buffer.compositor = NULL; + buffer->buffer.width = width; + buffer->buffer.height = height; + buffer->buffer.visual = visual; + buffer->buffer.attach = NULL; + buffer->buffer.damage = drm_buffer_damage; + + if (visual->object.interface != &wl_visual_interface) { + /* FIXME: Define a real exception event instead of + * abusing this one */ + wl_client_post_event(client, + (struct wl_object *) drm->display, + WL_DISPLAY_INVALID_OBJECT, 0); + fprintf(stderr, "invalid visual in create_buffer\n"); + return; + } + + attribs[1] = width; + attribs[3] = height; + attribs[5] = stride / 4; + buffer->image = drv->API.CreateImageKHR(drv, drm->edisp, + EGL_NO_CONTEXT, + EGL_DRM_BUFFER_MESA, + (EGLClientBuffer) (intptr_t) name, + attribs); + + if (buffer->image == NULL) { + /* FIXME: Define a real exception event instead of + * abusing this one */ + wl_client_post_event(client, + (struct wl_object *) drm->display, + WL_DISPLAY_INVALID_OBJECT, 0); + fprintf(stderr, "failed to create image for name %d\n", name); + return; + } + + buffer->buffer.resource.object.id = id; + buffer->buffer.resource.object.interface = &wl_buffer_interface; + buffer->buffer.resource.object.implementation = (void (**)(void)) + &buffer_interface; + + buffer->buffer.resource.destroy = destroy_buffer; + + wl_client_add_resource(client, &buffer->buffer.resource); +} + +static void +drm_authenticate(struct wl_client *client, + struct wl_drm *drm, uint32_t id) +{ + if (drm->authenticate(drm->edisp, id) < 0) + wl_client_post_event(client, + (struct wl_object *) drm->display, + WL_DISPLAY_INVALID_OBJECT, 0); + else + wl_client_post_event(client, &drm->object, + WL_DRM_AUTHENTICATED); +} + +const static struct wl_drm_interface drm_interface = { + drm_authenticate, + drm_create_buffer +}; + +static void +post_drm_device(struct wl_client *client, struct wl_object *global) +{ + struct wl_drm *drm = (struct wl_drm *) global; + + wl_client_post_event(client, global, WL_DRM_DEVICE, drm->device_name); +} + +struct wl_drm * +wayland_drm_init(struct wl_display *display, _EGLDisplay *disp, + authenticate_t authenticate, char *device_name) +{ + struct wl_drm *drm; + + drm = malloc(sizeof *drm); + + drm->display = display; + drm->edisp = disp; + drm->authenticate = authenticate; + drm->device_name = strdup(device_name); + + drm->object.interface = &wl_drm_interface; + drm->object.implementation = (void (**)(void)) &drm_interface; + wl_display_add_object(display, &drm->object); + wl_display_add_global(display, &drm->object, post_drm_device); + + return drm; +} + +void +wayland_drm_destroy(struct wl_drm *drm) +{ + free(drm->device_name); + + /* FIXME: need wl_display_del_{object,global} */ + + free(drm); +} diff --git a/src/egl/wayland/wayland-drm/wayland-drm.h b/src/egl/wayland/wayland-drm/wayland-drm.h new file mode 100644 index 00000000000..675a6a5ce43 --- /dev/null +++ b/src/egl/wayland/wayland-drm/wayland-drm.h @@ -0,0 +1,26 @@ +#ifndef WAYLAND_DRM_H +#define WAYLAND_DRM_H + +#include "egldisplay.h" +#include "eglimage.h" + +#include + +struct wl_drm; + +typedef int (*authenticate_t) (_EGLDisplay *disp, uint32_t id); + +struct wl_drm_buffer { + struct wl_buffer buffer; + struct wl_drm *drm; + _EGLImage *image; +}; + +struct wl_drm * +wayland_drm_init(struct wl_display *display, _EGLDisplay *disp, + authenticate_t authenticate, char *device_name); + +void +wayland_drm_destroy(struct wl_drm *drm); + +#endif diff --git a/src/egl/wayland/wayland-egl.c b/src/egl/wayland/wayland-egl.c index 12fbdfa29c1..2c84bec64a5 100644 --- a/src/egl/wayland/wayland-egl.c +++ b/src/egl/wayland/wayland-egl.c @@ -12,10 +12,10 @@ #include #include -#include - #include "wayland-egl.h" #include "wayland-egl-priv.h" +#include "wayland-drm-client-protocol.h" +#include static void drm_handle_device(void *data, struct wl_drm *drm, const char *device) diff --git a/src/gallium/state_trackers/egl/Makefile b/src/gallium/state_trackers/egl/Makefile index 98167cceeb3..68643214060 100644 --- a/src/gallium/state_trackers/egl/Makefile +++ b/src/gallium/state_trackers/egl/Makefile @@ -26,6 +26,7 @@ x11_OBJECTS = $(x11_SOURCES:.c=.o) wayland_INCLUDES = \ -I$(TOP)/src/gallium/winsys \ -I$(TOP)/src/egl/wayland \ + -I$(TOP)/src/egl/wayland/wayland-drm \ $(shell pkg-config --cflags-only-I libdrm wayland-client) wayland_SOURCES = $(wildcard wayland/*.c) diff --git a/src/gallium/state_trackers/egl/wayland/native_wayland.c b/src/gallium/state_trackers/egl/wayland/native_wayland.c index b10fc54adb8..068c3cd7c8e 100644 --- a/src/gallium/state_trackers/egl/wayland/native_wayland.c +++ b/src/gallium/state_trackers/egl/wayland/native_wayland.c @@ -41,6 +41,7 @@ #include "radeon/drm/radeon_drm_public.h" #include +#include "wayland-drm-client-protocol.h" #include "wayland-egl-priv.h" #include -- 2.30.2