[UE-67487] Menu Lag on Linux

Hello!

I’m trying to resolve UE-67487 (at least in a hacky, works on my machine, way), and I just had some questions about the approach I’m taking.

I’ve tracked down the large computation time of opening a menu is rooted in the fact that:

  • Opening a menu creates a brand new SWindow every time, and therefore creates a new Viewport for every open (under SWindow::ShowWindow() in !bHasEverBeenShown conditional)
  • Calling FSlateApplicationBase::Get().GetRenderer()->CreateViewport( SharedThis( this ) ); for opening these windows takes a really long time (20-40 ms)

Two broad approaches could be taken:

  1. Reuse the same Viewport for menus not unlike how Tooltips behave. This would cause a long open time for the first time a menu is opened, but really fast every time after that
  2. Improve the performance of CreateViewport on Vulkan/Linux

From the surface, option 2 sounds like a more complicated, time consuming approach, so I’m favoring option 1. However, I’m not quite sure if creating a single Viewport that all menus will reuse is viable due just looking at the Viewport configuration options being generated. It may behoove me to just sustain a Viewport (via a sustained SWindow and/or FMenu) for each menu and just show/hide the NativeWindow whenever the menu needs to be shown

There is maybe a potential 3rd option that I don’t fully understand. It seems there may be some reuse logic in SMenuAnchor if GetPopupMethod() == EPopupMethod::UseCurrentWindow. It seems this value happens if the popup is Hosted; what is a Hosted popup? Is it viable to use this for the editor menus?

I’ll keep digging as I was able to come up with a “good enough for me” solution for UE-25471 to prevent FPS performance issues for tooltips.

However, it would be great to get some perspective from the code owners to help guide me towards some solution for this 1.5 year old issue that Linux users have been dealing with (It’s basically a deal breaker for developer experience to me). I’m happy to Zoom (or other teleconference) to throw some ideas around.

Thanks!

Diving a little deeper, the 20-40 ms lag is rooted at vkCreateSwapchainKHR in VulkanSwapChain.cpp. Every time a menu is shown, a new call the VulkanRHI API is made to reallocate a new swap chain. This also happens for tooltips too, but tooltips will not create a new swap chain if the last shown tooltip is the same as the current one.

Tooltips seem to take less time to draw (1-10 ms), and the only distinguishing factor I can see that’s different is the fact that the Vulkan Present mode for tooltips is VK_PRESENT_MODE_IMMEDIATE_KHR whereas menus are drawn with VK_PRESENT_MODE_FIFO_KHR

A couple of things here:

  • Looking at the Vulkan spec, it appears VK_PRESENT_MODE_FIFO_KHR specifically calls for waiting to prevent tearing. There may be some performance gains we can get by switching only menus to VK_PRESENT_MODE_IMMEDIATE_KHR which immediately presents the image (or VK_PRESENT_MODE_FIFO_RELAXED_KHR which may also work)
  • I’m not quite sure why UE4 is freeing/allocating swap chains frequently for menus and tooltips (which are pretty static layers for the editor). NVIDIA’s dos and don’ts calls out to not do this explicitly:

Don’t create and destroy resources if possible. Resource creation, destruction, and memory binding are expensive operations on the CPU.

I’m curious if it’d be worthwhile to just allocate a swap chain for the full size of the editor and reuse it. All menus could have a single dedicated swap chain that they use to draw multiple windows on. This could definitely be naive thinking without fully understanding how this works, but this seems like a fairly reasonable approach. For a 1080p screen, that’d only be ~6-7 mb of video ram. This would be a small price for a completely different dev experience

Adding the -vulkanpresentmode=0 argument to UE4Editor to force the present mode to VK_PRESENT_MODE_IMMEDIATE_KHR for the menus did not affect the performance at all (I am verifying the command line flag does take and the mode was changed)

Thanks alot
Everything went well