feat(root): add hybrid Optimus mode caching and command extensions
- New Features - Introduced cached configuration for hybrid Optimus systems - Added command‑line options for switching, resetting, and cache management - Enhancements - Integrated clap‑derived CLI parsing - Updated project dependencies via Cargo.lock - Improved error handling and logging
This commit is contained in:
4 files changed
+1180
No files matched your search
@@ -24,3 +24,4 @@ target
|
||||
# Added by cargo
|
||||
|
||||
/target
|
||||
./lapctl.py
|
||||
Generated
+358
@@ -0,0 +1,358 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"jiff",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"log",
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lapctl"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"env_logger",
|
||||
"log",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||
@@ -4,3 +4,9 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
log = "0.4"
|
||||
env_logger = "0.11"
|
||||
regex = "1.10"
|
||||
@@ -0,0 +1,815 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
|
||||
# begin constants definition
|
||||
|
||||
VERSION = "3.5.2"
|
||||
|
||||
# Note: Do NOT remove this in cleanup!
|
||||
CACHE_FILE_PATH = "/var/cache/lapctl/cache.json"
|
||||
|
||||
BLACKLIST_PATH = "/etc/modprobe.d/blacklist-nvidia.conf"
|
||||
|
||||
BLACKLIST_CONTENT = """# Automatically generated by lapctl
|
||||
|
||||
blacklist nouveau
|
||||
blacklist nova_core
|
||||
blacklist nova_drm
|
||||
blacklist nvidia
|
||||
blacklist nvidia_drm
|
||||
blacklist nvidia_uvm
|
||||
blacklist nvidia_modeset
|
||||
blacklist nvidia_current
|
||||
blacklist nvidia_current_drm
|
||||
blacklist nvidia_current_uvm
|
||||
blacklist nvidia_current_modeset
|
||||
blacklist i2c_nvidia_gpu
|
||||
alias nouveau off
|
||||
alias nova_core off
|
||||
alias nova_drm off
|
||||
alias nvidia off
|
||||
alias nvidia_drm off
|
||||
alias nvidia_uvm off
|
||||
alias nvidia_modeset off
|
||||
alias nvidia_current off
|
||||
alias nvidia_current_drm off
|
||||
alias nvidia_current_uvm off
|
||||
alias nvidia_current_modeset off
|
||||
alias i2c_nvidia_gpu off
|
||||
"""
|
||||
|
||||
UDEV_INTEGRATED_PATH = "/etc/udev/rules.d/50-remove-nvidia.rules"
|
||||
|
||||
UDEV_INTEGRATED = """# Automatically generated by lapctl
|
||||
|
||||
# Remove NVIDIA USB xHCI Host Controller devices, if present
|
||||
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{power/control}="auto", ATTR{remove}="1"
|
||||
|
||||
# Remove NVIDIA USB Type-C UCSI devices, if present
|
||||
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{power/control}="auto", ATTR{remove}="1"
|
||||
|
||||
# Remove NVIDIA Audio devices, if present
|
||||
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{power/control}="auto", ATTR{remove}="1"
|
||||
|
||||
# Remove NVIDIA VGA/3D controller devices
|
||||
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x03[0-9]*", ATTR{power/control}="auto", ATTR{remove}="1"
|
||||
"""
|
||||
|
||||
UDEV_PM_PATH = "/etc/udev/rules.d/80-nvidia-pm.rules"
|
||||
|
||||
UDEV_PM_CONTENT = """# Automatically generated by lapctl
|
||||
|
||||
# Remove NVIDIA USB xHCI Host Controller devices, if present
|
||||
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{remove}="1"
|
||||
|
||||
# Remove NVIDIA USB Type-C UCSI devices, if present
|
||||
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{remove}="1"
|
||||
|
||||
# Remove NVIDIA Audio devices, if present
|
||||
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{remove}="1"
|
||||
|
||||
# Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind
|
||||
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto"
|
||||
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto"
|
||||
|
||||
# Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind
|
||||
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on"
|
||||
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on"
|
||||
"""
|
||||
|
||||
XORG_PATH = "/etc/X11/xorg.conf"
|
||||
|
||||
XORG_INTEL = """# Automatically generated by lapctl
|
||||
|
||||
Section "ServerLayout"
|
||||
Identifier "layout"
|
||||
Screen 0 "nvidia"
|
||||
Inactive "intel"
|
||||
EndSection
|
||||
|
||||
Section "Device"
|
||||
Identifier "nvidia"
|
||||
Driver "nvidia"
|
||||
BusID "{}"
|
||||
EndSection
|
||||
|
||||
Section "Screen"
|
||||
Identifier "nvidia"
|
||||
Device "nvidia"
|
||||
Option "AllowEmptyInitialConfiguration"
|
||||
EndSection
|
||||
|
||||
Section "Device"
|
||||
Identifier "intel"
|
||||
Driver "modesetting"
|
||||
EndSection
|
||||
|
||||
Section "Screen"
|
||||
Identifier "intel"
|
||||
Device "intel"
|
||||
EndSection
|
||||
"""
|
||||
|
||||
XORG_AMD = """# Automatically generated by lapctl
|
||||
|
||||
Section "ServerLayout"
|
||||
Identifier "layout"
|
||||
Screen 0 "nvidia"
|
||||
Inactive "amdgpu"
|
||||
EndSection
|
||||
|
||||
Section "Device"
|
||||
Identifier "nvidia"
|
||||
Driver "nvidia"
|
||||
BusID "{}"
|
||||
EndSection
|
||||
|
||||
Section "Screen"
|
||||
Identifier "nvidia"
|
||||
Device "nvidia"
|
||||
Option "AllowEmptyInitialConfiguration"
|
||||
EndSection
|
||||
|
||||
Section "Device"
|
||||
Identifier "amdgpu"
|
||||
Driver "amdgpu"
|
||||
EndSection
|
||||
|
||||
Section "Screen"
|
||||
Identifier "amd"
|
||||
Device "amdgpu"
|
||||
EndSection
|
||||
"""
|
||||
|
||||
EXTRA_XORG_PATH = "/etc/X11/xorg.conf.d/10-nvidia.conf"
|
||||
|
||||
EXTRA_XORG_CONTENT = """# Automatically generated by lapctl
|
||||
|
||||
Section "OutputClass"
|
||||
Identifier "nvidia"
|
||||
MatchDriver "nvidia-drm"
|
||||
Driver "nvidia"
|
||||
"""
|
||||
|
||||
FORCE_COMP = ' Option "ForceCompositionPipeline" "true"\n'
|
||||
|
||||
COOLBITS = ' Option "Coolbits" "{}"\n'
|
||||
|
||||
MODESET_PATH = "/etc/modprobe.d/nvidia.conf"
|
||||
|
||||
MODESET_CONTENT = """# Automatically generated by lapctl
|
||||
|
||||
options nvidia-drm modeset=1
|
||||
options nvidia NVreg_UsePageAttributeTable=1 NVreg_InitializeSystemMemoryAllocations=0
|
||||
"""
|
||||
|
||||
MODESET_CURRENT_CONTENT = """# Automatically generated by lapctl
|
||||
|
||||
options nvidia-current-drm modeset=1
|
||||
options nvidia-current NVreg_UsePageAttributeTable=1 NVreg_InitializeSystemMemoryAllocations=0
|
||||
"""
|
||||
|
||||
MODESET_RTD3 = """# Automatically generated by lapctl
|
||||
|
||||
options nvidia-drm modeset=1
|
||||
options nvidia "NVreg_DynamicPowerManagement=0x0{}"
|
||||
options nvidia NVreg_UsePageAttributeTable=1 NVreg_InitializeSystemMemoryAllocations=0
|
||||
"""
|
||||
|
||||
MODESET_CURRENT_RTD3 = """# Automatically generated by lapctl
|
||||
|
||||
options nvidia-current-drm modeset=1
|
||||
options nvidia-current "NVreg_DynamicPowerManagement=0x0{}"
|
||||
options nvidia-current NVreg_UsePageAttributeTable=1 NVreg_InitializeSystemMemoryAllocations=0
|
||||
"""
|
||||
|
||||
SDDM_XSETUP_PATH = "/usr/share/sddm/scripts/Xsetup"
|
||||
|
||||
SDDM_XSETUP_CONTENT = """#!/bin/sh
|
||||
# Xsetup - run as root before the login dialog appears
|
||||
|
||||
"""
|
||||
|
||||
LIGHTDM_SCRIPT_PATH = "/etc/lightdm/nvidia.sh"
|
||||
|
||||
LIGHTDM_CONFIG_PATH = "/etc/lightdm/lightdm.conf.d/20-nvidia.conf"
|
||||
|
||||
LIGHTDM_CONFIG_CONTENT = """# Automatically generated by lapctl
|
||||
|
||||
[Seat:*]
|
||||
display-setup-script=/etc/lightdm/nvidia.sh
|
||||
"""
|
||||
|
||||
NVIDIA_XRANDR_SCRIPT = """#!/bin/sh
|
||||
# Automatically generated by lapctl
|
||||
|
||||
current=""
|
||||
|
||||
xrandr --setprovideroutputsource "{}" NVIDIA-0
|
||||
xrandr --auto
|
||||
|
||||
for next in $(xrandr --listmonitors | grep -E " *[0-9]+:.*" | cut -d" " -f6); do
|
||||
[ -z "$current" ] && current=$next && continue
|
||||
xrandr --output "$current" --auto --output "$next" --auto --right-of "$current"
|
||||
current=$next
|
||||
done
|
||||
"""
|
||||
|
||||
SUPPORTED_MODES = ["integrated", "hybrid", "nvidia"]
|
||||
SUPPORTED_DISPLAY_MANAGERS = ["gdm", "gdm3", "sddm", "lightdm"]
|
||||
RTD3_MODES = [0, 1, 2, 3]
|
||||
|
||||
# end constants definition
|
||||
|
||||
|
||||
def graphics_mode_switcher(
|
||||
graphics_mode,
|
||||
user_display_manager,
|
||||
enable_force_comp,
|
||||
coolbits_value,
|
||||
rtd3_value,
|
||||
use_nvidia_current,
|
||||
):
|
||||
print(f"Switching to {graphics_mode} mode")
|
||||
|
||||
if graphics_mode == "integrated":
|
||||
if logging.getLogger().level == logging.DEBUG:
|
||||
service = subprocess.run(
|
||||
["systemctl", "disable", "nvidia-persistenced.service"]
|
||||
)
|
||||
else:
|
||||
service = subprocess.run(
|
||||
["systemctl", "disable", "nvidia-persistenced.service"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
if service.returncode == 0:
|
||||
print("Successfully disabled nvidia-persistenced.service")
|
||||
else:
|
||||
logging.error("An error ocurred while disabling service")
|
||||
|
||||
cleanup()
|
||||
|
||||
# blacklist all nouveau, nova and Nvidia modules
|
||||
create_file(BLACKLIST_PATH, BLACKLIST_CONTENT)
|
||||
|
||||
# power off the Nvidia GPU with udev rules
|
||||
create_file(UDEV_INTEGRATED_PATH, UDEV_INTEGRATED)
|
||||
|
||||
rebuild_initramfs()
|
||||
elif graphics_mode == "hybrid":
|
||||
print(
|
||||
f"Enable PCI-Express Runtime D3 (RTD3) Power Management: {rtd3_value or False}"
|
||||
)
|
||||
cleanup()
|
||||
|
||||
if logging.getLogger().level == logging.DEBUG:
|
||||
service = subprocess.run(
|
||||
["systemctl", "enable", "nvidia-persistenced.service"]
|
||||
)
|
||||
else:
|
||||
service = subprocess.run(
|
||||
["systemctl", "enable", "nvidia-persistenced.service"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
if service.returncode == 0:
|
||||
print("Successfully enabled nvidia-persistenced.service")
|
||||
else:
|
||||
logging.error("An error ocurred while enabling service")
|
||||
|
||||
if rtd3_value == None:
|
||||
if use_nvidia_current:
|
||||
create_file(MODESET_PATH, MODESET_CURRENT_CONTENT)
|
||||
else:
|
||||
create_file(MODESET_PATH, MODESET_CONTENT)
|
||||
else:
|
||||
# setup rtd3
|
||||
if use_nvidia_current:
|
||||
create_file(MODESET_PATH, MODESET_CURRENT_RTD3.format(rtd3_value))
|
||||
else:
|
||||
create_file(MODESET_PATH, MODESET_RTD3.format(rtd3_value))
|
||||
create_file(UDEV_PM_PATH, UDEV_PM_CONTENT)
|
||||
|
||||
rebuild_initramfs()
|
||||
elif graphics_mode == "nvidia":
|
||||
print(f"Enable ForceCompositionPipeline: {enable_force_comp}")
|
||||
print(f"Enable Coolbits: {coolbits_value or False}")
|
||||
|
||||
if logging.getLogger().level == logging.DEBUG:
|
||||
service = subprocess.run(
|
||||
["systemctl", "enable", "nvidia-persistenced.service"]
|
||||
)
|
||||
else:
|
||||
service = subprocess.run(
|
||||
["systemctl", "enable", "nvidia-persistenced.service"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
if service.returncode == 0:
|
||||
print("Successfully enabled nvidia-persistenced.service")
|
||||
else:
|
||||
logging.error("An error ocurred while enabling service")
|
||||
|
||||
cleanup()
|
||||
# get the Nvidia dGPU PCI bus
|
||||
nvidia_gpu_pci_bus = get_nvidia_gpu_pci_bus()
|
||||
|
||||
# get iGPU vendor
|
||||
igpu_vendor = get_igpu_vendor()
|
||||
|
||||
# create the X.org config
|
||||
if igpu_vendor == "intel":
|
||||
create_file(XORG_PATH, XORG_INTEL.format(nvidia_gpu_pci_bus))
|
||||
elif igpu_vendor == "amd":
|
||||
create_file(XORG_PATH, XORG_AMD.format(nvidia_gpu_pci_bus))
|
||||
|
||||
# enable modeset for Nvidia driver
|
||||
if use_nvidia_current:
|
||||
create_file(MODESET_PATH, MODESET_CURRENT_CONTENT)
|
||||
else:
|
||||
create_file(MODESET_PATH, MODESET_CONTENT)
|
||||
|
||||
# extra Xorg config
|
||||
if enable_force_comp and coolbits_value != None:
|
||||
create_file(
|
||||
EXTRA_XORG_PATH,
|
||||
EXTRA_XORG_CONTENT
|
||||
+ FORCE_COMP
|
||||
+ COOLBITS.format(coolbits_value)
|
||||
+ "EndSection\n",
|
||||
)
|
||||
elif enable_force_comp:
|
||||
create_file(
|
||||
EXTRA_XORG_PATH, EXTRA_XORG_CONTENT + FORCE_COMP + "EndSection\n"
|
||||
)
|
||||
elif coolbits_value != None:
|
||||
create_file(
|
||||
EXTRA_XORG_PATH,
|
||||
EXTRA_XORG_CONTENT + COOLBITS.format(coolbits_value) + "EndSection\n",
|
||||
)
|
||||
|
||||
# try to detect the display manager if not provided
|
||||
if user_display_manager == None:
|
||||
display_manager = get_display_manager()
|
||||
else:
|
||||
display_manager = user_display_manager
|
||||
|
||||
# only sddm and lightdm require further config
|
||||
if display_manager == "sddm":
|
||||
# backup Xsetup
|
||||
if os.path.exists(SDDM_XSETUP_PATH):
|
||||
logging.info("Creating Xsetup backup")
|
||||
with open(SDDM_XSETUP_PATH, mode="r", encoding="utf-8") as f:
|
||||
create_file(SDDM_XSETUP_PATH + ".bak", f.read())
|
||||
create_file(SDDM_XSETUP_PATH, generate_xrandr_script(igpu_vendor), True)
|
||||
elif display_manager == "lightdm":
|
||||
create_file(LIGHTDM_SCRIPT_PATH, generate_xrandr_script(igpu_vendor), True)
|
||||
create_file(LIGHTDM_CONFIG_PATH, LIGHTDM_CONFIG_CONTENT)
|
||||
|
||||
rebuild_initramfs()
|
||||
print("Operation completed successfully")
|
||||
print("Please reboot your computer for changes to take effect!")
|
||||
|
||||
|
||||
def cleanup():
|
||||
# define list of files to remove
|
||||
to_remove = [
|
||||
BLACKLIST_PATH,
|
||||
UDEV_INTEGRATED_PATH,
|
||||
UDEV_PM_PATH,
|
||||
XORG_PATH,
|
||||
EXTRA_XORG_PATH,
|
||||
MODESET_PATH,
|
||||
LIGHTDM_SCRIPT_PATH,
|
||||
LIGHTDM_CONFIG_PATH,
|
||||
# legacy files
|
||||
"/etc/X11/xorg.conf.d/90-nvidia.conf",
|
||||
"/lib/udev/rules.d/50-remove-nvidia.rules",
|
||||
"/lib/udev/rules.d/80-nvidia-pm.rules",
|
||||
]
|
||||
|
||||
# remove each file in the list
|
||||
for file_path in to_remove:
|
||||
try:
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
logging.info(f"Removed file {file_path}")
|
||||
except OSError as e:
|
||||
# only warn if file exists (code 2)
|
||||
if e.errno != 2:
|
||||
logging.error(f"Failed to remove file '{file_path}': {e}")
|
||||
|
||||
# restore Xsetup backup if found
|
||||
backup_path = SDDM_XSETUP_PATH + ".bak"
|
||||
if os.path.exists(backup_path):
|
||||
logging.info("Restoring Xsetup backup")
|
||||
with open(backup_path, mode="r", encoding="utf-8") as f:
|
||||
create_file(SDDM_XSETUP_PATH, f.read())
|
||||
# remove backup
|
||||
os.remove(backup_path)
|
||||
logging.info(f"Removed file {backup_path}")
|
||||
|
||||
|
||||
def get_nvidia_gpu_pci_bus():
|
||||
lspci_output = subprocess.check_output(["lspci"]).decode("utf-8")
|
||||
for line in lspci_output.splitlines():
|
||||
if "NVIDIA" in line and (
|
||||
"VGA compatible controller" in line or "3D controller" in line
|
||||
):
|
||||
# remove leading zeros
|
||||
pci_bus_id = line.split()[0].replace("0000:", "")
|
||||
logging.info(f"Found Nvidia GPU at {pci_bus_id}")
|
||||
break
|
||||
else:
|
||||
logging.error("Could not find Nvidia GPU")
|
||||
print("Try switching to hybrid mode first!")
|
||||
sys.exit(1)
|
||||
|
||||
# need to return the BusID in 'PCI:bus:device:function' format
|
||||
# also perform hexadecimal to decimal conversion
|
||||
bus, device_function = pci_bus_id.split(":")
|
||||
device, function = device_function.split(".")
|
||||
return f"PCI:{int(bus, 16)}:{int(device, 16)}:{int(function, 16)}"
|
||||
|
||||
|
||||
def get_igpu_vendor():
|
||||
lspci_output = subprocess.check_output(["lspci"]).decode("utf-8")
|
||||
for line in lspci_output.splitlines():
|
||||
if "VGA compatible controller" in line or "Display controller" in line:
|
||||
if "Intel" in line:
|
||||
logging.info("Found Intel iGPU")
|
||||
return "intel"
|
||||
elif "ATI" in line or "AMD" in line or "AMD/ATI" in line:
|
||||
logging.info("Found AMD iGPU")
|
||||
return "amd"
|
||||
logging.warning("Could not find Intel or AMD iGPU")
|
||||
return None
|
||||
|
||||
|
||||
def get_display_manager():
|
||||
try:
|
||||
with open(
|
||||
"/etc/systemd/system/display-manager.service", "r", encoding="utf-8"
|
||||
) as f:
|
||||
content = f.read()
|
||||
match = re.search(r"ExecStart=(.+)\n", content)
|
||||
if match:
|
||||
# only return the final component of the path
|
||||
display_manager = os.path.basename(match.group(1))
|
||||
logging.info(f"Found {display_manager} Display Manager")
|
||||
return display_manager
|
||||
except FileNotFoundError:
|
||||
logging.warning("Display Manager detection is not available")
|
||||
|
||||
|
||||
def generate_xrandr_script(igpu_vendor):
|
||||
if igpu_vendor == "intel":
|
||||
return NVIDIA_XRANDR_SCRIPT.format("modesetting")
|
||||
elif igpu_vendor == "amd":
|
||||
amd_igpu_name = get_amd_igpu_name()
|
||||
if amd_igpu_name != None:
|
||||
return NVIDIA_XRANDR_SCRIPT.format(amd_igpu_name)
|
||||
else:
|
||||
return NVIDIA_XRANDR_SCRIPT.format("modesetting")
|
||||
else:
|
||||
return NVIDIA_XRANDR_SCRIPT.format("modesetting")
|
||||
|
||||
|
||||
def get_amd_igpu_name():
|
||||
if not os.path.exists("/usr/bin/xrandr"):
|
||||
logging.warning(
|
||||
"The 'xrandr' command is not available. Make sure the package is installed!"
|
||||
)
|
||||
return None
|
||||
|
||||
try:
|
||||
xrandr_output = subprocess.check_output(["xrandr", "--listproviders"]).decode(
|
||||
"utf-8"
|
||||
)
|
||||
except subprocess.CalledProcessError:
|
||||
logging.warning("Failed to run the 'xrandr' command.")
|
||||
|
||||
pattern = re.compile(r"(name:).*(ATI*|AMD*|AMD\/ATI)*")
|
||||
|
||||
if pattern.findall(xrandr_output):
|
||||
return re.search(pattern, xrandr_output).group(0)[5:]
|
||||
else:
|
||||
logging.warning("Could not find AMD iGPU in 'xrandr' output.")
|
||||
return None
|
||||
|
||||
|
||||
def rebuild_initramfs():
|
||||
# OSTree systems first
|
||||
if any(os.path.exists(dir) for dir in ["/ostree", "/sysroot/ostree"]):
|
||||
print("Rebuilding the initramfs with rpm-ostree...")
|
||||
command = ["rpm-ostree", "initramfs", "--enable", "--arg=--force"]
|
||||
|
||||
# Debian and Ubuntu derivatives
|
||||
elif os.path.exists("/etc/debian_version"):
|
||||
command = ["update-initramfs", "-u", "-k", "all"]
|
||||
# RHEL and SUSE derivatives
|
||||
elif os.path.exists("/etc/redhat-release") or os.path.exists("/usr/bin/zypper"):
|
||||
command = ["dracut", "--force", "--regenerate-all"]
|
||||
# EndeavourOS with dracut
|
||||
elif os.path.exists("/usr/lib/endeavouros-release") and os.path.exists(
|
||||
"/usr/bin/dracut"
|
||||
):
|
||||
command = ["dracut-rebuild"]
|
||||
# ALT Linux
|
||||
elif os.path.exists("/etc/altlinux-release"):
|
||||
command = ["make-initrd"]
|
||||
# Arch Linux
|
||||
elif os.path.exists("/etc/arch-release"):
|
||||
command = ["mkinitcpio", "-P"]
|
||||
else:
|
||||
command = []
|
||||
|
||||
if shutil.which("systemd-inhibit"):
|
||||
command = [
|
||||
"systemd-inhibit",
|
||||
"--who=lapctl",
|
||||
"--why",
|
||||
"Rebuilding initramfs",
|
||||
"--",
|
||||
*command,
|
||||
]
|
||||
|
||||
if len(command) != 0:
|
||||
print("Rebuilding the initramfs...")
|
||||
if logging.getLogger().level == logging.DEBUG:
|
||||
p = subprocess.run(command)
|
||||
else:
|
||||
p = subprocess.run(
|
||||
command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
|
||||
)
|
||||
if p.returncode == 0:
|
||||
print("Successfully rebuilt the initramfs!")
|
||||
else:
|
||||
logging.error("An error ocurred while rebuilding the initramfs")
|
||||
|
||||
|
||||
def create_file(path, content, executable=False):
|
||||
try:
|
||||
# create the parent folders if needed
|
||||
if not os.path.exists(os.path.dirname(path)):
|
||||
os.makedirs(os.path.dirname(path))
|
||||
with open(path, mode="w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
logging.info(f"Created file {path}")
|
||||
if logging.getLogger().level == logging.DEBUG:
|
||||
print(content)
|
||||
|
||||
# add execution privilege
|
||||
if executable:
|
||||
subprocess.run(["chmod", "+x", path], stdout=subprocess.DEVNULL)
|
||||
logging.info(f"Added execution privilege to file {path}")
|
||||
except OSError as e:
|
||||
logging.error(f"Failed to create file '{path}': {e}")
|
||||
|
||||
|
||||
def assert_root():
|
||||
if os.geteuid() != 0:
|
||||
logging.error("This operation requires root privileges")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
# define CLI arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--version",
|
||||
action="version",
|
||||
version=VERSION,
|
||||
help="Output the current version",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-q", "--query", action="store_true", help="Query the current graphics mode"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--switch",
|
||||
type=str,
|
||||
metavar="MODE",
|
||||
action="store",
|
||||
choices=SUPPORTED_MODES,
|
||||
help="Switch the graphics mode. Available choices: %(choices)s",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dm",
|
||||
type=str,
|
||||
metavar="DISPLAY_MANAGER",
|
||||
action="store",
|
||||
choices=SUPPORTED_DISPLAY_MANAGERS,
|
||||
help="Manually specify your Display Manager for Nvidia mode. Available choices: %(choices)s",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--force-comp",
|
||||
action="store_true",
|
||||
help="Enable ForceCompositionPipeline on Nvidia mode",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--coolbits",
|
||||
type=int,
|
||||
nargs="?",
|
||||
metavar="VALUE",
|
||||
action="store",
|
||||
const=28,
|
||||
help="Enable Coolbits on Nvidia mode. Default if specified: %(const)s",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--rtd3",
|
||||
type=int,
|
||||
nargs="?",
|
||||
metavar="VALUE",
|
||||
action="store",
|
||||
choices=RTD3_MODES,
|
||||
const=2,
|
||||
help="Setup PCI-Express Runtime D3 (RTD3) Power Management on Hybrid mode. Available choices: %(choices)s. Default if specified: %(const)s",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--use-nvidia-current",
|
||||
action="store_true",
|
||||
help="Use nvidia-current instead of nvidia for kernel modules",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--reset-sddm", action="store_true", help="Restore default Xsetup file"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--reset", action="store_true", help="Revert changes made by lapctl"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cache-create",
|
||||
action="store_true",
|
||||
help="Create cache used by lapctl; only works in hybrid mode",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cache-delete",
|
||||
action="store_true",
|
||||
help="Delete cache created by lapctl",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cache-query", action="store_true", help="Show cache created by lapctl"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose", default=False, action="store_true", help="Enable verbose mode"
|
||||
)
|
||||
|
||||
# print help if no arg is provided
|
||||
if len(sys.argv) == 1:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# log formatting
|
||||
logging.basicConfig(format="%(levelname)s: %(message)s")
|
||||
|
||||
# set debug level for verbose mode
|
||||
if args.verbose:
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
|
||||
if args.query:
|
||||
mode = get_current_mode()
|
||||
print(mode)
|
||||
return
|
||||
elif args.cache_create:
|
||||
assert_root()
|
||||
CachedConfig(args).create_cache_file()
|
||||
return
|
||||
elif args.cache_delete:
|
||||
assert_root()
|
||||
CachedConfig.delete_cache_file()
|
||||
return
|
||||
elif args.cache_query:
|
||||
CachedConfig.show_cache_file()
|
||||
return
|
||||
|
||||
if args.switch or args.reset_sddm or args.reset:
|
||||
with CachedConfig(args).adapter():
|
||||
if args.switch:
|
||||
assert_root()
|
||||
graphics_mode_switcher(
|
||||
args.switch,
|
||||
args.dm,
|
||||
args.force_comp,
|
||||
args.coolbits,
|
||||
args.rtd3,
|
||||
args.use_nvidia_current,
|
||||
)
|
||||
elif args.reset_sddm:
|
||||
assert_root()
|
||||
create_file(SDDM_XSETUP_PATH, SDDM_XSETUP_CONTENT, True)
|
||||
print("Operation completed successfully")
|
||||
elif args.reset:
|
||||
assert_root()
|
||||
cleanup()
|
||||
CachedConfig.delete_cache_file()
|
||||
rebuild_initramfs()
|
||||
print("Operation completed successfully")
|
||||
|
||||
|
||||
class CachedConfig:
|
||||
"""Adapter for config from CACHE_FILE_PATH"""
|
||||
|
||||
def __init__(self, app_args) -> None:
|
||||
self.app_args = app_args
|
||||
self.current_mode = get_current_mode()
|
||||
|
||||
@contextmanager
|
||||
def adapter(self):
|
||||
global get_nvidia_gpu_pci_bus
|
||||
use_cache = os.path.exists(CACHE_FILE_PATH)
|
||||
|
||||
if self.is_hybrid(): # recreate cache file when in hybrid mode
|
||||
self.create_cache_file()
|
||||
|
||||
if use_cache:
|
||||
self.read_cache_file() # might not be in hybrid mode
|
||||
|
||||
# rebind function to use cached value instead of detection
|
||||
get_nvidia_gpu_pci_bus = self.get_nvidia_gpu_pci_bus
|
||||
|
||||
yield # back to main ...
|
||||
|
||||
def create_cache_file(self):
|
||||
if not self.is_hybrid():
|
||||
raise ValueError(
|
||||
"--cache-create requires that the system be in the hybrid Optimus mode"
|
||||
)
|
||||
|
||||
self.nvidia_gpu_pci_bus = get_nvidia_gpu_pci_bus()
|
||||
self.obj = self.create_cache_obj(self.nvidia_gpu_pci_bus)
|
||||
self.write_cache_file()
|
||||
|
||||
def create_cache_obj(self, nvidia_gpu_pci_bus):
|
||||
return {"nvidia_gpu_pci_bus": nvidia_gpu_pci_bus}
|
||||
|
||||
def is_hybrid(self):
|
||||
return "hybrid" == self.current_mode
|
||||
|
||||
def get_nvidia_gpu_pci_bus(self):
|
||||
return self.nvidia_gpu_pci_bus
|
||||
|
||||
@staticmethod
|
||||
def delete_cache_file():
|
||||
os.remove(CACHE_FILE_PATH)
|
||||
os.removedirs(os.path.dirname(CACHE_FILE_PATH))
|
||||
logging.debug(f"Removed file {CACHE_FILE_PATH}")
|
||||
|
||||
def read_cache_file(self):
|
||||
from json import loads
|
||||
|
||||
if os.path.exists(CACHE_FILE_PATH):
|
||||
with open(CACHE_FILE_PATH, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
self.obj = loads(content)
|
||||
self.nvidia_gpu_pci_bus = self.obj["nvidia_gpu_pci_bus"]
|
||||
elif self.is_hybrid():
|
||||
self.nvidia_gpu_pci_bus = get_nvidia_gpu_pci_bus()
|
||||
else:
|
||||
raise ValueError(
|
||||
"No cache present. Operation requires that the system be in the hybrid Optimus mode"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def show_cache_file():
|
||||
content = f"ERROR: Could not read {CACHE_FILE_PATH}"
|
||||
if os.path.exists(CACHE_FILE_PATH):
|
||||
with open(CACHE_FILE_PATH, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
print(content)
|
||||
|
||||
def write_cache_file(self):
|
||||
from json import dump
|
||||
|
||||
os.makedirs(os.path.dirname(CACHE_FILE_PATH), exist_ok=True)
|
||||
|
||||
with open(CACHE_FILE_PATH, "w", encoding="utf-8") as f:
|
||||
dump(self.obj, fp=f, indent=4, sort_keys=False)
|
||||
|
||||
logging.debug(f"Created file {CACHE_FILE_PATH}")
|
||||
|
||||
|
||||
def get_current_mode():
|
||||
mode = "hybrid"
|
||||
if os.path.exists(BLACKLIST_PATH) and (
|
||||
os.path.exists(UDEV_INTEGRATED_PATH)
|
||||
or os.path.exists("/lib/udev/rules.d/50-remove-nvidia.rules")
|
||||
):
|
||||
mode = "integrated"
|
||||
elif os.path.exists(XORG_PATH) and os.path.exists(MODESET_PATH):
|
||||
mode = "nvidia"
|
||||
return mode
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user