.gitignore | 1 debian/changelog | 10 debian/control | 4 debian/patches/egl-platform-rs.patch | 1185 ++++++++++++++++++++++++++++++++++ debian/patches/khr_platform_mir.patch | 82 ++ debian/patches/series | 3 debian/patches/vulkan-mir.patch | 1065 ++++++++++++++++++++++++++++++ debian/rules | 1 8 files changed, 2349 insertions(+), 2 deletions(-)
New commits: commit e7332d41cc28a6e1b6606be1c41b682949a923ae Author: Timo Aaltonen <tjaal...@debian.org> Date: Tue Mar 28 19:48:32 2017 +0300 upload to zesty diff --git a/debian/changelog b/debian/changelog index 08dffad..cd5ad0d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -mesa (17.0.2-1ubuntu2) UNRELEASED; urgency=medium +mesa (17.0.2-1ubuntu2) zesty; urgency=medium [ Cemil Azizoglu ] * egl-platform-rs.patch: Add support for Mir's new render surface based @@ -6,7 +6,7 @@ mesa (17.0.2-1ubuntu2) UNRELEASED; urgency=medium * khr_platform_mir.patch: Add EGL_KHR_platform_mir * vulkan-mir.patch: Add Vulkan WSI driver for Mir - -- Timo Aaltonen <tjaal...@debian.org> Tue, 28 Mar 2017 19:15:55 +0300 + -- Timo Aaltonen <tjaal...@debian.org> Tue, 28 Mar 2017 19:22:29 +0300 mesa (17.0.2-1ubuntu1) zesty; urgency=medium commit fb51f537b0a542a149a7e83806117405c2b0f1c6 Author: Cemil Azizoglu <cemil.azizo...@canonical.com> Date: Mon Feb 13 11:09:32 2017 -0600 Add platform-rs, vulkan-mir, EGL_KHR_platform_mir. This commit - incorporates support for Mir's new render surface based EGL driver (alpha) - adds Vulkan WSI driver for Mir (alpha) - adds EGL_KHR_platform_mir (yet to be ratified) The render surface-based backend is implemented as a new platform so the legacy (buffer stream-based) backend can be supported simultaneously. TODO: - Mir-team intends to change the name 'render surface' (and all its associated symbols) to 'surface' in the very new feature. As soon as that happens this patch will require a refresh. diff --git a/.gitignore b/.gitignore index 9644092..991556e 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,4 @@ Makefile.in .install-gallium-links /src/git_sha1.h TAGS +/.project diff --git a/debian/changelog b/debian/changelog index 38ee0c7..08dffad 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,13 @@ +mesa (17.0.2-1ubuntu2) UNRELEASED; urgency=medium + + [ Cemil Azizoglu ] + * egl-platform-rs.patch: Add support for Mir's new render surface based + EGL driver + * khr_platform_mir.patch: Add EGL_KHR_platform_mir + * vulkan-mir.patch: Add Vulkan WSI driver for Mir + + -- Timo Aaltonen <tjaal...@debian.org> Tue, 28 Mar 2017 19:15:55 +0300 + mesa (17.0.2-1ubuntu1) zesty; urgency=medium * Merge from Debian experimental. diff --git a/debian/control b/debian/control index 0cb9185..b678c73 100644 --- a/debian/control +++ b/debian/control @@ -38,7 +38,7 @@ Build-Depends: libxcb-randr0-dev, libxcb-sync-dev, libxshmfence-dev (>= 1.1), - libmirclient-dev [linux-any], + libmirclient-dev (>= 0.26.2) [linux-any], mir-client-platform-mesa-dev [linux-any], python, python-mako, @@ -157,7 +157,7 @@ Depends: libx11-xcb-dev, libwayland-dev (>= 1.11.0) [linux-any], ${misc:Depends}, - libmirclient-dev [!arm64 !powerpc !ppc64 !ppc64el !kfreebsd-any !hurd-any], + libmirclient-dev (>= 0.26.2) [!arm64 !powerpc !ppc64 !ppc64el !kfreebsd-any !hurd-any], Multi-Arch: same Description: free implementation of the EGL API -- development files This package contains the development environment required for compiling diff --git a/debian/patches/egl-platform-rs.patch b/debian/patches/egl-platform-rs.patch new file mode 100644 index 0000000..210f4f4 --- /dev/null +++ b/debian/patches/egl-platform-rs.patch @@ -0,0 +1,1185 @@ +--- a/configure.ac ++++ b/configure.ac +@@ -91,6 +91,7 @@ XSHMFENCE_REQUIRED=1.1 + XVMC_REQUIRED=1.0.6 + PYTHON_MAKO_REQUIRED=0.8.0 + LIBSENSORS_REQUIRED=4.0.0 ++MIR_REQUIRED=0.26.2 + + dnl LLVM versions + LLVM_REQUIRED_GALLIUM=3.3.0 +@@ -2131,9 +2132,15 @@ for plat in $egl_platforms; do + android) + PKG_CHECK_MODULES([ANDROID], [cutils hardware sync]) + ;; +- mir) +- PKG_CHECK_MODULES([MIR], [mirclient mir-client-platform-mesa]) +- ;; ++ ++ mir) ++ PKG_CHECK_MODULES([MIR], [mirclient mir-client-platform-mesa]) ++ ;; ++ ++ rs) ++ PKG_CHECK_MODULES([RS], [mirclient >= $MIR_REQUIRED]) ++ ;; ++ + *) + AC_MSG_ERROR([EGL platform '$plat' does not exist]) + ;; +@@ -2161,6 +2168,7 @@ AM_CONDITIONAL(HAVE_EGL_PLATFORM_DRM, ec + AM_CONDITIONAL(HAVE_EGL_PLATFORM_SURFACELESS, echo "$egl_platforms" | grep -q 'surfaceless') + AM_CONDITIONAL(HAVE_EGL_PLATFORM_ANDROID, echo "$egl_platforms" | grep -q 'android') + AM_CONDITIONAL(HAVE_EGL_PLATFORM_MIR, echo "$egl_platforms" | grep -q 'mir') ++AM_CONDITIONAL(HAVE_EGL_PLATFORM_RS, echo "$egl_platforms" | grep -q 'rs') + + AC_SUBST([EGL_NATIVE_PLATFORM]) + AC_SUBST([EGL_CFLAGS]) +--- a/include/EGL/eglplatform.h ++++ b/include/EGL/eglplatform.h +@@ -112,6 +112,13 @@ typedef MirEGLNativeDisplayType EGLNativ + typedef void *EGLNativePixmapType; + typedef MirEGLNativeWindowType EGLNativeWindowType; + ++#elif defined(RS_EGL_PLATFORM) ++ ++#include <mir_toolkit/mir_client_library.h> ++typedef MirEGLNativeDisplayType EGLNativeDisplayType; ++typedef void *EGLNativePixmapType; ++typedef MirEGLNativeWindowType EGLNativeWindowType; ++ + #elif defined(__unix__) || defined(__APPLE__) + + #if defined(MESA_EGL_NO_X11_HEADERS) +--- a/src/egl/Makefile.am ++++ b/src/egl/Makefile.am +@@ -97,6 +97,13 @@ AM_CFLAGS += $(MIR_CFLAGS) + dri2_backend_FILES += drivers/dri2/platform_mir.c + endif + ++if HAVE_EGL_PLATFORM_RS ++AM_CFLAGS += -DHAVE_RS_PLATFORM ++AM_CFLAGS += $(RS_CFLAGS) ++libEGL_la_LIBADD += $(RS_LIBS) ++dri2_backend_FILES += drivers/dri2/platform_rs.c ++endif ++ + AM_CFLAGS += \ + -I$(top_srcdir)/src/loader \ + -I$(top_srcdir)/src/egl/drivers/dri2 \ +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -844,6 +844,11 @@ dri2_initialize(_EGLDriver *drv, _EGLDis + ret = dri2_initialize_android(drv, disp); + break; + #endif ++#ifdef HAVE_RS_PLATFORM ++ case _EGL_PLATFORM_RS: ++ ret = dri2_initialize_rs(drv, disp); ++ break; ++#endif + default: + _eglLog(_EGL_WARNING, "No EGL platform enabled."); + return EGL_FALSE; +@@ -911,6 +916,13 @@ dri2_display_release(_EGLDisplay *disp) + } + break; + #endif ++#ifdef HAVE_RS_PLATFORM ++ case _EGL_PLATFORM_RS: ++ if (dri2_dpy->own_device) { ++ gbm_device_destroy(&dri2_dpy->gbm_dri->base.base); ++ } ++ break; ++#endif + #ifdef HAVE_MIR_PLATFORM + case _EGL_PLATFORM_MIR: + if (dri2_dpy->own_device) { +@@ -941,7 +953,8 @@ dri2_display_release(_EGLDisplay *disp) + * for the cleanup. + */ + if (disp->Platform != _EGL_PLATFORM_DRM && +- disp->Platform != _EGL_PLATFORM_MIR) { ++ disp->Platform != _EGL_PLATFORM_MIR && ++ disp->Platform != _EGL_PLATFORM_RS) { + for (i = 0; dri2_dpy->driver_configs[i]; i++) + free((__DRIconfig *) dri2_dpy->driver_configs[i]); + free(dri2_dpy->driver_configs); +--- a/src/egl/drivers/dri2/egl_dri2.h ++++ b/src/egl/drivers/dri2/egl_dri2.h +@@ -74,6 +74,10 @@ + #include <mir_toolkit/mesa/native_display.h> + #endif + ++#ifdef HAVE_RS_PLATFORM ++#include <mir_toolkit/mir_connection.h> ++#endif ++ + #include "eglconfig.h" + #include "eglcontext.h" + #include "egldisplay.h" +@@ -234,6 +238,11 @@ struct dri2_egl_display + #ifdef HAVE_MIR_PLATFORM + MirMesaEGLNativeDisplay *mir_disp; + #endif ++#ifdef HAVE_RS_PLATFORM ++ MirConnection* mir_conn; ++ pthread_mutex_t lock; ++ pthread_cond_t cv; ++#endif + }; + + struct dri2_egl_context +@@ -292,10 +301,10 @@ struct dri2_egl_surface + void *data; + int data_size; + #endif +-#if HAVE_DRM_PLATFORM || defined(HAVE_MIR_PLATFORM) ++#if HAVE_DRM_PLATFORM || defined(HAVE_MIR_PLATFORM) || defined(HAVE_RS_PLATFORM) + struct gbm_bo *bo; + #endif +-#ifdef HAVE_MIR_PLATFORM ++#if defined(HAVE_MIR_PLATFORM) || defined(HAVE_RS_PLATFORM) + int fd; + int buffer_age; + #endif +@@ -314,6 +323,10 @@ struct dri2_egl_surface + __DRIbuffer *local_buffers[__DRI_BUFFER_COUNT]; + #endif + ++#ifdef HAVE_RS_PLATFORM ++ void* sc; ++#endif ++ + #if defined(HAVE_SURFACELESS_PLATFORM) + __DRIimage *front; + unsigned int visual; +@@ -413,6 +426,9 @@ dri2_initialize_surfaceless(_EGLDriver * + EGLBoolean + dri2_initialize_mir(_EGLDriver *drv, _EGLDisplay *disp); + ++EGLBoolean ++dri2_initialize_rs(_EGLDriver *drv, _EGLDisplay *disp); ++ + void + dri2_flush_drawable_for_swapbuffers(_EGLDisplay *disp, _EGLSurface *draw); + +@@ -443,5 +459,4 @@ dri2_set_WL_bind_wayland_display(_EGLDri + } + #endif + } +- + #endif /* EGL_DRI2_INCLUDED */ +--- /dev/null ++++ b/src/egl/drivers/dri2/platform_rs.c +@@ -0,0 +1,962 @@ ++/* ++ * Copyright © 2016 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: ++ * Cemil Azizoglu <cemil.azizo...@canonical.com> ++ */ ++ ++#include <mir_toolkit/mir_presentation_chain.h> ++#include <mir_toolkit/mir_buffer.h> ++#include <mir_toolkit/rs/mir_render_surface.h> ++#include <mir_toolkit/extensions/gbm_buffer.h> ++#include <mir_toolkit/extensions/mesa_drm_auth.h> ++ ++#include <string.h> ++#include <stdio.h> ++#include <xf86drm.h> ++ ++#include "egl_dri2.h" ++#include "egl_dri2_fallbacks.h" ++#include "loader.h" ++ ++#define MAX_BUFFERS (4) ++#define NUM_DEFAULT_BUFFERS (3) /* Can be at most MAX_BUFFERS */ ++ ++enum buffer_state ++{ ++ buffer_state_none = 0, ++ buffer_state_available, ++ buffer_state_acquired, ++ buffer_state_submitted, ++}; ++ ++typedef struct SwapChain ++{ ++ MirRenderSurface* surface; ++ MirPresentationChain* chain; ++ MirPixelFormat format; ++ uint32_t gbm_format; ++ unsigned int buffer_count; ++ MirBuffer* buffers[MAX_BUFFERS]; ++ enum buffer_state state[MAX_BUFFERS]; ++ uint32_t next_buffer_to_use; ++ pthread_mutex_t lock; ++ pthread_cond_t cv; ++ struct MirExtensionGbmBufferV2 const* gbm_buffer_ext; ++} SwapChain; ++ ++static uint32_t ++mir_format_to_gbm_format(MirPixelFormat format) ++{ ++ uint32_t gbm_pf; ++ ++ switch (format) ++ { ++ case mir_pixel_format_argb_8888: ++ gbm_pf = GBM_FORMAT_ARGB8888; ++ break; ++ case mir_pixel_format_xrgb_8888: ++ gbm_pf = GBM_FORMAT_XRGB8888; ++ break; ++ case mir_pixel_format_abgr_8888: ++ gbm_pf = GBM_FORMAT_ABGR8888; ++ break; ++ case mir_pixel_format_xbgr_8888: ++ gbm_pf = GBM_FORMAT_XBGR8888; ++ break; ++ case mir_pixel_format_rgb_565: ++ gbm_pf = GBM_FORMAT_RGB565; ++ break; ++ default: ++ gbm_pf = UINT32_MAX; ++ break; ++ } ++ ++ return gbm_pf; ++} ++ ++static int ++get_format_bpp(MirPixelFormat format) ++{ ++ int bpp; ++ ++ switch (format) { ++ case mir_pixel_format_argb_8888: ++ case mir_pixel_format_xrgb_8888: ++ case mir_pixel_format_abgr_8888: ++ case mir_pixel_format_xbgr_8888: ++ bpp = 4; ++ break; ++ case mir_pixel_format_rgb_565: ++ bpp = 2; ++ break; ++ default: ++ bpp = 0; ++ break; ++ } ++ ++ return bpp; ++} ++ ++static struct gbm_bo * ++create_gbm_bo_from_buffer(struct gbm_device* gbm_dev, int fd, int width, int height, uint32_t stride, uint32_t format) ++{ ++ struct gbm_import_fd_data data; ++ ++ _eglLog(_EGL_INFO, "importing fd=%d", fd); ++ data.fd = fd; ++ data.width = width; ++ data.height = height; ++ data.format = format; ++ data.stride = stride; ++ ++ return gbm_bo_import(gbm_dev, GBM_BO_IMPORT_FD, &data, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); ++} ++ ++static void ++clear_cached_buffers(struct dri2_egl_surface *dri2_surf) ++{ ++ size_t i; ++ for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { ++ if (dri2_surf->color_buffers[i].bo != NULL) ++ gbm_bo_destroy(dri2_surf->color_buffers[i].bo); ++ dri2_surf->color_buffers[i].bo = NULL; ++ dri2_surf->color_buffers[i].fd = -1; ++ dri2_surf->color_buffers[i].age = 0; ++ } ++} ++ ++static ssize_t ++find_cached_buffer_with_fd(struct dri2_egl_surface *dri2_surf, int fd) ++{ ++ ssize_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { ++ if (dri2_surf->color_buffers[i].fd == fd) ++ return i; ++ } ++ ++ return -1; ++} ++ ++static void ++cache_buffer(struct dri2_egl_surface *dri2_surf, size_t slot, ++ int fd, int width, int height, uint32_t stride) ++{ ++ SwapChain* sc = (SwapChain *)dri2_surf->sc; ++ struct dri2_egl_display *dri2_dpy = ++ dri2_egl_display(dri2_surf->base.Resource.Display); ++ ++ if (dri2_surf->color_buffers[slot].bo != NULL) ++ gbm_bo_destroy(dri2_surf->color_buffers[slot].bo); ++ ++ dri2_surf->color_buffers[slot].bo = create_gbm_bo_from_buffer( ++ &dri2_dpy->gbm_dri->base.base, ++ fd, width, height, stride, ++ sc->gbm_format); ++ ++ _eglLog(_EGL_INFO, " imported bo : %p format = %d (GBM_FORMAT_ARGB8888=%d)", ++ (void*)dri2_surf->color_buffers[slot].bo, gbm_bo_get_format(dri2_surf->color_buffers[slot].bo), GBM_FORMAT_ARGB8888); ++ ++ dri2_surf->color_buffers[slot].fd = fd; ++} ++ ++static size_t ++find_best_cache_slot(struct dri2_egl_surface *dri2_surf) ++{ ++ size_t i; ++ size_t start_slot = 0; ++ ++ /* ++ * If we have a back buffer, start searching after it to ensure ++ * we don't reuse the slot too soon. ++ */ ++ if (dri2_surf->back != NULL) { ++ start_slot = dri2_surf->back - dri2_surf->color_buffers; ++ start_slot = (start_slot + 1) % ARRAY_SIZE(dri2_surf->color_buffers); ++ } ++ ++ /* Try to find an empty slot */ ++ for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { ++ size_t slot = (start_slot + i) % ARRAY_SIZE(dri2_surf->color_buffers); ++ if (dri2_surf->color_buffers[slot].bo == NULL) ++ return slot; ++ } ++ ++ /* If we don't have an empty slot, use the start slot */ ++ return start_slot; ++} ++ ++static void ++update_cached_buffer_ages(struct dri2_egl_surface *dri2_surf, size_t used_slot) ++{ ++ /* ++ * If 3 (Mir surfaces are triple buffered at most) other buffers have been ++ * used since a buffer was used, we probably won't need this buffer again. ++ */ ++ static const int destruction_age = 3; ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { ++ if (dri2_surf->color_buffers[i].bo != NULL) { ++ if (i == used_slot) { ++ dri2_surf->color_buffers[i].age = 0; ++ } ++ else { ++ ++dri2_surf->color_buffers[i].age; ++ if (dri2_surf->color_buffers[i].age == destruction_age) { ++ gbm_bo_destroy(dri2_surf->color_buffers[i].bo); ++ dri2_surf->color_buffers[i].bo = NULL; ++ dri2_surf->color_buffers[i].fd = -1; ++ } ++ } ++ } ++ } ++} ++ ++static int ++dri2_rs_authenticate(_EGLDisplay *disp, uint32_t id) ++{ ++ return 0; ++} ++ ++static void ++buffer_submit_callback(MirBuffer* buffer, void* context) ++{ ++ SwapChain* sc = (SwapChain*) context; ++ ++// _eglLog(_EGL_DEBUG, "Buffer %p returned from server", (void*) buffer); ++ for (uint32_t i = 0; i < sc->buffer_count; i++) ++ if (sc->buffers[i] == buffer) ++ { ++ pthread_mutex_lock(&sc->lock); ++ assert(sc->state[i] == buffer_state_submitted); ++ sc->state[i] = buffer_state_available; ++ pthread_mutex_unlock(&sc->lock); ++ pthread_cond_broadcast(&sc->cv); ++ } ++} ++ ++static EGLBoolean ++mir_submit_buffer(struct dri2_egl_surface *dri2_surf) ++{ ++ SwapChain* sc = (SwapChain *)dri2_surf->sc; ++ ++ for (uint32_t i = 0; i < sc->buffer_count; i++) ++ { ++ if (sc->state[i] == buffer_state_acquired) ++ { ++ int buffer_fd = sc->gbm_buffer_ext->fd(sc->buffers[i]); ++ if (buffer_fd == dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->fd) ++ { ++// _eglLog(_EGL_DEBUG, "..submitting buffer %p", sc->buffers[i]); ++ sc->state[i] = buffer_state_submitted; ++ mir_presentation_chain_submit_buffer(sc->chain, ++ sc->buffers[i], ++ buffer_submit_callback, ++ sc); ++ break; ++ } ++ } ++ } ++ ++ return EGL_TRUE; ++} ++ ++static EGLBoolean ++mir_acquire_buffer(struct dri2_egl_display *dri2_dpy, struct dri2_egl_surface *dri2_surf) ++{ ++ SwapChain* sc = (SwapChain *)dri2_surf->sc; ++ MirBuffer* buffer = NULL; ++ unsigned int buffer_width, buffer_height; ++ bool found = false; ++ ssize_t buf_slot = -1; ++ ++ if (!sc) ++ return EGL_TRUE; ++ ++ uint32_t wrap = (sc->next_buffer_to_use-1)%(sc->buffer_count); ++ do ++ { ++ uint32_t const next_buffer = sc->next_buffer_to_use; ++ if (sc->state[next_buffer] == buffer_state_available) ++ { ++ int rs_width, rs_height; ++ ++ found = true; ++ sc->state[next_buffer] = buffer_state_acquired; ++ buffer = sc->buffers[next_buffer]; ++ buffer_width = mir_buffer_get_width(buffer); ++ buffer_height = mir_buffer_get_height(buffer); ++ ++ // _eglLog(_EGL_DEBUG, "..acquired buffer %p with fd = %d", sc->buffers[sc->next_buffer_to_use], mbp->fd[0]); ++ mir_render_surface_get_size(sc->surface, &rs_width, &rs_height); ++ if ((rs_width != buffer_width) || (rs_height != buffer_height)) ++ { ++ // release the old buffer ++ mir_buffer_release(buffer); ++ // .. replace it with a new buffer ++ sc->buffers[next_buffer] = ++ sc->gbm_buffer_ext->allocate_buffer_gbm_sync( ++ dri2_dpy->mir_conn, ++ rs_width, rs_height, ++ sc->gbm_format, ++ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); ++ ++ buffer = sc->buffers[next_buffer]; ++ buffer_width = rs_width; ++ buffer_height = rs_height; ++ } ++ } ++ else ++ { ++ if (next_buffer == wrap) ++ { ++ pthread_mutex_lock(&sc->lock); ++ pthread_cond_wait(&sc->cv, &sc->lock); ++ pthread_mutex_unlock(&sc->lock); ++ } ++ } ++ ++ sc->next_buffer_to_use = (next_buffer+1)%(sc->buffer_count); ++ } ++ while(!found); ++ ++ if (buffer_width && buffer_height) { ++ dri2_surf->base.Width = buffer_width; ++ dri2_surf->base.Height = buffer_height; ++ } ++ ++ int buffer_fd = sc->gbm_buffer_ext->fd(buffer); ++ assert(buffer_fd > 0); ++ unsigned int buffer_age = sc->gbm_buffer_ext->age(buffer); ++ uint32_t buffer_stride = sc->gbm_buffer_ext->stride(buffer); ++ buf_slot = find_cached_buffer_with_fd(dri2_surf, buffer_fd); ++ ++ if (buf_slot != -1) { ++ /* ++ * If we get a new buffer with an fd of a previously cached buffer, ++ * replace the old buffer in the cache... ++ */ ++ if (buffer_age == 0) ++ cache_buffer(dri2_surf, buf_slot, buffer_fd, buffer_width, buffer_height, buffer_stride); ++ /* ... otherwise just reuse the existing cached buffer */ ++ } ++ else { ++ /* We got a new buffer with an fd that's not in the cache, so add it */ ++ buf_slot = find_best_cache_slot(dri2_surf); ++ cache_buffer(dri2_surf, buf_slot, buffer_fd, buffer_width, buffer_height, buffer_stride); ++ } ++ ++ update_cached_buffer_ages(dri2_surf, buf_slot); ++ ++ dri2_surf->back = &dri2_surf->color_buffers[buf_slot]; ++ dri2_surf->back->buffer_age = buffer_age; ++ dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->name = 0; ++ dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->fd = buffer_fd; ++ dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->pitch = buffer_stride; ++ ++ return EGL_TRUE; ++} ++ ++static _EGLSurface * ++dri2_rs_create_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; ++ const __DRIconfig *config; ++ MirRenderSurface* surface = window; ++ SwapChain *sc = calloc(1, sizeof(SwapChain)); ++ int width = 0, height = 0; ++ uint32_t num_buffers = 0; ++ ++ if (!mir_render_surface_is_valid(surface)) ++ { ++ _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_rs_create_window_surface: surface is bad"); ++ return NULL; ++ } ++ ++ sc->surface = surface; ++ sc->format = dri2_conf->base.NativeVisualID; ++ _eglLog(_EGL_INFO, "Mir pixel format requested : %d", sc->format); ++ sc->gbm_format = mir_format_to_gbm_format(sc->format); ++ ++ if (sc->gbm_format == UINT32_MAX) ++ { ++ _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_rs_create_window_surface: bad format"); ++ return NULL; ++ } ++ ++ mir_render_surface_get_size(surface, &width, &height); ++ _eglLog(_EGL_INFO, "render surface of size : %dx%d", width, height); ++ ++ sc->chain = mir_render_surface_get_presentation_chain(surface); ++ if (!mir_presentation_chain_is_valid(sc->chain)) ++ { ++ _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_rs_create_window_surface: pc is bad"); ++ return NULL; ++ } ++ ++ pthread_mutex_init(&sc->lock, NULL); ++ pthread_cond_init(&sc->cv, NULL); ++ ++ char* str_num = getenv("MIR_EGL_CLIENT_BUFFERS"); ++ if (str_num) ++ num_buffers = atoi(str_num); ++ if ((num_buffers < 2) || (num_buffers > MAX_BUFFERS)) ++ num_buffers = NUM_DEFAULT_BUFFERS; ++ ++ _eglLog(_EGL_INFO, "Allocating %d buffers", num_buffers); ++ sc->gbm_buffer_ext = mir_extension_gbm_buffer_v2(dri2_dpy->mir_conn); ++ assert(sc->gbm_buffer_ext); ++ assert(sc->gbm_buffer_ext->allocate_buffer_gbm_sync); ++ assert(sc->gbm_buffer_ext->fd); ++ assert(sc->gbm_buffer_ext->stride); ++ assert(sc->gbm_buffer_ext->age); ++ ++ for (unsigned int i = 0; i < num_buffers; i++) ++ { ++ sc->buffers[i] = ++ sc->gbm_buffer_ext->allocate_buffer_gbm_sync(dri2_dpy->mir_conn, ++ width, height, ++ sc->gbm_format, ++ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); ++ assert(sc->state[i] == buffer_state_none); ++ sc->state[i] = buffer_state_available; ++ sc->buffer_count++; ++ } ++ ++ _eglLog(_EGL_INFO, "Presentation chain : %p", sc->chain); ++ _eglLog(_EGL_INFO, "\tcontains %d buffers", sc->buffer_count); ++ for (uint32_t i=0; i<sc->buffer_count; i++) { ++ _eglLog(_EGL_INFO, "Buffer #%d %dx%d: %p", ++ i, ++ mir_buffer_get_width(sc->buffers[i]), ++ mir_buffer_get_height(sc->buffers[i]), ++ sc->buffers[i]); ++ } ++ ++ dri2_surf = calloc(1, sizeof *dri2_surf); ++ if (!dri2_surf) { ++ _eglError(EGL_BAD_ALLOC, "dri2_rs_create_window_surface"); ++ return NULL; ++ } ++ ++ if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list)) ++ goto cleanup_surf; ++ ++ dri2_surf->sc = sc; ++ ++ dri2_surf->base.Width = width; ++ dri2_surf->base.Height = height; ++ ++ dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] = ++ calloc(sizeof(*dri2_surf->dri_buffers[0]), 1); ++ 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; ++ ++ dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->cpp = get_format_bpp(sc->format); ++ ++ clear_cached_buffers(dri2_surf); ++ ++ if(!mir_acquire_buffer(dri2_dpy, dri2_surf)) ++ goto cleanup_surf; ++ ++ config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT, ++ dri2_surf->base.GLColorspace); ++ ++ if (dri2_dpy->gbm_dri) { ++ struct gbm_dri_surface *surf = malloc(sizeof *surf); ++ ++ dri2_surf->gbm_surf = surf; ++ surf->base.gbm = &dri2_dpy->gbm_dri->base.base; ++ surf->base.width = dri2_surf->base.Width; ++ surf->base.height = dri2_surf->base.Height; ++ surf->base.format = sc->gbm_format; ++ surf->base.flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; ++ surf->dri_private = dri2_surf; ++ ++ dri2_surf->dri_drawable = ++ (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen, ++ config, ++ dri2_surf->gbm_surf); ++ } ++ else { ++ dri2_surf->dri_drawable = ++ (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen, ++ 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 _EGLSurface * ++dri2_rs_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp, ++ _EGLConfig *conf, void *native_window, ++ const EGLint *attrib_list) ++{ ++ _eglError(EGL_BAD_PARAMETER, "EGL pixmap surfaces are unsupported on Mir (RS)"); ++ return NULL; ++} ++ ++static EGLBoolean ++dri2_rs_destroy_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; ++ ++ clear_cached_buffers(dri2_surf); ++ ++ (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable); ++ ++ for (i = 0; i < __DRI_BUFFER_COUNT; ++i) { ++ if (dri2_surf->dri_buffers[i]) { ++ if ((i == __DRI_BUFFER_FRONT_LEFT) || ++ (i == __DRI_BUFFER_BACK_LEFT)) { ++ free(dri2_surf->dri_buffers[i]); ++ } ++ else { ++ dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, ++ dri2_surf->dri_buffers[i]); ++ } ++ } ++ } ++ ++ free(dri2_surf->gbm_surf); ++ ++ SwapChain *sc = (SwapChain *)dri2_surf->sc; ++ dri2_surf->sc = NULL; ++ ++ bool wait_for_buffers; ++ do ++ { ++ sleep(0); ++ wait_for_buffers = false; ++ ++ for (uint32_t i = 0; i < sc->buffer_count; i++) ++ { ++ if (sc->state[i] > buffer_state_available) ++ wait_for_buffers = true; ++ } ++ } while(wait_for_buffers); ++ ++ for (uint32_t i = 0; i < sc->buffer_count; i++) { ++ if(sc->buffers[i]) ++ { ++ mir_buffer_release(sc->buffers[i]); ++ sc->buffers[i] = NULL; ++ } ++ } ++ ++ pthread_mutex_destroy(&sc->lock); ++ pthread_cond_destroy(&sc->cv); ++ ++ free(sc); ++ free(surf); ++ ++ return EGL_TRUE; ++} ++ ++static _EGLImage * ++dri2_rs_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, ++ _EGLContext *ctx, EGLenum target, ++ EGLClientBuffer buffer, const EGLint *attr_list) ++{ ++ (void) drv; ++ ++ switch (target) { ++ case EGL_NATIVE_PIXMAP_KHR: ++ _eglError(EGL_BAD_PARAMETER, "Mir has no native pixmaps"); ++ return NULL; ++ default: ++ return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list); ++ } ++} ++ ++static EGLBoolean ++dri2_rs_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, ++ _EGLSurface *surf, EGLint interval) ++{ ++ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); ++ SwapChain* sc = (SwapChain *)dri2_surf->sc; ++ MirPresentationChain* chain = sc->chain; ++ MirPresentMode mode; ++ ++ switch (interval) { ++ case 0: ++ mode = mir_present_mode_mailbox; ++ break; ++ case 1: ++ mode = mir_present_mode_fifo; ++ break; ++ default: ++ _eglError(EGL_BAD_PARAMETER, "Mir only supports swap interval 0 and 1"); ++ return EGL_FALSE; ++ } ++ ++ mir_presentation_chain_set_mode(chain, mode); ++ return EGL_TRUE; ++} ++ ++static EGLBoolean ++dri2_rs_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); ++ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); ++ int rc; ++ ++ (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); ++ ++ rc = mir_submit_buffer(dri2_surf); ++ ++ if (rc) ++ rc = mir_acquire_buffer(dri2_dpy, dri2_surf); ++ ++ (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); ++ ++ return rc; ++} ++ ++static EGLint ++dri2_rs_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, ++ _EGLSurface *surf) ++{ ++ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); ++ if (dri2_surf->back) ++ { ++ return dri2_surf->back->buffer_age; ++ } ++ return 0; ++} ++ ++static __DRIbuffer* ++dri2_rs_get_buffers_with_format(__DRIdrawable *driDrawable, ++ int *width, ++ int *height, ++ unsigned int *attachments, ++ int count, ++ int *out_count, ++ void *data) ++{ ++ struct dri2_egl_surface *dri2_surf = data; ++ 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 these buffers valid */ ++ assert(attachments[i] != __DRI_BUFFER_FRONT_LEFT); ++ 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 ||