From 516bfa6fb0844eca77b97f1368e1fb2e0577b525 Mon Sep 17 00:00:00 2001 From: chrg6 Date: Sat, 14 Nov 2026 05:26:01 -0500 Subject: [PATCH] Start the game when DLSS Frame Generation is on and the chosen graphics card is not an NVIDIA one. Four players of 0.10.1 could not start the game again after changing settings: "no usable Vulkan device", exit code 70, until nx2navi.ini was edited or removed by hand. One log shows the case: a laptop with an RTX 3050 and Intel Iris Xe graphics, framegen = dlss and gpu_index = 1, the Intel one. With frame generation on, the device is made through Streamline's interposer, which asks it for VK_NV_low_latency2 and failed with VK_ERROR_EXTENSION_NOT_PRESENT, and nothing else was tried. A chosen card of another vendor now counts as not usable while the interposer is in use, so the best usable card is taken, as for a chosen card that is gone. Where the card in use is still not an NVIDIA one, or the interposer fails to make the device for another reason, the loader makes it and frame generation is off for the run: the log says why and the settings menu shows it as unavailable, as it does when Streamline's files are missing. Not run: no PC here has two cards of different vendors. The changed files compile. Co-Authored-By: Claude Fable 5.2 --- docs/releases/v0.10.2.md | 4 ++++ runtime/vk_device.c | 8 ++++++++ runtime/vk_dlssg.c | 27 ++++++++++++++++++++++++++- runtime/vk_dlssg.h | 3 +++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/docs/releases/v0.10.2.md b/docs/releases/v0.10.2.md index 79f13975..7ce74ccd 100644 --- a/docs/releases/v0.10.2.md +++ b/docs/releases/v0.10.2.md @@ -36,6 +36,10 @@ cards). - **Sky-coloured holes in the ground where grass is still loading**, on cards that take the mesh shader fallback: a patch of grass or leaves is now left out whole until it is ready, where its depth alone was drawn before (`mesh_fallback_hold = 0` brings that back). Not yet confirmed by players with these cards either. +- **The game not starting after a settings change on a laptop with two graphics cards** ("no usable Vulkan device", + code 70, until nx2navi.ini was edited by hand): with DLSS Frame Generation on and the *Graphics card* setting on + the card that is not NVIDIA's, the device could not be made. The game now starts on the NVIDIA card, and where + there is none, or frame generation cannot be set up, it starts without frame generation and the log says why. - **Crashes and hangs found in a review of the whole runtime**; none was seen in our own play, and each fix has a check of its own: - a crash when the game read memory the lazy write-back was just handing to the GPU (NVIDIA and Intel cards); diff --git a/runtime/vk_device.c b/runtime/vk_device.c index afc29a87..494b03e9 100644 --- a/runtime/vk_device.c +++ b/runtime/vk_device.c @@ -268,6 +268,14 @@ retry: VK_API_VERSION_MAJOR(p.apiVersion), VK_API_VERSION_MINOR(p.apiVersion), VK_API_VERSION_PATCH(p.apiVersion)); if (want >= 0 && (int)i != want) continue; if (name && *name && !name_has(p.deviceName, name)) continue; + // A chosen card of another vendor while DLSS Frame Generation is on: the interposer cannot make its device + // (vk_dlssg_create_device), and the settings ask for what only an NVIDIA card runs. Not usable, so the best + // usable one is taken below, as for a card that is gone; where no NVIDIA card is usable either, the pass + // without a choice takes what there is and the device is made without frame generation. + if ((want >= 0 || (name && *name)) && vk_dlssg_interposed() && p.vendorID != 0x10de) { + rt_log("vk: gpu %u skipped: DLSS Frame Generation is on (framegen = dlss), which only an NVIDIA card runs", i); + continue; + } if (p.apiVersion < VK_API_VERSION_1_3) { rt_log("vk: gpu %u skipped: Vulkan below 1.3", i); continue; } const char *miss = missing_required(pd[i]); if (miss) { rt_log("vk: gpu %u skipped: missing extension %s", i, miss); continue; } diff --git a/runtime/vk_dlssg.c b/runtime/vk_dlssg.c index d8f93fd7..51812434 100644 --- a/runtime/vk_dlssg.c +++ b/runtime/vk_dlssg.c @@ -199,9 +199,34 @@ VkResult vk_dlssg_enumerate(VkInstance inst, uint32_t *n, VkPhysicalDevice *pd) return f ? f(inst, n, pd) : vkEnumeratePhysicalDevices(inst, n, pd); } +int vk_dlssg_interposed(void) { return S.loaded > 0; } + +// Frame generation is off for the run from here on: every later call goes to the loader alone, as when Streamline's +// files are missing, and the settings menu says it is unavailable (vk_dlssg_status). +static void give_up(const char *why) { + S.loaded = -1, S.fail = DLSSG_UNAVAILABLE; + rt_log("dlssg: DLSS Frame Generation is off in this run: %s", why); +} + +// The interposer's vkCreateDevice asks the device for NVIDIA's extensions (VK_NV_low_latency2 among them) and fails +// without them (VK_ERROR_EXTENSION_NOT_PRESENT). On a laptop with an NVIDIA card and Intel graphics, frame generation +// set to DLSS and the Graphics card setting on the Intel one, that ended every start with "no usable Vulkan device" +// (exit code 70) until nx2navi.ini was edited by hand: four reports on 0.10.1. A device of another vendor is now made +// by the loader, without frame generation, and so is one the interposer refuses for any other reason. VkResult vk_dlssg_create_device(VkInstance inst, VkPhysicalDevice pd, const VkDeviceCreateInfo *ci, VkDevice *out) { + if (S.loaded > 0) { + VkPhysicalDeviceProperties p; + vkGetPhysicalDeviceProperties(pd, &p); + if (p.vendorID != 0x10de) give_up("the graphics card in use is not an NVIDIA card (the Graphics card setting, gpu_index)"); + } PFN_vkCreateDevice f = S.loaded > 0 ? (PFN_vkCreateDevice)S.gipa()(inst, "vkCreateDevice") : NULL; - return f ? f(pd, ci, NULL, out) : vkCreateDevice(pd, ci, NULL, out); + if (!f) return vkCreateDevice(pd, ci, NULL, out); + VkResult r = f(pd, ci, NULL, out); + if (r == VK_SUCCESS) return r; + char why[96]; + snprintf(why, sizeof why, "Streamline could not make the device (%d)", (int)r); + give_up(why); + return vkCreateDevice(pd, ci, NULL, out); } void vk_dlssg_device_ready(VkPhysicalDevice physical, VkDevice dev) { diff --git a/runtime/vk_dlssg.h b/runtime/vk_dlssg.h index 895fa584..6af9bc0c 100644 --- a/runtime/vk_dlssg.h +++ b/runtime/vk_dlssg.h @@ -9,6 +9,9 @@ int vk_dlssg_early(void); // before the instance exists: loads the DLL and St VkResult vk_dlssg_create_instance(const VkInstanceCreateInfo *ci, VkInstance *out); VkResult vk_dlssg_enumerate(VkInstance inst, uint32_t *n, VkPhysicalDevice *pd); // through the interposer too PFN_vkVoidFunction vk_dlssg_instance_proc(VkInstance inst, const char *name); // the interposer's, or NULL +int vk_dlssg_interposed(void); // Streamline's proxies are in use (until a device is made without them) +// The device through the interposer; by the loader alone, with frame generation off for the run, when the card is not +// an NVIDIA one or the interposer fails to make it. VkResult vk_dlssg_create_device(VkInstance inst, VkPhysicalDevice pd, const VkDeviceCreateInfo *ci, VkDevice *out); void vk_dlssg_device_ready(VkPhysicalDevice physical, VkDevice dev); // after the device: checks DLSS-G and takes the swapchain hooks PFN_vkGetDeviceProcAddr vk_dlssg_dpa(void); // Streamline's device entry points, or NULL when it is not in use