[mutter] cogl/onscreen: Add API to scanout a buffer directly



commit 3da8c1bfdc1fa486111c1e1dff363fb931612468
Author: Jonas Ådahl <jadahl gmail com>
Date:   Thu Sep 12 10:47:46 2019 +0200

    cogl/onscreen: Add API to scanout a buffer directly
    
    Instead of always swapping buffers and flipping the back buffer, make it
    possible to scan out a provided buffer directly without swapping any EGL
    buffers.
    
    A buffer is passed as an object implementing the empty CoglScanout
    interface. It is only possible to do this in the native backend; and the
    interface is implemented by MetaDrmBufferGbm. When directly scanned out,
    instead of calling gbm_surface_lock_front_buffer() to get the gbm_bo and
    fbid, get it directly from the MetaDrmBufferGbm, and use that to create
    the page flip KMS update.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/798

 cogl/cogl/cogl-onscreen.c                  | 21 +++++++
 cogl/cogl/cogl-onscreen.h                  |  9 +++
 cogl/cogl/cogl-scanout.c                   | 27 +++++++++
 cogl/cogl/cogl-scanout.h                   | 35 ++++++++++++
 cogl/cogl/cogl.h                           |  1 +
 cogl/cogl/meson.build                      |  2 +
 cogl/cogl/winsys/cogl-winsys-private.h     |  5 ++
 src/backends/native/meta-drm-buffer-gbm.c  | 12 +++-
 src/backends/native/meta-renderer-native.c | 89 +++++++++++++++++++++++++-----
 9 files changed, 185 insertions(+), 16 deletions(-)
---
diff --git a/cogl/cogl/cogl-onscreen.c b/cogl/cogl/cogl-onscreen.c
index 704e1c44b..892a0af3b 100644
--- a/cogl/cogl/cogl-onscreen.c
+++ b/cogl/cogl/cogl-onscreen.c
@@ -405,6 +405,27 @@ cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen)
   return winsys->onscreen_get_buffer_age (onscreen);
 }
 
+void
+cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
+                              CoglScanout  *scanout)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  const CoglWinsysVtable *winsys;
+  CoglFrameInfo *info;
+
+  g_return_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
+  g_return_if_fail (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT));
+
+  info = _cogl_frame_info_new ();
+  info->frame_counter = onscreen->frame_counter;
+  g_queue_push_tail (&onscreen->pending_frame_infos, info);
+
+  winsys = _cogl_framebuffer_get_winsys (framebuffer);
+  winsys->onscreen_direct_scanout (onscreen, scanout);
+
+  onscreen->frame_counter++;
+}
+
 #ifdef COGL_HAS_X11_SUPPORT
 uint32_t
 cogl_x11_onscreen_get_window_xid (CoglOnscreen *onscreen)
diff --git a/cogl/cogl/cogl-onscreen.h b/cogl/cogl/cogl-onscreen.h
index 40bd6780b..fd95edd82 100644
--- a/cogl/cogl/cogl-onscreen.h
+++ b/cogl/cogl/cogl-onscreen.h
@@ -50,6 +50,8 @@ G_BEGIN_DECLS
 typedef struct _CoglOnscreen CoglOnscreen;
 #define COGL_ONSCREEN(X) ((CoglOnscreen *)(X))
 
+typedef struct _CoglScanout CoglScanout;
+
 /**
  * cogl_onscreen_get_gtype:
  *
@@ -284,6 +286,13 @@ cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
                                         const int *rectangles,
                                         int n_rectangles);
 
+/**
+ * cogl_onscreen_direct_scanout: (skip)
+ */
+void
+cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
+                              CoglScanout  *scanout);
+
 /**
  * cogl_onscreen_swap_region:
  * @onscreen: A #CoglOnscreen framebuffer
diff --git a/cogl/cogl/cogl-scanout.c b/cogl/cogl/cogl-scanout.c
new file mode 100644
index 000000000..759cd62a4
--- /dev/null
+++ b/cogl/cogl/cogl-scanout.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cogl-config.h"
+
+#include "cogl-scanout.h"
+
+G_DEFINE_INTERFACE (CoglScanout, cogl_scanout, G_TYPE_OBJECT)
+
+static void
+cogl_scanout_default_init (CoglScanoutInterface *iface)
+{
+}
diff --git a/cogl/cogl/cogl-scanout.h b/cogl/cogl/cogl-scanout.h
new file mode 100644
index 000000000..5f2f7e907
--- /dev/null
+++ b/cogl/cogl/cogl-scanout.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef COGL_SCANOUT_H
+#define COGL_SCANOUT_H
+
+#include "cogl/cogl-types.h"
+
+#include <glib-object.h>
+
+#define COGL_TYPE_SCANOUT (cogl_scanout_get_type ())
+COGL_EXPORT
+G_DECLARE_INTERFACE (CoglScanout, cogl_scanout,
+                     COGL, SCANOUT, GObject)
+
+struct _CoglScanoutInterface
+{
+  GTypeInterface parent_iface;
+};
+
+#endif /* COGL_SCANOUT_H */
diff --git a/cogl/cogl/cogl.h b/cogl/cogl/cogl.h
index 6ad0227df..7eb6cfa74 100644
--- a/cogl/cogl/cogl.h
+++ b/cogl/cogl/cogl.h
@@ -122,6 +122,7 @@
 #include <cogl/cogl-fence.h>
 #include <cogl/cogl-glib-source.h>
 #include <cogl/cogl-trace.h>
+#include <cogl/cogl-scanout.h>
 /* XXX: This will definitly go away once all the Clutter winsys
  * code has been migrated down into Cogl! */
 #include <cogl/deprecated/cogl-clutter.h>
diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build
index 54c4a1612..21f6d8c0c 100644
--- a/cogl/cogl/meson.build
+++ b/cogl/cogl/meson.build
@@ -122,6 +122,7 @@ cogl_nonintrospected_headers = [
   'cogl-version.h',
   'cogl-gtype-private.h',
   'cogl-glib-source.h',
+  'cogl-scanout.h',
 ]
 
 cogl_nodist_headers = [
@@ -347,6 +348,7 @@ cogl_sources = [
   'cogl-closure-list.c',
   'cogl-fence.c',
   'cogl-fence-private.h',
+  'cogl-scanout.c',
   'deprecated/cogl-material-compat.c',
   'deprecated/cogl-program.c',
   'deprecated/cogl-program-private.h',
diff --git a/cogl/cogl/winsys/cogl-winsys-private.h b/cogl/cogl/winsys/cogl-winsys-private.h
index d849ef705..01a45b765 100644
--- a/cogl/cogl/winsys/cogl-winsys-private.h
+++ b/cogl/cogl/winsys/cogl-winsys-private.h
@@ -33,6 +33,7 @@
 
 #include "cogl-renderer.h"
 #include "cogl-onscreen.h"
+#include "cogl-scanout.h"
 
 #ifdef COGL_HAS_XLIB_SUPPORT
 #include "cogl-texture-pixmap-x11-private.h"
@@ -117,6 +118,10 @@ typedef struct _CoglWinsysVtable
                                         const int *rectangles,
                                         int n_rectangles);
 
+  void
+  (*onscreen_direct_scanout) (CoglOnscreen *onscreen,
+                              CoglScanout  *scanout);
+
   void
   (*onscreen_set_visibility) (CoglOnscreen *onscreen,
                               gboolean visibility);
diff --git a/src/backends/native/meta-drm-buffer-gbm.c b/src/backends/native/meta-drm-buffer-gbm.c
index 1c8a20f77..3985e26bc 100644
--- a/src/backends/native/meta-drm-buffer-gbm.c
+++ b/src/backends/native/meta-drm-buffer-gbm.c
@@ -44,7 +44,12 @@ struct _MetaDrmBufferGbm
   uint32_t fb_id;
 };
 
-G_DEFINE_TYPE (MetaDrmBufferGbm, meta_drm_buffer_gbm, META_TYPE_DRM_BUFFER)
+static void
+cogl_scanout_iface_init (CoglScanoutInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaDrmBufferGbm, meta_drm_buffer_gbm, META_TYPE_DRM_BUFFER,
+                         G_IMPLEMENT_INTERFACE (COGL_TYPE_SCANOUT,
+                                                cogl_scanout_iface_init))
 
 struct gbm_bo *
 meta_drm_buffer_gbm_get_bo (MetaDrmBufferGbm *buffer_gbm)
@@ -161,6 +166,11 @@ meta_drm_buffer_gbm_get_fb_id (MetaDrmBuffer *buffer)
   return META_DRM_BUFFER_GBM (buffer)->fb_id;
 }
 
+static void
+cogl_scanout_iface_init (CoglScanoutInterface *iface)
+{
+}
+
 static void
 meta_drm_buffer_gbm_finalize (GObject *object)
 {
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index b363a2b05..c86965b41 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -2013,6 +2013,34 @@ retry:
     }
 }
 
+static void
+ensure_crtc_modes (CoglOnscreen  *onscreen,
+                   MetaKmsUpdate *kms_update)
+{
+  CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
+  MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
+  CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->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);
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+  MetaPowerSave power_save_mode;
+
+  power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
+  if (onscreen_native->pending_set_crtc &&
+      power_save_mode == META_POWER_SAVE_ON)
+    {
+      meta_onscreen_native_set_crtc_mode (onscreen,
+                                          renderer_gpu_data,
+                                          kms_update);
+      onscreen_native->pending_set_crtc = FALSE;
+    }
+}
+
 static void
 meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
                                                const int    *rectangles,
@@ -2026,8 +2054,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
   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);
   MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
   MetaKms *kms = meta_backend_native_get_kms (backend_native);
   CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
@@ -2036,7 +2062,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
   CoglFrameInfo *frame_info;
   gboolean egl_context_changed = FALSE;
   MetaKmsUpdate *kms_update;
-  MetaPowerSave power_save_mode;
   g_autoptr (GError) error = NULL;
   MetaDrmBufferGbm *buffer_gbm;
   g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
@@ -2095,18 +2120,7 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
 
   update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed);
 
-  /* If this is the first framebuffer to be presented then we now setup the
-   * crtc modes, else we flip from the previous buffer */
-
-  power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
-  if (onscreen_native->pending_set_crtc &&
-      power_save_mode == META_POWER_SAVE_ON)
-    {
-      meta_onscreen_native_set_crtc_mode (onscreen,
-                                          renderer_gpu_data,
-                                          kms_update);
-      onscreen_native->pending_set_crtc = FALSE;
-    }
+  ensure_crtc_modes (onscreen, kms_update);
 
   onscreen_native->pending_queue_swap_notify_frame_count = renderer_native->frame_counter;
   meta_onscreen_native_flip_crtcs (onscreen, kms_update);
@@ -2200,6 +2214,50 @@ meta_renderer_native_create_dma_buf (CoglRenderer  *cogl_renderer,
   return NULL;
 }
 
+static void
+meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
+                                     CoglScanout  *scanout)
+{
+  CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
+  MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
+  MetaGpuKms *render_gpu = onscreen_native->render_gpu;
+  CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->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);
+  MetaKms *kms = meta_backend_native_get_kms (backend_native);
+  CoglFrameInfo *frame_info;
+  MetaKmsUpdate *kms_update;
+  g_autoptr (GError) error = NULL;
+
+  kms_update = meta_kms_ensure_pending_update (kms);
+
+  wait_for_pending_flips (onscreen);
+
+  frame_info = g_queue_peek_tail (&onscreen->pending_frame_infos);
+  frame_info->global_frame_counter = renderer_native->frame_counter;
+
+  renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
+                                                         render_gpu);
+
+  g_return_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, kms_update);
+
+  onscreen_native->pending_queue_swap_notify_frame_count =
+    renderer_native->frame_counter;
+  meta_onscreen_native_flip_crtcs (onscreen, kms_update);
+
+  meta_kms_post_pending_update_sync (kms);
+}
+
 static gboolean
 meta_renderer_native_init_egl_context (CoglContext *cogl_context,
                                        GError     **error)
@@ -2923,6 +2981,7 @@ get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer)
       vtable.onscreen_swap_region = NULL;
       vtable.onscreen_swap_buffers_with_damage =
         meta_onscreen_native_swap_buffers_with_damage;
+      vtable.onscreen_direct_scanout = meta_onscreen_native_direct_scanout;
 
       vtable.context_get_clock_time = meta_renderer_native_get_clock_time;
 


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