renderer/native: Prefer hardware rendering for primary GPU

Mutter prefers platform devices over anything else as the primary GPU.
This will not work too well, when a platform device does not actually
have a rendering GPU but is a display-only device. An example of this
are DisplayLink devices with the proprietary driver stack, which exposes
a DRM KMS platform device but without any rendering driver.

Mutter cannot rely on EGL init failing on such devices either, because
nowadays Mesa supports software renderers on GBM, so the initialization
may well succeed.

The hardware rendering capability is recognized by matching the GL
renderer string to the known Mesa software renderers. At this time,
there is no better alternative to detecting this.

The secondary GPU data is abused for the GL renderer, as the Cogl
context may not have been created yet.  Also, the Cogl context would
only be created on the primary GPU, but at this point the primary GPU
has not been chosen yet. Hence, GPU copy path GL context is used as a
proxy and predictor of what the Cogl context might be if it was created.
Mind, that even the GL flavour are not the same between Cogl and
secondary contexts, so this is stretch but it should be just enough.

The logic to choose the primary GPU is changed to always prefer hardware
rendering devices while also maintaining the old order of preferring
platform over boot_vga devices.

Co-authored by: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>

https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
This commit is contained in:
Pekka Paalanen 2018-12-10 16:49:58 +02:00 committed by Jonas Ådahl
parent 60ac2838b5
commit 22f865122c

View File

@ -112,6 +112,7 @@ typedef struct _MetaRendererNativeGpuData
*/ */
struct { struct {
MetaSharedFramebufferCopyMode copy_mode; MetaSharedFramebufferCopyMode copy_mode;
gboolean is_hardware_rendering;
/* For GPU blit mode */ /* For GPU blit mode */
EGLContext egl_context; EGLContext egl_context;
@ -3207,6 +3208,8 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
EGLConfig egl_config; EGLConfig egl_config;
EGLContext egl_context; EGLContext egl_context;
char **missing_gl_extensions; char **missing_gl_extensions;
const char *renderer_str;
gboolean is_hardware;
if (!create_secondary_egl_config (egl, renderer_gpu_data->mode, egl_display, if (!create_secondary_egl_config (egl, renderer_gpu_data->mode, egl_display,
&egl_config, error)) &egl_config, error))
@ -3229,6 +3232,14 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
return FALSE; return FALSE;
} }
renderer_str = (const char *) glGetString (GL_RENDERER);
if (g_str_has_prefix (renderer_str, "llvmpipe") ||
g_str_has_prefix (renderer_str, "softpipe") ||
g_str_has_prefix (renderer_str, "swrast"))
is_hardware = FALSE;
else
is_hardware = TRUE;
if (!meta_gles3_has_extensions (renderer_native->gles3, if (!meta_gles3_has_extensions (renderer_native->gles3,
&missing_gl_extensions, &missing_gl_extensions,
"GL_OES_EGL_image_external", "GL_OES_EGL_image_external",
@ -3244,6 +3255,7 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
g_free (missing_gl_extensions); g_free (missing_gl_extensions);
} }
renderer_gpu_data->secondary.is_hardware_rendering = is_hardware;
renderer_gpu_data->secondary.egl_context = egl_context; renderer_gpu_data->secondary.egl_context = egl_context;
renderer_gpu_data->secondary.egl_config = egl_config; renderer_gpu_data->secondary.egl_config = egl_config;
renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_GPU; renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_GPU;
@ -3254,6 +3266,7 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
static void static void
init_secondary_gpu_data_cpu (MetaRendererNativeGpuData *renderer_gpu_data) init_secondary_gpu_data_cpu (MetaRendererNativeGpuData *renderer_gpu_data)
{ {
renderer_gpu_data->secondary.is_hardware_rendering = FALSE;
renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_CPU; renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_CPU;
} }
@ -3272,6 +3285,16 @@ init_secondary_gpu_data (MetaRendererNativeGpuData *renderer_gpu_data)
init_secondary_gpu_data_cpu (renderer_gpu_data); init_secondary_gpu_data_cpu (renderer_gpu_data);
} }
static gboolean
gpu_kms_is_hardware_rendering (MetaRendererNative *renderer_native,
MetaGpuKms *gpu_kms)
{
MetaRendererNativeGpuData *data;
data = meta_renderer_native_get_gpu_data (renderer_native, gpu_kms);
return data->secondary.is_hardware_rendering;
}
static MetaRendererNativeGpuData * static MetaRendererNativeGpuData *
create_renderer_gpu_data_gbm (MetaRendererNative *renderer_native, create_renderer_gpu_data_gbm (MetaRendererNative *renderer_native,
MetaGpuKms *gpu_kms, MetaGpuKms *gpu_kms,
@ -3619,31 +3642,54 @@ on_gpu_added (MetaMonitorManager *monitor_manager,
} }
static MetaGpuKms * static MetaGpuKms *
choose_primary_gpu (MetaMonitorManager *manager) choose_primary_gpu (MetaMonitorManager *manager,
MetaRendererNative *renderer_native)
{ {
GList *gpus = meta_monitor_manager_get_gpus (manager); GList *gpus = meta_monitor_manager_get_gpus (manager);
GList *l; GList *l;
int allow_sw;
/* Prefer a platform device */ /*
for (l = gpus; l; l = l->next) * Check first hardware rendering devices, and if none found,
{ * then software rendering devices.
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data); */
for (allow_sw = 0; allow_sw < 2; allow_sw++)
{
/* Prefer a platform device */
for (l = gpus; l; l = l->next)
{
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
if (meta_gpu_kms_is_platform_device (gpu_kms)) if (meta_gpu_kms_is_platform_device (gpu_kms) &&
return gpu_kms; (allow_sw == 1 ||
} gpu_kms_is_hardware_rendering (renderer_native, gpu_kms)))
return gpu_kms;
}
/* Otherwise a device we booted with */ /* Otherwise a device we booted with */
for (l = gpus; l; l = l->next) for (l = gpus; l; l = l->next)
{ {
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data); MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
if (meta_gpu_kms_is_boot_vga (gpu_kms)) if (meta_gpu_kms_is_boot_vga (gpu_kms) &&
return gpu_kms; (allow_sw == 1 ||
} gpu_kms_is_hardware_rendering (renderer_native, gpu_kms)))
return gpu_kms;
}
/* Lastly, just pick the first device */ /* Fall back to any device */
return META_GPU_KMS (gpus->data); for (l = gpus; l; l = l->next)
{
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
if (allow_sw == 1 ||
gpu_kms_is_hardware_rendering (renderer_native, gpu_kms))
return gpu_kms;
}
}
g_assert_not_reached ();
return NULL;
} }
static gboolean static gboolean
@ -3668,7 +3714,8 @@ meta_renderer_native_initable_init (GInitable *initable,
return FALSE; return FALSE;
} }
renderer_native->primary_gpu_kms = choose_primary_gpu (monitor_manager); renderer_native->primary_gpu_kms = choose_primary_gpu (monitor_manager,
renderer_native);
return TRUE; return TRUE;
} }