summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Ã…dahl <jadahl@gmail.com>2020-10-17 23:08:28 +0200
committerRobert Mader <robert.mader@posteo.de>2021-01-30 09:11:45 +0000
commit3e4ece50d3fbf60bbc241129ba11c642588f4a1a (patch)
treea5bed618b7d19ae5380588fb13fec62ed3259693
parentb5afa6db23f43e2c94bdc418da04b7df22e882dd (diff)
downloadmutter-3e4ece50d3fbf60bbc241129ba11c642588f4a1a.tar.gz
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>
-rw-r--r--src/backends/native/meta-backend-native-types.h2
-rw-r--r--src/backends/native/meta-onscreen-native.c2196
-rw-r--r--src/backends/native/meta-onscreen-native.h69
-rw-r--r--src/backends/native/meta-renderer-native-private.h113
-rw-r--r--src/backends/native/meta-renderer-native.c2393
-rw-r--r--src/meson.build5
6 files changed, 2500 insertions, 2278 deletions
diff --git a/src/backends/native/meta-backend-native-types.h b/src/backends/native/meta-backend-native-types.h
index ba73b4a56..0668a84e4 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 000000000..1617668ce
--- /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 000000000..10a3a610f
--- /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 000000000..2193d85e4
--- /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 a542af194..555bd413d 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)
+MetaGles3 *
+meta_renderer_native_get_gles3 (MetaRendererNative *renderer_native)
{
- return meta_renderer_native_get_egl (onscreen_native->renderer_native);
+ return renderer_native->gles3;
}
-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)
-{
- /*
- * 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)
+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,563 +447,6 @@ 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)
-{
- 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
-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,
-};
-
-#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 */
-
-static void
-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 gboolean
-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);
- g_list_free_full (renderer_native->power_save_page_flip_onscreens,
- g_object_unref);
- renderer_native->power_save_page_flip_onscreens = NULL;
- renderer_native->power_save_page_flip_source_id = 0;
-
- return G_SOURCE_REMOVE;
-}
-
-static void
-queue_dummy_power_save_page_flip (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)
- {
- renderer_native->power_save_page_flip_source_id =
- g_timeout_add (timeout_ms,
- dummy_power_save_page_flip_cb,
- renderer_native);
- }
-
- renderer_native->power_save_page_flip_onscreens =
- g_list_prepend (renderer_native->power_save_page_flip_onscreens,
- g_object_ref (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)
-{
- 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 CoglContext *
cogl_context_from_renderer_native (MetaRendererNative *renderer_native)
{
@@ -1566,16 +457,16 @@ cogl_context_from_renderer_native (MetaRendererNative *renderer_native)
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)
+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)
{
CoglContext *cogl_context =
cogl_context_from_renderer_native (renderer_native);
@@ -1642,286 +533,11 @@ create_dma_buf_framebuffer (MetaRendererNative *renderer_native,
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);
+ 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);
return meta_kms_crtc_get_device (kms_crtc);
@@ -1930,14 +546,9 @@ kms_device_from_view (MetaRendererView *view)
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);
+ MetaCrtc *crtc = meta_renderer_view_get_crtc (view);
+
+ return meta_crtc_get_gpu (crtc);
}
static void
@@ -1962,6 +573,41 @@ configure_disabled_crtcs (MetaGpu *gpu,
}
}
+static gboolean
+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) 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;
+ renderer_native->power_save_page_flip_source_id = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
+void
+meta_renderer_native_queue_power_save_page_flip (MetaRendererNative *renderer_native,
+ CoglOnscreen *onscreen)
+{
+ const unsigned int timeout_ms = 100;
+
+ if (!renderer_native->power_save_page_flip_source_id)
+ {
+ renderer_native->power_save_page_flip_source_id =
+ g_timeout_add (timeout_ms,
+ dummy_power_save_page_flip_cb,
+ renderer_native);
+ }
+
+ renderer_native->power_save_page_flip_onscreens =
+ g_list_prepend (renderer_native->power_save_page_flip_onscreens,
+ g_object_ref (onscreen));
+}
+
static void
clear_kept_alive_onscreens (MetaRendererNative *renderer_native)
{
@@ -1970,7 +616,7 @@ clear_kept_alive_onscreens (MetaRendererNative *renderer_native)
renderer_native->kept_alive_onscreens = NULL;
}
-static void
+void
meta_renderer_native_post_mode_set_updates (MetaRendererNative *renderer_native)
{
MetaRenderer *renderer = META_RENDERER (renderer_native);
@@ -2066,182 +712,6 @@ unset_disabled_crtcs (MetaBackend *backend,
}
}
-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,
@@ -2288,14 +758,15 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
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);
+ 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;
@@ -2321,146 +792,6 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
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)
@@ -2490,415 +821,6 @@ meta_renderer_native_init_egl_context (CoglContext *cogl_context,
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;
-
- 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;
-
- 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 (!meta_renderer_native_create_surface_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);
- }
-}
-
-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 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);
-}
-
static const CoglWinsysEGLVtable
_cogl_winsys_egl_vtable = {
.add_config_attributes = meta_renderer_native_add_egl_config_attributes,
@@ -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;
- }
-
- 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);
+ CoglFramebuffer *framebuffer =
+ clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
+ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
- 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 8875fb2ef..3683907ff 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',