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. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4015>
This commit is contained in:
parent
9cb01597c9
commit
ceed33b68e
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user