fix(game-env): DOOM (2016) keeps the swapchain image count it asks for (#1987)

DOOM (2016) asks for exactly two swapchain images and stops with "FATAL
ERROR: getSwapchainImagesKHR failed with error (VK_SUCCESS)" when it gets
more. Every game launch gets GAMESCOPE_WSI_MIN_IMAGE_COUNT=8 and
GAMESCOPE_WSI_ENSURE_MIN_IMAGE_COUNT=1, so gamescope's WSI layer gave it 8
images (3 with only the count removed) and the game crashed on start.

When DOOMx64vk.exe sits beside the launched program (DOOMx64.exe for a GOG
install, or DOOMx64vk.exe), both variables are removed and
vk_x11_strict_image_count=true is set, the option Mesa's driconf gives the
game. Other games keep the defaults. A per-game value in the environment
editor still wins.

Tested on an AYANEO Pocket FIT with DroidDeck 0.6.9 and the same values set
per game: the swapchain gets 2 images and the game reaches its main menu at
60 fps; before, it crashed on every launch.
This commit is contained in:
The412Banner authored and GitHub committed 2026-11-02 02:02:18 +00:00
1 parent 84a04d9ead
commit 40dfcd94f9
3 files changed
+50

No files matched your search

+7
View File
@@ -113,6 +113,13 @@ same WSI layer, and with eight images and no frame limit it drew flat out
(about 240 frames a second at 120 Hz) and heated the device. Values set in the
launch options or the environment editor are kept.
DOOM (2016) is the exception (`DOOMx64vk.exe` beside the launched program, which
is `DOOMx64.exe` for a GOG install). It asks for exactly two images and stops with
`FATAL ERROR: getSwapchainImagesKHR failed with error (VK_SUCCESS)` when it gets
more, so its fix removes both variables, also from its launch options, and sets
`vk_x11_strict_image_count=true`, the option Mesa's driconf gives the game. A
per-game value in the environment editor still wins.
## Defaults and available suggestions
The initial configuration enables Mesa shader caching with
@@ -124,6 +124,17 @@ def arkham_city_x87(game):
@fix
def doom_2016_swapchain_images(game):
if "doomx64vk.exe" in game.files and game.stem in ("doomx64", "doomx64vk"):
images = {
"GAMESCOPE_WSI_MIN_IMAGE_COUNT": None,
"GAMESCOPE_WSI_ENSURE_MIN_IMAGE_COUNT": None,
"vk_x11_strict_image_count": "true",
}
return images, [], "DOOM (2016): the swapchain keeps the image count the game asks for"
@fix
def teardown_vsync(game):
if game.stem == "teardown":
+32
View File
@@ -873,6 +873,38 @@ class GameEnvironmentTest(unittest.TestCase):
(game / "D3DGear64.DLL").unlink()
self.assertEqual(MODULE["engine_fixes"](str(game / "TheCrew2.exe"), []), ({}, [], []))
def test_doom_2016_keeps_the_swapchain_image_count_it_asks_for(self):
with tempfile.TemporaryDirectory() as tmp:
game = Path(tmp) / "DOOM (2016)"
game.mkdir()
for name in ("DOOMx64.exe", "DOOMx64vk.exe", "Galaxy64.dll"):
(game / name).touch()
images = {
"GAMESCOPE_WSI_MIN_IMAGE_COUNT": None,
"GAMESCOPE_WSI_ENSURE_MIN_IMAGE_COUNT": None,
"vk_x11_strict_image_count": "true",
}
for exe in ("DOOMx64.exe", "DOOMx64vk.exe"):
env, extra, notes = MODULE["engine_fixes"](str(game / exe), [])
self.assertEqual((env, extra), (images, []))
self.assertTrue(notes)
launched = {"GAMESCOPE_WSI_MIN_IMAGE_COUNT": "8", "GAMESCOPE_WSI_ENSURE_MIN_IMAGE_COUNT": "1"}
result = MODULE["apply_config"](launched, {"version": 1}, "3566086475", env)
self.assertNotIn("GAMESCOPE_WSI_MIN_IMAGE_COUNT", result)
self.assertNotIn("GAMESCOPE_WSI_ENSURE_MIN_IMAGE_COUNT", result)
self.assertEqual(result["vk_x11_strict_image_count"], "true")
config = {"version": 1, "games": {"3566086475": {"GAMESCOPE_WSI_MIN_IMAGE_COUNT": "3"}}}
self.assertEqual(MODULE["apply_config"](launched, config, "3566086475", env)["GAMESCOPE_WSI_MIN_IMAGE_COUNT"], "3")
eternal = Path(tmp) / "DOOMEternal"
eternal.mkdir()
(eternal / "DOOMEternalx64vk.exe").touch()
self.assertEqual(MODULE["engine_fixes"](str(eternal / "DOOMEternalx64vk.exe"), []), ({}, [], []))
other = Path(tmp) / "Other"
other.mkdir()
for name in ("Other.exe", "DOOMx64vk.exe"):
(other / name).touch()
self.assertEqual(MODULE["engine_fixes"](str(other / "Other.exe"), []), ({}, [], []))
def test_dll_overrides_from_several_fixes_are_all_kept(self):
with tempfile.TemporaryDirectory() as tmp:
for name in ("Game.exe", "Game.pck", "GodotSharp.dll", "libsentry.windows.release.x86_64.dll", "d3dgear64.dll"):