1
0
Fork 0

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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4015>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
This commit is contained in:
Gert-dev 2024-10-03 14:56:07 +02:00 committed by Mingi Sung
parent a4c0df1b59
commit ab6179b9d7
Signed by: sungmg
GPG key ID: 41BAFD6FFD8036C5

View file

@ -29,6 +29,7 @@
#include "backends/native/meta-onscreen-native.h"
#include <glib/gstdio.h>
#include <drm_fourcc.h>
#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;