dxvk
dxvk copied to clipboard
D3D9 Partial Presentation Mega-issue
Made to consolidate the other issues which concern the lack of partial presentation in dxvk.
This issue most commonly presents itself as the application being mostly black except for any element that changes look or redraws when hovered over with the mouse. Like a button that has a highlight when the mouse cursor is on it
Example screenshots
Return of Reckoning launcher
It is most common in various game launchers and wpf apps. A few games might use it too.
It can usually be worked around in dxvk by setting d3d9.shaderModel = 1
which have been added in the past into dxvk for a few launchers.
If set in a local config usually you'll only want this to affect the launcher itself. Which can be done like below for a specific exe in dxvk.conf
[RoRLauncher.exe]
d3d9.shaderModel = 1
Tho setting d3d9.shaderModel = 1
is not always a desirable solution since in some cases the app might become very sluggish if it falls back on software rendering or if it's unpacked into a temporary folder with a generic name where a config option can't reliably catch it.
Setting it for every app thrown this way is probably also not a welcome solution.
Concerned issues: https://github.com/doitsujin/dxvk/issues/2732 https://github.com/doitsujin/dxvk/issues/2240 https://github.com/doitsujin/dxvk/issues/2568 (Part of issue) https://github.com/doitsujin/dxvk/issues/2278 https://github.com/doitsujin/dxvk/issues/1476 https://github.com/doitsujin/dxvk/issues/2334 https://github.com/doitsujin/dxvk/issues/1481 (Maybe?) https://github.com/doitsujin/dxvk/issues/2456 https://github.com/doitsujin/dxvk/issues/2542 https://github.com/doitsujin/dxvk/issues/2860 (Likely) https://github.com/doitsujin/dxvk/issues/3005
It does seem to be a common WPF issue. Just for sake of completeness, WPF applications can also work around this by disabling hardware acceleration using a registry key
wine reg ADD 'HKCU\Software\Microsoft\Avalon.Graphics' /v 'DisableHWAcceleration' /t REG_DWORD /d 1 /f
https://learn.microsoft.com/en-us/dotnet/desktop/wpf/graphics-multimedia/graphics-rendering-registry-settings?view=netframeworkdesktop-4.8#disable-hardware-acceleration-option
WPF also disables hardware acceleration if we lie and tell the application that only shader model 1 is supported. We've added that workaround for a couple of applications but it's not something we want to do for every single WPF app.
I think it should be possible to implement this through vulkan, wined3d (using opengl with zink) supports it pretty well
Also worth pointing out, at least for Escape from Tarkov launcher, both forcing Shader Model 1.0 or disabling the WPF acceleration by the wine registry entry as @rsw0x mentioned, it makes MangoHud not working for me, otherwise it works.
I think it should be possible to implement this through vulkan, wined3d (using opengl with zink) supports it pretty well
following up on this, wined3d vulkan works as well!
I believe there are two aspects to this (and I'm not sure I'm up to date with latest dxvk developments):
Some applications use DirectX correctly and request D3DSWAPEFFECT_COPY. They "rightfully" expect backbuffer contents to be unchanged after calling Present. When rendering a frame, they might update only parts of the backbuffer and then call Present, indicating which region of the backbuffer was updated (dirty region). As I understand it, the COPY swap effect is currently not supported by dxvk, so this won't work. dxvk always swaps back/front buffers on Present without copying old backbuffer contents into the new backbuffer.
Some other applications use DirectX "incorrectly" and request D3DSWAPEFFECT_DISCARD. The docs say you must always draw the full frame when using DISCARD because the backbuffer contents after Present are undefined, and you can't call Present with a dirty region / source rect / dest rect. Now these applications just ignore that limitation of DISCARD and pretend that it works like COPY. See #3005 (uses source rect / dest rect with DISCARD) or #3250 (I believe this assumes back buffer contents survive Present with DISCARD).
And it seems like that works on Windows in windowed mode, probably because (I'm speculating here) there is only one framebuffer in the swapchain, which is always used as the backbuffer. On Present, the contents are probably copied by the compositor and that's it. There is no actual "swapping" of framebuffers involved, so DISCARD behaves like COPY in windowed mode.
Because of the GetFrontBufferData method, dxvk needs a way to access the current front buffer and that's why it does its own swapping. But maybe that's also possible through some Vulkan extension instead, and the explicit front buffer and related swapping for the "1 backbuffer" case in dxvk can be dropped? I believe that would make it cheaper to implement the COPY swap effect in windowed mode, because no swapping / copying in dxvk would be needed when there's only 1 backbuffer and no "explicit" frontbuffer in dxvk.
Does anyone know any good ways to test GetFrontBufferData()? I hacked up some changes to implement that method by reading from the Vulkan swapchain directly, instead of from the "internal" dxvk frontbuffer. It passes the related wine testsuite test, but that's very basic and I feel like I must be missing something. Maybe some "source available" game/test app/... that uses DirectX9 that I could patch to add some GetFrontBufferData() calls?
If it turns out that something like this actually works and there are no real downsides to it, I believe the "internal"/"explicit" frontbuffer could be dropped from the dxvk d3d9 swapchain, which would probably be a nice step forward for some of the games that have the partial presentation and/or "dropped backbuffer" issues. However I'm probably just missing something important and it can't actually work.
Edit: I found the old ToyShop ATI demo, it takes a screenshot on PrintScreen key press (at least when disabling the gnome screenshot feature)
So my little experiment does work on my setup and correctly takes a screenshot using GetFrontBufferData() in the ToyShop ATI demo without needing an "internal" frontbuffer. (I'm sure there are bugs though.)
However, I have now looked into the Vulkan docs a bit more and figured out what dxvk authors probably realized years ago: This appears to be an invalid use of the Vulkan API, so I'm just lucky that it happens to work on my setup. The Vulkan swapchain image is not supposed to be used in any way when it is not acquired (notably, to make GetFrontBufferData() work, the layout needs to be transitioned to the "TRANSFER_SRC" layout):
Use of a presentable image must occur only after the image is returned by vkAcquireNextImageKHR, and before it is released by vkQueuePresentKHR. This includes transitioning the image layout and rendering commands.
Apparently, there is no call in the Vulkan API like "give me access to the last swapchain image that I Present()ed so I can copy it for a screenshot", at least I couldn't find one. I'm not sure how examples like this handle this though, maybe they don't synchronize that access either and it just happens to work most of the time?
Anyway, I'm now back in the "we can't have correct GetFrontBufferData() without an internal frontbuffer and internal swapping, which destroys the COPY swapeffect and partial presentation" camp.
Apparently, there is no call in the Vulkan API like "give me access to the last swapchain image that I Present()ed so I can copy it for a screenshot", at least I couldn't find one.
Perhaps this may be of interest.
Thanks for the VK_KHR_shared_presentable_image
link! However, unfortunately it looks like support for this extension basically does not exist for desktop systems. Also, I believe that preventing tearing would be difficult and platform-specific when using that extension, and I'm not sure if it might impact performance negatively in some setups.
GitHub was a bit too eager here. The PR said "hopefully fixes".