Skip to content

Commit

Permalink
Add ForcedGpu option (#206)
Browse files Browse the repository at this point in the history
* Minor formatting fix

* WIP: Added ForcedGpuId and PrimeOffload options

* Global.PrimeOffload set to true by default

* Remove unnecessary error handling for sysfs IO

* Refactor: Merge Prime & ForcedGpuId into ForcedGpu

* ForcedGpu is now validated by config.go
Also did some refactoring to share validation logic across binaries

* prime: Do not redefine existing env vars

* prime: handle cases with 3+ gpus and opengl
In these circumstances, there's no way for us to determine the right gpu
...so abort and prompt the user to explictly choose it...
...or to try the vulkan renderer

* prime: Remove vendor check, only probe driver.
It's actually unnecessary to check the card's vendor.
Instead, just check for its driver. If it's nvidia, apply the...
...GLX workaround.

* prime -> gpu: major codebase refactor

* Yet another refactor: removed vid:nid logic
Now gpu works entirely around indexes

* oops: fixed inverted condition in gpu probe

* gpu: validate if index exists by checking length

* gpu: use PrimeNone string instead of literal
I just noticed this and it was really bothering me. It had to be fixed.

* card: Refactor prime logic around new sysinfo
Hopefully the last refactor of this code

* cardpick: Remove unnecessary env return

* cardpick: improve readbility, consolidate prime

* setIfUndefined as env method instead of function

* Simplify prime check variable names

Co-authored-by: sewn <sewn@disroot.org>
Signed-off-by: Jrelvas <55360900+Noted-Jrelvas@users.noreply.github.com>

* Fix env "set if undefined" method

Co-authored-by: sewn <sewn@disroot.org>
Signed-off-by: Jrelvas <55360900+Noted-Jrelvas@users.noreply.github.com>

* Remove log for env set

Co-authored-by: sewn <sewn@disroot.org>
Signed-off-by: Jrelvas <55360900+Noted-Jrelvas@users.noreply.github.com>

* Update cardpick code for suggestions made

* Consolidate BinaryParse into setup method

* Do not run pickCard logic if opt is empty string

* Reduced complexity of cardpick prime check

* The pickCard rewrite.

* Turn pickCard into a binary method

* config: return error directly in binary setup

* cardpick: Declare aIdx and prime in one var clause

* cardpick: removed unnecessary opt var

* Update internal/config/cardpick.go (format change)

Co-authored-by: sewn <sewn@disroot.org>
Signed-off-by: Jrelvas <55360900+Noted-Jrelvas@users.noreply.github.com>

* env: use self directly in set

* binary: Moved setenv from pickCard into setup.

---------

Signed-off-by: Jrelvas <55360900+Noted-Jrelvas@users.noreply.github.com>
Co-authored-by: sewn <sewn@disroot.org>
  • Loading branch information
jrelvas-ipc and apprehensions authored Oct 24, 2023
1 parent 0cddacf commit 28fadcb
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 2 deletions.
79 changes: 79 additions & 0 deletions internal/config/cardpick.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package config

import (
"errors"
"fmt"
"strconv"
"strings"

"github.com/vinegarhq/vinegar/sysinfo"
)

// opt accepts the following values:
// aliases - "integrated", "prime-discrete" and "none": Equivalent to "0", "1" or empty. Enables an extra "prime" check.
// integer - GPU index
// empty - Skips logic and does nothing.
func (b *Binary) pickCard() error {
aliases := map[string]string{
"integrated": "0",
"prime-discrete": "1",
"none": "",
}

var (
aIdx string
prime bool
)

aIdx = b.ForcedGpu
if a, ok := aliases[b.ForcedGpu]; ok {
aIdx = a
prime = true
}

if aIdx == "" {
return nil
}

n := len(sysinfo.Cards)

// Check if the system actually has PRIME offload and there's no ambiguity with the GPUs.
if prime {
vk := (b.Dxvk && b.Renderer == "D3D11") || b.Renderer == "Vulkan"

if n != 2 && (!vk && n != 1) {
return fmt.Errorf("opengl is not capable of choosing the right gpu, it must be explicitly defined")
}

if n != 2 {
return nil
}

if !sysinfo.Cards[0].Embedded {
return nil
}
}

idx, err := strconv.Atoi(aIdx)
if err != nil {
return err
}

if idx < 0 {
return errors.New("gpu index cannot be negative")
}
if n < idx+1 {
return errors.New("gpu not found")
}
c := sysinfo.Cards[idx]

b.Env.Set("MESA_VK_DEVICE_SELECT_FORCE_DEFAULT_DEVICE", "1")
b.Env.Set("DRI_PRIME", aIdx)

if strings.HasSuffix(c.Driver, "nvidia") { //Workaround for OpenGL in nvidia GPUs
b.Env.Set("__GLX_VENDOR_LIBRARY_NAME", "nvidia")
} else {
b.Env.Set("__GLX_VENDOR_LIBRARY_NAME", "mesa")
}
return nil
}
25 changes: 23 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type Binary struct {
Dxvk bool `toml:"dxvk"`
FFlags roblox.FFlags `toml:"fflags"`
Env Environment `toml:"env"`
ForcedGpu string `toml:"gpu"`
}

type Config struct {
Expand Down Expand Up @@ -88,6 +89,9 @@ func Default() Config {
"__GL_THREADED_OPTIMIZATIONS": "1",
},

Global: Binary{
ForcedGpu: "prime-discrete",
},
Player: Binary{
DiscordRPC: true,
Dxvk: true,
Expand All @@ -113,6 +117,19 @@ func Default() Config {
}
}

func (b *Binary) setup() error {
if !roblox.ValidRenderer(b.Renderer) {
return errors.New("invalid renderer given")
}

if err := b.pickCard(); err != nil {
return err
}

b.Env.Setenv()
return nil
}

func (c *Config) setup() error {
if c.SanitizeEnv {
util.SanitizeEnv()
Expand All @@ -135,8 +152,12 @@ func (c *Config) setup() error {
log.Printf("Using Wine Root: %s", c.WineRoot)
}

if !roblox.ValidRenderer(c.Player.Renderer) || !roblox.ValidRenderer(c.Studio.Renderer) {
return fmt.Errorf("invalid renderer given to either player or studio")
if err := c.Player.setup(); err != nil {
return fmt.Errorf("player: %w", err)
}

if err := c.Studio.setup(); err != nil {
return fmt.Errorf("studio: %w", err)
}

c.Env.Setenv()
Expand Down
9 changes: 9 additions & 0 deletions internal/config/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ import (

type Environment map[string]string

// Set will only set the given environment key and value if it isn't already set
// within the Environment.
func (e *Environment) Set(key, value string) {
if _, ok := (*e)[key]; ok {
return
}
(*e)[key] = value
}

func (e *Environment) Setenv() {
for name, value := range *e {
os.Setenv(name, value)
Expand Down

0 comments on commit 28fadcb

Please sign in to comment.