From 3da8c1bfdc1fa486111c1e1dff363fb931612468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 12 Sep 2019 10:47:46 +0200 Subject: [PATCH] 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(-) create mode 100644 cogl/cogl/cogl-scanout.c create mode 100644 cogl/cogl/cogl-scanout.h 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 . + */ + +#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 . + */ + +#ifndef COGL_SCANOUT_H +#define COGL_SCANOUT_H + +#include "cogl/cogl-types.h" + +#include + +#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 #include #include +#include /* XXX: This will definitly go away once all the Clutter winsys * code has been migrated down into Cogl! */ #include 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;