[mutter] renderer/native: Move out CoglOnscreen code to separate file



commit 3e4ece50d3fbf60bbc241129ba11c642588f4a1a
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Sat Oct 17 23:08:28 2020 +0200

    renderer/native: Move out CoglOnscreen code to separate file
    
    To get meta-renderer-native.c down to a bit more managable size, and to
    isolate "onscreen" functionality from other (at least partly), move out
    the things related to CoglOnscreen to meta-onscreen-native.[ch].
    
    A couple of structs are moved to a new shared header file, as
    abstracting those types (e.g. (primary, secondary) render devices) will
    be dealt with later.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1514>

 src/backends/native/meta-backend-native-types.h    |    2 +
 src/backends/native/meta-onscreen-native.c         | 2196 +++++++++++++++
 src/backends/native/meta-onscreen-native.h         |   69 +
 src/backends/native/meta-renderer-native-private.h |  113 +
 src/backends/native/meta-renderer-native.c         | 2791 +++-----------------
 src/meson.build                                    |    5 +-
 6 files changed, 2699 insertions(+), 2477 deletions(-)
---
diff --git a/src/backends/native/meta-backend-native-types.h b/src/backends/native/meta-backend-native-types.h
index ba73b4a563..0668a84e4f 100644
--- a/src/backends/native/meta-backend-native-types.h
+++ b/src/backends/native/meta-backend-native-types.h
@@ -25,5 +25,7 @@ typedef struct _MetaBackendNative MetaBackendNative;
 typedef struct _MetaSeatNative MetaSeatNative;
 typedef struct _MetaSeatImpl MetaSeatImpl;
 typedef struct _MetaKeymapNative MetaKeymapNative;
+typedef struct _MetaRendererNative MetaRendererNative;
+typedef struct _MetaGpuKms MetaGpuKms;
 
 #endif /* META_BACKEND_NATIVE_TYPES_H */
diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c
new file mode 100644
index 0000000000..1617668cee
--- /dev/null
+++ b/src/backends/native/meta-onscreen-native.c
@@ -0,0 +1,2196 @@
+/*
+ * Copyright (C) 2011 Intel Corporation.
+ * Copyright (C) 2016-2020 Red Hat
+ * Copyright (c) 2018,2019 DisplayLink (UK) Ltd.
+ *
+ * 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 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.
+ *
+ */
+
+#include "config.h"
+
+#include "backends/native/meta-onscreen-native.h"
+
+#include <drm_fourcc.h>
+
+#include "backends/meta-egl-ext.h"
+#include "backends/native/meta-cogl-utils.h"
+#include "backends/native/meta-crtc-kms.h"
+#include "backends/native/meta-drm-buffer-dumb.h"
+#include "backends/native/meta-drm-buffer-gbm.h"
+#include "backends/native/meta-drm-buffer-import.h"
+#include "backends/native/meta-drm-buffer.h"
+#include "backends/native/meta-kms-utils.h"
+#include "backends/native/meta-kms.h"
+#include "backends/native/meta-output-kms.h"
+#include "backends/native/meta-renderer-native-gles3.h"
+#include "backends/native/meta-renderer-native-private.h"
+
+typedef enum _MetaSharedFramebufferImportStatus
+{
+  /* Not tried importing yet. */
+  META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE,
+  /* Tried before and failed. */
+  META_SHARED_FRAMEBUFFER_IMPORT_STATUS_FAILED,
+  /* Tried before and succeeded. */
+  META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK
+} MetaSharedFramebufferImportStatus;
+
+typedef struct _MetaOnscreenNativeSecondaryGpuState
+{
+  MetaGpuKms *gpu_kms;
+  MetaRendererNativeGpuData *renderer_gpu_data;
+
+  EGLSurface egl_surface;
+
+  struct {
+    struct gbm_surface *surface;
+    MetaDrmBuffer *current_fb;
+    MetaDrmBuffer *next_fb;
+  } gbm;
+
+  struct {
+    MetaDrmBufferDumb *current_dumb_fb;
+    MetaDrmBufferDumb *dumb_fbs[2];
+  } cpu;
+
+  gboolean noted_primary_gpu_copy_ok;
+  gboolean noted_primary_gpu_copy_failed;
+  MetaSharedFramebufferImportStatus import_status;
+} MetaOnscreenNativeSecondaryGpuState;
+
+typedef struct _MetaOnscreenNative
+{
+  MetaRendererNative *renderer_native;
+  MetaGpuKms *render_gpu;
+  MetaOutput *output;
+  MetaCrtc *crtc;
+
+  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
+
+  struct {
+    struct gbm_surface *surface;
+    MetaDrmBuffer *current_fb;
+    MetaDrmBuffer *next_fb;
+  } gbm;
+
+#ifdef HAVE_EGL_DEVICE
+  struct {
+    EGLStreamKHR stream;
+
+    MetaDrmBufferDumb *dumb_fb;
+  } egl;
+#endif
+
+  MetaRendererView *view;
+} MetaOnscreenNative;
+
+static void
+swap_secondary_drm_fb (CoglOnscreen *onscreen)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
+
+  secondary_gpu_state = onscreen_native->secondary_gpu_state;
+  if (!secondary_gpu_state)
+    return;
+
+  g_set_object (&secondary_gpu_state->gbm.current_fb,
+                secondary_gpu_state->gbm.next_fb);
+  g_clear_object (&secondary_gpu_state->gbm.next_fb);
+}
+
+static void
+free_current_secondary_bo (CoglOnscreen *onscreen)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
+
+  secondary_gpu_state = onscreen_native->secondary_gpu_state;
+  if (!secondary_gpu_state)
+    return;
+
+  g_clear_object (&secondary_gpu_state->gbm.current_fb);
+}
+
+static void
+free_current_bo (CoglOnscreen *onscreen)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+
+  g_clear_object (&onscreen_native->gbm.current_fb);
+  free_current_secondary_bo (onscreen);
+}
+
+static void
+meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+
+  if (!onscreen_native->gbm.next_fb)
+    return;
+
+  free_current_bo (onscreen);
+
+  g_set_object (&onscreen_native->gbm.current_fb, onscreen_native->gbm.next_fb);
+  g_clear_object (&onscreen_native->gbm.next_fb);
+
+  swap_secondary_drm_fb (onscreen);
+}
+
+static void
+maybe_update_frame_info (MetaCrtc      *crtc,
+                         CoglFrameInfo *frame_info,
+                         int64_t        time_ns)
+{
+  const MetaCrtcConfig *crtc_config;
+  const MetaCrtcModeInfo *crtc_mode_info;
+  float refresh_rate;
+
+  g_return_if_fail (crtc);
+
+  crtc_config = meta_crtc_get_config (crtc);
+  if (!crtc_config)
+    return;
+
+  crtc_mode_info = meta_crtc_mode_get_info (crtc_config->mode);
+  refresh_rate = crtc_mode_info->refresh_rate;
+  if (refresh_rate >= frame_info->refresh_rate)
+    {
+      frame_info->presentation_time = time_ns;
+      frame_info->refresh_rate = refresh_rate;
+    }
+}
+
+static void
+meta_onscreen_native_notify_frame_complete (CoglOnscreen *onscreen)
+{
+  CoglFrameInfo *info;
+
+  info = cogl_onscreen_pop_head_frame_info (onscreen);
+
+  g_assert (!cogl_onscreen_peek_head_frame_info (onscreen));
+
+  _cogl_onscreen_notify_frame_sync (onscreen, info);
+  _cogl_onscreen_notify_complete (onscreen, info);
+  cogl_object_unref (info);
+}
+
+static void
+notify_view_crtc_presented (MetaRendererView *view,
+                            MetaKmsCrtc      *kms_crtc,
+                            int64_t           time_ns)
+{
+  ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
+  CoglFramebuffer *framebuffer =
+    clutter_stage_view_get_onscreen (stage_view);
+  CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
+  CoglFrameInfo *frame_info;
+  MetaCrtc *crtc;
+  MetaRendererNativeGpuData *renderer_gpu_data;
+
+  frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
+
+  crtc = META_CRTC (meta_crtc_kms_from_kms_crtc (kms_crtc));
+  maybe_update_frame_info (crtc, frame_info, time_ns);
+
+  meta_onscreen_native_notify_frame_complete (onscreen);
+
+  renderer_gpu_data =
+    meta_renderer_native_get_gpu_data (renderer_native,
+                                       onscreen_native->render_gpu);
+  switch (renderer_gpu_data->mode)
+    {
+    case META_RENDERER_NATIVE_MODE_GBM:
+      meta_onscreen_native_swap_drm_fb (onscreen);
+      break;
+#ifdef HAVE_EGL_DEVICE
+    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+      break;
+#endif
+    }
+}
+
+static int64_t
+timeval_to_nanoseconds (const struct timeval *tv)
+{
+  int64_t usec = ((int64_t) tv->tv_sec) * G_USEC_PER_SEC + tv->tv_usec;
+  int64_t nsec = usec * 1000;
+
+  return nsec;
+}
+
+static void
+page_flip_feedback_flipped (MetaKmsCrtc  *kms_crtc,
+                            unsigned int  sequence,
+                            unsigned int  tv_sec,
+                            unsigned int  tv_usec,
+                            gpointer      user_data)
+{
+  MetaRendererView *view = user_data;
+  struct timeval page_flip_time;
+
+  page_flip_time = (struct timeval) {
+    .tv_sec = tv_sec,
+    .tv_usec = tv_usec,
+  };
+
+  notify_view_crtc_presented (view, kms_crtc,
+                              timeval_to_nanoseconds (&page_flip_time));
+}
+
+static void
+page_flip_feedback_ready (MetaKmsCrtc *kms_crtc,
+                          gpointer     user_data)
+{
+  MetaRendererView *view = user_data;
+  CoglFramebuffer *framebuffer =
+    clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
+  CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+  CoglFrameInfo *frame_info;
+
+  frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
+  frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
+
+  meta_onscreen_native_notify_frame_complete (onscreen);
+}
+
+static void
+page_flip_feedback_mode_set_fallback (MetaKmsCrtc *kms_crtc,
+                                      gpointer     user_data)
+{
+  MetaRendererView *view = user_data;
+  MetaCrtc *crtc;
+  MetaGpuKms *gpu_kms;
+  int64_t now_ns;
+
+  /*
+   * We ended up not page flipping, thus we don't have a presentation time to
+   * use. Lets use the next best thing: the current time.
+   */
+
+  crtc = META_CRTC (meta_crtc_kms_from_kms_crtc (kms_crtc));
+  gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
+  now_ns = meta_gpu_kms_get_current_time_ns (gpu_kms);
+
+  notify_view_crtc_presented (view, kms_crtc, now_ns);
+}
+
+static void
+page_flip_feedback_discarded (MetaKmsCrtc  *kms_crtc,
+                              gpointer      user_data,
+                              const GError *error)
+{
+  MetaRendererView *view = user_data;
+  MetaCrtc *crtc;
+  MetaGpuKms *gpu_kms;
+  int64_t now_ns;
+
+  /*
+   * Page flipping failed, but we want to fail gracefully, so to avoid freezing
+   * the frame clack, pretend we flipped.
+   */
+
+  if (error &&
+      !g_error_matches (error,
+                        G_IO_ERROR,
+                        G_IO_ERROR_PERMISSION_DENIED))
+    g_warning ("Page flip discarded: %s", error->message);
+
+  crtc = META_CRTC (meta_crtc_kms_from_kms_crtc (kms_crtc));
+  gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
+  now_ns = meta_gpu_kms_get_current_time_ns (gpu_kms);
+
+  notify_view_crtc_presented (view, kms_crtc, now_ns);
+}
+
+static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = {
+  .flipped = page_flip_feedback_flipped,
+  .ready = page_flip_feedback_ready,
+  .mode_set_fallback = page_flip_feedback_mode_set_fallback,
+  .discarded = page_flip_feedback_discarded,
+};
+
+static MetaEgl *
+meta_onscreen_native_get_egl (MetaOnscreenNative *onscreen_native)
+{
+  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
+
+  return meta_renderer_native_get_egl (renderer_native);
+}
+
+#ifdef HAVE_EGL_DEVICE
+static int
+custom_egl_stream_page_flip (gpointer custom_page_flip_data,
+                             gpointer user_data)
+{
+  MetaOnscreenNative *onscreen_native = custom_page_flip_data;
+  MetaRendererView *view = user_data;
+  MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
+  MetaRendererNativeGpuData *renderer_gpu_data;
+  EGLDisplay *egl_display;
+  EGLAttrib *acquire_attribs;
+  g_autoptr (GError) error = NULL;
+
+  acquire_attribs = (EGLAttrib[]) {
+    EGL_DRM_FLIP_EVENT_DATA_NV,
+    (EGLAttrib) view,
+    EGL_NONE
+  };
+
+  renderer_gpu_data =
+    meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
+                                       onscreen_native->render_gpu);
+
+  egl_display = renderer_gpu_data->egl_display;
+  if (!meta_egl_stream_consumer_acquire_attrib (egl,
+                                                egl_display,
+                                                onscreen_native->egl.stream,
+                                                acquire_attribs,
+                                                &error))
+    {
+      if (g_error_matches (error, META_EGL_ERROR, EGL_RESOURCE_BUSY_EXT))
+        return -EBUSY;
+      else
+        return -EINVAL;
+    }
+
+  return 0;
+}
+#endif /* HAVE_EGL_DEVICE */
+
+void
+meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen)
+{
+  CoglFrameInfo *frame_info;
+
+  meta_onscreen_native_swap_drm_fb (onscreen);
+
+  frame_info = cogl_onscreen_peek_tail_frame_info (onscreen);
+  frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
+  meta_onscreen_native_notify_frame_complete (onscreen);
+}
+
+static void
+meta_onscreen_native_flip_crtc (CoglOnscreen                *onscreen,
+                                MetaRendererView            *view,
+                                MetaCrtc                    *crtc,
+                                MetaKmsPageFlipListenerFlag  flags)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
+  MetaGpuKms *render_gpu = onscreen_native->render_gpu;
+  MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc);
+  MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
+  MetaRendererNativeGpuData *renderer_gpu_data;
+  MetaGpuKms *gpu_kms;
+  MetaKmsDevice *kms_device;
+  MetaKms *kms;
+  MetaKmsUpdate *kms_update;
+  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state = NULL;
+  MetaDrmBuffer *buffer;
+
+  COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeFlipCrtcs,
+                           "Onscreen (flip CRTCs)");
+
+  gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
+  kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
+  kms = meta_kms_device_get_kms (kms_device);
+  kms_update = meta_kms_ensure_pending_update (kms, kms_device);
+
+  g_assert (meta_gpu_kms_is_crtc_active (gpu_kms, crtc));
+
+  renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
+                                                         render_gpu);
+  switch (renderer_gpu_data->mode)
+    {
+    case META_RENDERER_NATIVE_MODE_GBM:
+      if (gpu_kms == render_gpu)
+        {
+          buffer = onscreen_native->gbm.next_fb;
+        }
+      else
+        {
+          secondary_gpu_state = onscreen_native->secondary_gpu_state;
+          buffer = secondary_gpu_state->gbm.next_fb;
+        }
+
+      meta_crtc_kms_assign_primary_plane (crtc_kms, buffer, kms_update);
+
+      break;
+#ifdef HAVE_EGL_DEVICE
+    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+      meta_kms_update_set_custom_page_flip (kms_update,
+                                            custom_egl_stream_page_flip,
+                                            onscreen_native);
+      break;
+#endif
+    }
+
+  meta_kms_update_add_page_flip_listener (kms_update,
+                                          kms_crtc,
+                                          &page_flip_listener_vtable,
+                                          flags,
+                                          g_object_ref (view),
+                                          g_object_unref);
+}
+
+static void
+meta_onscreen_native_set_crtc_mode (CoglOnscreen              *onscreen,
+                                    MetaRendererNativeGpuData *renderer_gpu_data)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
+  MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
+  MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
+  MetaKms *kms = meta_kms_device_get_kms (kms_device);
+  MetaKmsUpdate *kms_update;
+
+  COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeSetCrtcModes,
+                           "Onscreen (set CRTC modes)");
+
+  kms_update = meta_kms_ensure_pending_update (kms, kms_device);
+
+  switch (renderer_gpu_data->mode)
+    {
+    case META_RENDERER_NATIVE_MODE_GBM:
+      break;
+#ifdef HAVE_EGL_DEVICE
+    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+      {
+        MetaDrmBuffer *buffer;
+
+        buffer = META_DRM_BUFFER (onscreen_native->egl.dumb_fb);
+        meta_crtc_kms_assign_primary_plane (crtc_kms, buffer, kms_update);
+        break;
+      }
+#endif
+    }
+
+  meta_crtc_kms_set_mode (crtc_kms, kms_update);
+  meta_output_kms_set_underscan (META_OUTPUT_KMS (onscreen_native->output),
+                                 kms_update);
+}
+
+static void
+secondary_gpu_release_dumb (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
+{
+  unsigned i;
+
+  for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++)
+    g_clear_object (&secondary_gpu_state->cpu.dumb_fbs[i]);
+}
+
+static void
+secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
+{
+  MetaBackend *backend = meta_get_backend ();
+  MetaEgl *egl = meta_backend_get_egl (backend);
+
+  if (secondary_gpu_state->egl_surface != EGL_NO_SURFACE)
+    {
+      MetaRendererNativeGpuData *renderer_gpu_data;
+
+      renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
+      meta_egl_destroy_surface (egl,
+                                renderer_gpu_data->egl_display,
+                                secondary_gpu_state->egl_surface,
+                                NULL);
+    }
+
+  g_clear_object (&secondary_gpu_state->gbm.current_fb);
+  g_clear_object (&secondary_gpu_state->gbm.next_fb);
+  g_clear_pointer (&secondary_gpu_state->gbm.surface, gbm_surface_destroy);
+
+  secondary_gpu_release_dumb (secondary_gpu_state);
+
+  g_free (secondary_gpu_state);
+}
+
+static gboolean
+import_shared_framebuffer (CoglOnscreen                        *onscreen,
+                           MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaGpuKms *gpu_kms;
+  MetaKmsDevice *kms_device;
+  struct gbm_device *gbm_device;
+  MetaDrmBufferGbm *buffer_gbm;
+  MetaDrmBufferImport *buffer_import;
+  g_autoptr (GError) error = NULL;
+
+  buffer_gbm = META_DRM_BUFFER_GBM (onscreen_native->gbm.next_fb);
+
+  gpu_kms = secondary_gpu_state->gpu_kms;
+  kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
+  gbm_device = meta_gbm_device_from_gpu (gpu_kms);
+  buffer_import = meta_drm_buffer_import_new (kms_device,
+                                              gbm_device,
+                                              buffer_gbm,
+                                              &error);
+  if (!buffer_import)
+    {
+      g_debug ("Zero-copy disabled for %s, meta_drm_buffer_import_new failed: %s",
+               meta_gpu_kms_get_file_path (secondary_gpu_state->gpu_kms),
+               error->message);
+
+      g_warn_if_fail (secondary_gpu_state->import_status ==
+                      META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE);
+
+      /*
+       * Fall back. If META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE is
+       * in effect, we have COPY_MODE_PRIMARY prepared already, so we
+       * simply retry with that path. Import status cannot be FAILED,
+       * because we should not retry if failed once.
+       *
+       * If import status is OK, that is unexpected and we do not
+       * have the fallback path prepared which means this output cannot
+       * work anymore.
+       */
+      secondary_gpu_state->renderer_gpu_data->secondary.copy_mode =
+        META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY;
+
+      secondary_gpu_state->import_status =
+        META_SHARED_FRAMEBUFFER_IMPORT_STATUS_FAILED;
+      return FALSE;
+    }
+
+  /*
+   * next_fb may already contain a fallback buffer, so clear it only
+   * when we are sure to succeed.
+   */
+  g_clear_object (&secondary_gpu_state->gbm.next_fb);
+  secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_import);
+
+  if (secondary_gpu_state->import_status ==
+      META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE)
+    {
+      /*
+       * Clean up the cpu-copy part of
+       * init_secondary_gpu_state_cpu_copy_mode ()
+       */
+      secondary_gpu_release_dumb (secondary_gpu_state);
+
+      g_debug ("Using zero-copy for %s succeeded once.",
+               meta_gpu_kms_get_file_path (secondary_gpu_state->gpu_kms));
+    }
+
+  secondary_gpu_state->import_status =
+    META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK;
+  return TRUE;
+}
+
+static void
+copy_shared_framebuffer_gpu (CoglOnscreen                        *onscreen,
+                             MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
+                             MetaRendererNativeGpuData           *renderer_gpu_data,
+                             gboolean                            *egl_context_changed)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
+  MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
+  MetaGles3 *gles3 = meta_renderer_native_get_gles3 (renderer_native);
+  GError *error = NULL;
+  gboolean use_modifiers;
+  MetaKmsDevice *kms_device;
+  MetaDrmBufferGbm *buffer_gbm;
+  struct gbm_bo *bo;
+
+  COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferSecondaryGpu,
+                           "FB Copy (secondary GPU)");
+
+  g_warn_if_fail (secondary_gpu_state->gbm.next_fb == NULL);
+  g_clear_object (&secondary_gpu_state->gbm.next_fb);
+
+  if (!meta_egl_make_current (egl,
+                              renderer_gpu_data->egl_display,
+                              secondary_gpu_state->egl_surface,
+                              secondary_gpu_state->egl_surface,
+                              renderer_gpu_data->secondary.egl_context,
+                              &error))
+    {
+      g_warning ("Failed to make current: %s", error->message);
+      g_error_free (error);
+      return;
+    }
+
+  *egl_context_changed = TRUE;
+
+
+  buffer_gbm = META_DRM_BUFFER_GBM (onscreen_native->gbm.next_fb);
+  bo =  meta_drm_buffer_gbm_get_bo (buffer_gbm);
+  if (!meta_renderer_native_gles3_blit_shared_bo (egl,
+                                                  gles3,
+                                                  renderer_gpu_data->egl_display,
+                                                  renderer_gpu_data->secondary.egl_context,
+                                                  secondary_gpu_state->egl_surface,
+                                                  bo,
+                                                  &error))
+    {
+      g_warning ("Failed to blit shared framebuffer: %s", error->message);
+      g_error_free (error);
+      return;
+    }
+
+  if (!meta_egl_swap_buffers (egl,
+                              renderer_gpu_data->egl_display,
+                              secondary_gpu_state->egl_surface,
+                              &error))
+    {
+      g_warning ("Failed to swap buffers: %s", error->message);
+      g_error_free (error);
+      return;
+    }
+
+  use_modifiers = meta_renderer_native_use_modifiers (renderer_native);
+  kms_device = meta_gpu_kms_get_kms_device (secondary_gpu_state->gpu_kms);
+  buffer_gbm =
+    meta_drm_buffer_gbm_new_lock_front (kms_device,
+                                        secondary_gpu_state->gbm.surface,
+                                        use_modifiers,
+                                        &error);
+  if (!buffer_gbm)
+    {
+      g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s",
+                 error->message);
+      g_error_free (error);
+      return;
+    }
+
+  secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_gbm);
+}
+
+static MetaDrmBufferDumb *
+secondary_gpu_get_next_dumb_buffer (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
+{
+  MetaDrmBufferDumb *current_dumb_fb;
+
+  current_dumb_fb = secondary_gpu_state->cpu.current_dumb_fb;
+  if (current_dumb_fb == secondary_gpu_state->cpu.dumb_fbs[0])
+    return secondary_gpu_state->cpu.dumb_fbs[1];
+  else
+    return secondary_gpu_state->cpu.dumb_fbs[0];
+}
+
+static gboolean
+copy_shared_framebuffer_primary_gpu (CoglOnscreen                        *onscreen,
+                                     MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
+  MetaGpuKms *primary_gpu;
+  MetaRendererNativeGpuData *primary_gpu_data;
+  MetaDrmBufferDumb *buffer_dumb;
+  MetaDrmBuffer *buffer;
+  int width, height, stride;
+  uint32_t drm_format;
+  CoglFramebuffer *dmabuf_fb;
+  int dmabuf_fd;
+  g_autoptr (GError) error = NULL;
+  CoglPixelFormat cogl_format;
+  int ret;
+
+  COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferPrimaryGpu,
+                           "FB Copy (primary GPU)");
+
+  primary_gpu = meta_renderer_native_get_primary_gpu (renderer_native);
+  primary_gpu_data =
+    meta_renderer_native_get_gpu_data (renderer_native, primary_gpu);
+  if (!primary_gpu_data->secondary.has_EGL_EXT_image_dma_buf_import_modifiers)
+    return FALSE;
+
+  buffer_dumb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state);
+  buffer = META_DRM_BUFFER (buffer_dumb);
+
+  width = meta_drm_buffer_get_width (buffer);
+  height = meta_drm_buffer_get_height (buffer);
+  stride = meta_drm_buffer_get_stride (buffer);
+  drm_format = meta_drm_buffer_get_format (buffer);
+
+  g_assert (cogl_framebuffer_get_width (framebuffer) == width);
+  g_assert (cogl_framebuffer_get_height (framebuffer) == height);
+
+  ret = meta_cogl_pixel_format_from_drm_format (drm_format,
+                                                &cogl_format,
+                                                NULL);
+  g_assert (ret);
+
+  dmabuf_fd = meta_drm_buffer_dumb_ensure_dmabuf_fd (buffer_dumb, &error);
+  if (!dmabuf_fd)
+    {
+      g_debug ("Failed to create DMA buffer: %s", error->message);
+      return FALSE;
+    }
+
+  dmabuf_fb =
+    meta_renderer_native_create_dma_buf_framebuffer (renderer_native,
+                                                     dmabuf_fd,
+                                                     width,
+                                                     height,
+                                                     stride,
+                                                     0, DRM_FORMAT_MOD_LINEAR,
+                                                     drm_format,
+                                                     &error);
+
+  if (error)
+    {
+      g_debug ("%s: Failed to blit DMA buffer image: %s",
+               G_STRFUNC, error->message);
+      return FALSE;
+    }
+
+  if (!cogl_blit_framebuffer (framebuffer, COGL_FRAMEBUFFER (dmabuf_fb),
+                              0, 0, 0, 0,
+                              width, height,
+                              &error))
+    {
+      g_object_unref (dmabuf_fb);
+      return FALSE;
+    }
+
+  g_object_unref (dmabuf_fb);
+
+  g_clear_object (&secondary_gpu_state->gbm.next_fb);
+  secondary_gpu_state->gbm.next_fb = buffer;
+  secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb;
+
+  return TRUE;
+}
+
+static void
+copy_shared_framebuffer_cpu (CoglOnscreen                        *onscreen,
+                             MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
+                             MetaRendererNativeGpuData           *renderer_gpu_data)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
+  MetaDrmBufferDumb *buffer_dumb;
+  MetaDrmBuffer *buffer;
+  int width, height, stride;
+  uint32_t drm_format;
+  void *buffer_data;
+  CoglBitmap *dumb_bitmap;
+  CoglPixelFormat cogl_format;
+  gboolean ret;
+
+  COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferCpu,
+                           "FB Copy (CPU)");
+
+  buffer_dumb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state);
+  buffer = META_DRM_BUFFER (buffer_dumb);
+
+  width = meta_drm_buffer_get_width (buffer);
+  height = meta_drm_buffer_get_height (buffer);
+  stride = meta_drm_buffer_get_stride (buffer);
+  drm_format = meta_drm_buffer_get_format (buffer);
+  buffer_data = meta_drm_buffer_dumb_get_data (buffer_dumb);
+
+  g_assert (cogl_framebuffer_get_width (framebuffer) == width);
+  g_assert (cogl_framebuffer_get_height (framebuffer) == height);
+
+  ret = meta_cogl_pixel_format_from_drm_format (drm_format,
+                                                &cogl_format,
+                                                NULL);
+  g_assert (ret);
+
+  dumb_bitmap = cogl_bitmap_new_for_data (cogl_context,
+                                          width,
+                                          height,
+                                          cogl_format,
+                                          stride,
+                                          buffer_data);
+
+  if (!cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
+                                                 0 /* x */,
+                                                 0 /* y */,
+                                                 COGL_READ_PIXELS_COLOR_BUFFER,
+                                                 dumb_bitmap))
+    g_warning ("Failed to CPU-copy to a secondary GPU output");
+
+  cogl_object_unref (dumb_bitmap);
+
+  g_clear_object (&secondary_gpu_state->gbm.next_fb);
+  secondary_gpu_state->gbm.next_fb = buffer;
+  secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb;
+}
+
+static void
+update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
+
+  COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeGpuStatePreSwapBuffers,
+                           "Onscreen (secondary gpu pre-swap-buffers)");
+
+  secondary_gpu_state = onscreen_native->secondary_gpu_state;
+  if (secondary_gpu_state)
+    {
+      MetaRendererNativeGpuData *renderer_gpu_data;
+
+      renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
+      switch (renderer_gpu_data->secondary.copy_mode)
+        {
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
+          /* Done after eglSwapBuffers. */
+          break;
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO:
+          /* Done after eglSwapBuffers. */
+          if (secondary_gpu_state->import_status ==
+              META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK)
+            break;
+          /* prepare fallback */
+          G_GNUC_FALLTHROUGH;
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
+          if (!copy_shared_framebuffer_primary_gpu (onscreen,
+                                                    secondary_gpu_state))
+            {
+              if (!secondary_gpu_state->noted_primary_gpu_copy_failed)
+                {
+                  g_debug ("Using primary GPU to copy for %s failed once.",
+                           meta_gpu_kms_get_file_path (secondary_gpu_state->gpu_kms));
+                  secondary_gpu_state->noted_primary_gpu_copy_failed = TRUE;
+                }
+
+              copy_shared_framebuffer_cpu (onscreen,
+                                           secondary_gpu_state,
+                                           renderer_gpu_data);
+            }
+          else if (!secondary_gpu_state->noted_primary_gpu_copy_ok)
+            {
+              g_debug ("Using primary GPU to copy for %s succeeded once.",
+                       meta_gpu_kms_get_file_path (secondary_gpu_state->gpu_kms));
+              secondary_gpu_state->noted_primary_gpu_copy_ok = TRUE;
+            }
+          break;
+        }
+    }
+}
+
+static void
+update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen,
+                                              gboolean     *egl_context_changed)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
+  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
+
+  COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeGpuStatePostSwapBuffers,
+                           "Onscreen (secondary gpu post-swap-buffers)");
+
+  secondary_gpu_state = onscreen_native->secondary_gpu_state;
+  if (secondary_gpu_state)
+    {
+      MetaRendererNativeGpuData *renderer_gpu_data;
+
+      renderer_gpu_data =
+        meta_renderer_native_get_gpu_data (renderer_native,
+                                           secondary_gpu_state->gpu_kms);
+retry:
+      switch (renderer_gpu_data->secondary.copy_mode)
+        {
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO:
+          if (!import_shared_framebuffer (onscreen,
+                                          secondary_gpu_state))
+            goto retry;
+          break;
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
+          copy_shared_framebuffer_gpu (onscreen,
+                                       secondary_gpu_state,
+                                       renderer_gpu_data,
+                                       egl_context_changed);
+          break;
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
+          /* Done before eglSwapBuffers. */
+          break;
+        }
+    }
+}
+
+static void
+ensure_crtc_modes (CoglOnscreen *onscreen)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
+  CoglRenderer *cogl_renderer = cogl_context->display->renderer;
+  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
+  MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
+
+  if (meta_renderer_native_pop_pending_mode_set (renderer_native,
+                                                 onscreen_native->view))
+    meta_onscreen_native_set_crtc_mode (onscreen, renderer_gpu_data);
+}
+
+void
+meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen  *onscreen,
+                                               const int     *rectangles,
+                                               int            n_rectangles,
+                                               CoglFrameInfo *frame_info,
+                                               gpointer       user_data)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
+  CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
+  CoglRenderer *cogl_renderer = cogl_context->display->renderer;
+  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
+  MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
+  MetaRenderer *renderer = META_RENDERER (renderer_native);
+  MetaBackend *backend = meta_renderer_get_backend (renderer);
+  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+  MetaKms *kms = meta_backend_native_get_kms (backend_native);
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaGpuKms *render_gpu = onscreen_native->render_gpu;
+  MetaKmsDevice *render_kms_device = meta_gpu_kms_get_kms_device (render_gpu);
+  ClutterFrame *frame = user_data;
+  const CoglWinsysVtable *parent_vtable;
+  gboolean egl_context_changed = FALSE;
+  gboolean use_modifiers;
+  MetaPowerSave power_save_mode;
+  g_autoptr (GError) error = NULL;
+  MetaDrmBufferGbm *buffer_gbm;
+  MetaKmsCrtc *kms_crtc;
+  MetaKmsDevice *kms_device;
+  MetaKmsUpdateFlag flags;
+  g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
+  const GError *feedback_error;
+
+  COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers,
+                           "Onscreen (swap-buffers)");
+
+  update_secondary_gpu_state_pre_swap_buffers (onscreen);
+
+  parent_vtable = meta_get_renderer_native_parent_vtable ();
+  parent_vtable->onscreen_swap_buffers_with_damage (onscreen,
+                                                    rectangles,
+                                                    n_rectangles,
+                                                    frame_info,
+                                                    user_data);
+
+  renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
+                                                         render_gpu);
+  switch (renderer_gpu_data->mode)
+    {
+    case META_RENDERER_NATIVE_MODE_GBM:
+      g_warn_if_fail (onscreen_native->gbm.next_fb == NULL);
+      g_clear_object (&onscreen_native->gbm.next_fb);
+
+      use_modifiers = meta_renderer_native_use_modifiers (renderer_native);
+      buffer_gbm =
+        meta_drm_buffer_gbm_new_lock_front (render_kms_device,
+                                            onscreen_native->gbm.surface,
+                                            use_modifiers,
+                                            &error);
+      if (!buffer_gbm)
+        {
+          g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s",
+                     error->message);
+          return;
+        }
+
+      onscreen_native->gbm.next_fb = META_DRM_BUFFER (buffer_gbm);
+
+      break;
+#ifdef HAVE_EGL_DEVICE
+    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+      break;
+#endif
+    }
+
+  update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed);
+
+  power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
+  if (power_save_mode == META_POWER_SAVE_ON)
+    {
+      ensure_crtc_modes (onscreen);
+      meta_onscreen_native_flip_crtc (onscreen,
+                                      onscreen_native->view,
+                                      onscreen_native->crtc,
+                                      META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE);
+    }
+  else
+    {
+      meta_renderer_native_queue_power_save_page_flip (renderer_native,
+                                                       onscreen);
+      clutter_frame_set_result (frame,
+                                CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
+      return;
+    }
+
+  /*
+   * If we changed EGL context, cogl will have the wrong idea about what is
+   * current, making it fail to set it when it needs to. Avoid that by making
+   * EGL_NO_CONTEXT current now, making cogl eventually set the correct
+   * context.
+   */
+  if (egl_context_changed)
+    _cogl_winsys_egl_ensure_current (cogl_display);
+
+  COGL_TRACE_BEGIN_SCOPED (MetaRendererNativePostKmsUpdate,
+                           "Onscreen (post pending update)");
+  kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
+  kms_device = meta_kms_crtc_get_device (kms_crtc);
+
+  switch (renderer_gpu_data->mode)
+    {
+    case META_RENDERER_NATIVE_MODE_GBM:
+      if (meta_renderer_native_has_pending_mode_sets (renderer_native))
+        {
+          meta_topic (META_DEBUG_KMS,
+                      "Postponing primary plane composite update for CRTC %u (%s)",
+                      meta_kms_crtc_get_id (kms_crtc),
+                      meta_kms_device_get_path (kms_device));
+
+          clutter_frame_set_result (frame,
+                                    CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
+          return;
+        }
+      else if (meta_renderer_native_has_pending_mode_set (renderer_native))
+        {
+          meta_topic (META_DEBUG_KMS, "Posting global mode set updates on %s",
+                      meta_kms_device_get_path (kms_device));
+
+          meta_renderer_native_notify_mode_sets_reset (renderer_native);
+          meta_renderer_native_post_mode_set_updates (renderer_native);
+          clutter_frame_set_result (frame,
+                                    CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
+          return;
+        }
+      break;
+#ifdef HAVE_EGL_DEVICE
+    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+      if (meta_renderer_native_has_pending_mode_set (renderer_native))
+        {
+          meta_renderer_native_notify_mode_sets_reset (renderer_native);
+          meta_renderer_native_post_mode_set_updates (renderer_native);
+          clutter_frame_set_result (frame,
+                                    CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
+         return;
+        }
+      break;
+#endif
+    }
+
+  meta_topic (META_DEBUG_KMS,
+              "Posting primary plane composite update for CRTC %u (%s)",
+              meta_kms_crtc_get_id (kms_crtc),
+              meta_kms_device_get_path (kms_device));
+
+  flags = META_KMS_UPDATE_FLAG_NONE;
+  kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
+
+  switch (meta_kms_feedback_get_result (kms_feedback))
+    {
+    case META_KMS_FEEDBACK_PASSED:
+      clutter_frame_set_result (frame,
+                                CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
+      break;
+    case META_KMS_FEEDBACK_FAILED:
+      clutter_frame_set_result (frame,
+                                CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
+
+      feedback_error = meta_kms_feedback_get_error (kms_feedback);
+      if (!g_error_matches (feedback_error,
+                            G_IO_ERROR,
+                            G_IO_ERROR_PERMISSION_DENIED))
+        g_warning ("Failed to post KMS update: %s", feedback_error->message);
+      break;
+    }
+}
+
+gboolean
+meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen,
+                                                   uint32_t      drm_format,
+                                                   uint64_t      drm_modifier,
+                                                   uint32_t      stride)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  const MetaCrtcConfig *crtc_config;
+  MetaDrmBuffer *fb;
+  struct gbm_bo *gbm_bo;
+
+  crtc_config = meta_crtc_get_config (onscreen_native->crtc);
+  if (crtc_config->transform != META_MONITOR_TRANSFORM_NORMAL)
+    return FALSE;
+
+  if (onscreen_native->secondary_gpu_state)
+    return FALSE;
+
+  if (!onscreen_native->gbm.surface)
+    return FALSE;
+
+  fb = onscreen_native->gbm.current_fb ? onscreen_native->gbm.current_fb
+                                       : onscreen_native->gbm.next_fb;
+  if (!fb)
+    return FALSE;
+
+  if (!META_IS_DRM_BUFFER_GBM (fb))
+    return FALSE;
+
+  gbm_bo = meta_drm_buffer_gbm_get_bo (META_DRM_BUFFER_GBM (fb));
+
+  if (gbm_bo_get_format (gbm_bo) != drm_format)
+    return FALSE;
+
+  if (gbm_bo_get_modifier (gbm_bo) != drm_modifier)
+    return FALSE;
+
+  if (gbm_bo_get_stride (gbm_bo) != stride)
+    return FALSE;
+
+  return TRUE;
+}
+
+gboolean
+meta_onscreen_native_direct_scanout (CoglOnscreen   *onscreen,
+                                     CoglScanout    *scanout,
+                                     CoglFrameInfo  *frame_info,
+                                     gpointer        user_data,
+                                     GError        **error)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaGpuKms *render_gpu = onscreen_native->render_gpu;
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
+  CoglRenderer *cogl_renderer = cogl_context->display->renderer;
+  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
+  MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
+  MetaRenderer *renderer = META_RENDERER (renderer_native);
+  MetaBackend *backend = meta_renderer_get_backend (renderer);
+  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
+  MetaKms *kms = meta_backend_native_get_kms (backend_native);
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+  MetaPowerSave power_save_mode;
+  ClutterFrame *frame = user_data;
+  MetaKmsCrtc *kms_crtc;
+  MetaKmsDevice *kms_device;
+  MetaKmsUpdateFlag flags;
+  g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
+  const GError *feedback_error;
+
+  power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
+  if (power_save_mode != META_POWER_SAVE_ON)
+    {
+      g_set_error_literal (error,
+                           COGL_SCANOUT_ERROR,
+                           COGL_SCANOUT_ERROR_INHIBITED,
+                           NULL);
+      return FALSE;
+    }
+
+  if (meta_renderer_native_has_pending_mode_set (renderer_native))
+    {
+      g_set_error_literal (error,
+                           COGL_SCANOUT_ERROR,
+                           COGL_SCANOUT_ERROR_INHIBITED,
+                           NULL);
+      return FALSE;
+    }
+
+  renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
+                                                         render_gpu);
+
+  g_warn_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM);
+  g_warn_if_fail (!onscreen_native->gbm.next_fb);
+
+  g_set_object (&onscreen_native->gbm.next_fb, META_DRM_BUFFER (scanout));
+
+  ensure_crtc_modes (onscreen);
+  meta_onscreen_native_flip_crtc (onscreen,
+                                  onscreen_native->view,
+                                  onscreen_native->crtc,
+                                  META_KMS_PAGE_FLIP_LISTENER_FLAG_NO_DISCARD);
+
+  kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
+  kms_device = meta_kms_crtc_get_device (kms_crtc);
+
+  meta_topic (META_DEBUG_KMS,
+              "Posting direct scanout update for CRTC %u (%s)",
+              meta_kms_crtc_get_id (kms_crtc),
+              meta_kms_device_get_path (kms_device));
+
+  flags = META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR;
+  kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
+  switch (meta_kms_feedback_get_result (kms_feedback))
+    {
+    case META_KMS_FEEDBACK_PASSED:
+      clutter_frame_set_result (frame,
+                                CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
+      break;
+    case META_KMS_FEEDBACK_FAILED:
+      feedback_error = meta_kms_feedback_get_error (kms_feedback);
+
+      if (g_error_matches (feedback_error,
+                           G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
+        break;
+
+      g_clear_object (&onscreen_native->gbm.next_fb);
+      g_propagate_error (error, g_error_copy (feedback_error));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+add_onscreen_frame_info (MetaCrtc *crtc)
+{
+  MetaGpu *gpu = meta_crtc_get_gpu (crtc);
+  MetaBackend *backend = meta_gpu_get_backend (gpu);
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+  MetaStageNative *stage_native =
+    meta_clutter_backend_native_get_stage_native (clutter_backend);
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+  MetaRendererView *view = meta_renderer_get_view_for_crtc (renderer, crtc);
+
+  clutter_stage_cogl_add_onscreen_frame_info (CLUTTER_STAGE_COGL (stage_native),
+                                              CLUTTER_STAGE_VIEW (view));
+}
+
+void
+meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
+                                   ClutterFrame *frame)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaCrtc *crtc = onscreen_native->crtc;
+  MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
+  MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);;
+  MetaKms *kms = meta_kms_device_get_kms (kms_device);
+  MetaKmsUpdateFlag flags;
+  MetaKmsUpdate *kms_update;
+  g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
+  const GError *error;
+
+  kms_update = meta_kms_get_pending_update (kms, kms_device);
+  if (!kms_update)
+    {
+      clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
+      return;
+    }
+
+  meta_kms_update_add_page_flip_listener (kms_update,
+                                          kms_crtc,
+                                          &page_flip_listener_vtable,
+                                          META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE,
+                                          g_object_ref (onscreen_native->view),
+                                          g_object_unref);
+
+  flags = META_KMS_UPDATE_FLAG_NONE;
+  kms_feedback = meta_kms_post_pending_update_sync (kms,
+                                                    kms_device,
+                                                    flags);
+  switch (meta_kms_feedback_get_result (kms_feedback))
+    {
+    case META_KMS_FEEDBACK_PASSED:
+      add_onscreen_frame_info (crtc);
+      clutter_frame_set_result (frame,
+                                CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
+      break;
+    case META_KMS_FEEDBACK_FAILED:
+      add_onscreen_frame_info (crtc);
+      clutter_frame_set_result (frame,
+                                CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
+
+      error = meta_kms_feedback_get_error (kms_feedback);
+      if (!g_error_matches (error,
+                            G_IO_ERROR,
+                            G_IO_ERROR_PERMISSION_DENIED))
+        g_warning ("Failed to post KMS update: %s", error->message);
+      break;
+    }
+}
+
+static gboolean
+should_surface_be_sharable (CoglOnscreen *onscreen)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+
+  if (META_GPU_KMS (meta_crtc_get_gpu (onscreen_native->crtc)) ==
+      onscreen_native->render_gpu)
+    return FALSE;
+  else
+    return TRUE;
+}
+
+static uint32_t
+get_gbm_format_from_egl (MetaEgl    *egl,
+                         EGLDisplay  egl_display,
+                         EGLConfig   egl_config)
+{
+  uint32_t gbm_format;
+  EGLint native_visual_id;
+
+  if (meta_egl_get_config_attrib (egl,
+                                  egl_display,
+                                  egl_config,
+                                  EGL_NATIVE_VISUAL_ID,
+                                  &native_visual_id,
+                                  NULL))
+    gbm_format = (uint32_t) native_visual_id;
+  else
+    g_assert_not_reached ();
+
+  return gbm_format;
+}
+
+static GArray *
+get_supported_kms_modifiers (MetaCrtcKms *crtc_kms,
+                             uint32_t     format)
+{
+  GArray *modifiers;
+  GArray *crtc_mods;
+  unsigned int i;
+
+  crtc_mods = meta_crtc_kms_get_modifiers (crtc_kms, format);
+  if (!crtc_mods)
+    return NULL;
+
+  modifiers = g_array_new (FALSE, FALSE, sizeof (uint64_t));
+
+  /*
+   * For each modifier from base_crtc, check if it's available on all other
+   * CRTCs.
+   */
+  for (i = 0; i < crtc_mods->len; i++)
+    {
+      uint64_t modifier = g_array_index (crtc_mods, uint64_t, i);
+
+      g_array_append_val (modifiers, modifier);
+    }
+
+  if (modifiers->len == 0)
+    {
+      g_array_free (modifiers, TRUE);
+      return NULL;
+    }
+
+  return modifiers;
+}
+
+static GArray *
+get_supported_egl_modifiers (CoglOnscreen *onscreen,
+                             MetaCrtcKms  *crtc_kms,
+                             uint32_t      format)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
+  MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
+  MetaGpu *gpu;
+  MetaRendererNativeGpuData *renderer_gpu_data;
+  EGLint num_modifiers;
+  GArray *modifiers;
+  GError *error = NULL;
+  gboolean ret;
+
+  gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms));
+  renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
+                                                         META_GPU_KMS (gpu));
+
+  if (!meta_egl_has_extensions (egl, renderer_gpu_data->egl_display, NULL,
+                                "EGL_EXT_image_dma_buf_import_modifiers",
+                                NULL))
+    return NULL;
+
+  ret = meta_egl_query_dma_buf_modifiers (egl, renderer_gpu_data->egl_display,
+                                          format, 0, NULL, NULL,
+                                          &num_modifiers, NULL);
+  if (!ret || num_modifiers == 0)
+    return NULL;
+
+  modifiers = g_array_sized_new (FALSE, FALSE, sizeof (uint64_t),
+                                 num_modifiers);
+  ret = meta_egl_query_dma_buf_modifiers (egl, renderer_gpu_data->egl_display,
+                                          format, num_modifiers,
+                                          (EGLuint64KHR *) modifiers->data, NULL,
+                                          &num_modifiers, &error);
+
+  if (!ret)
+    {
+      g_warning ("Failed to query DMABUF modifiers: %s", error->message);
+      g_error_free (error);
+      g_array_free (modifiers, TRUE);
+      return NULL;
+    }
+
+  return modifiers;
+}
+
+static GArray *
+get_supported_modifiers (CoglOnscreen *onscreen,
+                         uint32_t      format)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
+  MetaGpu *gpu;
+  g_autoptr (GArray) modifiers = NULL;
+
+  gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms));
+  if (gpu == META_GPU (onscreen_native->render_gpu))
+    modifiers = get_supported_kms_modifiers (crtc_kms, format);
+  else
+    modifiers = get_supported_egl_modifiers (onscreen, crtc_kms, format);
+
+  return g_steal_pointer (&modifiers);
+}
+
+static GArray *
+get_supported_kms_formats (CoglOnscreen *onscreen)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
+
+  return meta_crtc_kms_copy_drm_format_list (crtc_kms);
+}
+
+static gboolean
+create_surfaces_gbm (CoglOnscreen        *onscreen,
+                     int                  width,
+                     int                  height,
+                     struct gbm_surface **gbm_surface,
+                     EGLSurface          *egl_surface,
+                     GError             **error)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
+  MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
+  CoglDisplay *cogl_display = cogl_context->display;
+  CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
+  CoglRenderer *cogl_renderer = cogl_display->renderer;
+  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
+  struct gbm_surface *new_gbm_surface = NULL;
+  EGLNativeWindowType egl_native_window;
+  EGLSurface new_egl_surface;
+  uint32_t format;
+  GArray *modifiers;
+
+  renderer_gpu_data =
+    meta_renderer_native_get_gpu_data (renderer_native,
+                                       onscreen_native->render_gpu);
+
+  format = get_gbm_format_from_egl (egl,
+                                    cogl_renderer_egl->edpy,
+                                    cogl_display_egl->egl_config);
+
+  if (meta_renderer_native_use_modifiers (renderer_native))
+    modifiers = get_supported_modifiers (onscreen, format);
+  else
+    modifiers = NULL;
+
+  if (modifiers)
+    {
+      new_gbm_surface =
+        gbm_surface_create_with_modifiers (renderer_gpu_data->gbm.device,
+                                           width, height, format,
+                                           (uint64_t *) modifiers->data,
+                                           modifiers->len);
+      g_array_free (modifiers, TRUE);
+    }
+
+  if (!new_gbm_surface)
+    {
+      uint32_t flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
+
+      if (should_surface_be_sharable (onscreen))
+        flags |= GBM_BO_USE_LINEAR;
+
+      new_gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device,
+                                            width, height,
+                                            format,
+                                            flags);
+    }
+
+  if (!new_gbm_surface)
+    {
+      g_set_error (error, COGL_WINSYS_ERROR,
+                   COGL_WINSYS_ERROR_CREATE_ONSCREEN,
+                   "Failed to allocate surface");
+      return FALSE;
+    }
+
+  egl_native_window = (EGLNativeWindowType) new_gbm_surface;
+  new_egl_surface =
+    meta_egl_create_window_surface (egl,
+                                    cogl_renderer_egl->edpy,
+                                    cogl_display_egl->egl_config,
+                                    egl_native_window,
+                                    NULL,
+                                    error);
+  if (new_egl_surface == EGL_NO_SURFACE)
+    {
+      gbm_surface_destroy (new_gbm_surface);
+      return FALSE;
+    }
+
+  *gbm_surface = new_gbm_surface;
+  *egl_surface = new_egl_surface;
+
+  return TRUE;
+}
+
+#ifdef HAVE_EGL_DEVICE
+static gboolean
+create_surfaces_egl_device (CoglOnscreen  *onscreen,
+                            int            width,
+                            int            height,
+                            EGLStreamKHR  *out_egl_stream,
+                            EGLSurface    *out_egl_surface,
+                            GError       **error)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
+  CoglDisplay *cogl_display = cogl_context->display;
+  CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
+  CoglRenderer *cogl_renderer = cogl_display->renderer;
+  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
+  MetaEgl *egl =
+    meta_renderer_native_get_egl (renderer_gpu_data->renderer_native);
+  EGLDisplay egl_display = renderer_gpu_data->egl_display;
+  EGLConfig egl_config;
+  EGLStreamKHR egl_stream;
+  EGLSurface egl_surface;
+  EGLint num_layers;
+  EGLOutputLayerEXT output_layer;
+  EGLAttrib output_attribs[3];
+  EGLint stream_attribs[] = {
+    EGL_STREAM_FIFO_LENGTH_KHR, 0,
+    EGL_CONSUMER_AUTO_ACQUIRE_EXT, EGL_FALSE,
+    EGL_NONE
+  };
+  EGLint stream_producer_attribs[] = {
+    EGL_WIDTH, width,
+    EGL_HEIGHT, height,
+    EGL_NONE
+  };
+
+  egl_stream = meta_egl_create_stream (egl, egl_display, stream_attribs, error);
+  if (egl_stream == EGL_NO_STREAM_KHR)
+    return FALSE;
+
+  output_attribs[0] = EGL_DRM_CRTC_EXT;
+  output_attribs[1] = meta_crtc_get_id (onscreen_native->crtc);
+  output_attribs[2] = EGL_NONE;
+
+  if (!meta_egl_get_output_layers (egl, egl_display,
+                                   output_attribs,
+                                   &output_layer, 1, &num_layers,
+                                   error))
+    {
+      meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
+      return FALSE;
+    }
+
+  if (num_layers < 1)
+    {
+      meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
+      g_set_error (error, G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "Unable to find output layers.");
+      return FALSE;
+    }
+
+  if (!meta_egl_stream_consumer_output (egl, egl_display,
+                                        egl_stream, output_layer,
+                                        error))
+    {
+      meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
+      return FALSE;
+    }
+
+  egl_config = cogl_display_egl->egl_config;
+  egl_surface = meta_egl_create_stream_producer_surface (egl,
+                                                         egl_display,
+                                                         egl_config,
+                                                         egl_stream,
+                                                         stream_producer_attribs,
+                                                         error);
+  if (egl_surface == EGL_NO_SURFACE)
+    {
+      meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
+      return FALSE;
+    }
+
+  *out_egl_stream = egl_stream;
+  *out_egl_surface = egl_surface;
+
+  return TRUE;
+}
+#endif /* HAVE_EGL_DEVICE */
+
+void
+meta_onscreen_native_set_view (CoglOnscreen     *onscreen,
+                               MetaRendererView *view)
+{
+  CoglOnscreenEgl *onscreen_egl;
+  MetaOnscreenNative *onscreen_native;
+
+  onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  onscreen_native->view = view;
+}
+
+gboolean
+meta_renderer_native_init_onscreen (CoglOnscreen *onscreen,
+                                    GError      **error)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
+  CoglDisplay *cogl_display = cogl_context->display;
+  CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
+  CoglOnscreenEgl *onscreen_egl;
+  MetaOnscreenNative *onscreen_native;
+
+  g_return_val_if_fail (cogl_display_egl->egl_context, FALSE);
+
+  onscreen_egl = cogl_onscreen_egl_new ();
+  cogl_onscreen_set_winsys (onscreen, onscreen_egl);
+
+  onscreen_native = g_slice_new0 (MetaOnscreenNative);
+  cogl_onscreen_egl_set_platform (onscreen_egl, onscreen_native);
+
+  /*
+   * Don't actually initialize anything here, since we may not have the
+   * information available yet, and there is no way to pass it at this stage.
+   * To properly allocate a MetaOnscreenNative, the caller must call
+   * meta_onscreen_native_allocate() after cogl_framebuffer_allocate().
+   *
+   * TODO: Turn CoglFramebuffer/CoglOnscreen into GObjects, so it's possible
+   * to add backend specific properties.
+   */
+
+  return TRUE;
+}
+
+static gboolean
+init_secondary_gpu_state_gpu_copy_mode (MetaRendererNative         *renderer_native,
+                                        CoglOnscreen               *onscreen,
+                                        MetaRendererNativeGpuData  *renderer_gpu_data,
+                                        GError                    **error)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
+  int width, height;
+  EGLNativeWindowType egl_native_window;
+  struct gbm_surface *gbm_surface;
+  EGLSurface egl_surface;
+  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
+  MetaGpuKms *gpu_kms;
+  uint32_t format;
+
+  width = cogl_framebuffer_get_width (framebuffer);
+  height = cogl_framebuffer_get_height (framebuffer);
+  format = get_gbm_format_from_egl (egl,
+                                    renderer_gpu_data->egl_display,
+                                    renderer_gpu_data->secondary.egl_config);
+
+  gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device,
+                                    width, height,
+                                    format,
+                                    GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+  if (!gbm_surface)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Failed to create gbm_surface: %s", strerror (errno));
+      return FALSE;
+    }
+
+  egl_native_window = (EGLNativeWindowType) gbm_surface;
+  egl_surface =
+    meta_egl_create_window_surface (egl,
+                                    renderer_gpu_data->egl_display,
+                                    renderer_gpu_data->secondary.egl_config,
+                                    egl_native_window,
+                                    NULL,
+                                    error);
+  if (egl_surface == EGL_NO_SURFACE)
+    {
+      gbm_surface_destroy (gbm_surface);
+      return FALSE;
+    }
+
+  secondary_gpu_state = g_new0 (MetaOnscreenNativeSecondaryGpuState, 1);
+
+  gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (onscreen_native->crtc));
+  secondary_gpu_state->gpu_kms = gpu_kms;
+  secondary_gpu_state->renderer_gpu_data = renderer_gpu_data;
+  secondary_gpu_state->gbm.surface = gbm_surface;
+  secondary_gpu_state->egl_surface = egl_surface;
+
+  onscreen_native->secondary_gpu_state = secondary_gpu_state;
+
+  return TRUE;
+}
+
+static uint32_t
+pick_secondary_gpu_framebuffer_format_for_cpu (CoglOnscreen *onscreen)
+{
+  /*
+   * cogl_framebuffer_read_pixels_into_bitmap () supported formats in
+   * preference order. Ideally these should depend on the render buffer
+   * format copy_shared_framebuffer_cpu () will be reading from but
+   * alpha channel ignored.
+   */
+  static const uint32_t preferred_formats[] =
+    {
+      /*
+       * DRM_FORMAT_XBGR8888 a.k.a GL_RGBA, GL_UNSIGNED_BYTE on
+       * little-endian is possibly the most optimized glReadPixels
+       * output format. glReadPixels cannot avoid manufacturing an alpha
+       * channel if the render buffer does not have one and converting
+       * to ABGR8888 may be more optimized than ARGB8888.
+       */
+      DRM_FORMAT_XBGR8888,
+      /* The rest are other fairly commonly used formats in OpenGL. */
+      DRM_FORMAT_XRGB8888,
+    };
+  g_autoptr (GArray) formats = NULL;
+  size_t k;
+  unsigned int i;
+  uint32_t drm_format;
+
+  formats = get_supported_kms_formats (onscreen);
+
+  /* Check if any of our preferred formats are supported. */
+  for (k = 0; k < G_N_ELEMENTS (preferred_formats); k++)
+    {
+      g_assert (meta_cogl_pixel_format_from_drm_format (preferred_formats[k],
+                                                        NULL,
+                                                        NULL));
+
+      for (i = 0; i < formats->len; i++)
+        {
+          drm_format = g_array_index (formats, uint32_t, i);
+
+          if (drm_format == preferred_formats[k])
+            return drm_format;
+        }
+    }
+
+  /*
+   * Otherwise just pick an arbitrary format we recognize. The formats
+   * list is not in any specific order and we don't know any better
+   * either.
+   */
+  for (i = 0; i < formats->len; i++)
+    {
+      drm_format = g_array_index (formats, uint32_t, i);
+
+      if (meta_cogl_pixel_format_from_drm_format (drm_format, NULL, NULL))
+        return drm_format;
+    }
+
+  return DRM_FORMAT_INVALID;
+}
+
+static gboolean
+init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative         *renderer_native,
+                                        CoglOnscreen               *onscreen,
+                                        MetaRendererNativeGpuData  *renderer_gpu_data,
+                                        GError                    **error)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
+  MetaGpuKms *gpu_kms;
+  MetaKmsDevice *kms_device;
+  int width, height;
+  unsigned int i;
+  uint32_t drm_format;
+  MetaDrmFormatBuf tmp;
+
+  drm_format = pick_secondary_gpu_framebuffer_format_for_cpu (onscreen);
+  if (drm_format == DRM_FORMAT_INVALID)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Could not find a suitable pixel format in CPU copy mode");
+      return FALSE;
+    }
+
+  width = cogl_framebuffer_get_width (framebuffer);
+  height = cogl_framebuffer_get_height (framebuffer);
+
+  gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (onscreen_native->crtc));
+  kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
+  g_debug ("Secondary GPU %s using DRM format '%s' (0x%x) for a %dx%d output.",
+           meta_gpu_kms_get_file_path (gpu_kms),
+           meta_drm_format_to_string (&tmp, drm_format),
+           drm_format,
+           width, height);
+
+  secondary_gpu_state = g_new0 (MetaOnscreenNativeSecondaryGpuState, 1);
+  secondary_gpu_state->renderer_gpu_data = renderer_gpu_data;
+  secondary_gpu_state->gpu_kms = gpu_kms;
+  secondary_gpu_state->egl_surface = EGL_NO_SURFACE;
+
+  for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++)
+    {
+      secondary_gpu_state->cpu.dumb_fbs[i] =
+        meta_drm_buffer_dumb_new (kms_device,
+                                  width, height,
+                                  drm_format,
+                                  error);
+      if (!secondary_gpu_state->cpu.dumb_fbs[i])
+        {
+          secondary_gpu_state_free (secondary_gpu_state);
+          return FALSE;
+        }
+    }
+
+  /*
+   * This function initializes everything needed for
+   * META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO as well.
+   */
+  secondary_gpu_state->import_status =
+    META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE;
+
+  onscreen_native->secondary_gpu_state = secondary_gpu_state;
+
+  return TRUE;
+}
+
+static gboolean
+init_secondary_gpu_state (MetaRendererNative  *renderer_native,
+                          CoglOnscreen        *onscreen,
+                          GError             **error)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaGpu *gpu = meta_crtc_get_gpu (onscreen_native->crtc);
+  MetaRendererNativeGpuData *renderer_gpu_data;
+
+  renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
+                                                         META_GPU_KMS (gpu));
+
+  switch (renderer_gpu_data->secondary.copy_mode)
+    {
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
+      if (!init_secondary_gpu_state_gpu_copy_mode (renderer_native,
+                                                   onscreen,
+                                                   renderer_gpu_data,
+                                                   error))
+        return FALSE;
+      break;
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO:
+      /*
+       * Initialize also the primary copy mode, so that if zero-copy
+       * path fails, which is quite likely, we can simply continue
+       * with the primary copy path on the very first frame.
+       */
+      G_GNUC_FALLTHROUGH;
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
+      if (!init_secondary_gpu_state_cpu_copy_mode (renderer_native,
+                                                   onscreen,
+                                                   renderer_gpu_data,
+                                                   error))
+        return FALSE;
+      break;
+    }
+
+  return TRUE;
+}
+
+CoglOnscreen *
+meta_onscreen_native_new (MetaRendererNative   *renderer_native,
+                          MetaGpuKms           *render_gpu,
+                          MetaOutput           *output,
+                          MetaCrtc             *crtc,
+                          CoglContext          *context,
+                          int                   width,
+                          int                   height,
+                          GError              **error)
+{
+  CoglOnscreen *onscreen;
+  CoglOnscreenEgl *onscreen_egl;
+  MetaOnscreenNative *onscreen_native;
+
+  onscreen = cogl_onscreen_new (context, width, height);
+
+  if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (onscreen), error))
+    {
+      g_object_unref (onscreen);
+      return NULL;
+    }
+
+  onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  onscreen_native->renderer_native = renderer_native;
+  onscreen_native->render_gpu = render_gpu;
+  onscreen_native->output = output;
+  onscreen_native->crtc = crtc;
+
+  if (META_GPU_KMS (meta_crtc_get_gpu (crtc)) != render_gpu)
+    {
+      if (!init_secondary_gpu_state (renderer_native, onscreen, error))
+        {
+          g_object_unref (onscreen);
+          return NULL;
+        }
+    }
+
+  return onscreen;
+}
+
+gboolean
+meta_onscreen_native_allocate (CoglOnscreen *onscreen,
+                               GError      **error)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  MetaRendererNativeGpuData *renderer_gpu_data;
+  struct gbm_surface *gbm_surface;
+  EGLSurface egl_surface;
+  int width;
+  int height;
+#ifdef HAVE_EGL_DEVICE
+  MetaKmsDevice *render_kms_device;
+  EGLStreamKHR egl_stream;
+#endif
+
+  /* If a kms_fd is set then the display width and height
+   * won't be available until meta_renderer_native_set_layout
+   * is called. In that case, defer creating the surface
+   * until then.
+   */
+  width = cogl_framebuffer_get_width (framebuffer);
+  height = cogl_framebuffer_get_height (framebuffer);
+  if (width == 0 || height == 0)
+    return TRUE;
+
+  renderer_gpu_data =
+    meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
+                                       onscreen_native->render_gpu);
+  switch (renderer_gpu_data->mode)
+    {
+    case META_RENDERER_NATIVE_MODE_GBM:
+      if (!create_surfaces_gbm (onscreen,
+                                width, height,
+                                &gbm_surface,
+                                &egl_surface,
+                                error))
+        return FALSE;
+
+      onscreen_native->gbm.surface = gbm_surface;
+      cogl_onscreen_egl_set_egl_surface (onscreen_egl, egl_surface);
+      break;
+#ifdef HAVE_EGL_DEVICE
+    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+      render_kms_device =
+        meta_gpu_kms_get_kms_device (onscreen_native->render_gpu);
+      onscreen_native->egl.dumb_fb =
+        meta_drm_buffer_dumb_new (render_kms_device,
+                                  width, height,
+                                  DRM_FORMAT_XRGB8888,
+                                  error);
+      if (!onscreen_native->egl.dumb_fb)
+        return FALSE;
+
+      if (!create_surfaces_egl_device (onscreen,
+                                       width, height,
+                                       &egl_stream,
+                                       &egl_surface,
+                                       error))
+        return FALSE;
+
+      onscreen_native->egl.stream = egl_stream;
+      cogl_onscreen_egl_set_egl_surface (onscreen_egl, egl_surface);
+      break;
+#endif /* HAVE_EGL_DEVICE */
+    }
+
+  return TRUE;
+}
+
+static void
+destroy_egl_surface (CoglOnscreen *onscreen)
+{
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  EGLSurface egl_surface;
+
+  egl_surface = cogl_onscreen_egl_get_egl_surface (onscreen_egl);
+  if (cogl_onscreen_egl_get_egl_surface (onscreen_egl) != EGL_NO_SURFACE)
+    {
+      MetaOnscreenNative *onscreen_native =
+        cogl_onscreen_egl_get_platform (onscreen_egl);
+      MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
+      CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+      CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
+      CoglRenderer *cogl_renderer = cogl_context->display->renderer;
+      CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+
+      meta_egl_destroy_surface (egl,
+                                cogl_renderer_egl->edpy,
+                                egl_surface,
+                                NULL);
+      cogl_onscreen_egl_set_egl_surface (onscreen_egl, EGL_NO_SURFACE);
+    }
+}
+
+void
+meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
+  CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
+  CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
+  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
+  MetaOnscreenNative *onscreen_native;
+  MetaRendererNative *renderer_native;
+  MetaRendererNativeGpuData *renderer_gpu_data;
+  EGLSurface egl_surface;
+
+  /* If we never successfully allocated then there's nothing to do */
+  if (onscreen_egl == NULL)
+    return;
+
+  onscreen_native =
+    cogl_onscreen_egl_get_platform (onscreen_egl);
+  renderer_native = onscreen_native->renderer_native;
+
+  egl_surface = cogl_onscreen_egl_get_egl_surface (onscreen_egl);
+  if (egl_surface != EGL_NO_SURFACE &&
+      (cogl_display_egl->current_draw_surface == egl_surface ||
+       cogl_display_egl->current_read_surface == egl_surface))
+    {
+      if (!_cogl_winsys_egl_make_current (cogl_display,
+                                          cogl_display_egl->dummy_surface,
+                                          cogl_display_egl->dummy_surface,
+                                          cogl_display_egl->egl_context))
+        g_warning ("Failed to clear current context");
+    }
+
+  renderer_gpu_data =
+    meta_renderer_native_get_gpu_data (renderer_native,
+                                       onscreen_native->render_gpu);
+  switch (renderer_gpu_data->mode)
+    {
+    case META_RENDERER_NATIVE_MODE_GBM:
+      /* flip state takes a reference on the onscreen so there should
+       * never be outstanding flips when we reach here. */
+      g_return_if_fail (onscreen_native->gbm.next_fb == NULL);
+
+      free_current_bo (onscreen);
+
+      destroy_egl_surface (onscreen);
+
+      if (onscreen_native->gbm.surface)
+        {
+          gbm_surface_destroy (onscreen_native->gbm.surface);
+          onscreen_native->gbm.surface = NULL;
+        }
+      break;
+#ifdef HAVE_EGL_DEVICE
+    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+      g_clear_object (&onscreen_native->egl.dumb_fb);
+
+      destroy_egl_surface (onscreen);
+
+      if (onscreen_native->egl.stream != EGL_NO_STREAM_KHR)
+        {
+          MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
+          CoglRenderer *cogl_renderer = cogl_context->display->renderer;
+          CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+
+          meta_egl_destroy_stream (egl,
+                                   cogl_renderer_egl->edpy,
+                                   onscreen_native->egl.stream,
+                                   NULL);
+          onscreen_native->egl.stream = EGL_NO_STREAM_KHR;
+        }
+      break;
+#endif /* HAVE_EGL_DEVICE */
+    }
+
+  g_clear_pointer (&onscreen_native->secondary_gpu_state,
+                   secondary_gpu_state_free);
+
+  g_slice_free (MetaOnscreenNative, onscreen_native);
+  cogl_onscreen_egl_free (cogl_onscreen_get_winsys (onscreen));
+  cogl_onscreen_set_winsys (onscreen, NULL);
+}
diff --git a/src/backends/native/meta-onscreen-native.h b/src/backends/native/meta-onscreen-native.h
new file mode 100644
index 0000000000..10a3a610f9
--- /dev/null
+++ b/src/backends/native/meta-onscreen-native.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016-2020 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ */
+
+#ifndef META_ONSCREEN_NATIVE_H
+#define META_ONSCREEN_NATIVE_H
+
+#include <glib.h>
+
+#include "backends/meta-backend-types.h"
+#include "backends/native/meta-backend-native-types.h"
+#include "clutter/clutter.h"
+#include "cogl/cogl.h"
+
+gboolean
+meta_renderer_native_init_onscreen (CoglOnscreen *onscreen,
+                                    GError      **error);
+
+void meta_renderer_native_release_onscreen (CoglOnscreen *onscreen);
+
+gboolean meta_onscreen_native_allocate (CoglOnscreen *onscreen,
+                                        GError      **error);
+
+void meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen  *onscreen,
+                                                    const int     *rectangles,
+                                                    int            n_rectangles,
+                                                    CoglFrameInfo *frame_info,
+                                                    gpointer       user_data);
+
+gboolean meta_onscreen_native_direct_scanout (CoglOnscreen   *onscreen,
+                                              CoglScanout    *scanout,
+                                              CoglFrameInfo  *frame_info,
+                                              gpointer        user_data,
+                                              GError        **error);
+
+void meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
+                                        ClutterFrame *frame);
+
+void meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen);
+
+void meta_onscreen_native_set_view (CoglOnscreen     *onscreen,
+                                    MetaRendererView *view);
+
+CoglOnscreen * meta_onscreen_native_new (MetaRendererNative  *renderer_native,
+                                         MetaGpuKms          *render_gpu,
+                                         MetaOutput          *output,
+                                         MetaCrtc            *crtc,
+                                         CoglContext         *cogl_context,
+                                         int                  width,
+                                         int                  height,
+                                         GError             **error);
+
+#endif /* META_ONSCREEN_NATIVE_H */
diff --git a/src/backends/native/meta-renderer-native-private.h 
b/src/backends/native/meta-renderer-native-private.h
new file mode 100644
index 0000000000..2193d85e47
--- /dev/null
+++ b/src/backends/native/meta-renderer-native-private.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2011 Intel Corporation.
+ * Copyright (C) 2016-2020 Red Hat
+ * Copyright (c) 2018,2019 DisplayLink (UK) Ltd.
+ *
+ * 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 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.
+ *
+ */
+
+#ifndef META_RENDERER_NATIVE_PRIVATE_H
+#define META_RENDERER_NATIVE_PRIVATE_H
+
+#include "backends/meta-gles3.h"
+#include "backends/native/meta-renderer-native.h"
+
+typedef enum _MetaSharedFramebufferCopyMode
+{
+  /* Zero-copy: primary GPU exports, secondary GPU imports as KMS FB */
+  META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO,
+  /* the secondary GPU will make the copy */
+  META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU,
+  /*
+   * The copy is made in the primary GPU rendering context, either
+   * as a CPU copy through Cogl read-pixels or as primary GPU copy
+   * using glBlitFramebuffer.
+   */
+  META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY
+} MetaSharedFramebufferCopyMode;
+
+typedef struct _MetaRendererNativeGpuData
+{
+  MetaRendererNative *renderer_native;
+
+  struct {
+    struct gbm_device *device;
+  } gbm;
+
+#ifdef HAVE_EGL_DEVICE
+  struct {
+    EGLDeviceEXT device;
+  } egl;
+#endif
+
+  MetaRendererNativeMode mode;
+
+  EGLDisplay egl_display;
+
+  /*
+   * Fields used for blitting iGPU framebuffer content onto dGPU framebuffers.
+   */
+  struct {
+    MetaSharedFramebufferCopyMode copy_mode;
+    gboolean is_hardware_rendering;
+    gboolean has_EGL_EXT_image_dma_buf_import_modifiers;
+
+    /* For GPU blit mode */
+    EGLContext egl_context;
+    EGLConfig egl_config;
+  } secondary;
+} MetaRendererNativeGpuData;
+
+MetaEgl * meta_renderer_native_get_egl (MetaRendererNative *renderer_native);
+
+MetaGles3 * meta_renderer_native_get_gles3 (MetaRendererNative *renderer_native);
+
+MetaRendererNativeGpuData * meta_renderer_native_get_gpu_data (MetaRendererNative *renderer_native,
+                                                               MetaGpuKms         *gpu_kms);
+
+gboolean meta_renderer_native_has_pending_mode_sets (MetaRendererNative *renderer_native);
+
+gboolean meta_renderer_native_has_pending_mode_set (MetaRendererNative *renderer_native);
+
+void meta_renderer_native_notify_mode_sets_reset (MetaRendererNative *renderer_native);
+
+void meta_renderer_native_post_mode_set_updates (MetaRendererNative *renderer_native);
+
+void meta_renderer_native_queue_power_save_page_flip (MetaRendererNative *renderer_native,
+                                                      CoglOnscreen       *onscreen);
+
+CoglFramebuffer * meta_renderer_native_create_dma_buf_framebuffer (MetaRendererNative  *renderer_native,
+                                                                   int                  dmabuf_fd,
+                                                                   uint32_t             width,
+                                                                   uint32_t             height,
+                                                                   uint32_t             stride,
+                                                                   uint32_t             offset,
+                                                                   uint64_t             modifier,
+                                                                   uint32_t             drm_format,
+                                                                   GError             **error);
+
+gboolean meta_renderer_native_pop_pending_mode_set (MetaRendererNative *renderer_native,
+                                                    MetaRendererView   *view);
+
+const CoglWinsysVtable * meta_get_renderer_native_parent_vtable (void);
+
+#endif /* META_RENDERER_NATIVE_PRIVATE_H */
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index a542af194b..555bd413d0 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -46,28 +46,14 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "backends/meta-backend-private.h"
-#include "backends/meta-crtc.h"
-#include "backends/meta-egl-ext.h"
-#include "backends/meta-egl.h"
 #include "backends/meta-gles3.h"
 #include "backends/meta-logical-monitor.h"
-#include "backends/meta-output.h"
-#include "backends/meta-renderer-view.h"
 #include "backends/native/meta-cogl-utils.h"
 #include "backends/native/meta-crtc-kms.h"
-#include "backends/native/meta-drm-buffer-dumb.h"
-#include "backends/native/meta-drm-buffer-gbm.h"
-#include "backends/native/meta-drm-buffer-import.h"
-#include "backends/native/meta-drm-buffer.h"
-#include "backends/native/meta-gpu-kms.h"
 #include "backends/native/meta-kms-device.h"
-#include "backends/native/meta-kms-update.h"
-#include "backends/native/meta-kms-utils.h"
 #include "backends/native/meta-kms.h"
-#include "backends/native/meta-output-kms.h"
-#include "backends/native/meta-renderer-native-gles3.h"
-#include "backends/native/meta-renderer-native.h"
+#include "backends/native/meta-onscreen-native.h"
+#include "backends/native/meta-renderer-native-private.h"
 #include "cogl/cogl.h"
 #include "core/boxes-private.h"
 
@@ -80,111 +66,6 @@
 #define DRM_FORMAT_INVALID 0
 #endif
 
-typedef enum _MetaSharedFramebufferCopyMode
-{
-  /* Zero-copy: primary GPU exports, secondary GPU imports as KMS FB */
-  META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO,
-  /* the secondary GPU will make the copy */
-  META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU,
-  /*
-   * The copy is made in the primary GPU rendering context, either
-   * as a CPU copy through Cogl read-pixels or as primary GPU copy
-   * using glBlitFramebuffer.
-   */
-  META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY
-} MetaSharedFramebufferCopyMode;
-
-typedef struct _MetaRendererNativeGpuData
-{
-  MetaRendererNative *renderer_native;
-
-  struct {
-    struct gbm_device *device;
-  } gbm;
-
-#ifdef HAVE_EGL_DEVICE
-  struct {
-    EGLDeviceEXT device;
-  } egl;
-#endif
-
-  MetaRendererNativeMode mode;
-
-  EGLDisplay egl_display;
-
-  /*
-   * Fields used for blitting iGPU framebuffer content onto dGPU framebuffers.
-   */
-  struct {
-    MetaSharedFramebufferCopyMode copy_mode;
-    gboolean is_hardware_rendering;
-    gboolean has_EGL_EXT_image_dma_buf_import_modifiers;
-
-    /* For GPU blit mode */
-    EGLContext egl_context;
-    EGLConfig egl_config;
-  } secondary;
-} MetaRendererNativeGpuData;
-
-typedef enum _MetaSharedFramebufferImportStatus
-{
-  /* Not tried importing yet. */
-  META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE,
-  /* Tried before and failed. */
-  META_SHARED_FRAMEBUFFER_IMPORT_STATUS_FAILED,
-  /* Tried before and succeeded. */
-  META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK
-} MetaSharedFramebufferImportStatus;
-
-typedef struct _MetaOnscreenNativeSecondaryGpuState
-{
-  MetaGpuKms *gpu_kms;
-  MetaRendererNativeGpuData *renderer_gpu_data;
-
-  EGLSurface egl_surface;
-
-  struct {
-    struct gbm_surface *surface;
-    MetaDrmBuffer *current_fb;
-    MetaDrmBuffer *next_fb;
-  } gbm;
-
-  struct {
-    MetaDrmBufferDumb *current_dumb_fb;
-    MetaDrmBufferDumb *dumb_fbs[2];
-  } cpu;
-
-  gboolean noted_primary_gpu_copy_ok;
-  gboolean noted_primary_gpu_copy_failed;
-  MetaSharedFramebufferImportStatus import_status;
-} MetaOnscreenNativeSecondaryGpuState;
-
-typedef struct _MetaOnscreenNative
-{
-  MetaRendererNative *renderer_native;
-  MetaGpuKms *render_gpu;
-  MetaOutput *output;
-  MetaCrtc *crtc;
-
-  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
-
-  struct {
-    struct gbm_surface *surface;
-    MetaDrmBuffer *current_fb;
-    MetaDrmBuffer *next_fb;
-  } gbm;
-
-#ifdef HAVE_EGL_DEVICE
-  struct {
-    EGLStreamKHR stream;
-
-    MetaDrmBufferDumb *dumb_fb;
-  } egl;
-#endif
-
-  MetaRendererView *view;
-} MetaOnscreenNative;
-
 struct _MetaRendererNative
 {
   MetaRenderer parent;
@@ -221,15 +102,15 @@ G_DEFINE_TYPE_WITH_CODE (MetaRendererNative,
 static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
 static const CoglWinsysVtable *parent_vtable;
 
-static MetaEgl *
-meta_renderer_native_get_egl (MetaRendererNative *renderer_native);
-
-static void
-free_current_secondary_bo (CoglOnscreen *onscreen);
-
 static void
 meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native);
 
+const CoglWinsysVtable *
+meta_get_renderer_native_parent_vtable (void)
+{
+  return parent_vtable;
+}
+
 static void
 meta_renderer_native_gpu_data_free (MetaRendererNativeGpuData *renderer_gpu_data)
 {
@@ -243,7 +124,7 @@ meta_renderer_native_gpu_data_free (MetaRendererNativeGpuData *renderer_gpu_data
   g_free (renderer_gpu_data);
 }
 
-static MetaRendererNativeGpuData *
+MetaRendererNativeGpuData *
 meta_renderer_native_get_gpu_data (MetaRendererNative *renderer_native,
                                    MetaGpuKms         *gpu_kms)
 {
@@ -282,7 +163,7 @@ meta_create_renderer_native_gpu_data (MetaGpuKms *gpu_kms)
   return g_new0 (MetaRendererNativeGpuData, 1);
 }
 
-static MetaEgl *
+MetaEgl *
 meta_renderer_native_get_egl (MetaRendererNative *renderer_native)
 {
   MetaRenderer *renderer = META_RENDERER (renderer_native);
@@ -296,415 +177,22 @@ meta_renderer_native_use_modifiers (MetaRendererNative *renderer_native)
   return renderer_native->use_modifiers;
 }
 
-static MetaEgl *
-meta_onscreen_native_get_egl (MetaOnscreenNative *onscreen_native)
-{
-  return meta_renderer_native_get_egl (onscreen_native->renderer_native);
-}
-
-static GArray *
-get_supported_kms_modifiers (MetaCrtcKms *crtc_kms,
-                             uint32_t     format)
-{
-  GArray *modifiers;
-  GArray *crtc_mods;
-  unsigned int i;
-
-  crtc_mods = meta_crtc_kms_get_modifiers (crtc_kms, format);
-  if (!crtc_mods)
-    return NULL;
-
-  modifiers = g_array_new (FALSE, FALSE, sizeof (uint64_t));
-
-  /*
-   * For each modifier from base_crtc, check if it's available on all other
-   * CRTCs.
-   */
-  for (i = 0; i < crtc_mods->len; i++)
-    {
-      uint64_t modifier = g_array_index (crtc_mods, uint64_t, i);
-
-      g_array_append_val (modifiers, modifier);
-    }
-
-  if (modifiers->len == 0)
-    {
-      g_array_free (modifiers, TRUE);
-      return NULL;
-    }
-
-  return modifiers;
-}
-
-static GArray *
-get_supported_egl_modifiers (CoglOnscreen *onscreen,
-                             MetaCrtcKms  *crtc_kms,
-                             uint32_t      format)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
-  MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
-  MetaGpu *gpu;
-  MetaRendererNativeGpuData *renderer_gpu_data;
-  EGLint num_modifiers;
-  GArray *modifiers;
-  GError *error = NULL;
-  gboolean ret;
-
-  gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms));
-  renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
-                                                         META_GPU_KMS (gpu));
-
-  if (!meta_egl_has_extensions (egl, renderer_gpu_data->egl_display, NULL,
-                                "EGL_EXT_image_dma_buf_import_modifiers",
-                                NULL))
-    return NULL;
-
-  ret = meta_egl_query_dma_buf_modifiers (egl, renderer_gpu_data->egl_display,
-                                          format, 0, NULL, NULL,
-                                          &num_modifiers, NULL);
-  if (!ret || num_modifiers == 0)
-    return NULL;
-
-  modifiers = g_array_sized_new (FALSE, FALSE, sizeof (uint64_t),
-                                 num_modifiers);
-  ret = meta_egl_query_dma_buf_modifiers (egl, renderer_gpu_data->egl_display,
-                                          format, num_modifiers,
-                                          (EGLuint64KHR *) modifiers->data, NULL,
-                                          &num_modifiers, &error);
-
-  if (!ret)
-    {
-      g_warning ("Failed to query DMABUF modifiers: %s", error->message);
-      g_error_free (error);
-      g_array_free (modifiers, TRUE);
-      return NULL;
-    }
-
-  return modifiers;
-}
-
-static GArray *
-get_supported_modifiers (CoglOnscreen *onscreen,
-                         uint32_t      format)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
-  MetaGpu *gpu;
-  g_autoptr (GArray) modifiers = NULL;
-
-  gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms));
-  if (gpu == META_GPU (onscreen_native->render_gpu))
-    modifiers = get_supported_kms_modifiers (crtc_kms, format);
-  else
-    modifiers = get_supported_egl_modifiers (onscreen, crtc_kms, format);
-
-  return g_steal_pointer (&modifiers);
-}
-
-static GArray *
-get_supported_kms_formats (CoglOnscreen *onscreen)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
-
-  return meta_crtc_kms_copy_drm_format_list (crtc_kms);
-}
-
-static uint32_t
-get_gbm_format_from_egl (MetaEgl    *egl,
-                         EGLDisplay  egl_display,
-                         EGLConfig   egl_config)
-{
-  uint32_t gbm_format;
-  EGLint native_visual_id;
-
-  if (meta_egl_get_config_attrib (egl,
-                                  egl_display,
-                                  egl_config,
-                                  EGL_NATIVE_VISUAL_ID,
-                                  &native_visual_id,
-                                  NULL))
-    gbm_format = (uint32_t) native_visual_id;
-  else
-    g_assert_not_reached ();
-
-  return gbm_format;
-}
-
-static gboolean
-init_secondary_gpu_state_gpu_copy_mode (MetaRendererNative         *renderer_native,
-                                        CoglOnscreen               *onscreen,
-                                        MetaRendererNativeGpuData  *renderer_gpu_data,
-                                        GError                    **error)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
-  int width, height;
-  EGLNativeWindowType egl_native_window;
-  struct gbm_surface *gbm_surface;
-  EGLSurface egl_surface;
-  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
-  MetaGpuKms *gpu_kms;
-  uint32_t format;
-
-  width = cogl_framebuffer_get_width (framebuffer);
-  height = cogl_framebuffer_get_height (framebuffer);
-  format = get_gbm_format_from_egl (egl,
-                                    renderer_gpu_data->egl_display,
-                                    renderer_gpu_data->secondary.egl_config);
-
-  gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device,
-                                    width, height,
-                                    format,
-                                    GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
-  if (!gbm_surface)
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Failed to create gbm_surface: %s", strerror (errno));
-      return FALSE;
-    }
-
-  egl_native_window = (EGLNativeWindowType) gbm_surface;
-  egl_surface =
-    meta_egl_create_window_surface (egl,
-                                    renderer_gpu_data->egl_display,
-                                    renderer_gpu_data->secondary.egl_config,
-                                    egl_native_window,
-                                    NULL,
-                                    error);
-  if (egl_surface == EGL_NO_SURFACE)
-    {
-      gbm_surface_destroy (gbm_surface);
-      return FALSE;
-    }
-
-  secondary_gpu_state = g_new0 (MetaOnscreenNativeSecondaryGpuState, 1);
-
-  gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (onscreen_native->crtc));
-  secondary_gpu_state->gpu_kms = gpu_kms;
-  secondary_gpu_state->renderer_gpu_data = renderer_gpu_data;
-  secondary_gpu_state->gbm.surface = gbm_surface;
-  secondary_gpu_state->egl_surface = egl_surface;
-
-  onscreen_native->secondary_gpu_state = secondary_gpu_state;
-
-  return TRUE;
-}
-
-static void
-secondary_gpu_release_dumb (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
-{
-  unsigned i;
-
-  for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++)
-    g_clear_object (&secondary_gpu_state->cpu.dumb_fbs[i]);
-}
-
-static void
-secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
-{
-  MetaBackend *backend = meta_get_backend ();
-  MetaEgl *egl = meta_backend_get_egl (backend);
-
-  if (secondary_gpu_state->egl_surface != EGL_NO_SURFACE)
-    {
-      MetaRendererNativeGpuData *renderer_gpu_data;
-
-      renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
-      meta_egl_destroy_surface (egl,
-                                renderer_gpu_data->egl_display,
-                                secondary_gpu_state->egl_surface,
-                                NULL);
-    }
-
-  g_clear_object (&secondary_gpu_state->gbm.current_fb);
-  g_clear_object (&secondary_gpu_state->gbm.next_fb);
-  g_clear_pointer (&secondary_gpu_state->gbm.surface, gbm_surface_destroy);
-
-  secondary_gpu_release_dumb (secondary_gpu_state);
-
-  g_free (secondary_gpu_state);
-}
-
-static uint32_t
-pick_secondary_gpu_framebuffer_format_for_cpu (CoglOnscreen *onscreen)
+MetaGles3 *
+meta_renderer_native_get_gles3 (MetaRendererNative *renderer_native)
 {
-  /*
-   * cogl_framebuffer_read_pixels_into_bitmap () supported formats in
-   * preference order. Ideally these should depend on the render buffer
-   * format copy_shared_framebuffer_cpu () will be reading from but
-   * alpha channel ignored.
-   */
-  static const uint32_t preferred_formats[] =
-    {
-      /*
-       * DRM_FORMAT_XBGR8888 a.k.a GL_RGBA, GL_UNSIGNED_BYTE on
-       * little-endian is possibly the most optimized glReadPixels
-       * output format. glReadPixels cannot avoid manufacturing an alpha
-       * channel if the render buffer does not have one and converting
-       * to ABGR8888 may be more optimized than ARGB8888.
-       */
-      DRM_FORMAT_XBGR8888,
-      /* The rest are other fairly commonly used formats in OpenGL. */
-      DRM_FORMAT_XRGB8888,
-    };
-  g_autoptr (GArray) formats = NULL;
-  size_t k;
-  unsigned int i;
-  uint32_t drm_format;
-
-  formats = get_supported_kms_formats (onscreen);
-
-  /* Check if any of our preferred formats are supported. */
-  for (k = 0; k < G_N_ELEMENTS (preferred_formats); k++)
-    {
-      g_assert (meta_cogl_pixel_format_from_drm_format (preferred_formats[k],
-                                                        NULL,
-                                                        NULL));
-
-      for (i = 0; i < formats->len; i++)
-        {
-          drm_format = g_array_index (formats, uint32_t, i);
-
-          if (drm_format == preferred_formats[k])
-            return drm_format;
-        }
-    }
-
-  /*
-   * Otherwise just pick an arbitrary format we recognize. The formats
-   * list is not in any specific order and we don't know any better
-   * either.
-   */
-  for (i = 0; i < formats->len; i++)
-    {
-      drm_format = g_array_index (formats, uint32_t, i);
-
-      if (meta_cogl_pixel_format_from_drm_format (drm_format, NULL, NULL))
-        return drm_format;
-    }
-
-  return DRM_FORMAT_INVALID;
+  return renderer_native->gles3;
 }
 
-static gboolean
-init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative         *renderer_native,
-                                        CoglOnscreen               *onscreen,
-                                        MetaRendererNativeGpuData  *renderer_gpu_data,
-                                        GError                    **error)
+gboolean
+meta_renderer_native_has_pending_mode_sets (MetaRendererNative *renderer_native)
 {
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
-  MetaGpuKms *gpu_kms;
-  MetaKmsDevice *kms_device;
-  int width, height;
-  unsigned int i;
-  uint32_t drm_format;
-  MetaDrmFormatBuf tmp;
-
-  drm_format = pick_secondary_gpu_framebuffer_format_for_cpu (onscreen);
-  if (drm_format == DRM_FORMAT_INVALID)
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Could not find a suitable pixel format in CPU copy mode");
-      return FALSE;
-    }
-
-  width = cogl_framebuffer_get_width (framebuffer);
-  height = cogl_framebuffer_get_height (framebuffer);
-
-  gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (onscreen_native->crtc));
-  kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
-  g_debug ("Secondary GPU %s using DRM format '%s' (0x%x) for a %dx%d output.",
-           meta_gpu_kms_get_file_path (gpu_kms),
-           meta_drm_format_to_string (&tmp, drm_format),
-           drm_format,
-           width, height);
-
-  secondary_gpu_state = g_new0 (MetaOnscreenNativeSecondaryGpuState, 1);
-  secondary_gpu_state->renderer_gpu_data = renderer_gpu_data;
-  secondary_gpu_state->gpu_kms = gpu_kms;
-  secondary_gpu_state->egl_surface = EGL_NO_SURFACE;
-
-  for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++)
-    {
-      secondary_gpu_state->cpu.dumb_fbs[i] =
-        meta_drm_buffer_dumb_new (kms_device,
-                                  width, height,
-                                  drm_format,
-                                  error);
-      if (!secondary_gpu_state->cpu.dumb_fbs[i])
-        {
-          secondary_gpu_state_free (secondary_gpu_state);
-          return FALSE;
-        }
-    }
-
-  /*
-   * This function initializes everything needed for
-   * META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO as well.
-   */
-  secondary_gpu_state->import_status =
-    META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE;
-
-  onscreen_native->secondary_gpu_state = secondary_gpu_state;
-
-  return TRUE;
+  return !!renderer_native->pending_mode_set_views;
 }
 
-static gboolean
-init_secondary_gpu_state (MetaRendererNative  *renderer_native,
-                          CoglOnscreen        *onscreen,
-                          GError             **error)
+gboolean
+meta_renderer_native_has_pending_mode_set (MetaRendererNative *renderer_native)
 {
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaGpu *gpu = meta_crtc_get_gpu (onscreen_native->crtc);
-  MetaRendererNativeGpuData *renderer_gpu_data;
-
-  renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
-                                                         META_GPU_KMS (gpu));
-
-  switch (renderer_gpu_data->secondary.copy_mode)
-    {
-    case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
-      if (!init_secondary_gpu_state_gpu_copy_mode (renderer_native,
-                                                   onscreen,
-                                                   renderer_gpu_data,
-                                                   error))
-        return FALSE;
-      break;
-    case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO:
-      /*
-       * Initialize also the primary copy mode, so that if zero-copy
-       * path fails, which is quite likely, we can simply continue
-       * with the primary copy path on the very first frame.
-       */
-      G_GNUC_FALLTHROUGH;
-    case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
-      if (!init_secondary_gpu_state_cpu_copy_mode (renderer_native,
-                                                   onscreen,
-                                                   renderer_gpu_data,
-                                                   error))
-        return FALSE;
-      break;
-    }
-
-  return TRUE;
+  return renderer_native->pending_mode_set;
 }
 
 static void
@@ -715,46 +203,6 @@ meta_renderer_native_disconnect (CoglRenderer *cogl_renderer)
   g_slice_free (CoglRendererEGL, cogl_renderer_egl);
 }
 
-static void
-free_current_secondary_bo (CoglOnscreen *onscreen)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
-
-  secondary_gpu_state = onscreen_native->secondary_gpu_state;
-  if (!secondary_gpu_state)
-    return;
-
-  g_clear_object (&secondary_gpu_state->gbm.current_fb);
-}
-
-static void
-free_current_bo (CoglOnscreen *onscreen)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-
-  g_clear_object (&onscreen_native->gbm.current_fb);
-  free_current_secondary_bo (onscreen);
-}
-
-static void
-meta_onscreen_native_notify_frame_complete (CoglOnscreen *onscreen)
-{
-  CoglFrameInfo *info;
-
-  info = cogl_onscreen_pop_head_frame_info (onscreen);
-
-  g_assert (!cogl_onscreen_peek_head_frame_info (onscreen));
-
-  _cogl_onscreen_notify_frame_sync (onscreen, info);
-  _cogl_onscreen_notify_complete (onscreen, info);
-  cogl_object_unref (info);
-}
-
 static gboolean
 meta_renderer_native_connect (CoglRenderer *cogl_renderer,
                               GError      **error)
@@ -999,254 +447,130 @@ meta_renderer_native_egl_cleanup_context (CoglDisplay *cogl_display)
     }
 }
 
-static void
-swap_secondary_drm_fb (CoglOnscreen *onscreen)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
-
-  secondary_gpu_state = onscreen_native->secondary_gpu_state;
-  if (!secondary_gpu_state)
-    return;
-
-  g_set_object (&secondary_gpu_state->gbm.current_fb,
-                secondary_gpu_state->gbm.next_fb);
-  g_clear_object (&secondary_gpu_state->gbm.next_fb);
-}
-
-static void
-meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen)
+static CoglContext *
+cogl_context_from_renderer_native (MetaRendererNative *renderer_native)
 {
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-
-  if (!onscreen_native->gbm.next_fb)
-    return;
-
-  free_current_bo (onscreen);
-
-  g_set_object (&onscreen_native->gbm.current_fb, onscreen_native->gbm.next_fb);
-  g_clear_object (&onscreen_native->gbm.next_fb);
+  MetaRenderer *renderer = META_RENDERER (renderer_native);
+  MetaBackend *backend = meta_renderer_get_backend (renderer);
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
 
-  swap_secondary_drm_fb (onscreen);
+  return clutter_backend_get_cogl_context (clutter_backend);
 }
 
-static void
-maybe_update_frame_info (MetaCrtc      *crtc,
-                         CoglFrameInfo *frame_info,
-                         int64_t        time_ns)
+CoglFramebuffer *
+meta_renderer_native_create_dma_buf_framebuffer (MetaRendererNative  *renderer_native,
+                                                 int                  dmabuf_fd,
+                                                 uint32_t             width,
+                                                 uint32_t             height,
+                                                 uint32_t             stride,
+                                                 uint32_t             offset,
+                                                 uint64_t             modifier,
+                                                 uint32_t             drm_format,
+                                                 GError             **error)
 {
-  const MetaCrtcConfig *crtc_config;
-  const MetaCrtcModeInfo *crtc_mode_info;
-  float refresh_rate;
-
-  g_return_if_fail (crtc);
+  CoglContext *cogl_context =
+    cogl_context_from_renderer_native (renderer_native);
+  CoglDisplay *cogl_display = cogl_context->display;
+  CoglRenderer *cogl_renderer = cogl_display->renderer;
+  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+  EGLDisplay egl_display = cogl_renderer_egl->edpy;
+  MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
+  EGLImageKHR egl_image;
+  uint32_t strides[1];
+  uint32_t offsets[1];
+  uint64_t modifiers[1];
+  CoglPixelFormat cogl_format;
+  CoglEglImageFlags flags;
+  CoglTexture2D *cogl_tex;
+  CoglOffscreen *cogl_fbo;
+  int ret;
 
-  crtc_config = meta_crtc_get_config (crtc);
-  if (!crtc_config)
-    return;
+  ret = meta_cogl_pixel_format_from_drm_format (drm_format,
+                                                &cogl_format,
+                                                NULL);
+  g_assert (ret);
 
-  crtc_mode_info = meta_crtc_mode_get_info (crtc_config->mode);
-  refresh_rate = crtc_mode_info->refresh_rate;
-  if (refresh_rate >= frame_info->refresh_rate)
-    {
-      frame_info->presentation_time = time_ns;
-      frame_info->refresh_rate = refresh_rate;
-    }
-}
+  strides[0] = stride;
+  offsets[0] = offset;
+  modifiers[0] = modifier;
+  egl_image = meta_egl_create_dmabuf_image (egl,
+                                            egl_display,
+                                            width,
+                                            height,
+                                            drm_format,
+                                            1 /* n_planes */,
+                                            &dmabuf_fd,
+                                            strides,
+                                            offsets,
+                                            modifiers,
+                                            error);
+  if (egl_image == EGL_NO_IMAGE_KHR)
+    return NULL;
 
-static void
-notify_view_crtc_presented (MetaRendererView *view,
-                            MetaKmsCrtc      *kms_crtc,
-                            int64_t           time_ns)
-{
-  ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
-  CoglFramebuffer *framebuffer =
-    clutter_stage_view_get_onscreen (stage_view);
-  CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
-  CoglFrameInfo *frame_info;
-  MetaCrtc *crtc;
-  MetaRendererNativeGpuData *renderer_gpu_data;
+  flags = COGL_EGL_IMAGE_FLAG_NO_GET_DATA;
+  cogl_tex = cogl_egl_texture_2d_new_from_image (cogl_context,
+                                                 width,
+                                                 height,
+                                                 cogl_format,
+                                                 egl_image,
+                                                 flags,
+                                                 error);
 
-  frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
+  meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
 
-  crtc = META_CRTC (meta_crtc_kms_from_kms_crtc (kms_crtc));
-  maybe_update_frame_info (crtc, frame_info, time_ns);
+  if (!cogl_tex)
+    return NULL;
 
-  meta_onscreen_native_notify_frame_complete (onscreen);
+  cogl_fbo = cogl_offscreen_new_with_texture (COGL_TEXTURE (cogl_tex));
+  cogl_object_unref (cogl_tex);
 
-  renderer_gpu_data =
-    meta_renderer_native_get_gpu_data (renderer_native,
-                                       onscreen_native->render_gpu);
-  switch (renderer_gpu_data->mode)
+  if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (cogl_fbo), error))
     {
-    case META_RENDERER_NATIVE_MODE_GBM:
-      meta_onscreen_native_swap_drm_fb (onscreen);
-      break;
-#ifdef HAVE_EGL_DEVICE
-    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
-      break;
-#endif
+      g_object_unref (cogl_fbo);
+      return NULL;
     }
-}
-
-static int64_t
-timeval_to_nanoseconds (const struct timeval *tv)
-{
-  int64_t usec = ((int64_t) tv->tv_sec) * G_USEC_PER_SEC + tv->tv_usec;
-  int64_t nsec = usec * 1000;
-
-  return nsec;
-}
-
-static void
-page_flip_feedback_flipped (MetaKmsCrtc  *kms_crtc,
-                            unsigned int  sequence,
-                            unsigned int  tv_sec,
-                            unsigned int  tv_usec,
-                            gpointer      user_data)
-{
-  MetaRendererView *view = user_data;
-  struct timeval page_flip_time;
-
-  page_flip_time = (struct timeval) {
-    .tv_sec = tv_sec,
-    .tv_usec = tv_usec,
-  };
 
-  notify_view_crtc_presented (view, kms_crtc,
-                              timeval_to_nanoseconds (&page_flip_time));
+  return COGL_FRAMEBUFFER (cogl_fbo);
 }
 
-static void
-page_flip_feedback_ready (MetaKmsCrtc *kms_crtc,
-                          gpointer     user_data)
+static MetaKmsDevice *
+kms_device_from_view (MetaRendererView *view)
 {
-  MetaRendererView *view = user_data;
-  CoglFramebuffer *framebuffer =
-    clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
-  CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
-  CoglFrameInfo *frame_info;
-
-  frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
-  frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
+  MetaCrtc *crtc = meta_renderer_view_get_crtc (view);
+  MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc);
+  MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
 
-  meta_onscreen_native_notify_frame_complete (onscreen);
+  return meta_kms_crtc_get_device (kms_crtc);
 }
 
-static void
-page_flip_feedback_mode_set_fallback (MetaKmsCrtc *kms_crtc,
-                                      gpointer     user_data)
+static MetaGpu *
+gpu_from_view (MetaRendererView *view)
 {
-  MetaRendererView *view = user_data;
-  MetaCrtc *crtc;
-  MetaGpuKms *gpu_kms;
-  int64_t now_ns;
-
-  /*
-   * We ended up not page flipping, thus we don't have a presentation time to
-   * use. Lets use the next best thing: the current time.
-   */
-
-  crtc = META_CRTC (meta_crtc_kms_from_kms_crtc (kms_crtc));
-  gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
-  now_ns = meta_gpu_kms_get_current_time_ns (gpu_kms);
+  MetaCrtc *crtc = meta_renderer_view_get_crtc (view);
 
-  notify_view_crtc_presented (view, kms_crtc, now_ns);
+  return meta_crtc_get_gpu (crtc);
 }
 
 static void
-page_flip_feedback_discarded (MetaKmsCrtc  *kms_crtc,
-                              gpointer      user_data,
-                              const GError *error)
-{
-  MetaRendererView *view = user_data;
-  MetaCrtc *crtc;
-  MetaGpuKms *gpu_kms;
-  int64_t now_ns;
-
-  /*
-   * Page flipping failed, but we want to fail gracefully, so to avoid freezing
-   * the frame clack, pretend we flipped.
-   */
-
-  if (error &&
-      !g_error_matches (error,
-                        G_IO_ERROR,
-                        G_IO_ERROR_PERMISSION_DENIED))
-    g_warning ("Page flip discarded: %s", error->message);
-
-  crtc = META_CRTC (meta_crtc_kms_from_kms_crtc (kms_crtc));
-  gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
-  now_ns = meta_gpu_kms_get_current_time_ns (gpu_kms);
-
-  notify_view_crtc_presented (view, kms_crtc, now_ns);
-}
-
-static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = {
-  .flipped = page_flip_feedback_flipped,
-  .ready = page_flip_feedback_ready,
-  .mode_set_fallback = page_flip_feedback_mode_set_fallback,
-  .discarded = page_flip_feedback_discarded,
-};
-
-#ifdef HAVE_EGL_DEVICE
-static int
-custom_egl_stream_page_flip (gpointer custom_page_flip_data,
-                             gpointer user_data)
+configure_disabled_crtcs (MetaGpu       *gpu,
+                          MetaKmsUpdate *kms_update)
 {
-  MetaOnscreenNative *onscreen_native = custom_page_flip_data;
-  MetaRendererView *view = user_data;
-  MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
-  MetaRendererNativeGpuData *renderer_gpu_data;
-  EGLDisplay *egl_display;
-  EGLAttrib *acquire_attribs;
-  g_autoptr (GError) error = NULL;
-
-  acquire_attribs = (EGLAttrib[]) {
-    EGL_DRM_FLIP_EVENT_DATA_NV,
-    (EGLAttrib) view,
-    EGL_NONE
-  };
-
-  renderer_gpu_data =
-    meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
-                                       onscreen_native->render_gpu);
+  GList *l;
 
-  egl_display = renderer_gpu_data->egl_display;
-  if (!meta_egl_stream_consumer_acquire_attrib (egl,
-                                                egl_display,
-                                                onscreen_native->egl.stream,
-                                                acquire_attribs,
-                                                &error))
+  for (l = meta_gpu_get_crtcs (gpu); l; l = l->next)
     {
-      if (g_error_matches (error, META_EGL_ERROR, EGL_RESOURCE_BUSY_EXT))
-        return -EBUSY;
-      else
-        return -EINVAL;
-    }
-
-  return 0;
-}
-#endif /* HAVE_EGL_DEVICE */
+      MetaCrtc *crtc = l->data;
+      MetaKmsCrtc *kms_crtc;
 
-static void
-dummy_power_save_page_flip (CoglOnscreen *onscreen)
-{
-  CoglFrameInfo *frame_info;
+      if (meta_crtc_get_config (crtc))
+        continue;
 
-  meta_onscreen_native_swap_drm_fb (onscreen);
+      kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
+      if (!meta_kms_crtc_is_active (kms_crtc))
+        continue;
 
-  frame_info = cogl_onscreen_peek_tail_frame_info (onscreen);
-  frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
-  meta_onscreen_native_notify_frame_complete (onscreen);
+      meta_kms_update_mode_set (kms_update, kms_crtc, NULL, NULL);
+    }
 }
 
 static gboolean
@@ -1255,7 +579,8 @@ dummy_power_save_page_flip_cb (gpointer user_data)
   MetaRendererNative *renderer_native = user_data;
 
   g_list_foreach (renderer_native->power_save_page_flip_onscreens,
-                  (GFunc) dummy_power_save_page_flip, NULL);
+                  (GFunc) meta_onscreen_native_dummy_power_save_page_flip,
+                  NULL);
   g_list_free_full (renderer_native->power_save_page_flip_onscreens,
                     g_object_unref);
   renderer_native->power_save_page_flip_onscreens = NULL;
@@ -1264,13 +589,10 @@ dummy_power_save_page_flip_cb (gpointer user_data)
   return G_SOURCE_REMOVE;
 }
 
-static void
-queue_dummy_power_save_page_flip (CoglOnscreen *onscreen)
+void
+meta_renderer_native_queue_power_save_page_flip (MetaRendererNative *renderer_native,
+                                                 CoglOnscreen       *onscreen)
 {
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
   const unsigned int timeout_ms = 100;
 
   if (!renderer_native->power_save_page_flip_source_id)
@@ -1287,696 +609,20 @@ queue_dummy_power_save_page_flip (CoglOnscreen *onscreen)
 }
 
 static void
-meta_onscreen_native_flip_crtc (CoglOnscreen                *onscreen,
-                                MetaRendererView            *view,
-                                MetaCrtc                    *crtc,
-                                MetaKmsPageFlipListenerFlag  flags)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
-  MetaGpuKms *render_gpu = onscreen_native->render_gpu;
-  MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc);
-  MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
-  MetaRendererNativeGpuData *renderer_gpu_data;
-  MetaGpuKms *gpu_kms;
-  MetaKmsDevice *kms_device;
-  MetaKms *kms;
-  MetaKmsUpdate *kms_update;
-  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state = NULL;
-  MetaDrmBuffer *buffer;
-
-  COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeFlipCrtcs,
-                           "Onscreen (flip CRTCs)");
-
-  gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
-  kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
-  kms = meta_kms_device_get_kms (kms_device);
-  kms_update = meta_kms_ensure_pending_update (kms, kms_device);
-
-  g_assert (meta_gpu_kms_is_crtc_active (gpu_kms, crtc));
-
-  renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
-                                                         render_gpu);
-  switch (renderer_gpu_data->mode)
-    {
-    case META_RENDERER_NATIVE_MODE_GBM:
-      if (gpu_kms == render_gpu)
-        {
-          buffer = onscreen_native->gbm.next_fb;
-        }
-      else
-        {
-          secondary_gpu_state = onscreen_native->secondary_gpu_state;
-          buffer = secondary_gpu_state->gbm.next_fb;
-        }
-
-      meta_crtc_kms_assign_primary_plane (crtc_kms, buffer, kms_update);
-
-      break;
-#ifdef HAVE_EGL_DEVICE
-    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
-      meta_kms_update_set_custom_page_flip (kms_update,
-                                            custom_egl_stream_page_flip,
-                                            onscreen_native);
-      break;
-#endif
-    }
-
-  meta_kms_update_add_page_flip_listener (kms_update,
-                                          kms_crtc,
-                                          &page_flip_listener_vtable,
-                                          flags,
-                                          g_object_ref (view),
-                                          g_object_unref);
-}
-
-static void
-meta_onscreen_native_set_crtc_mode (CoglOnscreen              *onscreen,
-                                    MetaRendererNativeGpuData *renderer_gpu_data)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
-  MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
-  MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
-  MetaKms *kms = meta_kms_device_get_kms (kms_device);
-  MetaKmsUpdate *kms_update;
-
-  COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeSetCrtcModes,
-                           "Onscreen (set CRTC modes)");
-
-  kms_update = meta_kms_ensure_pending_update (kms, kms_device);
-
-  switch (renderer_gpu_data->mode)
-    {
-    case META_RENDERER_NATIVE_MODE_GBM:
-      break;
-#ifdef HAVE_EGL_DEVICE
-    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
-      {
-        MetaDrmBuffer *buffer;
-
-        buffer = META_DRM_BUFFER (onscreen_native->egl.dumb_fb);
-        meta_crtc_kms_assign_primary_plane (crtc_kms, buffer, kms_update);
-        break;
-      }
-#endif
-    }
-
-  meta_crtc_kms_set_mode (crtc_kms, kms_update);
-  meta_output_kms_set_underscan (META_OUTPUT_KMS (onscreen_native->output),
-                                 kms_update);
-}
-
-static gboolean
-import_shared_framebuffer (CoglOnscreen                        *onscreen,
-                           MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaGpuKms *gpu_kms;
-  MetaKmsDevice *kms_device;
-  struct gbm_device *gbm_device;
-  MetaDrmBufferGbm *buffer_gbm;
-  MetaDrmBufferImport *buffer_import;
-  g_autoptr (GError) error = NULL;
-
-  buffer_gbm = META_DRM_BUFFER_GBM (onscreen_native->gbm.next_fb);
-
-  gpu_kms = secondary_gpu_state->gpu_kms;
-  kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
-  gbm_device = meta_gbm_device_from_gpu (gpu_kms);
-  buffer_import = meta_drm_buffer_import_new (kms_device,
-                                              gbm_device,
-                                              buffer_gbm,
-                                              &error);
-  if (!buffer_import)
-    {
-      g_debug ("Zero-copy disabled for %s, meta_drm_buffer_import_new failed: %s",
-               meta_gpu_kms_get_file_path (secondary_gpu_state->gpu_kms),
-               error->message);
-
-      g_warn_if_fail (secondary_gpu_state->import_status ==
-                      META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE);
-
-      /*
-       * Fall back. If META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE is
-       * in effect, we have COPY_MODE_PRIMARY prepared already, so we
-       * simply retry with that path. Import status cannot be FAILED,
-       * because we should not retry if failed once.
-       *
-       * If import status is OK, that is unexpected and we do not
-       * have the fallback path prepared which means this output cannot
-       * work anymore.
-       */
-      secondary_gpu_state->renderer_gpu_data->secondary.copy_mode =
-        META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY;
-
-      secondary_gpu_state->import_status =
-        META_SHARED_FRAMEBUFFER_IMPORT_STATUS_FAILED;
-      return FALSE;
-    }
-
-  /*
-   * next_fb may already contain a fallback buffer, so clear it only
-   * when we are sure to succeed.
-   */
-  g_clear_object (&secondary_gpu_state->gbm.next_fb);
-  secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_import);
-
-  if (secondary_gpu_state->import_status ==
-      META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE)
-    {
-      /*
-       * Clean up the cpu-copy part of
-       * init_secondary_gpu_state_cpu_copy_mode ()
-       */
-      secondary_gpu_release_dumb (secondary_gpu_state);
-
-      g_debug ("Using zero-copy for %s succeeded once.",
-               meta_gpu_kms_get_file_path (secondary_gpu_state->gpu_kms));
-    }
-
-  secondary_gpu_state->import_status =
-    META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK;
-  return TRUE;
-}
-
-static void
-copy_shared_framebuffer_gpu (CoglOnscreen                        *onscreen,
-                             MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
-                             MetaRendererNativeGpuData           *renderer_gpu_data,
-                             gboolean                            *egl_context_changed)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
-  MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
-  GError *error = NULL;
-  MetaKmsDevice *kms_device;
-  MetaDrmBufferGbm *buffer_gbm;
-  struct gbm_bo *bo;
-
-  COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferSecondaryGpu,
-                           "FB Copy (secondary GPU)");
-
-  g_warn_if_fail (secondary_gpu_state->gbm.next_fb == NULL);
-  g_clear_object (&secondary_gpu_state->gbm.next_fb);
-
-  if (!meta_egl_make_current (egl,
-                              renderer_gpu_data->egl_display,
-                              secondary_gpu_state->egl_surface,
-                              secondary_gpu_state->egl_surface,
-                              renderer_gpu_data->secondary.egl_context,
-                              &error))
-    {
-      g_warning ("Failed to make current: %s", error->message);
-      g_error_free (error);
-      return;
-    }
-
-  *egl_context_changed = TRUE;
-
-  buffer_gbm = META_DRM_BUFFER_GBM (onscreen_native->gbm.next_fb);
-  bo =  meta_drm_buffer_gbm_get_bo (buffer_gbm);
-  if (!meta_renderer_native_gles3_blit_shared_bo (egl,
-                                                  renderer_native->gles3,
-                                                  renderer_gpu_data->egl_display,
-                                                  renderer_gpu_data->secondary.egl_context,
-                                                  secondary_gpu_state->egl_surface,
-                                                  bo,
-                                                  &error))
-    {
-      g_warning ("Failed to blit shared framebuffer: %s", error->message);
-      g_error_free (error);
-      return;
-    }
-
-  if (!meta_egl_swap_buffers (egl,
-                              renderer_gpu_data->egl_display,
-                              secondary_gpu_state->egl_surface,
-                              &error))
-    {
-      g_warning ("Failed to swap buffers: %s", error->message);
-      g_error_free (error);
-      return;
-    }
-
-  kms_device = meta_gpu_kms_get_kms_device (secondary_gpu_state->gpu_kms);
-  buffer_gbm =
-    meta_drm_buffer_gbm_new_lock_front (kms_device,
-                                        secondary_gpu_state->gbm.surface,
-                                        renderer_native->use_modifiers,
-                                        &error);
-  if (!buffer_gbm)
-    {
-      g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s",
-                 error->message);
-      g_error_free (error);
-      return;
-    }
-
-  secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_gbm);
-}
-
-static MetaDrmBufferDumb *
-secondary_gpu_get_next_dumb_buffer (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
+clear_kept_alive_onscreens (MetaRendererNative *renderer_native)
 {
-  MetaDrmBufferDumb *current_dumb_fb;
-
-  current_dumb_fb = secondary_gpu_state->cpu.current_dumb_fb;
-  if (current_dumb_fb == secondary_gpu_state->cpu.dumb_fbs[0])
-    return secondary_gpu_state->cpu.dumb_fbs[1];
-  else
-    return secondary_gpu_state->cpu.dumb_fbs[0];
+  g_list_free_full (renderer_native->kept_alive_onscreens,
+                    g_object_unref);
+  renderer_native->kept_alive_onscreens = NULL;
 }
 
-static CoglContext *
-cogl_context_from_renderer_native (MetaRendererNative *renderer_native)
+void
+meta_renderer_native_post_mode_set_updates (MetaRendererNative *renderer_native)
 {
   MetaRenderer *renderer = META_RENDERER (renderer_native);
   MetaBackend *backend = meta_renderer_get_backend (renderer);
-  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
-
-  return clutter_backend_get_cogl_context (clutter_backend);
-}
-
-static CoglFramebuffer *
-create_dma_buf_framebuffer (MetaRendererNative  *renderer_native,
-                            int                  dmabuf_fd,
-                            uint32_t             width,
-                            uint32_t             height,
-                            uint32_t             stride,
-                            uint32_t             offset,
-                            uint64_t             modifier,
-                            uint32_t             drm_format,
-                            GError             **error)
-{
-  CoglContext *cogl_context =
-    cogl_context_from_renderer_native (renderer_native);
-  CoglDisplay *cogl_display = cogl_context->display;
-  CoglRenderer *cogl_renderer = cogl_display->renderer;
-  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
-  EGLDisplay egl_display = cogl_renderer_egl->edpy;
-  MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
-  EGLImageKHR egl_image;
-  uint32_t strides[1];
-  uint32_t offsets[1];
-  uint64_t modifiers[1];
-  CoglPixelFormat cogl_format;
-  CoglEglImageFlags flags;
-  CoglTexture2D *cogl_tex;
-  CoglOffscreen *cogl_fbo;
-  int ret;
-
-  ret = meta_cogl_pixel_format_from_drm_format (drm_format,
-                                                &cogl_format,
-                                                NULL);
-  g_assert (ret);
-
-  strides[0] = stride;
-  offsets[0] = offset;
-  modifiers[0] = modifier;
-  egl_image = meta_egl_create_dmabuf_image (egl,
-                                            egl_display,
-                                            width,
-                                            height,
-                                            drm_format,
-                                            1 /* n_planes */,
-                                            &dmabuf_fd,
-                                            strides,
-                                            offsets,
-                                            modifiers,
-                                            error);
-  if (egl_image == EGL_NO_IMAGE_KHR)
-    return NULL;
-
-  flags = COGL_EGL_IMAGE_FLAG_NO_GET_DATA;
-  cogl_tex = cogl_egl_texture_2d_new_from_image (cogl_context,
-                                                 width,
-                                                 height,
-                                                 cogl_format,
-                                                 egl_image,
-                                                 flags,
-                                                 error);
-
-  meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
-
-  if (!cogl_tex)
-    return NULL;
-
-  cogl_fbo = cogl_offscreen_new_with_texture (COGL_TEXTURE (cogl_tex));
-  cogl_object_unref (cogl_tex);
-
-  if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (cogl_fbo), error))
-    {
-      g_object_unref (cogl_fbo);
-      return NULL;
-    }
-
-  return COGL_FRAMEBUFFER (cogl_fbo);
-}
-
-static gboolean
-copy_shared_framebuffer_primary_gpu (CoglOnscreen                        *onscreen,
-                                     MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
-  MetaRendererNativeGpuData *primary_gpu_data;
-  MetaDrmBufferDumb *buffer_dumb;
-  MetaDrmBuffer *buffer;
-  int width, height, stride;
-  uint32_t drm_format;
-  CoglFramebuffer *dmabuf_fb;
-  int dmabuf_fd;
-  g_autoptr (GError) error = NULL;
-  CoglPixelFormat cogl_format;
-  int ret;
-
-  COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferPrimaryGpu,
-                           "FB Copy (primary GPU)");
-
-  primary_gpu_data =
-    meta_renderer_native_get_gpu_data (renderer_native,
-                                       renderer_native->primary_gpu_kms);
-  if (!primary_gpu_data->secondary.has_EGL_EXT_image_dma_buf_import_modifiers)
-    return FALSE;
-
-  buffer_dumb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state);
-  buffer = META_DRM_BUFFER (buffer_dumb);
-
-  width = meta_drm_buffer_get_width (buffer);
-  height = meta_drm_buffer_get_height (buffer);
-  stride = meta_drm_buffer_get_stride (buffer);
-  drm_format = meta_drm_buffer_get_format (buffer);
-
-  g_assert (cogl_framebuffer_get_width (framebuffer) == width);
-  g_assert (cogl_framebuffer_get_height (framebuffer) == height);
-
-  ret = meta_cogl_pixel_format_from_drm_format (drm_format,
-                                                &cogl_format,
-                                                NULL);
-  g_assert (ret);
-
-  dmabuf_fd = meta_drm_buffer_dumb_ensure_dmabuf_fd (buffer_dumb, &error);
-  if (!dmabuf_fd)
-    {
-      g_debug ("Failed to create DMA buffer: %s", error->message);
-      return FALSE;
-    }
-
-  dmabuf_fb = create_dma_buf_framebuffer (renderer_native,
-                                          dmabuf_fd,
-                                          width,
-                                          height,
-                                          stride,
-                                          0, DRM_FORMAT_MOD_LINEAR,
-                                          drm_format,
-                                          &error);
-
-  if (error)
-    {
-      g_debug ("%s: Failed to blit DMA buffer image: %s",
-               G_STRFUNC, error->message);
-      return FALSE;
-    }
-
-  if (!cogl_blit_framebuffer (framebuffer, COGL_FRAMEBUFFER (dmabuf_fb),
-                              0, 0, 0, 0,
-                              width, height,
-                              &error))
-    {
-      g_object_unref (dmabuf_fb);
-      return FALSE;
-    }
-
-  g_object_unref (dmabuf_fb);
-
-  g_clear_object (&secondary_gpu_state->gbm.next_fb);
-  secondary_gpu_state->gbm.next_fb = buffer;
-  secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb;
-
-  return TRUE;
-}
-
-static void
-copy_shared_framebuffer_cpu (CoglOnscreen                        *onscreen,
-                             MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
-                             MetaRendererNativeGpuData           *renderer_gpu_data)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
-  MetaDrmBufferDumb *buffer_dumb;
-  MetaDrmBuffer *buffer;
-  int width, height, stride;
-  uint32_t drm_format;
-  void *buffer_data;
-  CoglBitmap *dumb_bitmap;
-  CoglPixelFormat cogl_format;
-  gboolean ret;
-
-  COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferCpu,
-                           "FB Copy (CPU)");
-
-  buffer_dumb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state);
-  buffer = META_DRM_BUFFER (buffer_dumb);
-
-  width = meta_drm_buffer_get_width (buffer);
-  height = meta_drm_buffer_get_height (buffer);
-  stride = meta_drm_buffer_get_stride (buffer);
-  drm_format = meta_drm_buffer_get_format (buffer);
-  buffer_data = meta_drm_buffer_dumb_get_data (buffer_dumb);
-
-  g_assert (cogl_framebuffer_get_width (framebuffer) == width);
-  g_assert (cogl_framebuffer_get_height (framebuffer) == height);
-
-  ret = meta_cogl_pixel_format_from_drm_format (drm_format,
-                                                &cogl_format,
-                                                NULL);
-  g_assert (ret);
-
-  dumb_bitmap = cogl_bitmap_new_for_data (cogl_context,
-                                          width,
-                                          height,
-                                          cogl_format,
-                                          stride,
-                                          buffer_data);
-
-  if (!cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
-                                                 0 /* x */,
-                                                 0 /* y */,
-                                                 COGL_READ_PIXELS_COLOR_BUFFER,
-                                                 dumb_bitmap))
-    g_warning ("Failed to CPU-copy to a secondary GPU output");
-
-  cogl_object_unref (dumb_bitmap);
-
-  g_clear_object (&secondary_gpu_state->gbm.next_fb);
-  secondary_gpu_state->gbm.next_fb = buffer;
-  secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb;
-}
-
-static void
-update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
-
-  COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeGpuStatePreSwapBuffers,
-                           "Onscreen (secondary gpu pre-swap-buffers)");
-
-  secondary_gpu_state = onscreen_native->secondary_gpu_state;
-  if (secondary_gpu_state)
-    {
-      MetaRendererNativeGpuData *renderer_gpu_data;
-
-      renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
-      switch (renderer_gpu_data->secondary.copy_mode)
-        {
-        case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
-          /* Done after eglSwapBuffers. */
-          break;
-        case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO:
-          /* Done after eglSwapBuffers. */
-          if (secondary_gpu_state->import_status ==
-              META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK)
-            break;
-          /* prepare fallback */
-          G_GNUC_FALLTHROUGH;
-        case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
-          if (!copy_shared_framebuffer_primary_gpu (onscreen,
-                                                    secondary_gpu_state))
-            {
-              if (!secondary_gpu_state->noted_primary_gpu_copy_failed)
-                {
-                  g_debug ("Using primary GPU to copy for %s failed once.",
-                           meta_gpu_kms_get_file_path (secondary_gpu_state->gpu_kms));
-                  secondary_gpu_state->noted_primary_gpu_copy_failed = TRUE;
-                }
-
-              copy_shared_framebuffer_cpu (onscreen,
-                                           secondary_gpu_state,
-                                           renderer_gpu_data);
-            }
-          else if (!secondary_gpu_state->noted_primary_gpu_copy_ok)
-            {
-              g_debug ("Using primary GPU to copy for %s succeeded once.",
-                       meta_gpu_kms_get_file_path (secondary_gpu_state->gpu_kms));
-              secondary_gpu_state->noted_primary_gpu_copy_ok = TRUE;
-            }
-          break;
-        }
-    }
-}
-
-static void
-update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen,
-                                              gboolean     *egl_context_changed)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
-  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
-
-  COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeGpuStatePostSwapBuffers,
-                           "Onscreen (secondary gpu post-swap-buffers)");
-
-  secondary_gpu_state = onscreen_native->secondary_gpu_state;
-  if (secondary_gpu_state)
-    {
-      MetaRendererNativeGpuData *renderer_gpu_data;
-
-      renderer_gpu_data =
-        meta_renderer_native_get_gpu_data (renderer_native,
-                                           secondary_gpu_state->gpu_kms);
-retry:
-      switch (renderer_gpu_data->secondary.copy_mode)
-        {
-        case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO:
-          if (!import_shared_framebuffer (onscreen,
-                                          secondary_gpu_state))
-            goto retry;
-          break;
-        case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
-          copy_shared_framebuffer_gpu (onscreen,
-                                       secondary_gpu_state,
-                                       renderer_gpu_data,
-                                       egl_context_changed);
-          break;
-        case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
-          /* Done before eglSwapBuffers. */
-          break;
-        }
-    }
-}
-
-static void
-ensure_crtc_modes (CoglOnscreen *onscreen)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
-  CoglRenderer *cogl_renderer = cogl_context->display->renderer;
-  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
-  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
-  MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
-  MetaRenderer *renderer = META_RENDERER (renderer_native);
-  MetaBackend *backend = meta_renderer_get_backend (renderer);
-  MetaMonitorManager *monitor_manager =
-    meta_backend_get_monitor_manager (backend);
-  MetaPowerSave power_save_mode;
-  GList *link;
-
-  power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
-  link = g_list_find (renderer_native->pending_mode_set_views,
-                      onscreen_native->view);
-  if (link && power_save_mode == META_POWER_SAVE_ON)
-    {
-      meta_onscreen_native_set_crtc_mode (onscreen, renderer_gpu_data);
-      renderer_native->pending_mode_set_views =
-        g_list_delete_link (renderer_native->pending_mode_set_views, link);
-    }
-}
-
-static MetaKmsDevice *
-kms_device_from_view (MetaRendererView *view)
-{
-  CoglFramebuffer *framebuffer =
-    clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
-  CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
-  MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
-
-  return meta_kms_crtc_get_device (kms_crtc);
-}
-
-static MetaGpu *
-gpu_from_view (MetaRendererView *view)
-{
-  CoglFramebuffer *framebuffer =
-    clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
-  CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-
-  return meta_crtc_get_gpu (onscreen_native->crtc);
-}
-
-static void
-configure_disabled_crtcs (MetaGpu       *gpu,
-                          MetaKmsUpdate *kms_update)
-{
-  GList *l;
-
-  for (l = meta_gpu_get_crtcs (gpu); l; l = l->next)
-    {
-      MetaCrtc *crtc = l->data;
-      MetaKmsCrtc *kms_crtc;
-
-      if (meta_crtc_get_config (crtc))
-        continue;
-
-      kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
-      if (!meta_kms_crtc_is_active (kms_crtc))
-        continue;
-
-      meta_kms_update_mode_set (kms_update, kms_crtc, NULL, NULL);
-    }
-}
-
-static void
-clear_kept_alive_onscreens (MetaRendererNative *renderer_native)
-{
-  g_list_free_full (renderer_native->kept_alive_onscreens,
-                    g_object_unref);
-  renderer_native->kept_alive_onscreens = NULL;
-}
-
-static void
-meta_renderer_native_post_mode_set_updates (MetaRendererNative *renderer_native)
-{
-  MetaRenderer *renderer = META_RENDERER (renderer_native);
-  MetaBackend *backend = meta_renderer_get_backend (renderer);
-  MetaKms *kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend));
-  GList *l;
+  MetaKms *kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend));
+  GList *l;
 
   for (l = meta_renderer_get_views (renderer); l; l = l->next)
     {
@@ -1987,916 +633,192 @@ meta_renderer_native_post_mode_set_updates (MetaRendererNative *renderer_native)
       g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
       const GError *feedback_error;
 
-      kms_device = kms_device_from_view (view);
-
-      kms_update = meta_kms_get_pending_update (kms, kms_device);
-      if (!kms_update)
-        continue;
-
-      configure_disabled_crtcs (gpu_from_view (view), kms_update);
-
-      flags = META_KMS_UPDATE_FLAG_NONE;
-      kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
-
-      switch (meta_kms_feedback_get_result (kms_feedback))
-        {
-        case META_KMS_FEEDBACK_PASSED:
-          break;
-        case META_KMS_FEEDBACK_FAILED:
-          feedback_error = meta_kms_feedback_get_error (kms_feedback);
-          if (!g_error_matches (feedback_error,
-                                G_IO_ERROR,
-                                G_IO_ERROR_PERMISSION_DENIED))
-            g_warning ("Failed to post KMS update: %s", feedback_error->message);
-          break;
-        }
-    }
-
-  clear_kept_alive_onscreens (renderer_native);
-}
-
-static void
-unset_disabled_crtcs (MetaBackend *backend,
-                      MetaKms     *kms)
-{
-  GList *l;
-
-  meta_topic (META_DEBUG_KMS, "Disabling all disabled CRTCs");
-
-  for (l = meta_backend_get_gpus (backend); l; l = l->next)
-    {
-      MetaGpu *gpu = l->data;
-      MetaKmsDevice *kms_device =
-        meta_gpu_kms_get_kms_device (META_GPU_KMS (gpu));
-      GList *k;
-      gboolean did_mode_set = FALSE;
-      MetaKmsUpdateFlag flags;
-      g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
-
-      for (k = meta_gpu_get_crtcs (gpu); k; k = k->next)
-        {
-          MetaCrtc *crtc = k->data;
-          MetaKmsUpdate *kms_update;
-
-          if (meta_crtc_get_config (crtc))
-            continue;
-
-          kms_update = meta_kms_ensure_pending_update (kms, kms_device);
-          meta_crtc_kms_set_mode (META_CRTC_KMS (crtc), kms_update);
-
-          did_mode_set = TRUE;
-        }
-
-      if (!did_mode_set)
-        continue;
-
-      flags = META_KMS_UPDATE_FLAG_NONE;
-      kms_feedback = meta_kms_post_pending_update_sync (kms,
-                                                        kms_device,
-                                                        flags);
-      if (meta_kms_feedback_get_result (kms_feedback) !=
-          META_KMS_FEEDBACK_PASSED)
-        {
-          const GError *error = meta_kms_feedback_get_error (kms_feedback);
-
-          if (!g_error_matches (error, G_IO_ERROR,
-                                G_IO_ERROR_PERMISSION_DENIED))
-            g_warning ("Failed to post KMS update: %s", error->message);
-        }
-    }
-}
-
-static void
-meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen  *onscreen,
-                                               const int     *rectangles,
-                                               int            n_rectangles,
-                                               CoglFrameInfo *frame_info,
-                                               gpointer       user_data)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
-  CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
-  CoglRenderer *cogl_renderer = cogl_context->display->renderer;
-  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
-  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
-  MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
-  MetaRenderer *renderer = META_RENDERER (renderer_native);
-  MetaBackend *backend = meta_renderer_get_backend (renderer);
-  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
-  MetaMonitorManager *monitor_manager =
-    meta_backend_get_monitor_manager (backend);
-  MetaKms *kms = meta_backend_native_get_kms (backend_native);
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaGpuKms *render_gpu = onscreen_native->render_gpu;
-  MetaKmsDevice *render_kms_device = meta_gpu_kms_get_kms_device (render_gpu);
-  ClutterFrame *frame = user_data;
-  gboolean egl_context_changed = FALSE;
-  MetaPowerSave power_save_mode;
-  g_autoptr (GError) error = NULL;
-  MetaDrmBufferGbm *buffer_gbm;
-  MetaKmsCrtc *kms_crtc;
-  MetaKmsDevice *kms_device;
-  MetaKmsUpdateFlag flags;
-  g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
-  const GError *feedback_error;
-
-  COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers,
-                           "Onscreen (swap-buffers)");
-
-  update_secondary_gpu_state_pre_swap_buffers (onscreen);
-
-  parent_vtable->onscreen_swap_buffers_with_damage (onscreen,
-                                                    rectangles,
-                                                    n_rectangles,
-                                                    frame_info,
-                                                    user_data);
-
-  renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
-                                                         render_gpu);
-  switch (renderer_gpu_data->mode)
-    {
-    case META_RENDERER_NATIVE_MODE_GBM:
-      g_warn_if_fail (onscreen_native->gbm.next_fb == NULL);
-      g_clear_object (&onscreen_native->gbm.next_fb);
-
-      buffer_gbm =
-        meta_drm_buffer_gbm_new_lock_front (render_kms_device,
-                                            onscreen_native->gbm.surface,
-                                            renderer_native->use_modifiers,
-                                            &error);
-      if (!buffer_gbm)
-        {
-          g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s",
-                     error->message);
-          return;
-        }
-
-      onscreen_native->gbm.next_fb = META_DRM_BUFFER (buffer_gbm);
-
-      break;
-#ifdef HAVE_EGL_DEVICE
-    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
-      break;
-#endif
-    }
-
-  update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed);
-
-  power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
-  if (power_save_mode == META_POWER_SAVE_ON)
-    {
-      ensure_crtc_modes (onscreen);
-      meta_onscreen_native_flip_crtc (onscreen,
-                                      onscreen_native->view,
-                                      onscreen_native->crtc,
-                                      META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE);
-    }
-  else
-    {
-      queue_dummy_power_save_page_flip (onscreen);
-      clutter_frame_set_result (frame,
-                                CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
-      return;
-    }
-
-  /*
-   * If we changed EGL context, cogl will have the wrong idea about what is
-   * current, making it fail to set it when it needs to. Avoid that by making
-   * EGL_NO_CONTEXT current now, making cogl eventually set the correct
-   * context.
-   */
-  if (egl_context_changed)
-    _cogl_winsys_egl_ensure_current (cogl_display);
-
-  COGL_TRACE_BEGIN_SCOPED (MetaRendererNativePostKmsUpdate,
-                           "Onscreen (post pending update)");
-  kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
-  kms_device = meta_kms_crtc_get_device (kms_crtc);
-
-  switch (renderer_gpu_data->mode)
-    {
-    case META_RENDERER_NATIVE_MODE_GBM:
-      if (renderer_native->pending_mode_set_views)
-        {
-          meta_topic (META_DEBUG_KMS,
-                      "Postponing primary plane composite update for CRTC %u (%s)",
-                      meta_kms_crtc_get_id (kms_crtc),
-                      meta_kms_device_get_path (kms_device));
-
-          clutter_frame_set_result (frame,
-                                    CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
-          return;
-        }
-      else if (renderer_native->pending_mode_set)
-        {
-          meta_topic (META_DEBUG_KMS, "Posting global mode set updates on %s",
-                      meta_kms_device_get_path (kms_device));
-
-          renderer_native->pending_mode_set = FALSE;
-          meta_renderer_native_post_mode_set_updates (renderer_native);
-          clutter_frame_set_result (frame,
-                                    CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
-          return;
-        }
-      break;
-#ifdef HAVE_EGL_DEVICE
-    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
-      if (renderer_native->pending_mode_set)
-        {
-          renderer_native->pending_mode_set = FALSE;
-          meta_renderer_native_post_mode_set_updates (renderer_native);
-          clutter_frame_set_result (frame,
-                                    CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
-         return;
-        }
-      break;
-#endif
-    }
-
-  meta_topic (META_DEBUG_KMS,
-              "Posting primary plane composite update for CRTC %u (%s)",
-              meta_kms_crtc_get_id (kms_crtc),
-              meta_kms_device_get_path (kms_device));
-
-  flags = META_KMS_UPDATE_FLAG_NONE;
-  kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
-
-  switch (meta_kms_feedback_get_result (kms_feedback))
-    {
-    case META_KMS_FEEDBACK_PASSED:
-      clutter_frame_set_result (frame,
-                                CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
-      break;
-    case META_KMS_FEEDBACK_FAILED:
-      clutter_frame_set_result (frame,
-                                CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
-
-      feedback_error = meta_kms_feedback_get_error (kms_feedback);
-      if (!g_error_matches (feedback_error,
-                            G_IO_ERROR,
-                            G_IO_ERROR_PERMISSION_DENIED))
-        g_warning ("Failed to post KMS update: %s", feedback_error->message);
-      break;
-    }
-}
-
-static CoglDmaBufHandle *
-meta_renderer_native_create_dma_buf (CoglRenderer  *cogl_renderer,
-                                     int            width,
-                                     int            height,
-                                     GError       **error)
-{
-  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
-  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
-  MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
-
-  switch (renderer_gpu_data->mode)
-    {
-    case META_RENDERER_NATIVE_MODE_GBM:
-      {
-        CoglFramebuffer *dmabuf_fb;
-        CoglDmaBufHandle *dmabuf_handle;
-        struct gbm_bo *new_bo;
-        int stride;
-        int offset;
-        int bpp;
-        int dmabuf_fd = -1;
-
-        new_bo = gbm_bo_create (renderer_gpu_data->gbm.device,
-                                width, height, DRM_FORMAT_XRGB8888,
-                                GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR);
-
-        if (!new_bo)
-          {
-            g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                         "Failed to allocate buffer");
-            return NULL;
-          }
-
-        dmabuf_fd = gbm_bo_get_fd (new_bo);
-
-        if (dmabuf_fd == -1)
-          {
-            g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
-                         "Failed to export buffer's DMA fd: %s",
-                         g_strerror (errno));
-            return NULL;
-          }
-
-        stride = gbm_bo_get_stride (new_bo);
-        offset = gbm_bo_get_offset (new_bo, 0);
-        bpp = 4;
-        dmabuf_fb = create_dma_buf_framebuffer (renderer_native,
-                                                dmabuf_fd,
-                                                width, height,
-                                                stride,
-                                                offset,
-                                                DRM_FORMAT_MOD_LINEAR,
-                                                DRM_FORMAT_XRGB8888,
-                                                error);
-
-        if (!dmabuf_fb)
-          return NULL;
-
-        dmabuf_handle =
-          cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd,
-                                   width, height, stride, offset, bpp,
-                                   new_bo,
-                                   (GDestroyNotify) gbm_bo_destroy);
-        g_object_unref (dmabuf_fb);
-        return dmabuf_handle;
-      }
-      break;
-#ifdef HAVE_EGL_DEVICE
-    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
-      break;
-#endif
-    }
-
-  g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN,
-               "Current mode does not support exporting DMA buffers");
-
-  return NULL;
-}
-
-gboolean
-meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen,
-                                                   uint32_t      drm_format,
-                                                   uint64_t      drm_modifier,
-                                                   uint32_t      stride)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  const MetaCrtcConfig *crtc_config;
-  MetaDrmBuffer *fb;
-  struct gbm_bo *gbm_bo;
-
-  crtc_config = meta_crtc_get_config (onscreen_native->crtc);
-  if (crtc_config->transform != META_MONITOR_TRANSFORM_NORMAL)
-    return FALSE;
-
-  if (onscreen_native->secondary_gpu_state)
-    return FALSE;
-
-  if (!onscreen_native->gbm.surface)
-    return FALSE;
-
-  fb = onscreen_native->gbm.current_fb ? onscreen_native->gbm.current_fb
-                                       : onscreen_native->gbm.next_fb;
-  if (!fb)
-    return FALSE;
-
-  if (!META_IS_DRM_BUFFER_GBM (fb))
-    return FALSE;
-
-  gbm_bo = meta_drm_buffer_gbm_get_bo (META_DRM_BUFFER_GBM (fb));
-
-  if (gbm_bo_get_format (gbm_bo) != drm_format)
-    return FALSE;
-
-  if (gbm_bo_get_modifier (gbm_bo) != drm_modifier)
-    return FALSE;
-
-  if (gbm_bo_get_stride (gbm_bo) != stride)
-    return FALSE;
-
-  return TRUE;
-}
-
-static gboolean
-meta_onscreen_native_direct_scanout (CoglOnscreen   *onscreen,
-                                     CoglScanout    *scanout,
-                                     CoglFrameInfo  *frame_info,
-                                     gpointer        user_data,
-                                     GError        **error)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaGpuKms *render_gpu = onscreen_native->render_gpu;
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
-  CoglRenderer *cogl_renderer = cogl_context->display->renderer;
-  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
-  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
-  MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
-  MetaRenderer *renderer = META_RENDERER (renderer_native);
-  MetaBackend *backend = meta_renderer_get_backend (renderer);
-  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
-  MetaKms *kms = meta_backend_native_get_kms (backend_native);
-  MetaMonitorManager *monitor_manager =
-    meta_backend_get_monitor_manager (backend);
-  MetaPowerSave power_save_mode;
-  ClutterFrame *frame = user_data;
-  MetaKmsCrtc *kms_crtc;
-  MetaKmsDevice *kms_device;
-  MetaKmsUpdateFlag flags;
-  g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
-  const GError *feedback_error;
-
-  power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
-  if (power_save_mode != META_POWER_SAVE_ON)
-    {
-      g_set_error_literal (error,
-                           COGL_SCANOUT_ERROR,
-                           COGL_SCANOUT_ERROR_INHIBITED,
-                           NULL);
-      return FALSE;
-    }
-
-  if (renderer_native->pending_mode_set_views)
-    {
-      g_set_error_literal (error,
-                           COGL_SCANOUT_ERROR,
-                           COGL_SCANOUT_ERROR_INHIBITED,
-                           NULL);
-      return FALSE;
-    }
-
-  renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
-                                                         render_gpu);
-
-  g_warn_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM);
-  g_warn_if_fail (!onscreen_native->gbm.next_fb);
-
-  g_set_object (&onscreen_native->gbm.next_fb, META_DRM_BUFFER (scanout));
-
-  ensure_crtc_modes (onscreen);
-  meta_onscreen_native_flip_crtc (onscreen,
-                                  onscreen_native->view,
-                                  onscreen_native->crtc,
-                                  META_KMS_PAGE_FLIP_LISTENER_FLAG_NO_DISCARD);
-
-  kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
-  kms_device = meta_kms_crtc_get_device (kms_crtc);
-
-  meta_topic (META_DEBUG_KMS,
-              "Posting direct scanout update for CRTC %u (%s)",
-              meta_kms_crtc_get_id (kms_crtc),
-              meta_kms_device_get_path (kms_device));
-
-  flags = META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR;
-  kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
-  switch (meta_kms_feedback_get_result (kms_feedback))
-    {
-    case META_KMS_FEEDBACK_PASSED:
-      clutter_frame_set_result (frame,
-                                CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
-      break;
-    case META_KMS_FEEDBACK_FAILED:
-      feedback_error = meta_kms_feedback_get_error (kms_feedback);
-
-      if (g_error_matches (feedback_error,
-                           G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
-        break;
-
-      g_clear_object (&onscreen_native->gbm.next_fb);
-      g_propagate_error (error, g_error_copy (feedback_error));
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-static gboolean
-meta_renderer_native_init_egl_context (CoglContext *cogl_context,
-                                       GError     **error)
-{
-#ifdef HAVE_EGL_DEVICE
-  CoglRenderer *cogl_renderer = cogl_context->display->renderer;
-  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
-  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
-#endif
-
-  COGL_FLAGS_SET (cogl_context->winsys_features,
-                  COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT,
-                  TRUE);
-  COGL_FLAGS_SET (cogl_context->winsys_features,
-                  COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT,
-                  TRUE);
-  COGL_FLAGS_SET (cogl_context->winsys_features,
-                  COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
-                  TRUE);
-
-#ifdef HAVE_EGL_DEVICE
-  if (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_EGL_DEVICE)
-    COGL_FLAGS_SET (cogl_context->features,
-                    COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL, TRUE);
-#endif
-
-  return TRUE;
-}
-
-static gboolean
-should_surface_be_sharable (CoglOnscreen *onscreen)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-
-  if (META_GPU_KMS (meta_crtc_get_gpu (onscreen_native->crtc)) ==
-      onscreen_native->render_gpu)
-    return FALSE;
-  else
-    return TRUE;
-}
-
-static gboolean
-meta_renderer_native_create_surface_gbm (CoglOnscreen        *onscreen,
-                                         int                  width,
-                                         int                  height,
-                                         struct gbm_surface **gbm_surface,
-                                         EGLSurface          *egl_surface,
-                                         GError             **error)
-{
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
-  MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
-  CoglDisplay *cogl_display = cogl_context->display;
-  CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
-  CoglRenderer *cogl_renderer = cogl_display->renderer;
-  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
-  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
-  struct gbm_surface *new_gbm_surface = NULL;
-  EGLNativeWindowType egl_native_window;
-  EGLSurface new_egl_surface;
-  uint32_t format;
-  GArray *modifiers;
-
-  renderer_gpu_data =
-    meta_renderer_native_get_gpu_data (renderer_native,
-                                       onscreen_native->render_gpu);
-
-  format = get_gbm_format_from_egl (egl,
-                                    cogl_renderer_egl->edpy,
-                                    cogl_display_egl->egl_config);
-
-  if (renderer_native->use_modifiers)
-    modifiers = get_supported_modifiers (onscreen, format);
-  else
-    modifiers = NULL;
-
-  if (modifiers)
-    {
-      new_gbm_surface =
-        gbm_surface_create_with_modifiers (renderer_gpu_data->gbm.device,
-                                           width, height, format,
-                                           (uint64_t *) modifiers->data,
-                                           modifiers->len);
-      g_array_free (modifiers, TRUE);
-    }
-
-  if (!new_gbm_surface)
-    {
-      uint32_t flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
-
-      if (should_surface_be_sharable (onscreen))
-        flags |= GBM_BO_USE_LINEAR;
-
-      new_gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device,
-                                            width, height,
-                                            format,
-                                            flags);
-    }
-
-  if (!new_gbm_surface)
-    {
-      g_set_error (error, COGL_WINSYS_ERROR,
-                   COGL_WINSYS_ERROR_CREATE_ONSCREEN,
-                   "Failed to allocate surface");
-      return FALSE;
-    }
-
-  egl_native_window = (EGLNativeWindowType) new_gbm_surface;
-  new_egl_surface =
-    meta_egl_create_window_surface (egl,
-                                    cogl_renderer_egl->edpy,
-                                    cogl_display_egl->egl_config,
-                                    egl_native_window,
-                                    NULL,
-                                    error);
-  if (new_egl_surface == EGL_NO_SURFACE)
-    {
-      gbm_surface_destroy (new_gbm_surface);
-      return FALSE;
-    }
-
-  *gbm_surface = new_gbm_surface;
-  *egl_surface = new_egl_surface;
-
-  return TRUE;
-}
-
-#ifdef HAVE_EGL_DEVICE
-static gboolean
-meta_renderer_native_create_surface_egl_device (CoglOnscreen  *onscreen,
-                                                int            width,
-                                                int            height,
-                                                EGLStreamKHR  *out_egl_stream,
-                                                EGLSurface    *out_egl_surface,
-                                                GError       **error)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
-  CoglDisplay *cogl_display = cogl_context->display;
-  CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
-  CoglRenderer *cogl_renderer = cogl_display->renderer;
-  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
-  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
-  MetaEgl *egl =
-    meta_renderer_native_get_egl (renderer_gpu_data->renderer_native);
-  EGLDisplay egl_display = renderer_gpu_data->egl_display;
-  EGLConfig egl_config;
-  EGLStreamKHR egl_stream;
-  EGLSurface egl_surface;
-  EGLint num_layers;
-  EGLOutputLayerEXT output_layer;
-  EGLAttrib output_attribs[3];
-  EGLint stream_attribs[] = {
-    EGL_STREAM_FIFO_LENGTH_KHR, 0,
-    EGL_CONSUMER_AUTO_ACQUIRE_EXT, EGL_FALSE,
-    EGL_NONE
-  };
-  EGLint stream_producer_attribs[] = {
-    EGL_WIDTH, width,
-    EGL_HEIGHT, height,
-    EGL_NONE
-  };
-
-  egl_stream = meta_egl_create_stream (egl, egl_display, stream_attribs, error);
-  if (egl_stream == EGL_NO_STREAM_KHR)
-    return FALSE;
-
-  output_attribs[0] = EGL_DRM_CRTC_EXT;
-  output_attribs[1] = meta_crtc_get_id (onscreen_native->crtc);
-  output_attribs[2] = EGL_NONE;
-
-  if (!meta_egl_get_output_layers (egl, egl_display,
-                                   output_attribs,
-                                   &output_layer, 1, &num_layers,
-                                   error))
-    {
-      meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
-      return FALSE;
-    }
-
-  if (num_layers < 1)
-    {
-      meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
-      g_set_error (error, G_IO_ERROR,
-                   G_IO_ERROR_FAILED,
-                   "Unable to find output layers.");
-      return FALSE;
-    }
-
-  if (!meta_egl_stream_consumer_output (egl, egl_display,
-                                        egl_stream, output_layer,
-                                        error))
-    {
-      meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
-      return FALSE;
-    }
-
-  egl_config = cogl_display_egl->egl_config;
-  egl_surface = meta_egl_create_stream_producer_surface (egl,
-                                                         egl_display,
-                                                         egl_config,
-                                                         egl_stream,
-                                                         stream_producer_attribs,
-                                                         error);
-  if (egl_surface == EGL_NO_SURFACE)
-    {
-      meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
-      return FALSE;
-    }
-
-  *out_egl_stream = egl_stream;
-  *out_egl_surface = egl_surface;
-
-  return TRUE;
-}
-#endif /* HAVE_EGL_DEVICE */
-
-static gboolean
-meta_renderer_native_init_onscreen (CoglOnscreen *onscreen,
-                                    GError      **error)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
-  CoglDisplay *cogl_display = cogl_context->display;
-  CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
-  CoglOnscreenEgl *onscreen_egl;
-  MetaOnscreenNative *onscreen_native;
-
-  g_return_val_if_fail (cogl_display_egl->egl_context, FALSE);
-
-  onscreen_egl = cogl_onscreen_egl_new ();
-  cogl_onscreen_set_winsys (onscreen, onscreen_egl);
-
-  onscreen_native = g_slice_new0 (MetaOnscreenNative);
-  cogl_onscreen_egl_set_platform (onscreen_egl, onscreen_native);
-
-  /*
-   * Don't actually initialize anything here, since we may not have the
-   * information available yet, and there is no way to pass it at this stage.
-   * To properly allocate a MetaOnscreenNative, the caller must call
-   * meta_onscreen_native_allocate() after cogl_framebuffer_allocate().
-   *
-   * TODO: Turn CoglFramebuffer/CoglOnscreen into GObjects, so it's possible
-   * to add backend specific properties.
-   */
-
-  return TRUE;
-}
-
-static gboolean
-meta_onscreen_native_allocate (CoglOnscreen *onscreen,
-                               GError      **error)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  MetaRendererNativeGpuData *renderer_gpu_data;
-  struct gbm_surface *gbm_surface;
-  EGLSurface egl_surface;
-  int width;
-  int height;
-#ifdef HAVE_EGL_DEVICE
-  MetaKmsDevice *render_kms_device;
-  EGLStreamKHR egl_stream;
-#endif
-
-  /* If a kms_fd is set then the display width and height
-   * won't be available until meta_renderer_native_set_layout
-   * is called. In that case, defer creating the surface
-   * until then.
-   */
-  width = cogl_framebuffer_get_width (framebuffer);
-  height = cogl_framebuffer_get_height (framebuffer);
-  if (width == 0 || height == 0)
-    return TRUE;
+      kms_device = kms_device_from_view (view);
 
-  renderer_gpu_data =
-    meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
-                                       onscreen_native->render_gpu);
-  switch (renderer_gpu_data->mode)
-    {
-    case META_RENDERER_NATIVE_MODE_GBM:
-      if (!meta_renderer_native_create_surface_gbm (onscreen,
-                                                    width, height,
-                                                    &gbm_surface,
-                                                    &egl_surface,
-                                                    error))
-        return FALSE;
+      kms_update = meta_kms_get_pending_update (kms, kms_device);
+      if (!kms_update)
+        continue;
 
-      onscreen_native->gbm.surface = gbm_surface;
-      cogl_onscreen_egl_set_egl_surface (onscreen_egl, egl_surface);
-      break;
-#ifdef HAVE_EGL_DEVICE
-    case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
-      render_kms_device =
-        meta_gpu_kms_get_kms_device (onscreen_native->render_gpu);
-      onscreen_native->egl.dumb_fb =
-        meta_drm_buffer_dumb_new (render_kms_device,
-                                  width, height,
-                                  DRM_FORMAT_XRGB8888,
-                                  error);
-      if (!onscreen_native->egl.dumb_fb)
-        return FALSE;
+      configure_disabled_crtcs (gpu_from_view (view), kms_update);
 
-      if (!meta_renderer_native_create_surface_egl_device (onscreen,
-                                                           width, height,
-                                                           &egl_stream,
-                                                           &egl_surface,
-                                                           error))
-        return FALSE;
+      flags = META_KMS_UPDATE_FLAG_NONE;
+      kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
 
-      onscreen_native->egl.stream = egl_stream;
-      cogl_onscreen_egl_set_egl_surface (onscreen_egl, egl_surface);
-      break;
-#endif /* HAVE_EGL_DEVICE */
+      switch (meta_kms_feedback_get_result (kms_feedback))
+        {
+        case META_KMS_FEEDBACK_PASSED:
+          break;
+        case META_KMS_FEEDBACK_FAILED:
+          feedback_error = meta_kms_feedback_get_error (kms_feedback);
+          if (!g_error_matches (feedback_error,
+                                G_IO_ERROR,
+                                G_IO_ERROR_PERMISSION_DENIED))
+            g_warning ("Failed to post KMS update: %s", feedback_error->message);
+          break;
+        }
     }
 
-  return TRUE;
+  clear_kept_alive_onscreens (renderer_native);
 }
 
 static void
-destroy_egl_surface (CoglOnscreen *onscreen)
+unset_disabled_crtcs (MetaBackend *backend,
+                      MetaKms     *kms)
 {
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  EGLSurface egl_surface;
+  GList *l;
 
-  egl_surface = cogl_onscreen_egl_get_egl_surface (onscreen_egl);
-  if (cogl_onscreen_egl_get_egl_surface (onscreen_egl) != EGL_NO_SURFACE)
+  meta_topic (META_DEBUG_KMS, "Disabling all disabled CRTCs");
+
+  for (l = meta_backend_get_gpus (backend); l; l = l->next)
     {
-      MetaOnscreenNative *onscreen_native =
-        cogl_onscreen_egl_get_platform (onscreen_egl);
-      MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
-      CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-      CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
-      CoglRenderer *cogl_renderer = cogl_context->display->renderer;
-      CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+      MetaGpu *gpu = l->data;
+      MetaKmsDevice *kms_device =
+        meta_gpu_kms_get_kms_device (META_GPU_KMS (gpu));
+      GList *k;
+      gboolean did_mode_set = FALSE;
+      MetaKmsUpdateFlag flags;
+      g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
 
-      meta_egl_destroy_surface (egl,
-                                cogl_renderer_egl->edpy,
-                                egl_surface,
-                                NULL);
-      cogl_onscreen_egl_set_egl_surface (onscreen_egl, EGL_NO_SURFACE);
-    }
-}
+      for (k = meta_gpu_get_crtcs (gpu); k; k = k->next)
+        {
+          MetaCrtc *crtc = k->data;
+          MetaKmsUpdate *kms_update;
 
-static void
-meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
-  CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
-  CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
-  CoglOnscreenEgl *onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  MetaOnscreenNative *onscreen_native;
-  MetaRendererNative *renderer_native;
-  MetaRendererNativeGpuData *renderer_gpu_data;
-  EGLSurface egl_surface;
+          if (meta_crtc_get_config (crtc))
+            continue;
 
-  /* If we never successfully allocated then there's nothing to do */
-  if (onscreen_egl == NULL)
-    return;
+          kms_update = meta_kms_ensure_pending_update (kms, kms_device);
+          meta_crtc_kms_set_mode (META_CRTC_KMS (crtc), kms_update);
+
+          did_mode_set = TRUE;
+        }
 
-  onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  renderer_native = onscreen_native->renderer_native;
+      if (!did_mode_set)
+        continue;
 
-  egl_surface = cogl_onscreen_egl_get_egl_surface (onscreen_egl);
-  if (egl_surface != EGL_NO_SURFACE &&
-      (cogl_display_egl->current_draw_surface == egl_surface ||
-       cogl_display_egl->current_read_surface == egl_surface))
-    {
-      if (!_cogl_winsys_egl_make_current (cogl_display,
-                                          cogl_display_egl->dummy_surface,
-                                          cogl_display_egl->dummy_surface,
-                                          cogl_display_egl->egl_context))
-        g_warning ("Failed to clear current context");
+      flags = META_KMS_UPDATE_FLAG_NONE;
+      kms_feedback = meta_kms_post_pending_update_sync (kms,
+                                                        kms_device,
+                                                        flags);
+      if (meta_kms_feedback_get_result (kms_feedback) !=
+          META_KMS_FEEDBACK_PASSED)
+        {
+          const GError *error = meta_kms_feedback_get_error (kms_feedback);
+
+          if (!g_error_matches (error, G_IO_ERROR,
+                                G_IO_ERROR_PERMISSION_DENIED))
+            g_warning ("Failed to post KMS update: %s", error->message);
+        }
     }
+}
+
+static CoglDmaBufHandle *
+meta_renderer_native_create_dma_buf (CoglRenderer  *cogl_renderer,
+                                     int            width,
+                                     int            height,
+                                     GError       **error)
+{
+  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
+  MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
 
-  renderer_gpu_data =
-    meta_renderer_native_get_gpu_data (renderer_native,
-                                       onscreen_native->render_gpu);
   switch (renderer_gpu_data->mode)
     {
     case META_RENDERER_NATIVE_MODE_GBM:
-      /* flip state takes a reference on the onscreen so there should
-       * never be outstanding flips when we reach here. */
-      g_return_if_fail (onscreen_native->gbm.next_fb == NULL);
+      {
+        CoglFramebuffer *dmabuf_fb;
+        CoglDmaBufHandle *dmabuf_handle;
+        struct gbm_bo *new_bo;
+        int stride;
+        int offset;
+        int bpp;
+        int dmabuf_fd = -1;
+
+        new_bo = gbm_bo_create (renderer_gpu_data->gbm.device,
+                                width, height, DRM_FORMAT_XRGB8888,
+                                GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR);
 
-      free_current_bo (onscreen);
+        if (!new_bo)
+          {
+            g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                         "Failed to allocate buffer");
+            return NULL;
+          }
 
-      destroy_egl_surface (onscreen);
+        dmabuf_fd = gbm_bo_get_fd (new_bo);
 
-      if (onscreen_native->gbm.surface)
-        {
-          gbm_surface_destroy (onscreen_native->gbm.surface);
-          onscreen_native->gbm.surface = NULL;
-        }
+        if (dmabuf_fd == -1)
+          {
+            g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
+                         "Failed to export buffer's DMA fd: %s",
+                         g_strerror (errno));
+            return NULL;
+          }
+
+        stride = gbm_bo_get_stride (new_bo);
+        offset = gbm_bo_get_offset (new_bo, 0);
+        bpp = 4;
+        dmabuf_fb =
+          meta_renderer_native_create_dma_buf_framebuffer (renderer_native,
+                                                           dmabuf_fd,
+                                                           width, height,
+                                                           stride,
+                                                           offset,
+                                                           DRM_FORMAT_MOD_LINEAR,
+                                                           DRM_FORMAT_XRGB8888,
+                                                           error);
+
+        if (!dmabuf_fb)
+          return NULL;
+
+        dmabuf_handle =
+          cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd,
+                                   width, height, stride, offset, bpp,
+                                   new_bo,
+                                   (GDestroyNotify) gbm_bo_destroy);
+        g_object_unref (dmabuf_fb);
+        return dmabuf_handle;
+      }
       break;
 #ifdef HAVE_EGL_DEVICE
     case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
-      g_clear_object (&onscreen_native->egl.dumb_fb);
-
-      destroy_egl_surface (onscreen);
-
-      if (onscreen_native->egl.stream != EGL_NO_STREAM_KHR)
-        {
-          MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
-          CoglRenderer *cogl_renderer = cogl_context->display->renderer;
-          CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
-
-          meta_egl_destroy_stream (egl,
-                                   cogl_renderer_egl->edpy,
-                                   onscreen_native->egl.stream,
-                                   NULL);
-          onscreen_native->egl.stream = EGL_NO_STREAM_KHR;
-        }
       break;
-#endif /* HAVE_EGL_DEVICE */
+#endif
     }
 
-  g_clear_pointer (&onscreen_native->secondary_gpu_state,
-                   secondary_gpu_state_free);
+  g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN,
+               "Current mode does not support exporting DMA buffers");
+
+  return NULL;
+}
+
+static gboolean
+meta_renderer_native_init_egl_context (CoglContext *cogl_context,
+                                       GError     **error)
+{
+#ifdef HAVE_EGL_DEVICE
+  CoglRenderer *cogl_renderer = cogl_context->display->renderer;
+  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+  MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
+#endif
+
+  COGL_FLAGS_SET (cogl_context->winsys_features,
+                  COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT,
+                  TRUE);
+  COGL_FLAGS_SET (cogl_context->winsys_features,
+                  COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT,
+                  TRUE);
+  COGL_FLAGS_SET (cogl_context->winsys_features,
+                  COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
+                  TRUE);
+
+#ifdef HAVE_EGL_DEVICE
+  if (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_EGL_DEVICE)
+    COGL_FLAGS_SET (cogl_context->features,
+                    COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL, TRUE);
+#endif
 
-  g_slice_free (MetaOnscreenNative, onscreen_native);
-  cogl_onscreen_egl_free (cogl_onscreen_get_winsys (onscreen));
-  cogl_onscreen_set_winsys (onscreen, NULL);
+  return TRUE;
 }
 
 static const CoglWinsysEGLVtable
@@ -2926,46 +848,36 @@ meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native)
   meta_topic (META_DEBUG_KMS, "Queue mode set");
 }
 
-static CoglOnscreen *
-meta_renderer_native_create_onscreen (MetaRendererNative   *renderer_native,
-                                      MetaGpuKms           *render_gpu,
-                                      MetaOutput           *output,
-                                      MetaCrtc             *crtc,
-                                      CoglContext          *context,
-                                      int                   width,
-                                      int                   height,
-                                      GError              **error)
+void
+meta_renderer_native_notify_mode_sets_reset (MetaRendererNative *renderer_native)
 {
-  CoglOnscreen *onscreen;
-  CoglOnscreenEgl *onscreen_egl;
-  MetaOnscreenNative *onscreen_native;
+  renderer_native->pending_mode_set = FALSE;
+}
+
+gboolean
+meta_renderer_native_pop_pending_mode_set (MetaRendererNative *renderer_native,
+                                           MetaRendererView   *view)
+{
+  MetaRenderer *renderer = META_RENDERER (renderer_native);
+  MetaBackend *backend = meta_renderer_get_backend (renderer);
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+  MetaPowerSave power_save_mode;
+  GList *link;
 
-  onscreen = cogl_onscreen_new (context, width, height);
+  g_assert (META_IS_RENDERER_VIEW (view));
 
-  if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (onscreen), error))
-    {
-      g_object_unref (onscreen);
-      return NULL;
-    }
+  power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
+  if (power_save_mode != META_POWER_SAVE_ON)
+    return FALSE;
 
-  onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  onscreen_native->renderer_native = renderer_native;
-  onscreen_native->render_gpu = render_gpu;
-  onscreen_native->output = output;
-  onscreen_native->crtc = crtc;
-
-  if (META_GPU_KMS (meta_crtc_get_gpu (crtc)) != render_gpu)
-    {
-      if (!init_secondary_gpu_state (renderer_native, onscreen, error))
-        {
-          g_object_unref (onscreen);
-          return NULL;
-        }
-    }
+  link = g_list_find (renderer_native->pending_mode_set_views, view);
+  if (!link)
+    return FALSE;
 
-  return onscreen;
+  renderer_native->pending_mode_set_views =
+    g_list_delete_link (renderer_native->pending_mode_set_views, link);
+  return TRUE;
 }
 
 static CoglOffscreen *
@@ -3066,19 +978,6 @@ meta_renderer_native_create_cogl_renderer (MetaRenderer *renderer)
   return create_cogl_renderer_for_gpu (renderer_native->primary_gpu_kms);
 }
 
-static void
-meta_onscreen_native_set_view (CoglOnscreen     *onscreen,
-                               MetaRendererView *view)
-{
-  CoglOnscreenEgl *onscreen_egl;
-  MetaOnscreenNative *onscreen_native;
-
-  onscreen_egl = cogl_onscreen_get_winsys (onscreen);
-  onscreen_native =
-    cogl_onscreen_egl_get_platform (onscreen_egl);
-  onscreen_native->view = view;
-}
-
 static MetaMonitorTransform
 calculate_view_transform (MetaMonitorManager *monitor_manager,
                           MetaLogicalMonitor *logical_monitor,
@@ -3169,14 +1068,14 @@ meta_renderer_native_create_view (MetaRenderer       *renderer,
   onscreen_width = crtc_mode_info->width;
   onscreen_height = crtc_mode_info->height;
 
-  onscreen = meta_renderer_native_create_onscreen (renderer_native,
-                                                   renderer_native->primary_gpu_kms,
-                                                   output,
-                                                   crtc,
-                                                   cogl_context,
-                                                   onscreen_width,
-                                                   onscreen_height,
-                                                   &error);
+  onscreen = meta_onscreen_native_new (renderer_native,
+                                       renderer_native->primary_gpu_kms,
+                                       output,
+                                       crtc,
+                                       cogl_context,
+                                       onscreen_width,
+                                       onscreen_height,
+                                       &error);
   if (!onscreen)
     g_error ("Failed to allocate onscreen framebuffer: %s", error->message);
 
@@ -3309,78 +1208,18 @@ meta_renderer_native_prepare_frame (MetaRendererNative *renderer_native,
   meta_crtc_kms_maybe_set_gamma (crtc_kms, kms_device);
 }
 
-static void
-add_onscreen_frame_info (MetaCrtc *crtc)
-{
-  MetaGpu *gpu = meta_crtc_get_gpu (crtc);
-  MetaBackend *backend = meta_gpu_get_backend (gpu);
-  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
-  MetaStageNative *stage_native =
-    meta_clutter_backend_native_get_stage_native (clutter_backend);
-  MetaRenderer *renderer = meta_backend_get_renderer (backend);
-  MetaRendererView *view = meta_renderer_get_view_for_crtc (renderer, crtc);
-
-  clutter_stage_cogl_add_onscreen_frame_info (CLUTTER_STAGE_COGL (stage_native),
-                                              CLUTTER_STAGE_VIEW (view));
-}
-
 void
 meta_renderer_native_finish_frame (MetaRendererNative *renderer_native,
                                    MetaRendererView   *view,
                                    ClutterFrame       *frame)
 {
-  MetaRenderer *renderer = META_RENDERER (renderer_native);
-  MetaBackend *backend = meta_renderer_get_backend (renderer);
-  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
-  MetaKms *kms = meta_backend_native_get_kms (backend_native);
-
   if (!clutter_frame_has_result (frame))
     {
-      MetaCrtc *crtc = meta_renderer_view_get_crtc (view);
-      MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
-      MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);;
-      MetaKmsUpdateFlag flags;
-      MetaKmsUpdate *kms_update;
-      g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
-      const GError *error;
-
-      kms_update = meta_kms_get_pending_update (kms, kms_device);
-      if (!kms_update)
-        {
-          clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
-          return;
-        }
+      CoglFramebuffer *framebuffer =
+        clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
+      CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
 
-      meta_kms_update_add_page_flip_listener (kms_update,
-                                              kms_crtc,
-                                              &page_flip_listener_vtable,
-                                              META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE,
-                                              g_object_ref (view),
-                                              g_object_unref);
-
-      flags = META_KMS_UPDATE_FLAG_NONE;
-      kms_feedback = meta_kms_post_pending_update_sync (kms,
-                                                        kms_device,
-                                                        flags);
-      switch (meta_kms_feedback_get_result (kms_feedback))
-        {
-        case META_KMS_FEEDBACK_PASSED:
-          add_onscreen_frame_info (crtc);
-          clutter_frame_set_result (frame,
-                                    CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
-          break;
-        case META_KMS_FEEDBACK_FAILED:
-          add_onscreen_frame_info (crtc);
-          clutter_frame_set_result (frame,
-                                    CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
-
-          error = meta_kms_feedback_get_error (kms_feedback);
-          if (!g_error_matches (error,
-                                G_IO_ERROR,
-                                G_IO_ERROR_PERMISSION_DENIED))
-            g_warning ("Failed to post KMS update: %s", error->message);
-          break;
-        }
+      meta_onscreen_native_finish_frame (onscreen, frame);
     }
 }
 
diff --git a/src/meson.build b/src/meson.build
index 8875fb2efb..3683907ff3 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -669,7 +669,6 @@ if have_native_backend
     'backends/native/meta-monitor-manager-kms.h',
     'backends/native/meta-output-kms.c',
     'backends/native/meta-output-kms.h',
-    'backends/native/meta-renderer-native.c',
     'backends/native/meta-kms-connector-private.h',
     'backends/native/meta-kms-connector.c',
     'backends/native/meta-kms-connector.h',
@@ -703,10 +702,14 @@ if have_native_backend
     'backends/native/meta-kms-utils.h',
     'backends/native/meta-kms.c',
     'backends/native/meta-kms.h',
+    'backends/native/meta-onscreen-native.c',
+    'backends/native/meta-onscreen-native.h',
     'backends/native/meta-pointer-constraint-native.c',
     'backends/native/meta-pointer-constraint-native.h',
     'backends/native/meta-renderer-native-gles3.c',
     'backends/native/meta-renderer-native-gles3.h',
+    'backends/native/meta-renderer-native-private.h',
+    'backends/native/meta-renderer-native.c',
     'backends/native/meta-renderer-native.h',
     'backends/native/meta-seat-impl.c',
     'backends/native/meta-seat-impl.h',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]