From: Christopher James Halse Rogers <r...@ubuntu.com> A first pass at a Mir platform for EGL.
This is RFC mainly because I hope to shortly make Mir's API less painfully pointless-callback-based. There's no point in committing this as-is, but it's hopefully still useful to review. --- configure.ac | 5 +- src/egl/drivers/dri2/Makefile.am | 6 + src/egl/drivers/dri2/egl_dri2.c | 6 + src/egl/drivers/dri2/egl_dri2.h | 19 +- src/egl/drivers/dri2/platform_mir.c | 344 ++++++++++++++++++++++++++++++++++++ src/egl/main/Makefile.am | 6 + src/egl/main/egldisplay.c | 12 +- src/egl/main/egldisplay.h | 1 + 8 files changed, 395 insertions(+), 4 deletions(-) create mode 100644 src/egl/drivers/dri2/platform_mir.c diff --git a/configure.ac b/configure.ac index 7852595..6f35e9e 100644 --- a/configure.ac +++ b/configure.ac @@ -1559,7 +1559,9 @@ for plat in $egl_platforms; do android|gdi) ;; - + mir) + PKG_CHECK_MODULES([MIR], [mirclient]) + ;; *) AC_MSG_ERROR([EGL platform '$plat' does not exist]) ;; @@ -1587,6 +1589,7 @@ AM_CONDITIONAL(HAVE_EGL_PLATFORM_WAYLAND, echo "$egl_platforms" | grep 'wayland' AM_CONDITIONAL(HAVE_EGL_PLATFORM_DRM, echo "$egl_platforms" | grep 'drm' >/dev/null 2>&1) AM_CONDITIONAL(HAVE_EGL_PLATFORM_FBDEV, echo "$egl_platforms" | grep 'fbdev' >/dev/null 2>&1) AM_CONDITIONAL(HAVE_EGL_PLATFORM_NULL, echo "$egl_platforms" | grep 'null' >/dev/null 2>&1) +AM_CONDITIONAL(HAVE_EGL_PLATFORM_MIR, echo "$egl_platforms" | grep 'mir' >/dev/null 2>&1) AM_CONDITIONAL(HAVE_EGL_DRIVER_DRI2, test "x$HAVE_EGL_DRIVER_DRI2" != "x") AM_CONDITIONAL(HAVE_EGL_DRIVER_GLX, test "x$HAVE_EGL_DRIVER_GLX" != "x") diff --git a/src/egl/drivers/dri2/Makefile.am b/src/egl/drivers/dri2/Makefile.am index 45f7dfa..dfb0c05 100644 --- a/src/egl/drivers/dri2/Makefile.am +++ b/src/egl/drivers/dri2/Makefile.am @@ -62,3 +62,9 @@ if HAVE_EGL_PLATFORM_DRM libegl_dri2_la_SOURCES += platform_drm.c AM_CFLAGS += -DHAVE_DRM_PLATFORM endif + +if HAVE_EGL_PLATFORM_MIR +libegl_dri2_la_SOURCES += platform_mir.c +AM_CFLAGS += -DHAVE_MIR_PLATFORM +AM_CFLAGS += $(MIR_CFLAGS) +endif diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index b774919..ddd0314 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -599,6 +599,12 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp) return EGL_TRUE; return dri2_initialize_wayland(drv, disp); #endif +#ifdef HAVE_MIR_PLATFORM + case _EGL_PLATFORM_MIR: + if (disp->Options.TestOnly) + return EGL_TRUE; + return dri2_initialize_mir(drv, disp); +#endif #endif #ifdef HAVE_ANDROID_PLATFORM case _EGL_PLATFORM_ANDROID: diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 84ea2a6..d82b9f8 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -65,6 +65,10 @@ #endif /* HAVE_ANDROID_PLATFORM */ +#ifdef HAVE_MIR_PLATFORM +#include <mir_client_library.h> +#endif + #include "eglconfig.h" #include "eglcontext.h" #include "egldisplay.h" @@ -134,6 +138,10 @@ struct dri2_egl_display int formats; #endif +#ifdef HAVE_MIR_PLATFORM + MirConnection *mir_conn; +#endif + int (*authenticate) (_EGLDisplay *disp, uint32_t id); }; @@ -182,7 +190,9 @@ struct dri2_egl_surface struct gbm_dri_surface *gbm_surf; #endif -#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM) +#if defined(HAVE_WAYLAND_PLATFORM) \ + || defined(HAVE_DRM_PLATFORM) \ + || defined(HAVE_MIR_PLATFORM) __DRIbuffer *dri_buffers[__DRI_BUFFER_COUNT]; struct { #ifdef HAVE_WAYLAND_PLATFORM @@ -204,6 +214,10 @@ struct dri2_egl_surface /* EGL-owned buffers */ __DRIbuffer *local_buffers[__DRI_BUFFER_COUNT]; #endif + +#ifdef HAVE_MIR_PLATFORM + MirSurface *mir_surf; +#endif }; @@ -265,6 +279,9 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp); EGLBoolean dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *disp); +EGLBoolean +dri2_initialize_mir(_EGLDriver *drv, _EGLDisplay *disp); + char * dri2_get_driver_for_fd(int fd); char * diff --git a/src/egl/drivers/dri2/platform_mir.c b/src/egl/drivers/dri2/platform_mir.c new file mode 100644 index 0000000..965a1df --- /dev/null +++ b/src/egl/drivers/dri2/platform_mir.c @@ -0,0 +1,344 @@ +/* + * Copyright © 2012 Canonical, Inc + * + * 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: + * Christopher James Halse Rogers <christopher.halse.rog...@canonical.com> + */ + +#include <mir_client_library.h> + +#include "egl_dri2.h" + +#include <stdlib.h> +#include <string.h> + +static __DRIbuffer * +dri2_get_buffers_with_format(__DRIdrawable * driDrawable, + int *width, int *height, + unsigned int *attachments, int count, + int *out_count, void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + int i; + + dri2_surf->buffer_count = 0; + for (i = 0; i < 2*count; i+=2) { + assert(attachments[i] < __DRI_BUFFER_COUNT); + assert(dri2_surf->buffer_count < 5); + + if (dri2_surf->dri_buffers[attachments[i]] == NULL) { + /* Our frame callback must keep the back buffer valid */ + assert(attachments[i] != __DRI_BUFFER_BACK_LEFT); + + dri2_surf->dri_buffers[attachments[i]] = + dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, + attachments[i], attachments[i+1], + dri2_surf->base.Width, dri2_surf->base.Height); + + if (!dri2_surf->dri_buffers[attachments[i]]) + continue; + } + + memcpy(&dri2_surf->buffers[dri2_surf->buffer_count], + dri2_surf->dri_buffers[attachments[i]], + sizeof(__DRIbuffer)); + + dri2_surf->buffer_count++; + } + + assert(dri2_surf->base.Type == EGL_PIXMAP_BIT || + dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); + + *out_count = dri2_surf->buffer_count; + if (dri2_surf->buffer_count == 0) + return NULL; + + *width = dri2_surf->base.Width; + *height = dri2_surf->base.Height; + + return dri2_surf->buffers; +} + +static __DRIbuffer * +dri2_get_buffers(__DRIdrawable * driDrawable, + int *width, int *height, + unsigned int *attachments, int count, + int *out_count, void *loaderPrivate) +{ + unsigned int *attachments_with_format; + __DRIbuffer *buffer; + const unsigned int format = 32; + int i; + + attachments_with_format = calloc(count * 2, sizeof(unsigned int)); + if (!attachments_with_format) { + *out_count = 0; + return NULL; + } + + for (i = 0; i < count; ++i) { + attachments_with_format[2*i] = attachments[i]; + attachments_with_format[2*i + 1] = format; + } + + buffer = + dri2_get_buffers_with_format(driDrawable, + width, height, + attachments_with_format, count, + out_count, loaderPrivate); + + free(attachments_with_format); + + return buffer; +} + + +static void +dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) +{ + /* We don't *have* a client-usable front-buffer */ + (void) driDrawable; + (void) loaderPrivate; +} + +static void +mir_populate_colour_buffers(struct dri2_egl_surface *surf) +{ + MirBufferPackage buffer_package; + + mir_surface_get_current_buffer(surf->mir_surf, &buffer_package); + /* We expect name as the only data in our buffer */ + assert(buffer_package.data_items == 1); + + surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->name = buffer_package.data[0]; + surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->pitch = buffer_package.stride; +} + +/** + * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). + */ +static _EGLSurface * +dri2_create_mir_window_surface(_EGLDriver *drv, _EGLDisplay *disp, + _EGLConfig *conf, EGLNativeWindowType window, + const EGLint *attrib_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); + struct dri2_egl_surface *dri2_surf; + MirSurfaceParameters surf_params; + + (void) drv; + + dri2_surf = calloc(1, sizeof *dri2_surf); + if (!dri2_surf) { + _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); + return NULL; + } + + if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list)) + goto cleanup_surf; + + dri2_surf->mir_surf = (MirSurface *)window; + mir_surface_get_parameters(dri2_surf->mir_surf, &surf_params); + dri2_surf->base.Width = surf_params.width; + dri2_surf->base.Height = surf_params.height; + + dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT] = + calloc(sizeof(*dri2_surf->dri_buffers[0]), 1); + + dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment = + __DRI_BUFFER_BACK_LEFT; + /* We only do ARGB 8888 for the moment */ + dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->cpp = 4; + + mir_populate_colour_buffers(dri2_surf); + + dri2_surf->dri_drawable = + (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen, + dri2_conf->dri_double_config, + dri2_surf); + + if (dri2_surf->dri_drawable == NULL) { + _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable"); + } + + return &dri2_surf->base; + +cleanup_surf: + free(dri2_surf); + return NULL; +} + +static EGLBoolean +dri2_destroy_mir_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + int i; + + (void) drv; + + if (!_eglPutSurface(surf)) + return EGL_TRUE; + + (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable); + + for (i = 0; i < __DRI_BUFFER_COUNT; ++i) { + if (dri2_surf->dri_buffers[i] && i != __DRI_BUFFER_FRONT_LEFT) { + dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, + dri2_surf->dri_buffers[i]); + } + } + + free(surf); + + return EGL_TRUE; +} + +static void +surface_callback(MirSurface *surface, void *ctx) +{ + /* Do nothing; for now we make eglSwapBuffers block */ + (void)surface; + (void)ctx; +} + + +/** + * Called via eglSwapBuffers(), drv->API.SwapBuffers(). + */ +static EGLBoolean +dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) +{ + (void)drv; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); + + (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); + + mir_wait_for(mir_surface_next_buffer(dri2_surf->mir_surf, surface_callback, NULL)); + + mir_populate_colour_buffers(dri2_surf); + (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); + + return EGL_TRUE; +} + +static void connection_callback(MirConnection *conn, void *context) +{ + struct dri2_egl_display *dri2_dpy = context; + + dri2_dpy->mir_conn = conn; +} + +static int +dri2_mir_authenticate(_EGLDisplay *disp, uint32_t id) +{ + /* We come pre-authenticated */ + return 0; +} + +EGLBoolean +dri2_initialize_mir(_EGLDriver *drv, _EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy; + MirPlatformPackage platform; + const __DRIconfig *config; + static const unsigned int argb_masks[4] = + { 0xff0000, 0xff00, 0xff, 0xff000000 }; + uint32_t types; + int i; + + drv->API.CreateWindowSurface = dri2_create_mir_window_surface; + drv->API.DestroySurface = dri2_destroy_mir_surface; + drv->API.SwapBuffers = dri2_swap_buffers; + + dri2_dpy = calloc(1, sizeof *dri2_dpy); + if (!dri2_dpy) + return _eglError(EGL_BAD_ALLOC, "eglInitialize"); + + disp->DriverData = (void *) dri2_dpy; + if (disp->PlatformDisplay == NULL) { + mir_wait_for(mir_connect("some_socket_file", "EGL Client", + connection_callback, dri2_dpy)); + } else { + dri2_dpy->mir_conn = (MirConnection *)disp->PlatformDisplay; + } + + if (!mir_connection_is_valid(dri2_dpy->mir_conn)) { + _eglLog(_EGL_WARNING, "DRI2: mir_connect failed: %s", + mir_connection_get_error_message(dri2_dpy->mir_conn)); + goto cleanup_dpy; + } + + mir_connection_get_platform(dri2_dpy->mir_conn, &platform); + dri2_dpy->fd = platform.fd[0]; + dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd); + dri2_dpy->device_name = dri2_get_device_name_for_fd(dri2_dpy->fd); + + if (dri2_dpy->driver_name == NULL || + dri2_dpy->device_name == NULL) + goto cleanup_conn; + + if (!dri2_load_driver(disp)) + goto cleanup_conn; + + dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; + dri2_dpy->dri2_loader_extension.base.version = 3; + dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers; + dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer; + dri2_dpy->dri2_loader_extension.getBuffersWithFormat = + dri2_get_buffers_with_format; + + dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base; + dri2_dpy->extensions[1] = &image_lookup_extension.base; + dri2_dpy->extensions[2] = &use_invalidate.base; + dri2_dpy->extensions[3] = NULL; + + if (!dri2_create_screen(disp)) + goto cleanup_conn; + + types = EGL_WINDOW_BIT; + for (i = 0; dri2_dpy->driver_configs[i]; i++) { + config = dri2_dpy->driver_configs[i]; + dri2_add_config(disp, config, i + 1, 0, types, NULL, argb_masks); + } + + dri2_dpy->authenticate = dri2_mir_authenticate; + + disp->VersionMajor = 1; + disp->VersionMinor = 4; + + return EGL_TRUE; + + cleanup_conn: + if (disp->PlatformDisplay == NULL) + mir_connection_release(dri2_dpy->mir_conn); + cleanup_dpy: + free(dri2_dpy); + + return EGL_FALSE; +} diff --git a/src/egl/main/Makefile.am b/src/egl/main/Makefile.am index ca5257a..64af1fd 100644 --- a/src/egl/main/Makefile.am +++ b/src/egl/main/Makefile.am @@ -103,6 +103,12 @@ if HAVE_EGL_PLATFORM_NULL AM_CFLAGS += -DHAVE_NULL_PLATFORM endif +if HAVE_EGL_PLATFORM_MIR +AM_CFLAGS += -DHAVE_MIR_PLATFORM +AM_CFLAGS += $(MIR_CFLAGS) +libEGL_la_LIBADD += $(MIR_LIBS) +endif + if HAVE_EGL_DRIVER_GLX AM_CFLAGS += -D_EGL_BUILT_IN_DRIVER_GLX libEGL_la_LIBADD += ../drivers/glx/libegl_glx.la diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c index 985e781..da8136c 100644 --- a/src/egl/main/egldisplay.c +++ b/src/egl/main/egldisplay.c @@ -59,7 +59,9 @@ #include <sys/types.h> #include <sys/stat.h> #endif - +#ifdef HAVE_MIR_PLATFORM +#include <mir_client_library.h> +#endif /** * Map --with-egl-platforms names to platform types. @@ -74,7 +76,8 @@ static const struct { { _EGL_PLATFORM_DRM, "drm" }, { _EGL_PLATFORM_FBDEV, "fbdev" }, { _EGL_PLATFORM_NULL, "null" }, - { _EGL_PLATFORM_ANDROID, "android" } + { _EGL_PLATFORM_ANDROID, "android" }, + { _EGL_PLATFORM_MIR, "mir" }, }; @@ -154,6 +157,11 @@ _eglNativePlatformDetectNativeDisplay(EGLNativeDisplayType nativeDisplay) return _EGL_PLATFORM_FBDEV; #endif +#ifdef HAVE_MIR_PLATFORM + if (mir_connection_is_valid(nativeDisplay)) + return _EGL_PLATFORM_MIR; +#endif + if (_eglPointerIsDereferencable(nativeDisplay)) { void *first_pointer = *(void **) nativeDisplay; diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h index 4b33470..3999d22 100644 --- a/src/egl/main/egldisplay.h +++ b/src/egl/main/egldisplay.h @@ -46,6 +46,7 @@ enum _egl_platform_type { _EGL_PLATFORM_FBDEV, _EGL_PLATFORM_NULL, _EGL_PLATFORM_ANDROID, + _EGL_PLATFORM_MIR, _EGL_NUM_PLATFORMS, _EGL_INVALID_PLATFORM = -1 -- 1.8.1.2 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev