diff --git a/internal/config/cardpick.go b/internal/config/cardpick.go new file mode 100644 index 00000000..8d88d869 --- /dev/null +++ b/internal/config/cardpick.go @@ -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 +} diff --git a/internal/config/config.go b/internal/config/config.go index 00c5248d..087b4b96 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -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 { @@ -88,6 +89,9 @@ func Default() Config { "__GL_THREADED_OPTIMIZATIONS": "1", }, + Global: Binary{ + ForcedGpu: "prime-discrete", + }, Player: Binary{ DiscordRPC: true, Dxvk: true, @@ -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() @@ -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() diff --git a/internal/config/env.go b/internal/config/env.go index 1fab9de3..91482197 100644 --- a/internal/config/env.go +++ b/internal/config/env.go @@ -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)