This repository has been archived by the owner on May 31, 2022. It is now read-only.
forked from xulongwu4/nvidia-optimus-manager
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 680f000
Showing
4 changed files
with
313 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[Seat:*] | ||
display-stopped-script=/usr/bin/nvidia-optimus-manager autoconfigure |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
- `99-nvidia.conf`: copy to `/etc/lightdm/lightdm.conf.d/99-nvidia.conf` | ||
- `nvidia-optimus-autoconfig.service`: copy to `/etc/systemd/system/nvidia-optimus-autoconfig.service` | ||
- `nvidia-optimus-manager`: copy to `/usr/bin/nvidia-optimus-manager` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[Unit] | ||
Description=Automatic configuration for nvidia optimus | ||
|
||
[Service] | ||
Type=oneshot | ||
ExecStart=/usr/bin/nvidia-optimus-manager autoconfigure | ||
RemainAfterExit=yes | ||
|
||
[Install] | ||
WantedBy=multi-user.target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,298 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# prime-select | ||
# | ||
# Copyright 2013 Canonical Ltd. | ||
# Author: Alberto Milone <alberto.milone@canonical.com> | ||
# | ||
# Script to switch between NVIDIA and Intel graphics driver libraries. | ||
# | ||
# Usage: | ||
# prime-select nvidia|intel|query | ||
# nvidia: switches to NVIDIA's version of libGL.so | ||
# intel: switches to the open-source version of libGL.so | ||
# query: checks which version is currently active and writes | ||
# "nvidia", "intel" or "unknown" to the standard output | ||
# | ||
# Permission is hereby granted, free of charge, to any person | ||
# obtaining a copy of this software and associated documentation | ||
# files (the "Software"), to deal in the Software without | ||
# restriction, including without limitation the rights to use, | ||
# copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
# copies of the Software, and to permit persons to whom the | ||
# Software is furnished to do so, subject to the following | ||
# conditions: | ||
# | ||
# The above copyright notice and this permission notice shall be | ||
# included in all copies or substantial portions of the Software. | ||
# | ||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
# OTHER DEALINGS IN THE SOFTWARE. | ||
|
||
import glob | ||
import os | ||
import sys | ||
import re | ||
import subprocess | ||
import shutil | ||
|
||
from copy import deepcopy | ||
from subprocess import Popen, PIPE, CalledProcessError, DEVNULL, check_output | ||
|
||
|
||
class Switcher(object): | ||
|
||
def __init__(self): | ||
self._power_profile_path = '/proc/acpi/bbswitch' | ||
self._ldm_conf_file = '/etc/X11/xorg.conf.d/00-ldm.conf' | ||
self._blacklist_file = '/etc/modprobe.d/blacklist-nvidia.conf' | ||
self._opengl_settings = {'intel': 'Intel', 'hybrid': 'Intel', 'nvidia': 'NVIDIA'} | ||
if not self._validate_setting(): | ||
sys.stdout.write('The program is not supported on current platform\nExiting ...\n') | ||
sys.exit(1) | ||
|
||
def _validate_setting(self): | ||
if not self._check_ldm(): | ||
sys.stdout.write('The current configuration is not supported\n\n--- The linux-driver-management program is not installed ---\n\n') | ||
return False | ||
|
||
if not self._check_optimus(): | ||
sys.stdout.write('The current configuration is not supported\n\n--- NVIDIA Optimus hardware is not detected ---\n\n') | ||
return False | ||
|
||
if not self._check_nouveau(): | ||
sys.stdout.write('The current configuration is not supported\n\n--- The nouveau driver needs to be unloaded ---\n\n') | ||
return False | ||
|
||
if not self._check_nvidia_driver(): | ||
sys.stdout.write('The current configuration is not supported\n\n--- NVIDIA proprietary driver is not installed ---\n\n') | ||
return False | ||
|
||
if not self._check_bbswitch(): | ||
sys.stdout.write('The current configuration is not supported\n\n--- The bbswitch module is not loaded ---\n\n') | ||
return False | ||
|
||
return True | ||
|
||
def _check_ldm(self): | ||
return os.path.exists('/usr/bin/linux-driver-management') | ||
|
||
def _check_optimus(self): | ||
p1 = Popen(['/usr/bin/linux-driver-management', 'status'], stdout=PIPE) | ||
status = subprocess.call(['grep', '-i', 'optimus'], stdin=p1.stdout, stdout=DEVNULL) | ||
return not status | ||
|
||
def _check_nouveau(self): | ||
p1 = Popen(['lsmod'], stdout=PIPE) | ||
status = subprocess.call(['grep', 'nouveau'], stdin=p1.stdout, stdout=DEVNULL) | ||
return status | ||
|
||
def _check_nvidia_driver(self): | ||
status = subprocess.call(['modinfo', 'nvidia'], stdout=DEVNULL, stderr=DEVNULL) | ||
return not status | ||
|
||
def _check_bbswitch(self): | ||
p1 = Popen(['lsmod'], stdout=PIPE) | ||
status = subprocess.call(['grep', 'bbswitch'], stdin=p1.stdout, stdout=DEVNULL) | ||
return not status | ||
|
||
def _get_profile(self): | ||
|
||
opengl_vendor = self._get_opengl_vendor() | ||
|
||
if opengl_vendor == 'NVIDIA': | ||
return 'nvidia' | ||
elif opengl_vendor == 'Intel': | ||
if self._is_nvidia_offloaded(): | ||
return 'intel'; | ||
else: | ||
return 'hybrid' | ||
else: | ||
return 'unknown' | ||
|
||
def _get_opengl_vendor(self): | ||
try: | ||
vendor_str = check_output('glxinfo | grep -i opengl | grep -i vendor', shell=True, stderr=DEVNULL).decode('utf-8').lower() | ||
|
||
if 'nvidia' in vendor_str: | ||
return 'NVIDIA' | ||
elif 'intel' in vendor_str: | ||
return 'Intel' | ||
else: | ||
return 'unknown' | ||
except: | ||
return 'unknown' | ||
|
||
def _get_nvidia_card_power_status(self): | ||
try: | ||
settings = open(self._power_profile_path, 'r') | ||
return settings.read().split()[1] | ||
except: | ||
return 'unknown' | ||
|
||
def print_configuration(self): | ||
profile = self._get_profile() | ||
print('Current profile: %s' % profile) | ||
|
||
vendor = self._get_opengl_vendor() | ||
print('OpenGL vendor: %s' % vendor) | ||
|
||
power = self._get_nvidia_card_power_status() | ||
print('Discrete graphics card power status: %s' % power) | ||
|
||
return True | ||
|
||
def enable_profile(self, profile): | ||
current_profile = self._get_profile() | ||
current_opengl_vendor = self._get_opengl_vendor() | ||
|
||
if profile == current_profile: | ||
# No need to do anything if we're already using the desired | ||
# profile | ||
sys.stdout.write('Info: the %s profile is already set\n' % (profile)) | ||
return True | ||
|
||
sys.stdout.write('Info: selecting the %s profile\n' % (profile)) | ||
|
||
new_opengl_vendor = self._opengl_settings[profile] | ||
|
||
if profile == 'intel': | ||
self._blacklist_nvidia() | ||
else: | ||
self._nuke_blacklist_file() | ||
|
||
if profile == 'nvidia': | ||
self._ldm_configure() | ||
else: | ||
self._nuke_ldm_conf() | ||
|
||
self.autoconfigure() | ||
|
||
if current_opengl_vendor != new_opengl_vendor: | ||
sys.stdout.write('Log out to take effect\n') | ||
|
||
return True | ||
|
||
def _ldm_configure(self): | ||
subprocess.call(['/usr/bin/linux-driver-management', 'configure', 'gpu'], stdout=DEVNULL, stderr=DEVNULL) | ||
|
||
def _enable_nvidia(self): | ||
if self._get_nvidia_card_power_status() == 'OFF': | ||
self._power_on_nvidia_card() | ||
|
||
if self._get_nvidia_card_power_status() == 'ON' and self._is_nvidia_offloaded(): | ||
self._load_nvidia_driver() | ||
|
||
def _disable_nvidia(self): | ||
self._nuke_ldm_conf() | ||
if not self._is_nvidia_offloaded() and self._get_opengl_vendor() != 'NVIDIA': | ||
self._unload_nvidia_driver() | ||
|
||
if self._get_nvidia_card_power_status() == 'ON' and self._is_nvidia_offloaded(): | ||
self._power_off_nvidia_card() | ||
|
||
|
||
def autoconfigure(self): | ||
if os.path.exists(self._blacklist_file): | ||
self._disable_nvidia() | ||
else: | ||
self._enable_nvidia() | ||
|
||
def _nuke_blacklist_file(self): | ||
try: | ||
os.unlink(self._blacklist_file) | ||
except: | ||
pass | ||
|
||
def _nuke_ldm_conf(self): | ||
try: | ||
os.unlink(self._ldm_conf_file) | ||
except: | ||
pass | ||
|
||
def _blacklist_nvidia(self): | ||
blacklist_text = '''# Do not modify | ||
# This file was generated by prime-select | ||
blacklist nvidia | ||
blacklist nvidia_drm | ||
blacklist nvidia_uvm | ||
blacklist nvidia_modeset''' | ||
blacklist_fd = open(self._blacklist_file, 'w') | ||
blacklist_fd.write(blacklist_text) | ||
blacklist_fd.close() | ||
|
||
def _unload_nvidia_driver(self): | ||
subprocess.call(['/usr/bin/systemctl', 'stop', 'nvidia-persistenced']) | ||
subprocess.call(['/sbin/modprobe', '-r', 'nvidia_drm']) | ||
subprocess.call(['/sbin/modprobe', '-r', 'nvidia_uvm']) | ||
subprocess.call(['/sbin/modprobe', '-r', 'nvidia_modeset']) | ||
subprocess.call(['/sbin/modprobe', '-r', 'nvidia']) | ||
|
||
def _load_nvidia_driver(self): | ||
subprocess.call(['/sbin/modprobe', 'nvidia']) | ||
|
||
def _is_nvidia_offloaded(self): | ||
p1 = Popen(['lsmod'], stdout=PIPE) | ||
status = subprocess.call(['grep', 'nvidia'], stdin=p1.stdout, stdout=DEVNULL) | ||
return status | ||
|
||
def _power_off_nvidia_card(self): | ||
p1 = Popen(['echo', 'OFF'], stdout=PIPE) | ||
subprocess.call(['/usr/bin/tee', self._power_profile_path], stdin=p1.stdout, stdout=DEVNULL) | ||
|
||
def _power_on_nvidia_card(self): | ||
p1 = Popen(['echo', 'ON'], stdout=PIPE) | ||
subprocess.call(['/usr/bin/tee', self._power_profile_path], stdin=p1.stdout, stdout=DEVNULL) | ||
|
||
def check_root(): | ||
if not os.geteuid() == 0: | ||
sys.stderr.write("This operation requires root privileges\n") | ||
exit(1) | ||
|
||
def handle_query_error(): | ||
sys.stderr.write("Error: no profile can be found\n") | ||
exit(1) | ||
|
||
def usage(): | ||
sys.stderr.write("Usage:\n") | ||
sys.stderr.write(" %s status\n" % (sys.argv[0])) | ||
sys.stderr.write(" %s configure nvidia|hybrid|intel\n" % (sys.argv[0])) | ||
sys.stderr.write(" %s autoconfigure\n" % (sys.argv[0])) | ||
|
||
if __name__ == '__main__': | ||
try: | ||
arg = sys.argv[1] | ||
except IndexError: | ||
arg = None | ||
|
||
switcher = Switcher() | ||
|
||
status = 0 | ||
|
||
if arg == 'status' and len(sys.argv) == 2: | ||
if not switcher.print_configuration(): | ||
handle_query_error() | ||
else: | ||
status = 1 | ||
elif arg == 'autoconfigure' and len(sys.argv) == 2: | ||
check_root() | ||
switcher.autoconfigure() | ||
status = 1 | ||
elif arg == 'configure' and len(sys.argv) == 3: | ||
arg = sys.argv[2] | ||
if arg == 'intel' or arg == 'nvidia' or arg == 'hybrid': | ||
check_root() | ||
switcher.enable_profile(arg) | ||
status = 1 | ||
|
||
if not status: | ||
usage() | ||
sys.exit(1) | ||
|
||
exit(0) |