summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2018-03-17 21:57:08 -0300
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2018-03-21 03:01:54 -0300
commit67f8a3c52111a78313ae5b68ab8965f94672176f (patch)
treed5657d66efc3f6b390c498d2b2d0817b3a963ffe
parent602844ffcc562e45bb3ac9dee8ba6f757b9affeb (diff)
downloadmutter-gbsneto/wayland-stutter.tar.gz
gpu-kms: Ignore GPUs with no connectorsgbsneto/wayland-stutter
Mutter recently gained the ability to deal with multiple GPUs rendering at different displays. These GPUs would have a display connected to them, and Mutter was adapted in order to be aware of different GPUs and their outputs. However, one specific edge case appeared: PRIME systems. PRIME systems have two GPUs: * The integrated GPU (iGPU), usually Intel, which has connectors and deals with the routine load. * The dedicated GPU (dGPU), usually AMD or NVidia, which has no connectors at all and are there just to aid heavy loads. On those systems, the dGPU is aggressively put to sleep by the kernel to avoid energy waste. Waking it up is a costly operation. With Mutter's adaptation to deal with multiple GPUs, Mutter began wakening the dGPU every time some rendering had to be done. This was causing stuttering every time the dGPU was put to sleep, and Mutter asked it to wake up again. To fix this situation, this commit ignores GPUs with no connectors attached. Issue: #77
-rw-r--r--src/backends/native/meta-gpu-kms.c31
-rw-r--r--src/backends/native/meta-gpu-kms.h8
-rw-r--r--src/backends/native/meta-monitor-manager-kms.c7
3 files changed, 44 insertions, 2 deletions
diff --git a/src/backends/native/meta-gpu-kms.c b/src/backends/native/meta-gpu-kms.c
index 11951f557..b33389de6 100644
--- a/src/backends/native/meta-gpu-kms.c
+++ b/src/backends/native/meta-gpu-kms.c
@@ -64,6 +64,7 @@ struct _MetaGpuKms
gboolean page_flips_not_supported;
};
+G_DEFINE_QUARK (MetaGpuKmsError, meta_gpu_kms_error)
G_DEFINE_TYPE (MetaGpuKms, meta_gpu_kms, META_TYPE_GPU)
static gboolean
@@ -751,6 +752,8 @@ meta_gpu_kms_read_current (MetaGpu *gpu,
are freed by the platform-independent layer. */
free_resources (gpu_kms);
+ g_assert (resources.resources->count_connectors > 0);
+
init_connectors (gpu_kms, resources.resources);
init_modes (gpu_kms, resources.resources);
init_crtcs (gpu_kms, &resources);
@@ -774,12 +777,40 @@ meta_gpu_kms_new (MetaMonitorManagerKms *monitor_manager_kms,
GSource *source;
MetaKmsSource *kms_source;
MetaGpuKms *gpu_kms;
+ drmModeRes *drm_resources;
+ guint n_connectors;
int kms_fd;
kms_fd = meta_launcher_open_restricted (launcher, kms_file_path, error);
if (kms_fd == -1)
return NULL;
+ /* Some GPUs might have no connectors, for example dedicated GPUs on PRIME (hybrid) laptops.
+ * These GPUs cannot render anything on separate screens, and they are aggressively switched
+ * off by the kernel.
+ *
+ * If we add these PRIME GPUs to the GPU list anyway, Mutter keeps awakening the secondary GPU,
+ * and doing this causes a considerable stuttering. These GPUs are usually put to sleep again
+ * after ~2s without a workload.
+ *
+ * For now, to avoid this situation, only create the MetaGpuKms when the GPU has any connectors.
+ */
+ drm_resources = drmModeGetResources (kms_fd);
+
+ n_connectors = drm_resources->count_connectors;
+
+ drmModeFreeResources (drm_resources);
+
+ if (n_connectors == 0)
+ {
+ g_set_error (error,
+ META_GPU_KMS_ERROR,
+ META_GPU_KMS_ERROR_NO_CONNECTORS,
+ "No connectors available in this GPU. This is probably a dedicated GPU in a hybrid setup.");
+ meta_launcher_close_restricted (launcher, kms_fd);
+ return NULL;
+ }
+
gpu_kms = g_object_new (META_TYPE_GPU_KMS,
"monitor-manager", monitor_manager_kms,
NULL);
diff --git a/src/backends/native/meta-gpu-kms.h b/src/backends/native/meta-gpu-kms.h
index 6c7d5a312..3d0f5f65e 100644
--- a/src/backends/native/meta-gpu-kms.h
+++ b/src/backends/native/meta-gpu-kms.h
@@ -29,6 +29,14 @@
#include "backends/meta-gpu.h"
#include "backends/native/meta-monitor-manager-kms.h"
+typedef enum
+{
+ META_GPU_KMS_ERROR_NO_CONNECTORS,
+} MetaGpuKmsError;
+
+#define META_GPU_KMS_ERROR (meta_gpu_kms_error_quark ())
+GQuark meta_gpu_kms_error_quark (void);
+
#define META_TYPE_GPU_KMS (meta_gpu_kms_get_type ())
G_DECLARE_FINAL_TYPE (MetaGpuKms, meta_gpu_kms, META, GPU_KMS, MetaGpu)
diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c
index 3cee754d1..1a2eaec56 100644
--- a/src/backends/native/meta-monitor-manager-kms.c
+++ b/src/backends/native/meta-monitor-manager-kms.c
@@ -681,8 +681,11 @@ meta_monitor_manager_kms_initable_init (GInitable *initable,
gpu_kms = meta_gpu_kms_new (manager_kms, gpu_path, &secondary_error);
if (!gpu_kms)
{
- g_warning ("Failed to open secondary gpu '%s': %s",
- gpu_path, secondary_error->message);
+ if (g_error_matches (secondary_error, META_GPU_KMS_ERROR, META_GPU_KMS_ERROR_NO_CONNECTORS))
+ g_message ("Ignoring GPU %s due to the lack of connectors", gpu_path);
+ else
+ g_warning ("Failed to open secondary gpu '%s': %s", gpu_path, secondary_error->message);
+
continue;
}