#!/usr/bin/env bash

# Description:
#   Select which GPU to use for rendering by Hyprland and Niri.
#
# Envs exported:
#   HYPR_AQ_DRM_DEVICES - Colon-separated list of DRM device paths for Hyprland's AQ_DRM_DEVICES env
#   BRIGHTNESSCTL_DEVICE - Device identifier for brightnessctl

# Constants
niri_config_file="$HOME/.config/niri/config/misc.kdl"
prefer_order=(nvidia intel)

# Get vendor and path of each GPU
default_card_path="$(find /dev/dri/card* 2>/dev/null | head -n 1)"
default_render_path="$(find /dev/dri/renderD* 2>/dev/null | head -n 1)"
[[ -z "$default_card_path" ]] && default_card_path="/dev/dri/card0"
[[ -z "$default_render_path" ]] && default_render_path="/dev/dri/renderD128"
intel_card_path=""
nvidia_card_path=""
amd_card_path=""
intel_render_path=""
nvidia_render_path=""
amd_render_path=""

for link in /dev/dri/by-path/*-card; do
	[[ -e "$link" ]] || continue
	card="$(readlink -f "$link")"
	vfile="/sys/class/drm/$(basename "$card")/device/vendor"
	[[ -r "$vfile" ]] || continue
	vendor="$(cat "$vfile")"
	case "$vendor" in
	0x10de) nvidia_card_path="$card" ;;
	0x8086) intel_card_path="$card" ;;
	0x1002) amd_card_path="$card" ;;
	esac
done

for link in /dev/dri/by-path/*-render; do
	[[ -e "$link" ]] || continue
	render="$(readlink -f "$link")"
	vfile="/sys/class/drm/$(basename "$render")/device/vendor"
	[[ -r "$vfile" ]] || continue
	vendor="$(cat "$vfile")"
	case "$vendor" in
	0x10de) nvidia_render_path="$render" ;;
	0x8086) intel_render_path="$render" ;;
	0x1002) amd_render_path="$render" ;;
	esac
done

# Specify device for brightnessctl
# Only tested on my laptop with Intel iGPU & Nvidia dGPU
BRIGHTNESSCTL_DEVICE="auto"
if [[ -n "$intel_card_path" ]]; then
	BRIGHTNESSCTL_DEVICE="intel_backlight"
elif [[ -n "$nvidia_card_path" ]]; then
	BRIGHTNESSCTL_DEVICE="nvidia_0"
fi
export BRIGHTNESSCTL_DEVICE

# AQ_DRM_DEVICES allows multiple entries separated by colon
devices=""
for who in "${prefer_order[@]}"; do
	case "$who" in
	nvidia) [[ -n "$nvidia_card_path" ]] && devices="${devices:+$devices:}$nvidia_card_path" ;;
	intel) [[ -n "$intel_card_path" ]] && devices="${devices:+$devices:}$intel_card_path" ;;
	amd) [[ -n "$amd_card_path" ]] && devices="${devices:+$devices:}$amd_card_path" ;;
	esac
done
HYPR_AQ_DRM_DEVICES="${devices:-$default_card_path}"
export HYPR_AQ_DRM_DEVICES

# But niri only supports choosing one preferred render device
primary_render_device="$default_render_path"
for who in "${prefer_order[@]}"; do
	case "$who" in
	nvidia) [[ -n "$nvidia_render_path" ]] && {
		primary_render_device="$nvidia_render_path"
		break
	} ;;
	intel) [[ -n "$intel_render_path" ]] && {
		primary_render_device="$intel_render_path"
		break
	} ;;
	amd) [[ -n "$amd_render_path" ]] && {
		primary_render_device="$amd_render_path"
		break
	} ;;
	esac
done

# Update niri config
function update_niri_config() {
	local config_file="$1"
	local device_path="$2"

	[[ -f "$config_file" ]] || return

	if grep -qE '^\s*render-drm-device\s+"[^"]+"' "$config_file"; then
		local current
		current="$(grep -E '^\s*render-drm-device\s+"[^"]+"' "$config_file" | sed -E 's/^\s*render-drm-device\s+"([^"]+)".*/\1/')"
		[[ "$current" == "$device_path" ]] && return
		sed -i -E "s|^(\s*render-drm-device\s+)\"[^\"]+\"|\1\"$device_path\"|" "$config_file"
	else
		printf '\ndebug {\nrender-drm-device "%s"\n}\n' "$device_path" >>"$config_file"
	fi
}

update_niri_config "$niri_config_file" "$primary_render_device"
