gpu-kms: Ignore GPUs with no connectors

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
parent 14b7e79d
......@@ -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);
......
......@@ -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)
......
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment