backend: Copy damage rectangles to secondary GPU when available

Systems with AMD GPUs do not take advantage of Mutter's zero-copy path
when driving DisplayLink screens. This is due to a very slow CPU access
to the zero-copy texture. Instead they fall back on primary GPU doing a
copy of the texture for fast CPU access. This commit accelerates texture
copy by working through damage regions only.

Tests on a 4K screen with windowed applications show significant
reduction of GPU utilisation.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2033>
This commit is contained in:
Piotr Łopatka 2021-11-06 14:14:25 +00:00 committed by Marge Bot
parent b1c8ce110c
commit 33529426a9

View File

@ -747,7 +747,9 @@ secondary_gpu_get_next_dumb_buffer (MetaOnscreenNativeSecondaryGpuState *seconda
static gboolean static gboolean
copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscreen, copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscreen,
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state) MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
const int *rectangles,
int n_rectangles)
{ {
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
@ -814,7 +816,11 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre
error->message); error->message);
return FALSE; return FALSE;
} }
/* Limit the number of individual copies to 16 */
#define MAX_RECTS 16
if (n_rectangles == 0 || n_rectangles > MAX_RECTS)
{
if (!cogl_blit_framebuffer (framebuffer, COGL_FRAMEBUFFER (dmabuf_fb), if (!cogl_blit_framebuffer (framebuffer, COGL_FRAMEBUFFER (dmabuf_fb),
0, 0, 0, 0, 0, 0, 0, 0,
width, height, width, height,
@ -823,6 +829,25 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre
g_object_unref (dmabuf_fb); g_object_unref (dmabuf_fb);
return FALSE; return FALSE;
} }
}
else
{
int i;
for (i = 0; i < n_rectangles; ++i)
{
if (!cogl_blit_framebuffer (framebuffer, COGL_FRAMEBUFFER (dmabuf_fb),
rectangles[i * 4], rectangles[i * 4 + 1],
rectangles[i * 4], rectangles[i * 4 + 1],
rectangles[i * 4 + 2],
rectangles[i * 4 + 3],
&error))
{
g_object_unref (dmabuf_fb);
return FALSE;
}
}
}
g_object_unref (dmabuf_fb); g_object_unref (dmabuf_fb);
@ -890,7 +915,9 @@ copy_shared_framebuffer_cpu (CoglOnscreen *onscreen,
} }
static void static void
update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen) update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen,
const int *rectangles,
int n_rectangles)
{ {
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
@ -920,7 +947,9 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen)
G_GNUC_FALLTHROUGH; G_GNUC_FALLTHROUGH;
case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY: case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
if (!copy_shared_framebuffer_primary_gpu (onscreen, if (!copy_shared_framebuffer_primary_gpu (onscreen,
secondary_gpu_state)) secondary_gpu_state,
rectangles,
n_rectangles))
{ {
if (!secondary_gpu_state->noted_primary_gpu_copy_failed) if (!secondary_gpu_state->noted_primary_gpu_copy_failed)
{ {
@ -1041,7 +1070,9 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers, COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers,
"Onscreen (swap-buffers)"); "Onscreen (swap-buffers)");
update_secondary_gpu_state_pre_swap_buffers (onscreen); update_secondary_gpu_state_pre_swap_buffers (onscreen,
rectangles,
n_rectangles);
parent_class = COGL_ONSCREEN_CLASS (meta_onscreen_native_parent_class); parent_class = COGL_ONSCREEN_CLASS (meta_onscreen_native_parent_class);
parent_class->swap_buffers_with_damage (onscreen, parent_class->swap_buffers_with_damage (onscreen,