From ab6179b9d74e4bda2fa4003c7399c4aa4abaaf9e Mon Sep 17 00:00:00 2001 From: Gert-dev Date: Thu, 3 Oct 2024 14:56:07 +0200 Subject: [PATCH] onscreen/native: Use EGLSyncs instead of cogl_framebuffer_finish cogl_framebuffer_finish can result in a CPU-side stall because it waits for the primary GPU to flush and execute all commands that were queued before that. By using a GPU-side EGLSync we can let the primary GPU inform us when it is done with the queued commands instead. We then create another EGLSync on the secondary GPU using the same fd so the primary GPU effectively signals the secondary GPU when it is done rendering, causing the latter to wait for the former before copying part of the frames it needs for monitors attached to it directly. This solves the corruption that cogl_framebuffer_finish also solved, but without needing a CPU-side stall. (cherry picked from commit 3a40413f7cf036622da3c22c609b703c138c709c) Part-of: Signed-off-by: Mingi Sung --- src/backends/native/meta-onscreen-native.c | 46 +++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c index 021ada367..64400b1ba 100644 --- a/src/backends/native/meta-onscreen-native.c +++ b/src/backends/native/meta-onscreen-native.c @@ -29,6 +29,7 @@ #include "backends/native/meta-onscreen-native.h" +#include #include #include "backends/meta-egl-ext.h" @@ -851,12 +852,14 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, MetaDrmBufferFlags flags; MetaDrmBufferGbm *buffer_gbm = NULL; struct gbm_bo *bo; + EGLSync egl_sync = EGL_NO_SYNC; + g_autofd int sync_fd = -1; COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferSecondaryGpu, "copy_shared_framebuffer_gpu()"); if (renderer_gpu_data->secondary.needs_explicit_sync) - cogl_framebuffer_finish (COGL_FRAMEBUFFER (onscreen)); + sync_fd = cogl_context_get_latest_sync_fd (cogl_context); render_device = renderer_gpu_data->render_device; egl_display = meta_render_device_get_egl_display (render_device); @@ -872,6 +875,36 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, goto done; } + if (sync_fd >= 0) + { + EGLAttrib attribs[3]; + + attribs[0] = EGL_SYNC_NATIVE_FENCE_FD_ANDROID; + attribs[1] = g_steal_fd (&sync_fd); + attribs[2] = EGL_NONE; + + if (!meta_egl_create_sync (egl, + egl_display, + EGL_SYNC_NATIVE_FENCE_ANDROID, + attribs, + &egl_sync, + error)) + { + g_prefix_error (error, "Failed to create EGLSync on secondary GPU: "); + goto done; + } + + if (!meta_egl_wait_sync (egl, + egl_display, + egl_sync, + 0, + error)) + { + g_prefix_error (error, "Failed to wait for EGLSync on secondary GPU: "); + goto done; + } + } + buffer_gbm = META_DRM_BUFFER_GBM (primary_gpu_fb); bo = meta_drm_buffer_gbm_get_bo (buffer_gbm); if (!meta_renderer_native_gles3_blit_shared_bo (egl, @@ -919,6 +952,17 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, g_object_unref); done: + if (egl_sync != EGL_NO_SYNC) + { + g_autoptr (GError) local_error = NULL; + + if (!meta_egl_destroy_sync (egl, + egl_display, + egl_sync, + &local_error)) + g_warning ("Failed to destroy secondary GPU EGLSync: %s", local_error->message); + } + _cogl_winsys_egl_ensure_current (cogl_display); return buffer_gbm ? META_DRM_BUFFER (buffer_gbm) : NULL;