{ config, lib, pkgs, ... }: { hardware.graphics = { enable = true; enable32Bit = true; }; # --- Hybrid graphics: AMD Radeon 680M (iGPU, drives the internal panel) # + NVIDIA RTX 4050 Max-Q (dGPU, offload-only) — ASUS TUF Gaming A15 # FA507NU. Bus IDs come straight from `lspci` on this machine, not # guessed: 01:00.0 (NVIDIA) -> PCI:1:0:0, 35:00.0 (AMD) -> PCI:53:0:0 # (the PCI: form is decimal, 0x35 = 53). services.xserver.videoDrivers = [ "nvidia" ]; hardware.nvidia = { modesetting.enable = true; # Open GPU kernel modules — fine on Turing or newer, and this Ada # Lovelace RTX 4050 is well within support. open = true; nvidiaSettings = true; package = config.boot.kernelPackages.nvidiaPackages.stable; # Preserves video memory across suspend/resume, which is what fixes the # classic NVIDIA-laptop "black screen after lid close" hang. powerManagement.enable = true; # Runtime PM, i.e. letting the dGPU drop to D3cold when idle, is left # off on purpose: supergfxd below already power-cycles the dGPU when you # switch to Integrated mode, and driving both power paths at once is the # usual source of resume hangs on TUF laptops. If you want to try it: # powerManagement.finegrained = true; # PRIME render offload: the AMD iGPU drives the display at all times # (much better battery life than keeping the dGPU powered on), and the # NVIDIA GPU only spins up on demand for a specific process — run # anything with `nvidia-offload ` (generated by # enableOffloadCmd) to route it through the RTX 4050, e.g. games or # Blender's Cycles renderer. prime = { offload = { enable = true; enableOffloadCmd = true; }; amdgpuBusId = "PCI:53:0:0"; nvidiaBusId = "PCI:1:0:0"; }; }; # ASUS laptop control: keyboard backlight/fan curves/battery charge limit # (asusctl) and dGPU power-state switching between Integrated/Hybrid modes # (supergfxctl) — the two standard asus-linux.org daemons for ROG/TUF # laptops, both packaged directly in nixpkgs. services.asusd.enable = true; services.supergfxd.enable = true; hardware.opentabletdriver.enable = true; hardware.uinput.enable = true; boot.kernelModules = [ "uinput" "v4l2loopback" ]; # Virtual webcam device so ffmpeg (fed by the GoPro's stream) can appear # as a normal camera to apps like Discord. exclusive_caps=1 is required # for Chromium/WebRTC-based apps to recognize it as a real capture device. boot.extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ]; boot.extraModprobeConfig = '' options v4l2loopback devices=1 video_nr=10 card_label="GoPro Webcam" exclusive_caps=1 # DualSense/PS4 pads pair over Bluetooth then drop instantly; broken # ERTM in many adapters. Disabling it is the standard fix. options bluetooth disable_ertm=1 ''; hardware.bluetooth = { enable = true; powerOnBoot = true; settings = { General = { Experimental = true; # Battery level of connected devices FastConnectable = true; # Faster reconnects, more power draw }; Policy = { AutoEnable = true; }; }; }; # No blueman here: Plasma brings its own Bluetooth stack (bluedevil), and # running the GTK applet alongside it just gives you two tray icons # fighting over the same adapter. The desktop repo still has it enabled, # left over from the Budgie days. # Blog V4 needs the rtlsdrblog fork of librtlsdr, which is what # pkgs.rtl-sdr already is here. Also blacklists the DVB-T drivers. hardware.rtl-sdr.enable = true; # I2C bus, for DDC/CI brightness on an external monitor over HDMI/USB-C # via ddcutil. The internal panel goes through the kernel backlight class # instead — brightness-ctl picks whichever applies, see # modules/scripts/brightness-ctl.sh. hardware.i2c.enable = true; services.udev.extraRules = '' # ddcutil without root (i2c group, see modules/users.nix) SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660" ''; # No OpenRGB: that's the desktop's motherboard/RAM lighting. The keyboard # backlight on this machine is asusd's job (`asusctl aura`). services.printing.enable = true; }