Use so called prime instead of bumblebee for nvidia optimus based laptops

tutorial
optimus

#1
  • first of all, sorry for bad english

  • delete all gpu drivers with mhwd (mhwd -li list installed drivers)

  • get bus ids of gpus with lspci | grep VGA

Nvidia:

  • install video-nvidia with mhwd
  • edit (or create) /etc/X11/mhwd.d/nvidia.conf (busid need correct format, 01:00.0 -> 1:0:0):
Section "Module"
    Load "modesetting"
EndSection


Section "Device"
    Identifier     "nvidia"
    Driver         "nvidia"
    VendorName "NVIDIA Corporation"
    BoardName "Geforce GT630M"
    BusID    "PCI:1:0:0" # use correct busid for nvidia gpu
    Option   "Coolbits" "8" # show powermizer panel in nvidia settings, value depends on graphic card
EndSection


Section "Monitor" # eliminate "ghost" output, not needed
    Identifier "VGA-1-1"
    Option "Ignore" "1"
EndSection


Section "Monitor" # eliminate "ghost" output, not needed
    Identifier "VGA-0"
    Option "Ignore" "1"
EndSection
  • create file /etc/X11/mhwd.d/prime-offload.sh:
#!/bin/sh

#xrandr --dpi 96 # you can set dpi here (also in nvidia.conf file)
xrandr --setprovideroutputsource modesetting NVIDIA-0
xrandr --auto
exec nvidia-settings --load-config-only
  • add to .xinitrc or /etc/X11/xinit/xinitrc (or see edit below) if you dont use display manager:
[ -f /etc/X11/mhwd.d/prime-offload.sh ] && . /etc/X11/mhwd.d/prime-offload.sh &

EDIT 09.09.2017:
or

  • you can also create a new script in /etc/X11/xinitrc.d instead, this is possible the most convenient approach,
    e.g.:
    /etc/X11/xinit/xinitrc.d/99-prime-offload.sh:
#!/bin/sh

[ -f /etc/X11/mhwd.d/prime-offload.sh ] && . /etc/X11/mhwd.d/prime-offload.sh &

//EDIT

  • if you use display manager:
sddm:

edit /usr/share/sddm/scripts/Xsetup:

[ -f /etc/X11/mhwd.d/prime-offload.sh ] && . /etc/X11/mhwd.d/prime-offload.sh
lightdm:
  • create /etc/lightdm/display_setup.sh
#!/bin/sh
[ -f /etc/X11/mhwd.d/prime-offload.sh ] && . /etc/X11/mhwd.d/prime-offload.sh
  • make script executable:
chmod +x /etc/lightdm/display_setup.sh
  • Now configure lightdm to run the script by editing the [Seat:*] section in /etc/lightdm/lightdm.conf:
    /etc/lightdm/lightdm.conf:
[Seat:*]
display-setup-script=/etc/lightdm/display_setup.sh

(taken from arch webpage https://wiki.archlinux.org/index.php/NVIDIA_Optimus, never used lightdm myself)

  • edit/create /etc/modules-load.d/mhwd-gpu.conf:
nvidia
nvidia-drm
nvidia-uvm
  • edit/create /etc/modprobe.d/mhwd-gpu.conf:
blacklist nouveau
blacklist ttm
options nvidia-drm modeset=1

(last one is for vsync, not necessarily needed)

  • reboot pc, nvidia driver should work now, if not check /var/log/Xorg.0.log

Intel: (here you can use either intel driver or modesetting driver, modesetting driver should work without anything installed

  • install video-intel with mhwd (shouldn’t be necessary if you use modesetting, but never tested it without)
  • edit /etc/X11/mhwd.d/intel.conf (busid need correct format) :
INTEL DRIVER:
Section "OutputClass" # needed if nvidia module loaded
    Identifier "intel"
    ModulePath "/usr/lib/xorg/modules/extensions"
EndSection


Section "Device"
    Identifier  "intel"
    Driver      "intel"
    BusID       "PCI:0:2:0" # correct busid
    Option      "DRI"    "true"
    Option      "TearFree" "true" # not an option for modesetting
EndSection


Section "DRI"
        Group  "video"
        Mode   0666
EndSection
MODESETTING DRIVER:
Section "OutputClass" # needed if nvidia module loaded
    Identifier "intel"
    ModulePath "/usr/lib/xorg/modules/extensions"
EndSection


Section "Device"
    Identifier  "intel"
    Driver      "modesetting"
    BusID       "PCI:0:2:0" # correct busid
EndSection
  • edit /etc/modules-load.d/mhwd-gpu.conf (not necessary):
    either:
    leave empty

  • or:
    add nvidia modules

  • or:
    add nouveau (if you have xf86-video-nouveau installed.)

  • edit /etc/modprobe.d/mhwd-gpu.conf:
    either:

blacklist nouveau
blacklist ttm

or: (if you want to use nouveau)

blacklist nvidia
blacklist nvidia-modeset
blacklist nvidia-uvm
blacklist nvidia-drm
  • for switching without reboot, load nvidia modules with intel (or keep file empty)
  • outputclass section: I use it this way in the intel config because if nvidia module is loaded and you start x without modulepath libglx cant be found (for me)

Switching:

  • use script like this:
#!/usr/bin/python3

import os,shutil,subprocess,re
import argparse
import json


# default config
config = {
    "modules_load_file": "/etc/modules-load.d/mhwd-gpu.conf",
    "modules_modprobe_file": "/etc/modprobe.d/mhwd-gpu.conf",
    "mhwd_symlink_target": "/etc/X11/xorg.conf.d/90-mhwd.conf",
    "prime_offload_script": "/etc/X11/mhwd.d/prime-offload.sh",
    "driver": {
        "intel": {
            "xorg_file": "/etc/X11/mhwd.d/intel.conf",
            "xrandr_offload": False,
            "modules_load": [],
            "modules_blacklist": ["nouveau","ttm"],
            "modules_options": []
        },
        "nvidia": {
            "xorg_file": "/etc/X11/mhwd.d/nvidia.conf",
            "xrandr_offload": True,
            "modules_load": ["nvidia","nvidia-drm","nvidia-uvm"],
            "modules_blacklist": ["nouveau","ttm"],
            "modules_options": ["nvidia-drm modeset=1"]
        }
    }
}
        
def create_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-d", "--driver",
        #required=True,
        #choices=config["driver"].keys(),
        help="Switch to this driver (e.g. intel or nvidia)"
    )
    parser.add_argument(
        "-c", "--config",
        help="Path to config file (only needed if you want to use non default settings)"
    )
    parser.add_argument(
        "-s", "--show-config",
        nargs='?',
        const=True,
        metavar="Filename",
        help="Dumps default config to stdout or filename if specified (only useful if you want to mess around with default settings and use with -c switch afterwards)"
    )
    
    return(parser.parse_args())

class Info:
    def returnCurDrivers(self):
        from collections import OrderedDict
        sh = 'lspci -D|grep VGA'
        cmd = subprocess.getstatusoutput(sh)
        if cmd[0] == 0:
            gpus = OrderedDict() # mabey use just normal dict instead
            gpu = cmd[1].split("\n")
            for i,v in enumerate(gpu):
                gpus[i] = self.splitlspci(v)
            for k,v in gpus.items():
                f = open("/sys/bus/pci/devices/"+v[0]+"/uevent")
                v.append(f.read())
            return(gpus)
                
        else: # subprocess.getstatusoutput failed
            print("Error %s\nErrorcode %i " %(sh,cmd[0]))
        
    def splitlspci(self,cmd):
        pci = cmd.split(" ")[0]
        se = pci+'.*controller:'
        card = re.split(se,cmd)[1].lstrip()
        return([pci,card])

class Util:
    def changeModules(self,load,blacklist,options):
        # modules to load
        f1 = open(config["modules_load_file"],"w") # start with empty file
        if len(load) > 0:
            for i in load:
                f1.write(i+"\n")
                print("Load: %s" %i)
        f1.close()
        # modules to blacklist
        f2 = open(config["modules_modprobe_file"],"w") # start with empty file
        if len(blacklist) > 0:
            for j in blacklist:
                f2.write("blacklist "+j+"\n")
                print("Blacklist: %s" %j)
        # modules options
        if len(options) > 0:
            for k in options:
                f2.write("options "+k+"\n")
                print("Option: options %s" %k)
        f2.close()

    #
    # switchDriver function:
    # par1=conf to symlink
    # par2=target file symlink points to (default /etc/X11/xorg.conf.d/90-mhwd.conf)
    # par3=prime-offload script disable or enable
    # par4=modules to load (list)
    # par5=modules to blacklist (list)
    # par6=modules options (list)
    #
    def switchDriver(self,src, trg=config["mhwd_symlink_target"], *, prioff, mload, mblacklist, moptions):
        try:
            os.unlink(trg)
            os.symlink(src,trg)
            print("Symlink %s -> %s" %(src,trg))

            if prioff == False:
                fe = os.path.isfile(config["prime_offload_script"])
                if fe is True:
                    os.rename(config["prime_offload_script"],config["prime_offload_script"]+"-disabled")
            elif prioff:
                fe = os.path.isfile(config["prime_offload_script"]+"-disabled")
                if fe is True:
                    os.rename(config["prime_offload_script"]+"-disabled",config["prime_offload_script"])
            else:
                raise ValueError('%s\nUse either true or false not:\n%s' %(config["prime_offload_script"],str(prioff)))

            self.changeModules(mload,mblacklist,moptions)
            return True
        except Exception as e:
            return(str(e))


if __name__ == "__main__":
    args = create_parser()

    if args.show_config is True:
        print(json.dumps(config, indent=4, separators=(',', ': ')))
        exit(0)
    elif isinstance(args.show_config,str): # filename specified
        print("dump config to file %s" %args.show_config)
        with open(args.show_config,"w") as f:
            f.write(json.dumps(config, indent=4, separators=(',', ': ')))
        exit(0)
        
    if args.config is not None:
        with open(args.config,"r") as f:
            config = json.loads(f.read())
        if args.driver is None: print("No driver specified"); exit(1);
    
    if args.driver is not None:
        drivers = list(config["driver"].keys())
        if os.getuid() != 0:
            # not root user
            print("Please execute as root")
            exit(2)
        #elif args.driver in config["driver"].keys():
        elif args.driver in drivers:
            res = Util().switchDriver(
                  config["driver"][args.driver]["xorg_file"],
                  prioff=config["driver"][args.driver]["xrandr_offload"],
                  mload=config["driver"][args.driver]["modules_load"],
                  mblacklist=config["driver"][args.driver]["modules_blacklist"],
                  moptions=config["driver"][args.driver]["modules_options"]
                  )
            if res is True:
                print("Relogin or reboot now, please")
            else:
                print("ERROR\n%s" %res)
        else:
            #print("Unrecognized driver name, choose from %s" %" or ".join(list(config["driver"].keys())))
            print("Possible drivers: %s" %" or ".join(drivers))

    else:
        # No driver specified, show current used
        output = Info().returnCurDrivers()
        for k,v in output.items():
            #pci = v[0] # not needed, also in "info"PCI_SLOT_NAME
            card = v[1]
            info = v[2]
            print("GPU%i: %s\n%s" %(k,card,info))
  • if you use above script you can switch driver with e.g. ./script-name -d intel
  • you can mess around with loaded/blacklisted modules, used xorg.confs:
    save current config with ./script-name -s filename
    edit and ensure json not broken (dont use python booleans, use true and false instead)
  • use with ./script-name -c filename -d driver-name

Short summary:

  • deinstall unneeded and install needed packages (with mhwd)

  • adjust xorg.conf (symlink from /etc/X11/xorg.conf.d/90-mhwd.conf to /etc/X11/mhwd.d/config)

  • ensure right modules are loaded/blacklisted

  • nvidia: ensure xrandr setprovideroutputsource command and xrand auto command are executed

  • issues: check /var/log/Xorg.0.log

  • check arch webpages (https://wiki.archlinux.org/index.php/NVIDIA_Optimus and prime webpage)

  • if something goes wrong, is misconfigured, etc…, you likely end with black screen, if using a dislay manager switch to another tty and check /var/log/Xorg.0.log (e.g. with grep -E ‘WW|EE’ /var/log/Xorg.0.log )

  • you may need or want to use additional options in xorg.conf file

  • nvidia-uvm module is cuda related, should also work without loading

  • dont blame me if you broke your x server


Need help with hybrid graphic cards configuration
When will PRIME support be added to mhwd?
How to keep two conflicting drivers installed (disable one)
How to install Nvidia graphis on Laptop?
#2

i’ve moved this to the tutorials section!


#3

Can this be used to help nvidia prime incorporation into mhwd?

video-hybrid-intel-nvidia-prime

#4

Is this question directed towards me?

video-hybrid-intel-nvidia-prime shouldnt be that complicated:

  • check/adjust bus-id for intel and nvidia card for xorg conf
  • dont know whats the best approch for executing scipt that sets xrandr --setoutputsource …, imo its in /etc/X11/xinit/xinitrc.d/some-file (prime-offload script seems redundant but I use it that way to execute nvidia-settings --load-conf-only only with nvidia card, else it seems to reset to default settings. Also it seems that nvidia is using always default settings until once started). But you could also use just one script in /etc/X11/xinit/xinitrc.d (or in xinitrc or display-manager script) which executes the xrandr commands always

For switching of gpus, either use some python or bash script like above or a gui application (I wrote one in qt in the past but dropped it, because if gpu breaks (e.g. wrong xorg settings), switching to working gpu wont be possible then.)