Battle.net's CEF launcher crashes (int3 in DXVK d3d11) when DXGI reports HDR10. Automatic Wayland HDR now uses per-exe DXVK_CONFIG sections for WoW executables instead of a global DXVK_HDR=1.
#2 fix(env): scope automatic HDR to WoW executables
M README.md +14 -6
| @@ -54,17 +54,25 @@ bnetctl clean -a # Full purge (cache, prefix, desktop entry, data) | |||
| 54 | 54 | ||
| 55 | 55 | ## HDR on Wayland | |
| 56 | 56 | ||
| 57 | - | HDR is enabled automatically for native Wayland (`DXVK_HDR=1`). It requires | |
| 58 | - | **Wine >= 11.19**, an HDR-capable compositor with HDR enabled, and an HDR-capable | |
| 59 | - | monitor/game. An existing `DXVK_HDR` environment variable is respected, including | |
| 60 | - | an empty value. To disable HDR explicitly (also overriding `DXVK_HDR=1`): | |
| 57 | + | HDR is enabled automatically for native Wayland only for `WowClassic.exe`, | |
| 58 | + | `Wow.exe`, `WowClassicT.exe`, and `WowT.exe`, using per-executable | |
| 59 | + | `dxgi.enableHDR = True` sections in `DXVK_CONFIG`. This avoids exposing HDR to | |
| 60 | + | Battle.net's Chromium/CEF launcher. It requires **Wine >= 11.19**, an HDR-capable | |
| 61 | + | compositor with HDR enabled, and an HDR-capable monitor/game. | |
| 62 | + | ||
| 63 | + | An existing `DXVK_HDR` environment variable is respected, including an empty | |
| 64 | + | value; when it is set, no automatic config is added. Otherwise, the WoW sections | |
| 65 | + | are appended after any existing `DXVK_CONFIG` lines, preserving their scope. | |
| 66 | + | To skip automatic HDR entries and unset inherited `DXVK_HDR` (user-provided | |
| 67 | + | `DXVK_CONFIG` is left untouched): | |
| 61 | 68 | ||
| 62 | 69 | ```bash | |
| 63 | 70 | bnetctl launch --no-hdr | |
| 64 | 71 | ``` | |
| 65 | 72 | ||
| 66 | - | X11 mode does not set `DXVK_HDR`. Games started by Battle.net inherit its HDR | |
| 67 | - | policy; enable HDR in the game's own settings too. | |
| 73 | + | X11 mode leaves the user's HDR environment untouched. Games started by | |
| 74 | + | Battle.net inherit its per-executable config; enable HDR in the game's own | |
| 75 | + | settings too. | |
| 68 | 76 | ||
| 69 | 77 | For Wayland `install` and `launch`, bnetctl prefers CachyOS Wine when it meets the | |
| 70 | 78 | minimum, otherwise qualifying `wine` on PATH. If neither qualifies, it retains | |
| @@ -54,17 +54,25 @@ bnetctl clean -a # Full purge (cache, prefix, desktop entry, data) | |||||
| 54 | 54 | ||||
| 55 | ## HDR on Wayland | 55 | ## HDR on Wayland | ||
| 56 | 56 | ||||
| 57 | - | HDR is enabled automatically for native Wayland (`DXVK_HDR=1`). It requires | 57 | + | HDR is enabled automatically for native Wayland only for `WowClassic.exe`, |
| 58 | - | **Wine >= 11.19**, an HDR-capable compositor with HDR enabled, and an HDR-capable | 58 | + | `Wow.exe`, `WowClassicT.exe`, and `WowT.exe`, using per-executable |
| 59 | - | monitor/game. An existing `DXVK_HDR` environment variable is respected, including | 59 | + | `dxgi.enableHDR = True` sections in `DXVK_CONFIG`. This avoids exposing HDR to |
| 60 | - | an empty value. To disable HDR explicitly (also overriding `DXVK_HDR=1`): | 60 | + | Battle.net's Chromium/CEF launcher. It requires **Wine >= 11.19**, an HDR-capable |
| 61 | + | compositor with HDR enabled, and an HDR-capable monitor/game. | |||
| 62 | + | ||||
| 63 | + | An existing `DXVK_HDR` environment variable is respected, including an empty | |||
| 64 | + | value; when it is set, no automatic config is added. Otherwise, the WoW sections | |||
| 65 | + | are appended after any existing `DXVK_CONFIG` lines, preserving their scope. | |||
| 66 | + | To skip automatic HDR entries and unset inherited `DXVK_HDR` (user-provided | |||
| 67 | + | `DXVK_CONFIG` is left untouched): | |||
| 61 | 68 | ||||
| 62 | ```bash | 69 | ```bash | ||
| 63 | bnetctl launch --no-hdr | 70 | bnetctl launch --no-hdr | ||
| 64 | ``` | 71 | ``` | ||
| 65 | 72 | ||||
| 66 | - | X11 mode does not set `DXVK_HDR`. Games started by Battle.net inherit its HDR | 73 | + | X11 mode leaves the user's HDR environment untouched. Games started by |
| 67 | - | policy; enable HDR in the game's own settings too. | 74 | + | Battle.net inherit its per-executable config; enable HDR in the game's own |
| 75 | + | settings too. | |||
| 68 | 76 | ||||
| 69 | For Wayland `install` and `launch`, bnetctl prefers CachyOS Wine when it meets the | 77 | For Wayland `install` and `launch`, bnetctl prefers CachyOS Wine when it meets the | ||
| 70 | minimum, otherwise qualifying `wine` on PATH. If neither qualifies, it retains | 78 | minimum, otherwise qualifying `wine` on PATH. If neither qualifies, it retains | ||
M cmd/launch.go +5 -1
| @@ -53,7 +53,11 @@ func runLaunch(cmd *cobra.Command, args []string) error { | |||
| 53 | 53 | ||
| 54 | 54 | launcher := services.NewLaunchService(runtime, fs, cfg, func() *domain.WineEnv { | |
| 55 | 55 | enabled, reason := env.HDRStatus(driver, noHDR) | |
| 56 | - | log.Info("hdr env", "enabled", enabled, "reason", reason) | |
| 56 | + | if reason == "wayland default" { | |
| 57 | + | log.Info("hdr env", "enabled", enabled, "reason", reason, "scope", "WoW executables") | |
| 58 | + | } else { | |
| 59 | + | log.Info("hdr env", "enabled", enabled, "reason", reason) | |
| 60 | + | } | |
| 57 | 61 | return env.BuildGPUEnvForDisplayHDR(driver, noHDR) | |
| 58 | 62 | }, log, env.BattleNetArgsForDisplay(driver)...) | |
| 59 | 63 | ||
| @@ -53,7 +53,11 @@ func runLaunch(cmd *cobra.Command, args []string) error { | |||||
| 53 | 53 | ||||
| 54 | launcher := services.NewLaunchService(runtime, fs, cfg, func() *domain.WineEnv { | 54 | launcher := services.NewLaunchService(runtime, fs, cfg, func() *domain.WineEnv { | ||
| 55 | enabled, reason := env.HDRStatus(driver, noHDR) | 55 | enabled, reason := env.HDRStatus(driver, noHDR) | ||
| 56 | - | log.Info("hdr env", "enabled", enabled, "reason", reason) | 56 | + | if reason == "wayland default" { |
| 57 | + | log.Info("hdr env", "enabled", enabled, "reason", reason, "scope", "WoW executables") | |||
| 58 | + | } else { | |||
| 59 | + | log.Info("hdr env", "enabled", enabled, "reason", reason) | |||
| 60 | + | } | |||
| 57 | return env.BuildGPUEnvForDisplayHDR(driver, noHDR) | 61 | return env.BuildGPUEnvForDisplayHDR(driver, noHDR) | ||
| 58 | }, log, env.BattleNetArgsForDisplay(driver)...) | 62 | }, log, env.BattleNetArgsForDisplay(driver)...) | ||
| 59 | 63 | ||||
M internal/adapters/env/gpu.go +10 -2
| @@ -92,6 +92,10 @@ func BuildGPUEnvForDisplay(driver DisplayDriver) *domain.WineEnv { | |||
| 92 | 92 | return BuildGPUEnvForDisplayHDR(driver, false) | |
| 93 | 93 | } | |
| 94 | 94 | ||
| 95 | + | // wowHDRConfig uses DXVK's semicolon-separated config lines. Each section | |
| 96 | + | // matches an exact executable name, keeping HDR away from Battle.net's CEF. | |
| 97 | + | const wowHDRConfig = "[WowClassic.exe];dxgi.enableHDR = True;[Wow.exe];dxgi.enableHDR = True;[WowClassicT.exe];dxgi.enableHDR = True;[WowT.exe];dxgi.enableHDR = True" | |
| 98 | + | ||
| 95 | 99 | // BuildGPUEnvForDisplayHDR applies the launch HDR policy. | |
| 96 | 100 | func BuildGPUEnvForDisplayHDR(driver DisplayDriver, noHDR bool) *domain.WineEnv { | |
| 97 | 101 | env := &domain.WineEnv{ | |
| @@ -116,9 +120,13 @@ func BuildGPUEnvForDisplayHDR(driver DisplayDriver, noHDR bool) *domain.WineEnv | |||
| 116 | 120 | // Without an X11 display, Wine selects its native Wayland driver. | |
| 117 | 121 | env.Unset = append(env.Unset, "DISPLAY") | |
| 118 | 122 | if noHDR { | |
| 119 | - | env.Vars["DXVK_HDR"] = "0" | |
| 123 | + | env.Unset = append(env.Unset, "DXVK_HDR") | |
| 120 | 124 | } else if _, set := os.LookupEnv("DXVK_HDR"); !set { | |
| 121 | - | env.Vars["DXVK_HDR"] = "1" | |
| 125 | + | config := os.Getenv("DXVK_CONFIG") | |
| 126 | + | if config != "" { | |
| 127 | + | config += ";" | |
| 128 | + | } | |
| 129 | + | env.Vars["DXVK_CONFIG"] = config + wowHDRConfig | |
| 122 | 130 | } | |
| 123 | 131 | } | |
| 124 | 132 | ||
| @@ -92,6 +92,10 @@ func BuildGPUEnvForDisplay(driver DisplayDriver) *domain.WineEnv { | |||||
| 92 | return BuildGPUEnvForDisplayHDR(driver, false) | 92 | return BuildGPUEnvForDisplayHDR(driver, false) | ||
| 93 | } | 93 | } | ||
| 94 | 94 | ||||
| 95 | + | // wowHDRConfig uses DXVK's semicolon-separated config lines. Each section | |||
| 96 | + | // matches an exact executable name, keeping HDR away from Battle.net's CEF. | |||
| 97 | + | const wowHDRConfig = "[WowClassic.exe];dxgi.enableHDR = True;[Wow.exe];dxgi.enableHDR = True;[WowClassicT.exe];dxgi.enableHDR = True;[WowT.exe];dxgi.enableHDR = True" | |||
| 98 | + | ||||
| 95 | // BuildGPUEnvForDisplayHDR applies the launch HDR policy. | 99 | // BuildGPUEnvForDisplayHDR applies the launch HDR policy. | ||
| 96 | func BuildGPUEnvForDisplayHDR(driver DisplayDriver, noHDR bool) *domain.WineEnv { | 100 | func BuildGPUEnvForDisplayHDR(driver DisplayDriver, noHDR bool) *domain.WineEnv { | ||
| 97 | env := &domain.WineEnv{ | 101 | env := &domain.WineEnv{ | ||
| @@ -116,9 +120,13 @@ func BuildGPUEnvForDisplayHDR(driver DisplayDriver, noHDR bool) *domain.WineEnv | |||||
| 116 | // Without an X11 display, Wine selects its native Wayland driver. | 120 | // Without an X11 display, Wine selects its native Wayland driver. | ||
| 117 | env.Unset = append(env.Unset, "DISPLAY") | 121 | env.Unset = append(env.Unset, "DISPLAY") | ||
| 118 | if noHDR { | 122 | if noHDR { | ||
| 119 | - | env.Vars["DXVK_HDR"] = "0" | 123 | + | env.Unset = append(env.Unset, "DXVK_HDR") |
| 120 | } else if _, set := os.LookupEnv("DXVK_HDR"); !set { | 124 | } else if _, set := os.LookupEnv("DXVK_HDR"); !set { | ||
| 121 | - | env.Vars["DXVK_HDR"] = "1" | 125 | + | config := os.Getenv("DXVK_CONFIG") |
| 126 | + | if config != "" { | |||
| 127 | + | config += ";" | |||
| 128 | + | } | |||
| 129 | + | env.Vars["DXVK_CONFIG"] = config + wowHDRConfig | |||
| 122 | } | 130 | } | ||
| 123 | } | 131 | } | ||
| 124 | 132 | ||||
M internal/adapters/env/hdr_test.go +49 -6
| @@ -2,6 +2,7 @@ package env | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "os" | |
| 5 | + | "slices" | |
| 5 | 6 | "testing" | |
| 6 | 7 | ) | |
| 7 | 8 | ||
| @@ -14,11 +15,11 @@ func TestHDRPolicy(t *testing.T) { | |||
| 14 | 15 | want, reason string | |
| 15 | 16 | enabled bool | |
| 16 | 17 | }{ | |
| 17 | - | {"default", DisplayDriverWayland, false, nil, "1", "wayland default", true}, | |
| 18 | + | {"default", DisplayDriverWayland, false, nil, wowHDRConfig, "wayland default", true}, | |
| 18 | 19 | {"user on", DisplayDriverWayland, false, str("1"), "", "user DXVK_HDR=1", true}, | |
| 19 | 20 | {"user off", DisplayDriverWayland, false, str("0"), "", "user DXVK_HDR=0", false}, | |
| 20 | 21 | {"user empty", DisplayDriverWayland, false, str(""), "", "user DXVK_HDR=", false}, | |
| 21 | - | {"opt out", DisplayDriverWayland, true, str("1"), "0", "--no-hdr", false}, | |
| 22 | + | {"opt out", DisplayDriverWayland, true, str("1"), "", "--no-hdr", false}, | |
| 22 | 23 | {"x11", DisplayDriverX11, false, nil, "", "x11", false}, | |
| 23 | 24 | {"x11 inherited on", DisplayDriverX11, false, str("1"), "", "user env", true}, | |
| 24 | 25 | {"x11 inherited off", DisplayDriverX11, false, str("0"), "", "user env", false}, | |
| @@ -26,6 +27,7 @@ func TestHDRPolicy(t *testing.T) { | |||
| 26 | 27 | {"x11 ignores opt out", DisplayDriverX11, true, str("1"), "", "user env", true}, | |
| 27 | 28 | } { | |
| 28 | 29 | t.Run(tt.name, func(t *testing.T) { | |
| 30 | + | t.Setenv("DXVK_CONFIG", "") | |
| 29 | 31 | t.Setenv("DXVK_HDR", "") | |
| 30 | 32 | if tt.user == nil { | |
| 31 | 33 | if err := os.Unsetenv("DXVK_HDR"); err != nil { | |
| @@ -35,14 +37,20 @@ func TestHDRPolicy(t *testing.T) { | |||
| 35 | 37 | t.Setenv("DXVK_HDR", *tt.user) | |
| 36 | 38 | } | |
| 37 | 39 | got := BuildGPUEnvForDisplayHDR(tt.driver, tt.noHDR) | |
| 38 | - | if got.Vars["DXVK_HDR"] != tt.want { | |
| 39 | - | t.Fatalf("env: %v", got.Vars) | |
| 40 | + | if _, ok := got.Vars["DXVK_HDR"]; ok { | |
| 41 | + | t.Fatal("unexpected global HDR assignment") | |
| 42 | + | } | |
| 43 | + | if got.Vars["DXVK_CONFIG"] != tt.want { | |
| 44 | + | t.Fatalf("config: %q, want %q", got.Vars["DXVK_CONFIG"], tt.want) | |
| 40 | 45 | } | |
| 41 | 46 | if tt.want == "" { | |
| 42 | - | if _, ok := got.Vars["DXVK_HDR"]; ok { | |
| 43 | - | t.Fatal("unexpected HDR assignment") | |
| 47 | + | if _, ok := got.Vars["DXVK_CONFIG"]; ok { | |
| 48 | + | t.Fatal("unexpected config assignment") | |
| 44 | 49 | } | |
| 45 | 50 | } | |
| 51 | + | if unset := slices.Contains(got.Unset, "DXVK_HDR"); unset != (tt.driver == DisplayDriverWayland && tt.noHDR) { | |
| 52 | + | t.Fatalf("unexpected HDR unset policy: %v", got.Unset) | |
| 53 | + | } | |
| 46 | 54 | enabled, reason := HDRStatus(tt.driver, tt.noHDR) | |
| 47 | 55 | if enabled != tt.enabled || reason != tt.reason { | |
| 48 | 56 | t.Fatalf("status: %v %q", enabled, reason) | |
| @@ -51,3 +59,38 @@ func TestHDRPolicy(t *testing.T) { | |||
| 51 | 59 | } | |
| 52 | 60 | } | |
| 53 | 61 | func str(s string) *string { return &s } | |
| 62 | + | ||
| 63 | + | func TestHDRPreservesUserConfig(t *testing.T) { | |
| 64 | + | const entries = "[WowClassic.exe];dxgi.enableHDR = True;[Wow.exe];dxgi.enableHDR = True;[WowClassicT.exe];dxgi.enableHDR = True;[WowT.exe];dxgi.enableHDR = True" | |
| 65 | + | for _, userConfig := range []string{"", "dxgi.maxFrameLatency = 1", "[Battle.net.exe];dxgi.enableHDR = False", "[Other.exe];dxgi.syncInterval = 0;"} { | |
| 66 | + | t.Run(userConfig, func(t *testing.T) { | |
| 67 | + | t.Setenv("DXVK_CONFIG", userConfig) | |
| 68 | + | t.Setenv("DXVK_HDR", "") | |
| 69 | + | if err := os.Unsetenv("DXVK_HDR"); err != nil { | |
| 70 | + | t.Fatal(err) | |
| 71 | + | } | |
| 72 | + | want := entries | |
| 73 | + | if userConfig != "" { | |
| 74 | + | want = userConfig + ";" + entries | |
| 75 | + | } | |
| 76 | + | got := BuildGPUEnvForDisplayHDR(DisplayDriverWayland, false) | |
| 77 | + | if got.Vars["DXVK_CONFIG"] != want { | |
| 78 | + | t.Fatalf("config: %q, want %q", got.Vars["DXVK_CONFIG"], want) | |
| 79 | + | } | |
| 80 | + | got = BuildGPUEnvForDisplayHDR(DisplayDriverWayland, true) | |
| 81 | + | if _, ok := got.Vars["DXVK_CONFIG"]; ok { | |
| 82 | + | t.Fatal("opt out must not add config without inherited DXVK_HDR") | |
| 83 | + | } | |
| 84 | + | for _, noHDR := range []bool{false, true} { | |
| 85 | + | t.Setenv("DXVK_HDR", "1") | |
| 86 | + | got = BuildGPUEnvForDisplayHDR(DisplayDriverWayland, noHDR) | |
| 87 | + | if _, ok := got.Vars["DXVK_CONFIG"]; ok { | |
| 88 | + | t.Fatal("must leave inherited config untouched") | |
| 89 | + | } | |
| 90 | + | if os.Getenv("DXVK_CONFIG") != userConfig { | |
| 91 | + | t.Fatal("changed user environment") | |
| 92 | + | } | |
| 93 | + | } | |
| 94 | + | }) | |
| 95 | + | } | |
| 96 | + | } | |
| @@ -2,6 +2,7 @@ package env | |||||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "os" | 4 | "os" | ||
| 5 | + | "slices" | |||
| 5 | "testing" | 6 | "testing" | ||
| 6 | ) | 7 | ) | ||
| 7 | 8 | ||||
| @@ -14,11 +15,11 @@ func TestHDRPolicy(t *testing.T) { | |||||
| 14 | want, reason string | 15 | want, reason string | ||
| 15 | enabled bool | 16 | enabled bool | ||
| 16 | }{ | 17 | }{ | ||
| 17 | - | {"default", DisplayDriverWayland, false, nil, "1", "wayland default", true}, | 18 | + | {"default", DisplayDriverWayland, false, nil, wowHDRConfig, "wayland default", true}, |
| 18 | {"user on", DisplayDriverWayland, false, str("1"), "", "user DXVK_HDR=1", true}, | 19 | {"user on", DisplayDriverWayland, false, str("1"), "", "user DXVK_HDR=1", true}, | ||
| 19 | {"user off", DisplayDriverWayland, false, str("0"), "", "user DXVK_HDR=0", false}, | 20 | {"user off", DisplayDriverWayland, false, str("0"), "", "user DXVK_HDR=0", false}, | ||
| 20 | {"user empty", DisplayDriverWayland, false, str(""), "", "user DXVK_HDR=", false}, | 21 | {"user empty", DisplayDriverWayland, false, str(""), "", "user DXVK_HDR=", false}, | ||
| 21 | - | {"opt out", DisplayDriverWayland, true, str("1"), "0", "--no-hdr", false}, | 22 | + | {"opt out", DisplayDriverWayland, true, str("1"), "", "--no-hdr", false}, |
| 22 | {"x11", DisplayDriverX11, false, nil, "", "x11", false}, | 23 | {"x11", DisplayDriverX11, false, nil, "", "x11", false}, | ||
| 23 | {"x11 inherited on", DisplayDriverX11, false, str("1"), "", "user env", true}, | 24 | {"x11 inherited on", DisplayDriverX11, false, str("1"), "", "user env", true}, | ||
| 24 | {"x11 inherited off", DisplayDriverX11, false, str("0"), "", "user env", false}, | 25 | {"x11 inherited off", DisplayDriverX11, false, str("0"), "", "user env", false}, | ||
| @@ -26,6 +27,7 @@ func TestHDRPolicy(t *testing.T) { | |||||
| 26 | {"x11 ignores opt out", DisplayDriverX11, true, str("1"), "", "user env", true}, | 27 | {"x11 ignores opt out", DisplayDriverX11, true, str("1"), "", "user env", true}, | ||
| 27 | } { | 28 | } { | ||
| 28 | t.Run(tt.name, func(t *testing.T) { | 29 | t.Run(tt.name, func(t *testing.T) { | ||
| 30 | + | t.Setenv("DXVK_CONFIG", "") | |||
| 29 | t.Setenv("DXVK_HDR", "") | 31 | t.Setenv("DXVK_HDR", "") | ||
| 30 | if tt.user == nil { | 32 | if tt.user == nil { | ||
| 31 | if err := os.Unsetenv("DXVK_HDR"); err != nil { | 33 | if err := os.Unsetenv("DXVK_HDR"); err != nil { | ||
| @@ -35,14 +37,20 @@ func TestHDRPolicy(t *testing.T) { | |||||
| 35 | t.Setenv("DXVK_HDR", *tt.user) | 37 | t.Setenv("DXVK_HDR", *tt.user) | ||
| 36 | } | 38 | } | ||
| 37 | got := BuildGPUEnvForDisplayHDR(tt.driver, tt.noHDR) | 39 | got := BuildGPUEnvForDisplayHDR(tt.driver, tt.noHDR) | ||
| 38 | - | if got.Vars["DXVK_HDR"] != tt.want { | 40 | + | if _, ok := got.Vars["DXVK_HDR"]; ok { |
| 39 | - | t.Fatalf("env: %v", got.Vars) | 41 | + | t.Fatal("unexpected global HDR assignment") |
| 42 | + | } | |||
| 43 | + | if got.Vars["DXVK_CONFIG"] != tt.want { | |||
| 44 | + | t.Fatalf("config: %q, want %q", got.Vars["DXVK_CONFIG"], tt.want) | |||
| 40 | } | 45 | } | ||
| 41 | if tt.want == "" { | 46 | if tt.want == "" { | ||
| 42 | - | if _, ok := got.Vars["DXVK_HDR"]; ok { | 47 | + | if _, ok := got.Vars["DXVK_CONFIG"]; ok { |
| 43 | - | t.Fatal("unexpected HDR assignment") | 48 | + | t.Fatal("unexpected config assignment") |
| 44 | } | 49 | } | ||
| 45 | } | 50 | } | ||
| 51 | + | if unset := slices.Contains(got.Unset, "DXVK_HDR"); unset != (tt.driver == DisplayDriverWayland && tt.noHDR) { | |||
| 52 | + | t.Fatalf("unexpected HDR unset policy: %v", got.Unset) | |||
| 53 | + | } | |||
| 46 | enabled, reason := HDRStatus(tt.driver, tt.noHDR) | 54 | enabled, reason := HDRStatus(tt.driver, tt.noHDR) | ||
| 47 | if enabled != tt.enabled || reason != tt.reason { | 55 | if enabled != tt.enabled || reason != tt.reason { | ||
| 48 | t.Fatalf("status: %v %q", enabled, reason) | 56 | t.Fatalf("status: %v %q", enabled, reason) | ||
| @@ -51,3 +59,38 @@ func TestHDRPolicy(t *testing.T) { | |||||
| 51 | } | 59 | } | ||
| 52 | } | 60 | } | ||
| 53 | func str(s string) *string { return &s } | 61 | func str(s string) *string { return &s } | ||
| 62 | + | ||||
| 63 | + | func TestHDRPreservesUserConfig(t *testing.T) { | |||
| 64 | + | const entries = "[WowClassic.exe];dxgi.enableHDR = True;[Wow.exe];dxgi.enableHDR = True;[WowClassicT.exe];dxgi.enableHDR = True;[WowT.exe];dxgi.enableHDR = True" | |||
| 65 | + | for _, userConfig := range []string{"", "dxgi.maxFrameLatency = 1", "[Battle.net.exe];dxgi.enableHDR = False", "[Other.exe];dxgi.syncInterval = 0;"} { | |||
| 66 | + | t.Run(userConfig, func(t *testing.T) { | |||
| 67 | + | t.Setenv("DXVK_CONFIG", userConfig) | |||
| 68 | + | t.Setenv("DXVK_HDR", "") | |||
| 69 | + | if err := os.Unsetenv("DXVK_HDR"); err != nil { | |||
| 70 | + | t.Fatal(err) | |||
| 71 | + | } | |||
| 72 | + | want := entries | |||
| 73 | + | if userConfig != "" { | |||
| 74 | + | want = userConfig + ";" + entries | |||
| 75 | + | } | |||
| 76 | + | got := BuildGPUEnvForDisplayHDR(DisplayDriverWayland, false) | |||
| 77 | + | if got.Vars["DXVK_CONFIG"] != want { | |||
| 78 | + | t.Fatalf("config: %q, want %q", got.Vars["DXVK_CONFIG"], want) | |||
| 79 | + | } | |||
| 80 | + | got = BuildGPUEnvForDisplayHDR(DisplayDriverWayland, true) | |||
| 81 | + | if _, ok := got.Vars["DXVK_CONFIG"]; ok { | |||
| 82 | + | t.Fatal("opt out must not add config without inherited DXVK_HDR") | |||
| 83 | + | } | |||
| 84 | + | for _, noHDR := range []bool{false, true} { | |||
| 85 | + | t.Setenv("DXVK_HDR", "1") | |||
| 86 | + | got = BuildGPUEnvForDisplayHDR(DisplayDriverWayland, noHDR) | |||
| 87 | + | if _, ok := got.Vars["DXVK_CONFIG"]; ok { | |||
| 88 | + | t.Fatal("must leave inherited config untouched") | |||
| 89 | + | } | |||
| 90 | + | if os.Getenv("DXVK_CONFIG") != userConfig { | |||
| 91 | + | t.Fatal("changed user environment") | |||
| 92 | + | } | |||
| 93 | + | } | |||
| 94 | + | }) | |||
| 95 | + | } | |||
| 96 | + | } | |||
Comments00 unresolved
no comments yet.