adaptive sync

This commit is contained in:
nnduc
2026-10-19 23:21:54 +07:00
parent 9b8320cead
commit 96467a1c56
15 changed files with 169 additions and 848 deletions
+1
View File
@@ -35,3 +35,4 @@ export PATH="$HOME/.local/bin:$PATH"
alias ls='ls --color=auto' alias ls='ls --color=auto'
alias doc='docker-compose' alias doc='docker-compose'
alias cla='cd /home/nnduc/.cache/ && claude' alias cla='cd /home/nnduc/.cache/ && claude'
alias wa="watch -n1 "sensors | grep -E 'Tctl|edge|junction|mem:|Composite'""
+22
View File
@@ -0,0 +1,22 @@
# Shift_R+F12 shows/hides the HUD
no_display
toggle_hud=Shift_R+F12
fps
frametime
frame_timing
gpu_stats
cpu_stats
# diagnostics: log starts 20s after launch, Shift_L+F2 toggles logging
output_folder=/home/nnduc/mangologs
autostart_log=20
log_interval=0
toggle_logging=Shift_L+F2
gpu_core_clock
gpu_mem_clock
vram
ram
cpu_mhz
# fps
fps_limit=80,60,120,0
fps_limit_method=early
toggle_fps_limit=Shift_L+F1
+46 -3
View File
@@ -75,8 +75,51 @@ echo 3 | sudo tee /sys/class/drm/card*/device/pp_dpm_mclk
with `adaptive_sync off` games run without it. with `adaptive_sync off` games run without it.
- To turn off FreeSync for a single game (Xorg): `adaptive_sync=false %command%` - To turn off FreeSync for a single game (Xorg): `adaptive_sync=false %command%`
(Steam launch options). (Steam launch options).
- Login greeters (SDDM, LightDM, ...) are fullscreen and mostly static, so VRR
drops to the bottom of the range and flickers. `mesa/drirc` disables it for
any `*greeter*` executable; install system-wide (greeters don't read `~/.drirc`):
```bash
sudo cp xorg/20-amdgpu.conf /etc/X11/xorg.conf.d/
sudo cp mesa/drirc /etc/drirc
```
![stones](./screenshots/Screenshot_20240503_095414.png) ![stones](./screenshots/Screenshot_20240503_095414.png)
## Shader cache (Steam)
With Steam's *Shader Pre-caching* off (it re-downloads caches for every game
almost daily), Steam points Mesa at a temporary
`~/.local/share/Steam/shader_cache_temp_dir_*` and deletes it when the game
exits, so every session recompiles shaders (hitches everywhere, every time).
Steam only sets the legacy `MESA_GLSL_CACHE_DIR`, so the newer variable wins.
Set it session-wide (i3 is started by SDDM, `environment.d` doesn't reach
Steam). The cache lives in `/var/cache` so `~/.cache` cleaners don't wipe it,
with one private subdir per user: Mesa creates its dirs `0700`, so a single
shared dir can't work (and would let users poison each other's shaders).
`/etc/environment` can't expand `$USER`, so use `/etc/profile.d` (SDDM's
X11/Wayland sessions and TTY logins source it). Run as your normal user, not
from a root shell (`~` and `$USER` must be yours), with Steam closed:
```bash
sudo mkdir -p /var/cache/mesa_shader_cache
sudo chmod 1777 /var/cache/mesa_shader_cache # like /tmp: anyone creates own subdir
mv ~/.cache/mesa_shader_cache /var/cache/mesa_shader_cache/$USER # no sudo: keeps ownership
sudo sed -i '/^MESA_SHADER_CACHE_/d' /etc/environment
sudo tee /etc/profile.d/mesa-shader-cache.sh >/dev/null <<'EOF'
export MESA_SHADER_CACHE_DIR="/var/cache/mesa_shader_cache/$USER"
export MESA_SHADER_CACHE_MAX_SIZE=10G
export PRESSURE_VESSEL_FILESYSTEMS_RW=/var/cache/mesa_shader_cache
EOF
```
The last line matters: Steam runs games (native and Proton) in the Steam
Linux Runtime container, which shares `$HOME` but gives the game its own empty
`/var`. Without it the cache is written to a tmpfs inside the container and
thrown away when the game exits.
Re-login, then check it's yours and persists after playing (should print > 0):
```bash
echo $MESA_SHADER_CACHE_DIR; ls -ld $MESA_SHADER_CACHE_DIR # owner must be you
find $MESA_SHADER_CACHE_DIR -mmin -60 -type f | wc -l
```
Deleting the cache is harmless: shaders just recompile (stutter) on first use.
## Installing dependencies ## Installing dependencies
Package availability differs between distros — Arch has everything below in the Package availability differs between distros — Arch has everything below in the
@@ -191,9 +234,9 @@ sudo emerge --ask games-util/gamemode
Adaptive sync (sway): the desktop runs at a fixed 240 Hz with VRR off, because Adaptive sync (sway): the desktop runs at a fixed 240 Hz with VRR off, because
sway only renders on change and idle frame rates fall below the panel's 48 Hz sway only renders on change and idle frame rates fall below the panel's 48 Hz
floor (out of LFC range → flicker). `sway/scripts/vrr-follow` turns VRR on for floor (out of LFC range → flicker). gamemode turns VRR on for DP-1 while a
DP-1 only while the visible workspace has a fullscreen window; `lock-now` turns game runs and off when it exits (install `gamemode/gamemode.ini` to
it off while locked. Needs `jq`. `~/.config/gamemode.ini`); `lock-now` turns it off while locked.
### GPU monitoring & tuning ### GPU monitoring & tuning
+10 -1
View File
@@ -20,6 +20,11 @@ font pango:NotoSans 12
# text rendering and scalability on retina/hidpi displays (thanks to pango). # text rendering and scalability on retina/hidpi displays (thanks to pango).
#font pango:DejaVu Sans Mono 8 #font pango:DejaVu Sans Mono 8
# Clear leftover Wayland env (e.g. from a previous Hyprland/sway session) out of
# systemd/dbus so dbus-activated apps like Thunar don't try to use a dead compositor.
# Must run before anything dbus-activated starts.
exec --no-startup-id sh -c "systemctl --user unset-environment WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE SWAYSOCK; dbus-update-activation-environment --systemd DISPLAY XAUTHORITY XDG_CURRENT_DESKTOP=i3 XDG_SESSION_TYPE=x11; pkill -x Thunar"
# Start XDG autostart .desktop files using dex. See also # Start XDG autostart .desktop files using dex. See also
# https://wiki.archlinux.org/index.php/XDG_Autostart # https://wiki.archlinux.org/index.php/XDG_Autostart
exec --no-startup-id dex --autostart --environment i3 exec --no-startup-id dex --autostart --environment i3
@@ -58,6 +63,7 @@ exec --no-startup-id /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1
exec --no-startup-id ~/.config/i3/scripts/wallpaper-rotate $wallpaper_dir exec --no-startup-id ~/.config/i3/scripts/wallpaper-rotate $wallpaper_dir
exec --no-startup-id pasystray exec --no-startup-id pasystray
exec --no-startup-id polybar exec --no-startup-id polybar
exec --no-startup-id ~/.config/i3/scripts/guide-freeze
set $refresh_i3status killall -SIGUSR1 i3status set $refresh_i3status killall -SIGUSR1 i3status
@@ -99,7 +105,7 @@ floating_modifier $mod
#xrandr --output HDMI-2 --auto --right-of eDP1 #xrandr --output HDMI-2 --auto --right-of eDP1
# High refresh rates can flicker on AMD (VRAM clock switching), so run the # High refresh rates can flicker on AMD (VRAM clock switching), so run the
# desktop at 120Hz. See README "High refresh rate flicker". # desktop at 120Hz. See README "High refresh rate flicker".
exec --no-startup-id xrandr --output DisplayPort-0 --mode 1920x1080 --rate 120 exec --no-startup-id xrandr --output DisplayPort-0 --mode 1920x1080 --rate 240
# start a terminal # start a terminal
#bindsym $mod+Return exec i3-sensible-terminal #bindsym $mod+Return exec i3-sensible-terminal
@@ -108,6 +114,9 @@ bindsym $mod+Return exec $terminal
# kill focused window # kill focused window
bindsym $mod+Shift+q kill bindsym $mod+Shift+q kill
# freeze / resume focused window (SIGSTOP / SIGCONT)
bindsym $mod+m exec --no-startup-id ~/.config/i3/scripts/freeze-toggle
# start dmenu (a program launcher) # start dmenu (a program launcher)
#bindsym $mod+d exec --no-startup-id j4-dmenu-desktop #bindsym $mod+d exec --no-startup-id j4-dmenu-desktop
#bindsym $mod+d exec --no-startup-id dmenu #bindsym $mod+d exec --no-startup-id dmenu
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash
# Freeze / resume the focused window's process tree (SIGSTOP / SIGCONT).
pid=$(xdotool getactivewindow getwindowpid 2>/dev/null) || exit 1
# collect pid plus all descendants (Wine/Proton games spawn several)
descendants() {
local p
for p in $(pgrep -P "$1"); do
echo "$p"
descendants "$p"
done
}
pids="$pid $(descendants "$pid")"
name=$(ps -o comm= -p "$pid")
case "$(ps -o state= -p "$pid")" in
T*) kill -CONT $pids && notify-send -t 1500 "Resumed" "$name ($pid)" ;;
*) kill -STOP $pids && notify-send -t 1500 "Frozen" "$name ($pid)" ;;
esac
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
# Freeze/resume the focused window on the controller's Home/guide button (BTN_MODE).
# Stdlib only: reads raw evdev events. Gamepads are readable by the seat user.
import glob, os, select, signal, struct, subprocess, time
EV_KEY, BTN_MODE = 1, 0x13c
EVENT = struct.Struct('llHHi') # struct input_event
LONG_BITS = struct.calcsize('l') * 8
CMD = [os.path.expanduser('~/.config/i3/scripts/freeze-toggle')]
signal.signal(signal.SIGCHLD, signal.SIG_IGN) # auto-reap child processes
def has_btn_mode(path):
try:
with open(f'/sys/class/input/{os.path.basename(path)}/device/capabilities/key') as f:
words = f.read().split()
except OSError:
return False
bits = 0
for w in words:
bits = bits << LONG_BITS | int(w, 16)
return bits >> BTN_MODE & 1
fds = {} # fd -> device path
last = 0.0
rescan = 0.0
while True:
if time.monotonic() >= rescan: # pick up hotplugged controllers
for path in glob.glob('/dev/input/event*'):
if path not in fds.values() and has_btn_mode(path):
try:
fds[os.open(path, os.O_RDONLY)] = path
except OSError:
pass
rescan = time.monotonic() + 2
ready, _, _ = select.select(list(fds), [], [], 2)
for fd in ready:
try:
data = os.read(fd, EVENT.size * 64)
except OSError: # controller unplugged
os.close(fd)
del fds[fd]
continue
for sec, usec, type_, code, value in EVENT.iter_unpack(data):
if type_ == EV_KEY and code == BTN_MODE and value == 1:
now = sec + usec / 1e6
if now - last < 0.4: # GuliKit's Home button double-fires ~10ms apart
continue
last = now
subprocess.Popen(CMD, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+7
View File
@@ -0,0 +1,7 @@
<driconf>
<device>
<application name="Login greeters" executable_regexp=".*greeter.*">
<option name="adaptive_sync" value="false" />
</application>
</device>
</driconf>
+6 -6
View File
@@ -2,19 +2,19 @@
"Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" }, "Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" },
"coq.artifacts": { "branch": "artifacts", "commit": "d545035d06408f2d68cd03bc401425e42c298fc4" }, "coq.artifacts": { "branch": "artifacts", "commit": "d545035d06408f2d68cd03bc401425e42c298fc4" },
"coq.thirdparty": { "branch": "3p", "commit": "a021e24f1ff538d339aece0de80d621b68862701" }, "coq.thirdparty": { "branch": "3p", "commit": "a021e24f1ff538d339aece0de80d621b68862701" },
"coq_nvim": { "branch": "coq", "commit": "df4eb27b425568cea17f01a25a07cf447066ce81" }, "coq_nvim": { "branch": "coq", "commit": "0cdbf99893729c5ffa74064382efc53364d7045d" },
"fzf-lua": { "branch": "main", "commit": "05e44d38de0a79c11fba5f7bf8138791b1dbdd1e" }, "fzf-lua": { "branch": "main", "commit": "78b85d2a522b1e6a2d154216b3e532a1df1ad6d7" },
"gruvbox.nvim": { "branch": "main", "commit": "154eb5ff5b96d0641307113fa385eaf0d36d9796" }, "gruvbox.nvim": { "branch": "main", "commit": "154eb5ff5b96d0641307113fa385eaf0d36d9796" },
"julia-vim": { "branch": "master", "commit": "52b30547346b21bc93acda28d626795667f9e087" }, "julia-vim": { "branch": "master", "commit": "52b30547346b21bc93acda28d626795667f9e087" },
"lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" },
"lualine.nvim": { "branch": "master", "commit": "221ce6b2d999187044529f49da6554a92f740a96" }, "lualine.nvim": { "branch": "master", "commit": "221ce6b2d999187044529f49da6554a92f740a96" },
"nvim-autopairs": { "branch": "master", "commit": "430522f95fe4fb7c511ec64f8c1a90cc6a66c05c" }, "nvim-autopairs": { "branch": "master", "commit": "430522f95fe4fb7c511ec64f8c1a90cc6a66c05c" },
"nvim-bqf": { "branch": "main", "commit": "c282a62bec6c0621a1ef5132aa3f4c9fc4dcc2c7" }, "nvim-bqf": { "branch": "main", "commit": "c282a62bec6c0621a1ef5132aa3f4c9fc4dcc2c7" },
"nvim-lspconfig": { "branch": "master", "commit": "16286347bdba1333c7d124d9de9fe6630731b2b2" }, "nvim-lspconfig": { "branch": "master", "commit": "a9bb4d5f4276aa5cddc015faa3ecc5a7b5a26b14" },
"nvim-tree.lua": { "branch": "master", "commit": "b2aadda94b107480c48e548d6db51c6840b7b33c" }, "nvim-tree.lua": { "branch": "master", "commit": "478c69c0fe253caea88de9c5e138bfa77395a59a" },
"nvim-web-devicons": { "branch": "master", "commit": "5f032a85be210cd1c6ac98861eb3b187ff3bd5eb" }, "nvim-web-devicons": { "branch": "master", "commit": "58447c1fca354bbf184425e4a8d01deecbd6f3c4" },
"vim-fugitive": { "branch": "master", "commit": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0" }, "vim-fugitive": { "branch": "master", "commit": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0" },
"vim-ime": { "branch": "master", "commit": "79e3b02eb50a57305113550be7ca163b267b5e30" }, "vim-ime": { "branch": "master", "commit": "79e3b02eb50a57305113550be7ca163b267b5e30" },
"viml-surround": { "branch": "master", "commit": "98358bad347aa2b8a180c2edde84c3bd8a51fdd1" }, "viml-surround": { "branch": "master", "commit": "98358bad347aa2b8a180c2edde84c3bd8a51fdd1" },
"vimtex": { "branch": "master", "commit": "cb81778aee678b513af3de7f1ca5943e7ee31b2f" } "vimtex": { "branch": "master", "commit": "16a5609d17a436db7f48046d91747fd6a9d75c74" }
} }
-476
View File
@@ -1,476 +0,0 @@
# Simple daemon config file for PipeWire version "1.2.3" #
#
# Copy and edit this file in /etc/pipewire for system-wide changes
# or in ~/.config/pipewire for local changes.
#
# It is also possible to place a file with an updated section in
# /etc/pipewire/minimal.conf.d/ for system-wide changes or in
# ~/.config/pipewire/minimal.conf.d/ for local changes.
#
context.properties = {
## Configure properties in the system.
#library.name.system = support/libspa-support
#context.data-loop.library.name.system = support/libspa-support
#support.dbus = true
#link.max-buffers = 64
link.max-buffers = 16 # version < 3 clients can't handle more
#mem.warn-mlock = false
#mem.allow-mlock = true
#mem.mlock-all = false
#clock.power-of-two-quantum = true
#log.level = 2
#cpu.zero.denormals = false
core.daemon = true # listening for socket connections
core.name = pipewire-0 # core name and socket name
## Properties for the DSP configuration.
default.clock.rate = 48000
#default.clock.allowed-rates = [ 48000 ]
#default.clock.quantum = 1024
#default.clock.min-quantum = 32
#default.clock.max-quantum = 2048
#default.clock.quantum-limit = 8192
#default.clock.quantum-floor = 4
#default.video.width = 640
#default.video.height = 480
#default.video.rate.num = 25
#default.video.rate.denom = 1
#
settings.check-quantum = true
settings.check-rate = true
# This config can use udev or hardcoded ALSA devices. Make sure to
# change the alsa device below when disabling udev
minimal.use-udev = true
# Load the pulseaudio emulation daemon
minimal.use-pulse = true
}
context.properties.rules = [
{ matches = [ { cpu.vm.name = !null } ]
actions = {
update-props = {
# These overrides are only applied when running in a vm.
default.clock.min-quantum = 1024
}
}
}
]
context.spa-libs = {
#<factory-name regex> = <library-name>
#
# Used to find spa factory names. It maps an spa factory name
# regular expression to a library name that should contain
# that factory.
#
audio.convert.* = audioconvert/libspa-audioconvert
audio.adapt = audioconvert/libspa-audioconvert
api.alsa.* = alsa/libspa-alsa
support.* = support/libspa-support
}
context.modules = [
#{ name = <module-name>
# ( args = { <key> = <value> ... } )
# ( flags = [ ( ifexists ) ( nofail ) ] )
# ( condition = [ { <key> = <value> ... } ... ] )
#}
#
# Loads a module with the given parameters.
# If ifexists is given, the module is ignored when it is not found.
# If nofail is given, module initialization failures are ignored.
#
# Uses realtime scheduling to boost the audio thread priorities. This uses
# RTKit if the user doesn't have permission to use regular realtime
# scheduling.
{ name = libpipewire-module-rt
args = {
nice.level = -11
rt.prio = 88
#rt.time.soft = -1
#rt.time.hard = -1
}
flags = [ ifexists nofail ]
}
# The native communication protocol.
{ name = libpipewire-module-protocol-native }
# The profile module. Allows application to access profiler
# and performance data. It provides an interface that is used
# by pw-top and pw-profiler.
{ name = libpipewire-module-profiler }
# Allows applications to create metadata objects. It creates
# a factory for Metadata objects.
{ name = libpipewire-module-metadata }
# Creates a factory for making nodes that run in the
# context of the PipeWire server.
{ name = libpipewire-module-spa-node-factory }
{ name = libpipewire-module-spa-device-factory }
# Allows creating nodes that run in the context of the
# client. Is used by all clients that want to provide
# data to PipeWire.
{ name = libpipewire-module-client-node }
# The access module can perform access checks and block
# new clients.
{ name = libpipewire-module-access
args = {
# access.allowed to list an array of paths of allowed
# apps.
#access.allowed = [
# /usr/bin/pipewire-media-session
#]
# An array of rejected paths.
#access.rejected = [ ]
# An array of paths with restricted access.
#access.restricted = [ ]
# Anything not in the above lists gets assigned the
# access.force permission.
#access.force = flatpak
}
}
# Makes a factory for wrapping nodes in an adapter with a
# converter and resampler.
{ name = libpipewire-module-adapter }
# Makes a factory for creating links between ports.
{ name = libpipewire-module-link-factory }
{ name = libpipewire-module-protocol-pulse
condition = [ { minimal.use-pulse = true } ]
}
]
pulse.properties = {
# the addresses this server listens on
server.address = [
"unix:native"
]
}
stream.properties = {
adapter.auto-port-config = { mode = dsp }
}
context.objects = [
#{ factory = <factory-name>
# ( args = { <key> = <value> ... } )
# ( flags = [ ( nofail ) ] )
# ( condition = [ { <key> = <value> ... } ... ] )
#}
#
# Creates an object from a PipeWire factory with the given parameters.
# If nofail is given, errors are ignored (and no object is created).
#
#{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc node.description = videotestsrc "Spa:Pod:Object:Param:Props:patternType" = 1 } }
#{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = [ nofail ] }
#{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } }
#{ factory = spa-node-factory args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } }
#{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test node.description = audiotestsrc } }
#{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } }
# Make a default metadata store
{ factory = metadata
args = {
metadata.name = default
# metadata.values = [
# { key = default.audio.sink value = { name = somesink } }
# { key = default.audio.source value = { name = somesource } }
# ]
}
}
# A default dummy driver. This handles nodes marked with the "node.always-process"
# property when no other driver is currently active. JACK clients need this.
{ factory = spa-node-factory
args = {
factory.name = support.node.driver
node.name = Dummy-Driver
node.group = pipewire.dummy
priority.driver = 20000
}
}
{ factory = spa-node-factory
args = {
factory.name = support.node.driver
node.name = Freewheel-Driver
priority.driver = 19000
node.group = pipewire.freewheel
node.freewheel = true
#freewheel.wait = 10
}
}
# This creates a ALSA udev device that will enumerate all
# ALSA devices. Because it is using ACP and has the auto-profile
# property set, this will enable a profile and create associated
# nodes, which will be automatically configured to their best
# configuration with the auto-port-config settings.
# Extra node and device params can be given with node.param and
# device.param prefixes.
{ factory = spa-device-factory
args = {
factory.name = api.alsa.enum.udev
alsa.use-acp = true
device.object.properties = {
api.acp.auto-profile = true
api.acp.auto-port = true
device.object.properties = {
node.adapter = audio.adapt
resample.disable = false
adapter.auto-port-config = {
mode = dsp
monitor = false
control = false
position = preserve # unknown, aux
}
#node.param.Props = {
# channelVolumes = [ 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.6 ]
#}
}
#device.param.Profile = {
# #idx = 0
# name = pro-audio
#}
}
}
condition = [ { minimal.use-udev = true } ]
}
# This creates a single PCM source device for the given
# alsa device path hw:0. You can change source to sink
# to make a sink in the same way.
{ factory = adapter
args = {
factory.name = api.alsa.pcm.source
node.name = "system"
node.description = "system"
media.class = "Audio/Source"
api.alsa.path = "hw:4"
#api.alsa.period-size = 0
#api.alsa.period-num = 0
#api.alsa.headroom = 0
#api.alsa.start-delay = 0
#api.alsa.disable-mmap = false
#api.alsa.disable-batch = false
#api.alsa.use-chmap = false
#api.alsa.multirate = true
#latency.internal.rate = 0
#latency.internal.ns = 0
#clock.name = api.alsa.0
node.suspend-on-idle = false
#audio.format = "S32"
#audio.rate = 48000
#audio.allowed-rates = [ ]
#audio.channels = 4
#audio.position = [ FL FR RL RR ]
#resample.quality = 4
resample.disable = true
#monitor.channel-volumes = false
#channelmix.normalize = false
#channelmix.mix-lfe = true
#channelmix.upmix = true
#channelmix.upmix-method = psd # none, simple
#channelmix.lfe-cutoff = 150
#channelmix.fc-cutoff = 12000
#channelmix.rear-delay = 12.0
#channelmix.stereo-widen = 0.0
#channelmix.hilbert-taps = 0
#channelmix.disable = false
#dither.noise = 0
#node.param.Props = {
# params = [
# audio.channels 6
# ]
#}
adapter.auto-port-config = {
mode = dsp
monitor = false
control = false
position = unknown # aux, preserve
}
#node.param.PortConfig = {
# direction = Output
# mode = dsp
# format = {
# mediaType = audio
# mediaSubtype = raw
# format = F32
# rate = 48000
# channels = 4
# position = [ FL FR RL RR ]
# }
#}
#node.param.Props = {
# channelVolumes = [ 0.5 0.4 0.3 0.5 ]
#}
}
condition = [ { minimal.use-udev = false } ]
}
{ factory = adapter
args = {
factory.name = api.alsa.pcm.sink
node.name = "system"
node.description = "system"
media.class = "Audio/Sink"
api.alsa.path = "hw:4"
#api.alsa.period-size = 0
#api.alsa.period-num = 0
#api.alsa.headroom = 0
#api.alsa.start-delay = 0
#api.alsa.disable-mmap = false
#api.alsa.disable-batch = false
#api.alsa.use-chmap = false
#api.alsa.multirate = true
#latency.internal.rate = 0
#latency.internal.ns = 0
#clock.name = api.alsa.0
node.suspend-on-idle = false
#audio.format = "S32"
#audio.rate = 48000
#audio.allowed-rates = [ ]
#audio.channels = 2
#audio.position = "FL,FR"
#resample.quality = 4
resample.disable = true
#channelmix.normalize = false
#channelmix.mix-lfe = true
#channelmix.upmix = true
#channelmix.upmix-method = psd # none, simple
#channelmix.lfe-cutoff = 150
#channelmix.fc-cutoff = 12000
#channelmix.rear-delay = 12.0
#channelmix.stereo-widen = 0.0
#channelmix.hilbert-taps = 0
#channelmix.disable = false
#dither.noise = 0
#node.param.Props = {
# params = [
# audio.format S16
# ]
#}
adapter.auto-port-config = {
mode = dsp
monitor = false
control = false
position = unknown # aux, preserve
}
#node.param.PortConfig = {
# direction = Input
# mode = dsp
# monitor = true
# format = {
# mediaType = audio
# mediaSubtype = raw
# format = F32
# rate = 48000
# channels = 4
# }
#}
#node.param.Props = {
# channelVolumes = [ 0.5 0.4 0.3 0.5 ]
#}
}
condition = [ { minimal.use-udev = false } ]
}
# This creates a new Source node. It will have input ports
# that you can link, to provide audio for this source.
#{ factory = adapter
# args = {
# factory.name = support.null-audio-sink
# node.name = "my-mic"
# node.description = "Microphone"
# media.class = "Audio/Source/Virtual"
# audio.position = "FL,FR"
# monitor.passthrough = true
# adapter.auto-port-config = {
# mode = dsp
# monitor = true
# position = preserve # unknown, aux, preserve
# }
# }
#}
# This creates a new link between the source and the virtual
# source ports.
#{ factory = link-factory
# args = {
# link.output.node = system
# link.output.port = capture_1
# link.input.node = my-mic
# link.input.port = input_FL
# }
#}
#{ factory = link-factory
# args = {
# link.output.node = system
# link.output.port = capture_2
# link.input.node = my-mic
# link.input.port = input_FR
# }
#}
]
context.exec = [
#{ path = <program-name>
# ( args = "<arguments>" | [ <arg1> <arg2> ... ] )
# ( condition = [ { <key> = <value> ... } ... ] )
#}
#
# Execute the given program with arguments.
#
# You can optionally start the pulseaudio-server here as well
# but it is better to start it as a systemd service.
# It can be interesting to start another daemon here that listens
# on another address with the -a option (eg. -a tcp:4713).
#
##{ path = "/usr/bin/pipewire" args = "-c pipewire-pulse.conf" }
]
node.rules = [
{ matches = [
{
# all keys must match the value. ! negates. ~ starts regex.
#alsa.card_name = "ICUSBAUDIO7D"
#api.alsa.pcm.stream = "playback"
}
]
actions = {
update-props = {
#node.name = "alsa_playback.ICUSBAUDIO7D"
}
}
}
]
device.rules = [
{ matches = [
{
#alsa.card_name = "ICUSBAUDIO7D"
}
]
actions = {
update-props = {
#device.name = "alsa_card.ICUSBAUDIO7D"
#api.acp.auto-profile = false
#api.acp.auto-port = false
#device.param.Profile = {
# #idx = 0
# name = off
#}
}
}
}
]
-345
View File
@@ -1,345 +0,0 @@
# Daemon config file for PipeWire version "1.2.3" #
#
# Copy and edit this file in /etc/pipewire for system-wide changes
# or in ~/.config/pipewire for local changes.
#
# It is also possible to place a file with an updated section in
# /etc/pipewire/pipewire.conf.d/ for system-wide changes or in
# ~/.config/pipewire/pipewire.conf.d/ for local changes.
#
context.properties = {
## Configure properties in the system.
#library.name.system = support/libspa-support
#context.data-loop.library.name.system = support/libspa-support
#support.dbus = true
#link.max-buffers = 64
link.max-buffers = 16 # version < 3 clients can't handle more
mem.warn-mlock = true # Gentoo should have good RLIMITs now
#mem.allow-mlock = true
#mem.mlock-all = false
#clock.power-of-two-quantum = true
#log.level = 2
#cpu.zero.denormals = false
#loop.rt-prio = -1 # -1 = use module-rt prio, 0 disable rt
#loop.class = data.rt
#thread.affinity = [ 0 1 ] # optional array of CPUs
#context.num-data-loops = 1 # -1 = num-cpus, 0 = no data loops
#
#context.data-loops = [
# { loop.rt-prio = -1
# loop.class = [ data.rt audio.rt ]
# #library.name.system = support/libspa-support
# thread.name = data-loop.0
# #thread.affinity = [ 0 1 ] # optional array of CPUs
# }
#]
core.daemon = true # listening for socket connections
core.name = pipewire-0 # core name and socket name
## Properties for the DSP configuration.
default.clock.rate = 44100
default.clock.rates = [ 44100 96000 192000 384000]
default.clock.allowed-rates = [ 44100 96000 192000 384000]
#default.clock.quantum = 1024
#default.clock.min-quantum = 32
#default.clock.max-quantum = 2048
#default.clock.quantum-limit = 8192
#default.clock.quantum-floor = 4
#default.video.width = 640
#default.video.height = 480
#default.video.rate.num = 25
#default.video.rate.denom = 1
#
#settings.check-quantum = false
#settings.check-rate = false
# keys checked below to disable module loading
module.x11.bell = true
# enables autoloading of access module, when disabled an alternative
# access module needs to be loaded.
module.access = true
# enables autoloading of module-jackdbus-detect
module.jackdbus-detect = true
}
context.properties.rules = [
{ matches = [ { cpu.vm.name = !null } ]
actions = {
update-props = {
# These overrides are only applied when running in a vm.
default.clock.min-quantum = 1024
}
}
}
]
context.spa-libs = {
#<factory-name regex> = <library-name>
#
# Used to find spa factory names. It maps an spa factory name
# regular expression to a library name that should contain
# that factory.
#
audio.convert.* = audioconvert/libspa-audioconvert
avb.* = avb/libspa-avb
api.alsa.* = alsa/libspa-alsa
api.v4l2.* = v4l2/libspa-v4l2
api.libcamera.* = libcamera/libspa-libcamera
api.bluez5.* = bluez5/libspa-bluez5
api.vulkan.* = vulkan/libspa-vulkan
api.jack.* = jack/libspa-jack
support.* = support/libspa-support
video.convert.* = videoconvert/libspa-videoconvert
#videotestsrc = videotestsrc/libspa-videotestsrc
#audiotestsrc = audiotestsrc/libspa-audiotestsrc
}
context.modules = [
#{ name = <module-name>
# ( args = { <key> = <value> ... } )
# ( flags = [ ( ifexists ) ( nofail ) ] )
# ( condition = [ { <key> = <value> ... } ... ] )
#}
#
# Loads a module with the given parameters.
# If ifexists is given, the module is ignored when it is not found.
# If nofail is given, module initialization failures are ignored.
# If condition is given, the module is loaded only when the context
# properties all match the match rules.
#
# Uses realtime scheduling to boost the audio thread priorities. This uses
# RTKit if the user doesn't have permission to use regular realtime
# scheduling. You can also clamp utilisation values to improve scheduling
# on embedded and heterogeneous systems, e.g. Arm big.LITTLE devices.
{ name = libpipewire-module-rt
args = {
nice.level = -11
rt.prio = 88
#rt.time.soft = -1
#rt.time.hard = -1
#uclamp.min = 0
#uclamp.max = 1024
}
flags = [ ifexists nofail ]
}
# The native communication protocol.
{ name = libpipewire-module-protocol-native
args = {
# List of server Unix sockets, and optionally permissions
#sockets = [ { name = "pipewire-0" }, { name = "pipewire-0-manager" } ]
}
}
# The profile module. Allows application to access profiler
# and performance data. It provides an interface that is used
# by pw-top and pw-profiler.
{ name = libpipewire-module-profiler }
# Allows applications to create metadata objects. It creates
# a factory for Metadata objects.
{ name = libpipewire-module-metadata }
# Creates a factory for making devices that run in the
# context of the PipeWire server.
{ name = libpipewire-module-spa-device-factory }
# Creates a factory for making nodes that run in the
# context of the PipeWire server.
{ name = libpipewire-module-spa-node-factory }
# Allows creating nodes that run in the context of the
# client. Is used by all clients that want to provide
# data to PipeWire.
{ name = libpipewire-module-client-node }
# Allows creating devices that run in the context of the
# client. Is used by the session manager.
{ name = libpipewire-module-client-device }
# The portal module monitors the PID of the portal process
# and tags connections with the same PID as portal
# connections.
{ name = libpipewire-module-portal
flags = [ ifexists nofail ]
}
# The access module can perform access checks and block
# new clients.
{ name = libpipewire-module-access
args = {
# Socket-specific access permissions
#access.socket = { pipewire-0 = "default", pipewire-0-manager = "unrestricted" }
# Deprecated legacy mode (not socket-based),
# for now enabled by default if access.socket is not specified
#access.legacy = true
}
condition = [ { module.access = true } ]
}
# Makes a factory for wrapping nodes in an adapter with a
# converter and resampler.
{ name = libpipewire-module-adapter }
# Makes a factory for creating links between ports.
{ name = libpipewire-module-link-factory }
# Provides factories to make session manager objects.
{ name = libpipewire-module-session-manager }
# Use libcanberra to play X11 Bell
{ name = libpipewire-module-x11-bell
args = {
#sink.name = "@DEFAULT_SINK@"
#sample.name = "bell-window-system"
#x11.display = null
#x11.xauthority = null
}
flags = [ ifexists nofail ]
condition = [ { module.x11.bell = true } ]
}
{ name = libpipewire-module-jackdbus-detect
args = {
#jack.library = libjack.so.0
#jack.server = null
#jack.client-name = PipeWire
#jack.connect = true
#tunnel.mode = duplex # source|sink|duplex
source.props = {
#audio.channels = 2
#midi.ports = 1
#audio.position = [ FL FR ]
# extra sink properties
}
sink.props = {
#audio.channels = 2
#midi.ports = 1
#audio.position = [ FL FR ]
# extra sink properties
}
}
flags = [ ifexists nofail ]
condition = [ { module.jackdbus-detect = true } ]
}
]
context.objects = [
#{ factory = <factory-name>
# ( args = { <key> = <value> ... } )
# ( flags = [ ( nofail ) ] )
# ( condition = [ { <key> = <value> ... } ... ] )
#}
#
# Creates an object from a PipeWire factory with the given parameters.
# If nofail is given, errors are ignored (and no object is created).
# If condition is given, the object is created only when the context properties
# all match the match rules.
#
#{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc node.description = videotestsrc "Spa:Pod:Object:Param:Props:patternType" = 1 } }
#{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = [ nofail ] }
#{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } }
#{ factory = spa-node-factory args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } }
#{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test node.description = audiotestsrc } }
#{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } }
# A default dummy driver. This handles nodes marked with the "node.always-process"
# property when no other driver is currently active. JACK clients need this.
{ factory = spa-node-factory
args = {
factory.name = support.node.driver
node.name = Dummy-Driver
node.group = pipewire.dummy
node.sync-group = sync.dummy
priority.driver = 200000
#clock.id = monotonic # realtime | tai | monotonic-raw | boottime
#clock.name = "clock.system.monotonic"
}
}
{ factory = spa-node-factory
args = {
factory.name = support.node.driver
node.name = Freewheel-Driver
priority.driver = 190000
node.group = pipewire.freewheel
node.sync-group = sync.dummy
node.freewheel = true
#freewheel.wait = 10
}
}
# This creates a new Source node. It will have input ports
# that you can link, to provide audio for this source.
#{ factory = adapter
# args = {
# factory.name = support.null-audio-sink
# node.name = "my-mic"
# node.description = "Microphone"
# media.class = "Audio/Source/Virtual"
# audio.position = "FL,FR"
# monitor.passthrough = true
# }
#}
# This creates a single PCM source device for the given
# alsa device path hw:0. You can change source to sink
# to make a sink in the same way.
#{ factory = adapter
# args = {
# factory.name = api.alsa.pcm.source
# node.name = "alsa-source"
# node.description = "PCM Source"
# media.class = "Audio/Source"
# api.alsa.path = "hw:0"
# api.alsa.period-size = 1024
# api.alsa.headroom = 0
# api.alsa.disable-mmap = false
# api.alsa.disable-batch = false
# audio.format = "S16LE"
# audio.rate = 48000
# audio.channels = 2
# audio.position = "FL,FR"
# }
#}
# Use the metadata factory to create metadata and some default values.
#{ factory = metadata
# args = {
# metadata.name = my-metadata
# metadata.values = [
# { key = default.audio.sink value = { name = somesink } }
# { key = default.audio.source value = { name = somesource } }
# ]
# }
#}
]
context.exec = [
#{ path = <program-name>
# ( args = "<arguments>" | [ <arg1> <arg2> ... ] )
# ( condition = [ { <key> = <value> ... } ... ] )
#}
#
# Execute the given program with arguments.
# If condition is given, the program is executed only when the context
# properties all match the match rules.
#
# You can optionally start the session manager here,
# but it is better to start it as a systemd service.
# Run the session manager with -h for options.
#
#{ path = "/usr/bin/pipewire-media-session" args = ""
# condition = [ { exec.session-manager = null } { exec.session-manager = true } ] }
#
# You can optionally start the pulseaudio-server here as well
# but it is better to start it as a systemd service.
# It can be interesting to start another daemon here that listens
# on another address with the -a option (eg. -a tcp:4713).
#
#{ path = "/usr/bin/pipewire" args = [ "-c" "pipewire-pulse.conf" ]
# condition = [ { exec.pipewire-pulse = null } { exec.pipewire-pulse = true } ] }
]
-1
View File
@@ -39,7 +39,6 @@ exec --no-startup-id ~/.config/sway/scripts/wallpaper-rotate $wallpaper_dir
# adaptive_sync on the desktop makes sway stutter/flicker; 120Hz avoids AMD # adaptive_sync on the desktop makes sway stutter/flicker; 120Hz avoids AMD
# VRAM clock flicker at high refresh (see README). # VRAM clock flicker at high refresh (see README).
output DP-1 mode 1920x1080@240Hz adaptive_sync off allow_tearing yes output DP-1 mode 1920x1080@240Hz adaptive_sync off allow_tearing yes
exec_always pkill -xf '/bin/sh /home/nnduc/.config/sway/scripts/vrr-follow'; ~/.config/sway/scripts/vrr-follow
#output DP-1 mode 1920x1080@240Hz adaptive_sync on allow_tearing yes #output DP-1 mode 1920x1080@240Hz adaptive_sync on allow_tearing yes
### Idle configuration ### Idle configuration
+2 -2
View File
@@ -3,6 +3,6 @@ wall_dir="${1:?wallpaper directory required}"
img=$(find "$wall_dir" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | shuf -n1) img=$(find "$wall_dir" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | shuf -n1)
swaymsg -q output DP-1 adaptive_sync off # lock screen redraws rarely: fixed 240 Hz swaymsg -q output DP-1 adaptive_sync off # lock screen redraws rarely: fixed 240 Hz
swaylock -f ${img:+-i "$img"} swaylock -f ${img:+-i "$img"}
# once unlocked, let vrr-follow decide again (in background so swayidle/suspend aren't held up) # once unlocked, turn VRR back on if a game (gamemode) is still running
( while pgrep -x swaylock >/dev/null; do sleep 1; done ( while pgrep -x swaylock >/dev/null; do sleep 1; done
~/.config/sway/scripts/vrr-follow once ) & gamemoded -s | grep -q 'is active' && swaymsg -q output DP-1 adaptive_sync on ) &
-14
View File
@@ -1,14 +0,0 @@
#!/bin/sh
# adaptive_sync on DP-1 only while the visible workspace shows a fullscreen window
OUT=DP-1
update() {
if [ "$(swaymsg -t get_tree | jq --arg o "$OUT" '
.nodes[] | select(.name==$o) as $out | $out.nodes[]
| select(.name==$out.current_workspace)
| [.. | objects | select((.fullscreen_mode? // 0) > 0)] | length')" -gt 0 ]
then s=on; else s=off; fi
[ "$s" != "$last" ] && swaymsg -q output "$OUT" adaptive_sync "$s" && last=$s
}
[ "$1" = once ] && { update; exit; }
update
swaymsg -t subscribe -m '["workspace","window"]' | while read -r _; do update; done
+1
View File
@@ -23,6 +23,7 @@
"clock": { "clock": {
// "timezone": "America/New_York", // "timezone": "America/New_York",
"tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>", "tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>",
"format": "{:%Y-%m-%d %H:%M}",
"format-alt": "{:%Y-%m-%d %H:%M}" "format-alt": "{:%Y-%m-%d %H:%M}"
}, },
"bluetooth": { "bluetooth": {
+5
View File
@@ -0,0 +1,5 @@
Section "Device"
Identifier "AMD"
Driver "amdgpu"
Option "VariableRefresh" "true"
EndSection