{ pkgs
, lib
, config
, ... }: with lib; let
  cfg = config.global.gpu;

  intel = cfg.type == "intel" || (cfg.type == "prime" && config.hardware.nvidia.prime.intelBusId != "");
  amdgpu = cfg.type == "amdgpu" || (cfg.type == "prime" && config.hardware.nvidia.prime.amdgpuBusId != "");
  nvidia = cfg.type == "nvidia" || cfg.type == "prime";
in {
  imports = [
    ./plymouth.nix
    ./greetd.nix
  ];

  options.global.gpu = {
    enable = mkEnableOption "various setup required for GUI and support software";
    session = mkEnableOption "software required for a graphical session" // { default = true; };
    type = mkOption {
      type = with types; nullOr (enum [ "intel" "amdgpu" "nvidia" "prime" ]);
      default = null;
      description = "type of graphics acceleration used";
    };
    arc = mkOption {
      type = with types; nullOr str;
      default = null;
      description = "intel arc PCI ID if installed, enables toggling the arc before boot";
    };
  };

  config = mkIf cfg.enable {
    hardware.opengl = {
      enable = true;
      driSupport = true;
      driSupport32Bit = true;

      # https://nixos.wiki/wiki/Accelerated_Video_Playback
      extraPackages = with pkgs; optionals intel [
        intel-media-driver # LIBVA_DRIVER_NAME=iHD
        vaapiIntel         # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium)
        vaapiVdpau
        libvdpau-va-gl
        intel-compute-runtime
      ] ++
      optional nvidia nvidia-vaapi-driver ++
      optional (cfg.type == "nvidia") vulkan-validation-layers;
    };

    services.xserver = mkIf cfg.session {
      videoDrivers =
      optional nvidia "nvidia" ++
      optional (cfg.type == "amdgpu") "amdgpu";
      # inhibits default display manager

      displayManager.startx.enable = mkDefault true;
    };

    hardware.nvidia = mkIf nvidia {
      modesetting.enable = true;
      nvidiaSettings = true;

      prime = mkIf (cfg.type == "prime") {
        offload = {
          enable = true;
          enableOffloadCmd = true;
        };
      };

      powerManagement.enable = false;
      powerManagement.finegrained = false;
      open = false;
    };

    environment.variables = {
      # work around broken nvidia hw cursor on wayland
      WLR_NO_HARDWARE_CURSORS = mkIf (cfg.type == "nvidia") "1";
      # work around wlroots flickering on pure nvidia
      WLR_RENDERER = mkIf (cfg.type == "nvidia") "vulkan";
    };

    specialisation.integratedGraphics = mkIf (cfg.type == "prime") {
      configuration = {
        global.gpu.type = mkForce (if intel then "intel" else if amdgpu then "amdgpu" else "prime");
        boot.blacklistedKernelModules = [ "nouveau" ];
      };
    };

    specialisation.withArc = mkIf (cfg.arc != null) {
      configuration = {
        global.gpu.arc = mkForce null;
        powerManagement.cpuFreqGovernor = mkForce "performance";
      };
    };

    boot.initrd.kernelModules =
    optional amdgpu "amdgpu" ++
    optional (intel && cfg.arc == null) "i915" ++
    optionals nvidia [ "nvidia" "nvidia_drm" "nvidia_modeset" "nvidia_uvm" ] ++
    optional (cfg.arc != null) "vfio-pci";

    boot.extraModulePackages = optional nvidia config.boot.kernelPackages.nvidia_x11;

    boot.extraModprobeConfig = mkIf (cfg.arc != null) ''
      softdep drm pre: vfio-pci
      options vfio-pci ids=${cfg.arc}
    '';

    boot.kernelParams = optional intel "i915.fastboot=1";
  };
}
