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:
parent
a4c0df1b59
commit
ab6179b9d7
1 changed files with 45 additions and 1 deletions
|
@ -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…
Reference in a new issue