{ config, pkgs, lib, ... }:

# READ: https://nixos.wiki/wiki/Nvidia

with lib; let 
  cfg = config.modules.system.gpu.nvidia;
in {

  options.modules.system.gpu.nvidia = {
    enable = mkEnableOption "nvidia";

    open = mkEnableOption "open";
    powerManagement = mkEnableOption "powerManagement";
    finegrained = mkEnableOption "finegrained";
  };

  config = mkIf cfg.enable {
    hardware.graphics = {
      enable = true;
      enable32Bit = true;
    };

    # Load nvidia driver for Xorg and Wayland
    services.xserver.videoDrivers = ["nvidia"];

    hardware.nvidia = {

      # Modesetting is required.
      modesetting.enable = true;

      # Nvidia power management. Experimental, and can cause sleep/suspend to fail.
      # Enable this if you have graphical corruption issues or application crashes after waking
      # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead 
      # of just the bare essentials.
      powerManagement.enable = cfg.powerManagement;

      # Fine-grained power management. Turns off the GPU when not in use.
      powerManagement.finegrained = cfg.finegrained && cfg.powerManagement;

      # Use the NVidia open source kernel module (not to be confused with the
      # independent third-party "nouveau" open source driver).
      # Support is limited to the Turing and later architectures. Full list of 
      # supported GPUs is at: 
      # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus 
      # Only available from driver 515.43.04+
      # Currently alpha-quality/buggy, so false is currently the recommended setting.
      open = cfg.open;

      # Enable the Nvidia settings menu,
      # accessible via `nvidia-settings`.
      nvidiaSettings = true;

      # Optionally, you may need to select the appropriate driver version for your specific GPU.
      package = config.boot.kernelPackages.nvidiaPackages.production;
    };

  };
}
