Edit: I still think Streamline is creating some issues but this seems to be the main cause.
With SpecialK I can see the initialization of swapchains made by the game during startup.
Here’s the relative bits from Darktide’s console logs and SpecialK logs
Step 1: Console log, DS is started
09:25:07.860 [DirectStorage] Succeded to init direct storage with default values:
DisableBypassIO=false
ForceFileBuffering=false
ForceMappingLayer=false
Step 2: After a device is chosen for the game the shader cache is verified with FFX
09:25:12.211 [RenderInterface] Creating swapchain with render resolution: 3440x1440
09:25:12.341 [d3d12 pipeline state] PSO cache loading finished, current fail rate 0/3599 (0%)
---------------------------
08/11/2025 09:25:12.315: [ DXGI ] [!] IDXGIFactory7::CreateSwapChainForHwnd (17e86ba0490h, 005a0682h, 1fdefff628h) -- [ amd_fidelityfx_dx12.dll < ffxQuery>, tid=0x2b38 ]
Step 3: SK, XeSS starts building it’s pipelines, AMD Display Library is used to get a pointer to the GPU and monitors. Unlike ADL, Xess is set up with a device pointer
08/11/2025 09:25:12.478: [ DXGI ] [!] CreateDXGIFactory1 ( IDXGIFactory4, 1fdccfaa88h) -- [ libxess.dll < xessD3D12BuildPipelines>, tid=0x01fc ]
08/11/2025 09:25:12.481: [ DXGI ] [!] CreateDXGIFactory1 ( IDXGIFactory4, 1fdccfa848h) -- [ libxess.dll < xessD3D12BuildPipelines>, tid=0x01fc ]
08/11/2025 09:25:12.482: [ DXGI ] * Monitor 1: [ 3440x1440 | ( 0, 0) ] LG ULTRAGEAR :: SDR
08/11/2025 09:25:12.487: [ DXGI ] [!] CreateDXGIFactory1 ( IDXGIFactory4, 1fdccfa848h) -- [ libxess.dll < xessD3D12BuildPipelines>, tid=0x01fc ]
08/11/2025 09:25:12.697: [DisplayLib] ADL Init { Success }
08/11/2025 09:25:12.703: [DisplayLib] * Number of Reported AMD Adapters: 10 (2 active)
Step 4: Direct Storage need a d3d12 device pointer if it’s sending resources to the GPU. There’s one now, made by/for XeSS, but on the wrong thread!
08/11/2025 09:25:12.762: [ DStorage ] SK_IWrapDStorageFactory::CreateQueue (Priority=Normal, Name=direct_storage_file_queue, Capacity=8192)
08/11/2025 09:25:12.764: [ DStorage ] Adding D3D12 Device to DirectStorage queue desc.
08/11/2025 09:25:12.767: [ DXGI ] [!] CreateDXGIFactory1 ( IDXGIFactory4, 1fdeffeed8h) -- [ DStorageCore.dll , tid=0x2b38 ]
08/11/2025 09:25:12.790: [ DStorage ] Promoted IDstorageQueue to IDStorageQueue2
08/11/2025 09:25:13.029: [SEH-Except] Exception Code: e24c4a02 - Flags: (Non-Continuable) - Arg Count: 0 [ Calling Module: C:\Program Files (x86)\Steam\steamapps\common\Warhammer 40,000 DARKTIDE\binaries\Darktide.exe ]
08/11/2025 09:25:13.029: [SEH-Except] >> Best-Guess For Source of Exception: snscanf_s
Creating a big stall in the game logs as it fails:
09:25:12.757 warning: [Profiler] [renderer] Stall 187 ms on frame 0:
dispatch_loadtime 187 ms
d3d12_resource_context::dispatch 187 ms
09:25:12.757 warning: [Profiler] [main] Stall 187 ms on frame 0:
RenderInterface::setup 281 ms
RI::wait_for_fence 187 ms
09:25:12.794 [Application] STARTUP: setup boot packages, File: D:\a\d\rel_engine_darktide\release\2025_04_29_Patch1.8.x\runtime\application\application.cpp, Line: 4617
09:25:13.024 warning: [Profiler] [main] Stall 218 ms on frame 0:
Application::setup_boot_package 227 ms
PatchedResourcePackage::flush 227 ms
PatchedResourcePackage::finish_loading 227 ms
ResourceManager::flush(prio) 218 ms
The thread FFX is on in the beginning is tid=0x2b38, the same as the one used by direct storage here, while XeSS sets up it’s pipelines on tid=0x01fc
According to the XeSS guide, XeSS isn’t thread safe and wants all calls to it to be within the same thread.
I commented this already but directstorage needs a pointer to a device to work according to dstorage.h
/// summary
/// Optional device to use for writing to destination resources and
/// performing GPU decompression. The destination resource's device
/// must match this device.
///
/// This member may be null. If you specify a null device, then the
/// destination type must be DSTORAGE_REQUEST_DESTINATION_MEMORY.
/// summary
ID3D12Device* Device;
I don’t know how the game code is set up but it would be easiest to just make a new pointer for directstorage. Maybe don’t even start it until everything else is set up and you can guarantee it gets the right device on the right thread. Although Streamline and it’s proxy swapchain stuff probably complicates it.
And before anyone asks, no, you can’t remove the XeSS file from the game folder or the game crashes after launch
Original post
Issue Description (Required):
The game launcher relies on Nvidia streamline for GPUDetection.exe which it calls twice according to the launcher logs. If you remove the streamline files from the launcher folder it just fails and returns a generic device. The launcher then runs darktide_shader_cache_builder.exe which is also likely effected by streamline.
This is very bad.
The SystemCaps function used in Streamline to check GPUs states that devices aren’t released until shutdown but even though the launcher window disappears, Darktide.exe is still shown as a child process of the launcher in task manager. That’s at least one device and one to three swapchains just sitting there being managed by Streamline in the background.
This is a likely explanation for why the game never seems to use more than about half your memory/vram and pages a bunch of data: Streamline manages memory reservation/allocation unless told otherwise. If the shader cache builder called by the launcher was given a weird Streamline swapchain that tried to manage memory or was just given one of streamline’s weird proxy swapchains I bet that will cause problems. This may even be why it doesn’t generate PSOs if the shader cache bundled with the game was made through a similar setup that ends up calling streamline.
This also explains why the game suddenly had performance issues for many people when exclusive fullscreen was removed. I know the Microsoft article about fullscreen optimizations was cited as the reason exclusive fullscreen was removed from the game and I mostly agree but it may have unexpectedly helped with one thing. Windows has emulated stuff like telling an app it’s vram was flushed on losing focus ever since Vista so even if Dx12 doesn’t have exclusive fullscreen, setting that could have made the launcher Streamline stop managing resources for the actual game and let it have full control of the GPU.
It’s possible this is why something went wrong with the update that was supposed to officially support FSR4. Streamline does have functions to deal with other swapchain proxys and assuming AGS was updated to the latest version with RDNA4 support, having other Streamline swapchains active from the launcher when the game tries to proxy the swapchain used in the game would just make them try to hand over control by releasing their own device. One that I assume the game doesn’t have any control over as a child of the launcher. Queue game crash after title screen
I’m almost certain this is why direct storage is just worse for performance for so many people. A direct storage queue will resort to CPU fallback and send everything through memory if it doesn’t see a d3d12 device (looking at you, Monster Hunter Wilds). Darktide is a bit different. According to the game’s console logs, Direct Storage is initialized before the game even chooses what GPU to use which means it likely got assigned to one of the launcher’s Streamline swapchains.
Direct Storage documentation sucks so I can’t even be upset about this one but did you know you can just get those header files from the DS NuGet package and open it in Notepad++?I’ll copy and paste a relevant comment from dstorage.h:
/// </summary>
/// Optional device to use for writing to destination resources and
/// performing GPU decompression. The destination resource's device
/// must match this device.
///
/// This member may be null. If you specify a null device, then the
/// destination type must be DSTORAGE_REQUEST_DESTINATION_MEMORY.
/// </summary>
ID3D12Device* Device;
I’ve seen Axloss mention that Darktide’s direct storage implementation is custom. I don’t know if it uses GPU decompression or not. I know the game uses Oodle for network compression but Oodle also allows for both fast CPU data compression and lossless texture compression for textures that can be sent right to the GPU. Assuming Darktide uses data compression for meshes and lossless compression for textures both in the same directstorage queue, if this direct storage is broken that explains how doing things like turning off the mesh streamer or messing with feedback streamer settings and for textures makes the game not hitch so much. Less requests going through the queue means it’s less likely to become full and cause a stall.
By the way, the version of the Streamline files in the launcher folder are from 2023. Only the files in the main game folder have been updated along with the game. All of this can be fixed if you just use something else to get device info for the launcher instead of Streamline.
Platform (Required):
PC - Steam