From 22f865122cdab3a7b843c9e29e1da6b0c2f0b567 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 10 Dec 2018 16:49:58 +0200 Subject: [PATCH] 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 https://gitlab.gnome.org/GNOME/mutter/merge_requests/271 --- src/backends/native/meta-renderer-native.c | 83 +++++++++++++++++----- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index bd63347c8..1b74ae17c 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -112,6 +112,7 @@ typedef struct _MetaRendererNativeGpuData */ struct { MetaSharedFramebufferCopyMode copy_mode; + gboolean is_hardware_rendering; /* For GPU blit mode */ EGLContext egl_context; @@ -3207,6 +3208,8 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data, EGLConfig egl_config; EGLContext egl_context; char **missing_gl_extensions; + const char *renderer_str; + gboolean is_hardware; if (!create_secondary_egl_config (egl, renderer_gpu_data->mode, egl_display, &egl_config, error)) @@ -3229,6 +3232,14 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data, 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, &missing_gl_extensions, "GL_OES_EGL_image_external", @@ -3244,6 +3255,7 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data, 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_config = egl_config; 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 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; } @@ -3272,6 +3285,16 @@ init_secondary_gpu_data (MetaRendererNativeGpuData *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 * create_renderer_gpu_data_gbm (MetaRendererNative *renderer_native, MetaGpuKms *gpu_kms, @@ -3619,31 +3642,54 @@ on_gpu_added (MetaMonitorManager *monitor_manager, } static MetaGpuKms * -choose_primary_gpu (MetaMonitorManager *manager) +choose_primary_gpu (MetaMonitorManager *manager, + MetaRendererNative *renderer_native) { GList *gpus = meta_monitor_manager_get_gpus (manager); GList *l; + int allow_sw; - /* Prefer a platform device */ - for (l = gpus; l; l = l->next) - { - MetaGpuKms *gpu_kms = META_GPU_KMS (l->data); + /* + * Check first hardware rendering devices, and if none found, + * then software rendering devices. + */ + 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)) - return gpu_kms; - } + if (meta_gpu_kms_is_platform_device (gpu_kms) && + (allow_sw == 1 || + gpu_kms_is_hardware_rendering (renderer_native, gpu_kms))) + return gpu_kms; + } - /* Otherwise a device we booted with */ - for (l = gpus; l; l = l->next) - { - MetaGpuKms *gpu_kms = META_GPU_KMS (l->data); + /* Otherwise a device we booted with */ + for (l = gpus; l; l = l->next) + { + MetaGpuKms *gpu_kms = META_GPU_KMS (l->data); - if (meta_gpu_kms_is_boot_vga (gpu_kms)) - return gpu_kms; - } + if (meta_gpu_kms_is_boot_vga (gpu_kms) && + (allow_sw == 1 || + gpu_kms_is_hardware_rendering (renderer_native, gpu_kms))) + return gpu_kms; + } - /* Lastly, just pick the first device */ - return META_GPU_KMS (gpus->data); + /* Fall back to any device */ + 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 @@ -3668,7 +3714,8 @@ meta_renderer_native_initable_init (GInitable *initable, 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; }