summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nixos/modules/hardware/video/nvidia.nix120
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix11
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix12
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix6
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix4
-rw-r--r--nixos/modules/services/x11/xserver.nix10
-rw-r--r--pkgs/desktops/gnome-3/core/gdm/default.nix16
-rw-r--r--pkgs/desktops/gnome-3/core/gdm/gdm-session-worker_forward-vars.patch31
-rw-r--r--pkgs/desktops/gnome-3/core/gdm/gdm-session-worker_xserver-path.patch17
-rw-r--r--pkgs/desktops/gnome-3/core/gdm/gdm-x-session_session-wrapper.patch40
10 files changed, 244 insertions, 23 deletions
diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix
index eb1952280331..6944d1a4f76b 100644
--- a/nixos/modules/hardware/video/nvidia.nix
+++ b/nixos/modules/hardware/video/nvidia.nix
@@ -26,9 +26,73 @@ let
nvidia_libs32 = (nvidiaForKernel pkgs_i686.linuxPackages).override { libsOnly = true; kernel = null; };
enabled = nvidia_x11 != null;
+
+ cfg = config.hardware.nvidia;
+ optimusCfg = cfg.optimus_prime;
in
{
+ options = {
+ hardware.nvidia.modesetting.enable = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Enable kernel modesetting when using the NVIDIA proprietary driver.
+
+ Enabling this fixes screen tearing when using Optimus via PRIME (see
+ <option>hardware.nvidia.optimus_prime.enable</option>. This is not enabled
+ by default because it is not officially supported by NVIDIA and would not
+ work with SLI.
+ '';
+ };
+
+ hardware.nvidia.optimus_prime.enable = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Enable NVIDIA Optimus support using the NVIDIA proprietary driver via PRIME.
+ If enabled, the NVIDIA GPU will be always on and used for all rendering,
+ while enabling output to displays attached only to the integrated Intel GPU
+ without a multiplexer.
+
+ Note that this option only has any effect if the "nvidia" driver is specified
+ in <option>services.xserver.videoDrivers</option>, and it should preferably
+ be the only driver there.
+
+ If this is enabled, then the bus IDs of the NVIDIA and Intel GPUs have to be
+ specified (<option>hardware.nvidia.optimus_prime.nvidiaBusId</option> and
+ <option>hardware.nvidia.optimus_prime.intelBusId</option>).
+
+ If you enable this, you may want to also enable kernel modesetting for the
+ NVIDIA driver (<option>hardware.nvidia.modesetting.enable</option>) in order
+ to prevent tearing.
+
+ Note that this configuration will only be successful when a display manager
+ for which the <option>services.xserver.displayManager.setupCommands</option>
+ option is supported is used; notably, SLiM is not supported.
+ '';
+ };
+
+ hardware.nvidia.optimus_prime.nvidiaBusId = lib.mkOption {
+ type = lib.types.string;
+ default = "";
+ example = "PCI:1:0:0";
+ description = ''
+ Bus ID of the NVIDIA GPU. You can find it using lspci; for example if lspci
+ shows the NVIDIA GPU at "01:00.0", set this option to "PCI:1:0:0".
+ '';
+ };
+
+ hardware.nvidia.optimus_prime.intelBusId = lib.mkOption {
+ type = lib.types.string;
+ default = "";
+ example = "PCI:0:2:0";
+ description = ''
+ Bus ID of the Intel GPU. You can find it using lspci; for example if lspci
+ shows the Intel GPU at "00:02.0", set this option to "PCI:0:2:0".
+ '';
+ };
+ };
config = mkIf enabled {
assertions = [
@@ -36,16 +100,62 @@ in
assertion = config.services.xserver.displayManager.gdm.wayland;
message = "NVidia drivers don't support wayland";
}
+ {
+ assertion = !optimusCfg.enable ||
+ (optimusCfg.nvidiaBusId != "" && optimusCfg.intelBusId != "");
+ message = ''
+ When NVIDIA Optimus via PRIME is enabled, the GPU bus IDs must configured.
+ '';
+ }
];
- services.xserver.drivers = singleton
- { name = "nvidia"; modules = [ nvidia_x11.bin ]; libPath = [ nvidia_x11 ]; };
+ # If Optimus/PRIME is enabled, we:
+ # - Specify the configured NVIDIA GPU bus ID in the Device section for the
+ # "nvidia" driver.
+ # - Add the AllowEmptyInitialConfiguration option to the Screen section for the
+ # "nvidia" driver, in order to allow the X server to start without any outputs.
+ # - Add a separate Device section for the Intel GPU, using the "modesetting"
+ # driver and with the configured BusID.
+ # - Reference that Device section from the ServerLayout section as an inactive
+ # device.
+ # - Configure the display manager to run specific `xrandr` commands which will
+ # configure/enable displays connected to the Intel GPU.
+
+ services.xserver.drivers = singleton {
+ name = "nvidia";
+ modules = [ nvidia_x11.bin ];
+ libPath = [ nvidia_x11 ];
+ deviceSection = optionalString optimusCfg.enable
+ ''
+ BusID "${optimusCfg.nvidiaBusId}"
+ '';
+ screenSection =
+ ''
+ Option "RandRRotation" "on"
+ ${optionalString optimusCfg.enable "Option \"AllowEmptyInitialConfiguration\""}
+ '';
+ };
- services.xserver.screenSection =
+ services.xserver.extraConfig = optionalString optimusCfg.enable
+ ''
+ Section "Device"
+ Identifier "nvidia-optimus-intel"
+ Driver "modesetting"
+ BusID "${optimusCfg.intelBusId}"
+ Option "AccelMethod" "none"
+ EndSection
+ '';
+ services.xserver.serverLayoutSection = optionalString optimusCfg.enable
''
- Option "RandRRotation" "on"
+ Inactive "nvidia-optimus-intel"
'';
+ services.xserver.displayManager.setupCommands = optionalString optimusCfg.enable ''
+ # Added by nvidia configuration module for Optimus/PRIME.
+ ${pkgs.xorg.xrandr}/bin/xrandr --setprovideroutputsource modesetting NVIDIA-0
+ ${pkgs.xorg.xrandr}/bin/xrandr --auto
+ '';
+
environment.etc."nvidia/nvidia-application-profiles-rc" = mkIf nvidia_x11.useProfiles {
source = "${nvidia_x11.bin}/share/nvidia/nvidia-application-profiles-rc";
};
@@ -62,6 +172,8 @@ in
boot.kernelModules = [ "nvidia-uvm" ] ++
lib.optionals config.services.xserver.enable [ "nvidia" "nvidia_modeset" "nvidia_drm" ];
+ # If requested enable modesetting via kernel parameter.
+ boot.kernelParams = optional cfg.modesetting.enable "nvidia-drm.modeset=1";
# Create /dev/nvidia-uvm when the nvidia-uvm module is loaded.
services.udev.extraRules =
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 357fa8ce8f36..26b79730dd38 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -222,6 +222,17 @@ in
description = "List of arguments for the X server.";
};
+ setupCommands = mkOption {
+ type = types.lines;
+ default = "";
+ description = ''
+ Shell commands executed just after the X server has started.
+
+ This option is only effective for display managers for which this feature
+ is supported; currently these are LightDM, GDM and SDDM.
+ '';
+ };
+
sessionCommands = mkOption {
type = types.lines;
default = "";
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index a16cbee3bb39..6cc30b218f4a 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -7,6 +7,13 @@ let
cfg = config.services.xserver.displayManager;
gdm = pkgs.gnome3.gdm;
+ xSessionWrapper = if (cfg.setupCommands == "") then null else
+ pkgs.writeScript "gdm-x-session-wrapper" ''
+ #!${pkgs.bash}/bin/bash
+ ${cfg.setupCommands}
+ exec "$@"
+ '';
+
in
{
@@ -112,6 +119,11 @@ in
GDM_SESSIONS_DIR = "${cfg.session.desktops}/share/xsessions";
# Find the mouse
XCURSOR_PATH = "~/.icons:${pkgs.gnome3.adwaita-icon-theme}/share/icons";
+ } // optionalAttrs (xSessionWrapper != null) {
+ # Make GDM use this wrapper before running the session, which runs the
+ # configured setupCommands. This relies on a patched GDM which supports
+ # this environment variable.
+ GDM_X_SESSION_WRAPPER = "${xSessionWrapper}";
};
execCmd = "exec ${gdm}/bin/gdm";
};
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index a34f2370649f..16f1ddea1a75 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -62,6 +62,12 @@ let
${optionalString hasDefaultUserSession ''
user-session=${defaultSessionName}
''}
+ ${optionalString (dmcfg.setupCommands != "") ''
+ display-setup-script=${pkgs.writeScript "lightdm-display-setup" ''
+ #!${pkgs.bash}/bin/bash
+ ${dmcfg.setupCommands}
+ ''}
+ ''}
${cfg.extraSeatDefaults}
'';
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index 2a9826177737..522a0dc92d6f 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -20,6 +20,7 @@ let
Xsetup = pkgs.writeScript "Xsetup" ''
#!/bin/sh
${cfg.setupScript}
+ ${dmcfg.setupCommands}
'';
Xstop = pkgs.writeScript "Xstop" ''
@@ -137,7 +138,8 @@ in
xrandr --auto
'';
description = ''
- A script to execute when starting the display server.
+ A script to execute when starting the display server. DEPRECATED, please
+ use <option>services.xserver.displayManager.setupCommands</option>.
'';
};
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index 75bfeaac1fa3..297e36311656 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -374,6 +374,12 @@ in
description = "Contents of the first Monitor section of the X server configuration file.";
};
+ extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ description = "Additional contents (sections) included in the X server configuration file";
+ };
+
xrandrHeads = mkOption {
default = [];
example = [
@@ -754,6 +760,7 @@ in
Driver "${driver.driverName or driver.name}"
${if cfg.useGlamor then ''Option "AccelMethod" "glamor"'' else ""}
${cfg.deviceSection}
+ ${driver.deviceSection or ""}
${xrandrDeviceSection}
EndSection
@@ -765,6 +772,7 @@ in
''}
${cfg.screenSection}
+ ${driver.screenSection or ""}
${optionalString (cfg.defaultDepth != 0) ''
DefaultDepth ${toString cfg.defaultDepth}
@@ -794,6 +802,8 @@ in
'')}
${xrandrMonitorSections}
+
+ ${cfg.extraConfig}
'';
fonts.enableDefaultFonts = mkDefault true;
diff --git a/pkgs/desktops/gnome-3/core/gdm/default.nix b/pkgs/desktops/gnome-3/core/gdm/default.nix
index 6c810eb46342..f6049c8bda8c 100644
--- a/pkgs/desktops/gnome-3/core/gdm/default.nix
+++ b/pkgs/desktops/gnome-3/core/gdm/default.nix
@@ -37,13 +37,27 @@ stdenv.mkDerivation rec {
# Disable Access Control because our X does not support FamilyServerInterpreted yet
patches = [
+ # Change hardcoded paths to nix store paths.
(substituteAll {
src = ./fix-paths.patch;
inherit coreutils plymouth xwayland;
})
+
+ # The following patches implement certain environment variables in GDM which are set by
+ # the gdm configuration module (nixos/modules/services/x11/display-managers/gdm.nix).
+
+ # Look for session definition files in the directory specified by GDM_SESSIONS_DIR.
./sessions_dir.patch
+
+ # Allow specifying X server arguments with GDM_X_SERVER_EXTRA_ARGS.
./gdm-x-session_extra_args.patch
- ./gdm-session-worker_xserver-path.patch
+
+ # Allow specifying a wrapper for running the session command.
+ ./gdm-x-session_session-wrapper.patch
+
+ # Forwards certain environment variables to the gdm-x-session child process
+ # to ensure that the above two patches actually work.
+ ./gdm-session-worker_forward-vars.patch
];
installFlags = [
diff --git a/pkgs/desktops/gnome-3/core/gdm/gdm-session-worker_forward-vars.patch b/pkgs/desktops/gnome-3/core/gdm/gdm-session-worker_forward-vars.patch
new file mode 100644
index 000000000000..401b6aea0c28
--- /dev/null
+++ b/pkgs/desktops/gnome-3/core/gdm/gdm-session-worker_forward-vars.patch
@@ -0,0 +1,31 @@
+diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
+index 9ef4c5b..94da834 100644
+--- a/daemon/gdm-session-worker.c
++++ b/daemon/gdm-session-worker.c
+@@ -1515,6 +1515,16 @@ gdm_session_worker_load_env_d (GdmSessionWorker *worker)
+ g_object_unref (dir);
+ }
+
++static void
++gdm_session_worker_forward_var (GdmSessionWorker *worker, char const *var)
++{
++ char const *value = g_getenv(var);
++ if (value != NULL) {
++ g_debug ("forwarding %s= %s", var, value);
++ gdm_session_worker_set_environment_variable(worker, var, value);
++ }
++}
++
+ static gboolean
+ gdm_session_worker_accredit_user (GdmSessionWorker *worker,
+ GError **error)
+@@ -1559,6 +1569,9 @@ gdm_session_worker_accredit_user (GdmSessionWorker *worker,
+ goto out;
+ }
+
++ gdm_session_worker_forward_var(worker, "GDM_X_SERVER_EXTRA_ARGS");
++ gdm_session_worker_forward_var(worker, "GDM_X_SESSION_WRAPPER");
++
+ gdm_session_worker_update_environment_from_passwd_info (worker,
+ uid,
+ gid,
diff --git a/pkgs/desktops/gnome-3/core/gdm/gdm-session-worker_xserver-path.patch b/pkgs/desktops/gnome-3/core/gdm/gdm-session-worker_xserver-path.patch
deleted file mode 100644
index d020752fef3a..000000000000
--- a/pkgs/desktops/gnome-3/core/gdm/gdm-session-worker_xserver-path.patch
+++ /dev/null
@@ -1,17 +0,0 @@
-diff --git a/daemon/gdm-session-worker.c.orig b/daemon/gdm-session-worker.c
-index 7bbda49..592691d 100644
---- a/daemon/gdm-session-worker.c.orig
-+++ b/daemon/gdm-session-worker.c
-@@ -1557,6 +1557,12 @@ gdm_session_worker_accredit_user (GdmSessionWorker *worker,
- goto out;
- }
-
-+ if (g_getenv ("GDM_X_SERVER_EXTRA_ARGS") != NULL) {
-+ g_debug ("forwarding GDM_X_SERVER_EXTRA_ARGS= %s", g_getenv("GDM_X_SERVER_EXTRA_ARGS"));
-+ gdm_session_worker_set_environment_variable (worker, "GDM_X_SERVER_EXTRA_ARGS",
-+ g_getenv("GDM_X_SERVER_EXTRA_ARGS"));
-+ }
-+
- gdm_session_worker_update_environment_from_passwd_info (worker,
- uid,
- gid,
diff --git a/pkgs/desktops/gnome-3/core/gdm/gdm-x-session_session-wrapper.patch b/pkgs/desktops/gnome-3/core/gdm/gdm-x-session_session-wrapper.patch
new file mode 100644
index 000000000000..58481f0730fa
--- /dev/null
+++ b/pkgs/desktops/gnome-3/core/gdm/gdm-x-session_session-wrapper.patch
@@ -0,0 +1,40 @@
+diff --git a/daemon/gdm-x-session.c b/daemon/gdm-x-session.c
+index 88fe96f..b1b140a 100644
+--- a/daemon/gdm-x-session.c
++++ b/daemon/gdm-x-session.c
+@@ -664,18 +664,34 @@ spawn_session (State *state,
+ state->session_command,
+ NULL);
+ } else {
++ char const *session_wrapper;
++ char *eff_session_command;
+ int ret;
+ char **argv;
+
+- ret = g_shell_parse_argv (state->session_command,
++ session_wrapper = g_getenv("GDM_X_SESSION_WRAPPER");
++ if (session_wrapper != NULL) {
++ char *quoted_wrapper = g_shell_quote(session_wrapper);
++ eff_session_command = g_strjoin(" ", quoted_wrapper, state->session_command, NULL);
++ g_free(quoted_wrapper);
++ } else {
++ eff_session_command = state->session_command;
++ }
++
++ ret = g_shell_parse_argv (eff_session_command,
+ NULL,
+ &argv,
+ &error);
+
++ if (session_wrapper != NULL) {
++ g_free(eff_session_command);
++ }
++
+ if (!ret) {
+ g_debug ("could not parse session arguments: %s", error->message);
+ goto out;
+ }
++
+ subprocess = g_subprocess_launcher_spawnv (launcher,
+ (const char * const *) argv,
+ &error);