Closed shmerl closed 5 years ago
Not my bug. Enabling Vsync is done by setting the present mode during swap chain creation and DXVK has been doing that correctly since forever.
So do you think it's something in radv, or rather Wine or XWayland? Is there a variable that can force vsync for radv somehow? It could help checking this.
pretty sure this is something with xwayland, not radv or wine.
Though interesting, why this doesn't show up on wined3d path.
Don't know. Anyway, closing since this is not something I could work around even if I wanted to.
@doitsujin: can you please comment here to help xwayland developers to narrow down the issue?
One thing that comes to mind - can you post log files of the game running with vsync disabled? It should show which present mode it actually picks.
I see this:
info: Presenter: Actual swap chain properties:
Format: VK_FORMAT_B8G8R8A8_UNORM
Present mode: VK_PRESENT_MODE_IMMEDIATE_KHR
Buffer size: 1920x1200
Image count: 2
Is option dxgi.numBackBuffers
actually used anywhere? I don't see it being used in the code, besides setting
this->numBackBuffers = config.getOption<int32_t>("dxgi.numBackBuffers", 0);
@daenzer recommended increasing the number of images in the presenter to 3 for a test:
maybe the problem is that the "borderless fullscreen" windows are actually being treated like fullscreen by Xwayland, but because DXVK is using only two buffers in the swap chain, the next frame can only start rendering when the Wayland compositor releases the previous buffer. Does increasing the image count to >= 3 in DXVK help?
But the option doesn't have an effect, since it's not used.
Looks like I forgot to put it back in when rewriting the presenter, will fix.
Should work again as of 328871de7ebee04eb80ed7d64e1c139d79e364df .
Commented in xwayland bug, but in short, with that fix and dxgi.numBackBuffers = 3
set in config, it's not capping anymore!
@doitsujin: can you please add the workaround to the wiki?
To me that looks like a radv bug, you should open a bug report there. The Present spec doesn't give specific garantees for the number of buffers hold by the Xserver at a given time, and if XWayland needs one more, that's its right, and the client (radv) not doing it right. The proper fix would be (I think the ogl implementation does that) to allocate a few more buffers (in radv swapchain implementation) when the need is detected. But I don't know how that interacts with Vulkan.
If one really needs to use fewer buffers and needs early release, there's a Present flag for that that will always release right away but trigger a copy.
@shmerl done, although it probably only affects a handful of people at most.
@axeldavy in vulkan it's the application's responsibility to allocate the correct number of back buffers, the driver only reports the minimum required and maximum supported number of back buffers. 2 buffers are good enough for FIFO pesent mode, so bumping that up to 3 in the driver doesn't sound like a good idea.
At the same time, DXVK has no way of knowing about the XWayland presentation quirks when using the IMMEDIATE
present mode, since the vulkan limits are reported globally and not per present mode.
Then it is a radv bug, as looking at mesa source code, VK_PRESENT_MODE_IMMEDIATE_KHR triggers just XCB_PRESENT_OPTION_ASYNC as flag (which allows async flips, ie changing the buffer being shown during refresh).
If the backend doesn't do async flips, it just does the normal behaviour (ie wait next vsync for the swap), which is likely what is happening with XWayland. This seems inspired from the glx code, except the glx code switches to 3 back buffers if flips are detected.
Probably radv should do more like gallium nine when doing immediate mode, ie use the COPY flag instead of ASYNC, to garantee the buffer will be released right away.
@hakzsam: Do you think it's a radv issue?
Just a little background more background on the Present extension (which is converted by XWayland to a similar Wayland protocol).
Full protocol can be found here: https://github.com/freedesktop/xorg-presentproto/blob/master/presentproto.txt
Basically the crtc increments a counter every refresh, the msc. The client sends a pixmap to be presented to a X drawable at a given msc.
By default, at msc change, every presentation pending for that msc (or a previous) is done.
There are a few options: PresentOptionAsync indicates that "the operation will be performed as soon as possible, not necessarily waiting for the next vertical blank interval". PresentOptionCopy indicates that " 'pixmap' will be idle [...] as soon as the operation occurs."
The simplest implementation of Present is to trigger a gpu copy at the requested time. For PresentOptionAsync, that implementation would copy right away if the requested msc is in the past.
X current implementation is more complex, as it implements flips and async flips. Flips: . A buffer is on screen and will be released at next refresh. A buffer is pending to be shown on next refresh. None of these buffers will be released by the server until next fresh. If the app wants to render at full speed without cap, it needs thus 4 back buffers (the third back buffer is released when the fourth is sent). 3 buffers may be enough for > 60 fps if the Xserver doesn't lock 2 buffers until the vsync is near (I think there has been work for that, but I'm not 100% sure)
Async flips (on drivers that support it): . It is the same except the buffer shown on screen can be changed during refresh. I guess only 3 buffers are required for non vsynced.
XWayland: I guess it doesn't do async flips because Wayland doesn't want tearing, but I haven't checked.
To my knowledge, if PresentOptionAsync is set and flips are used (no async flips), Present will use a flip and thus wait next vsync, not trigger a copy (unless asked).
Because of these, a lot of buffers may be required for non vsynced. PresentOptionCopy prevents flips, as the only way to be able to have the pixmap idle at presentation time is to do a copy.
@axeldavy: so what is your conclusion, is radv doing something incorrectly or not? If you think the former, I can file a radv bug (@hakzsam didn't comment, so we'll see what other Mesa developers will say).
I discussed with radv devs, and the conclusion is that: . The spec has issue as mailbox, flip and immediate would need different minimum number of backbuffers . In theory thus, until the spec is fixed with an extension or something else (problem is known by khronos), one way would be to advertise the maximum number of backbuffers in radv, ie 4, which is the minimum for mailbox. Right now only 2 is advertised on x11, which is incorrect (4 is advertised for wayland). . Intel does have issue right now with async flipping, and disables it. Thus when using PresentOptionAsync, no async flip is used and we hit what I described. Amd does have async flip. . Radv doesn't want to use PresentOptionCopy because the tearing is ugly. One way would be for radv to not advertise support for IMMEDIATE if async flip is not available (there is a flag to fetch to know that), or use PresentOptionCopy only when async flip is not supported.
The bug is thus indeed radv.
EDIT: if you don't see the link with XWayland, here it is: when async flip is not available (intel or XWayland), PresentOptionAsync does nothing, and thus it behaves like Mailbox, and thus 4 buffers should be used. The implementation should either not advertise support for IMMEDIATE, or use PresentOptionCopy in this case (or say minimum 4 buffers, but in practice behave like Mailbox). 3 buffers happen to be enough on kde/XWayland because they don't implement buffer scanout (which avoids a copy when doing flip or mailbox). 4 will be needed when they do.
@axeldavy: Is there an open bug for radv already? Can you open one please otherwise, in order to track the issue? Thanks!
I ran some gaming tests using KWin Wayland session, and noticed a strange thing.
When using wined3d, framerate is uncapped when vsync is off in games as expected. But with dxvk, vysnc option is somehow ignored, and it's capped even when it's off. That doesn't happen under normal X session, only under Wayland one (when Wine is using XWayland).
Results:
KWin/XWayland, wined3d (vsync off):
KWin/XWayland, dxvk (vsync off):
I opened a corresponding XWayland bug here but it's likely something to do with Wine/dxvk.