Vulkan present mode: Preferred Native vs. Layered on DXGI Swapchain

(Apologies for the sending two questions in a row).

I have a Vulkan app running on Windows. I have noticed for a while that when I was resizing the window I would generally get a gutter effect like so

This problem obviously is more visible when the app uses the FIFO present mode which it needs to be. I don’t think this is strictly a Vulkan problem as a I have seen devs on Windows + DirectX having the same problem but I am hoping some people on the forum may have some insights into this. It’s impossible to find information on this on the net though I found by playing with applications like Blender that these app don’t suffer from that issue. Though Chrome does.

After going down the rabbit hole I found that it could have something to do with the Windows DWM. On windows it uses two possible modes the redirection surface / BitBlt model or the Flip model. This is well documented. To my knowledge you don’t control this directly through Vulkan as this is driver specific though you can switch between different models using the NV control panel (I am using a NV card here).

The two modes are:

  • Native
  • Layered DXGI

I understand Native would using the BitBlt mode while Layered would use the DX swapchain for flip. There is a godot post on this matter: Use DXGI to present frames rendered by Vulkan on Windows

The interesting thing is that I would think if I understand what I find on the net properly, that using the Layered path would be better. In fact people playing video games reported faster framerates with this mode. Though these are my observations regarding the gutter effect:

  • Native. PresentMon reports Copy with GPU GDI so I assume this is the BitBlt mode (redirection surface) → no gutter
  • Layered: PresentMon reports Independant Flip → gutter visible

When I tried to understand why I had the gutter effect it made no sense:

  • first the gutter shows up the most when you resize the window down. So it’s almost like the DWM lags behind by showing the window with an old size while the image rendered by VK is already smaller? It’s a guess.
  • It’s worth noting that I have been playing with
VkSwapchainPresentScalingCreateInfoEXT scaling_info = {
   	.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT,
   	.pNext = NULL,
   	.scalingBehavior = VK_PRESENT_SCALING_STRETCH_BIT_EXT,
   	.presentGravityX = VK_PRESENT_GRAVITY_CENTERED_BIT_EXT  ,
   	.presentGravityY = VK_PRESENT_GRAVITY_CENTERED_BIT_EXT  ,
   };

If I don’t do this, even in the native mode I get the gutter effect. I guess this is why VkSwapchainPresentScalingCreateInfoEXT is made in the first place, stretch the image when the surface held by the DWM has a different size, but then why does it work in Native mode and not in the Layered mode?

  • Generally speaking I was told that the Native mode implying a redirection surface was slower than the DXGI path which is why Vulkan/OpenGL app feels sluggish compared to DX apps on Windows. That’s why Godot considered using a DXGI swapchain approach as well but that leaves me puzzled since when I loop at PresentMon numbers when running the DXGI mode through the NV control panel my framerate is effectively lower (report 60 fps in Mailbox) than when using the Native mode (4K in mailbox)? DXGI limits the fps to 60 even in Mailbox present mode. Rather strange. Something feels broken there.

If anyone has experience which this matter, I’d love with they could share their knowledge on this. I will also try to post something on the NV forums as I don’t know what these two modes really do other what I have described, and try to ask them to explain the numbers I see (slower with DXGI and gutter even when I use VkSwapchainPresentScalingCreateInfoEXT ). Also I found this gutter effect really annoying and would think this is something there should be 1) a good / solid explanation for 2) a good robust solution to fix it?

Since this seems to be your core question, what exactly do you mean by gutter effect? It’s not obvious (to me).

From PresentMon: README-ConsoleApplication.md, I assume you mean:

PresentMode Description
Composed: Copy with GPU GDI Indicates the app is windowed, and is copying contents into a surface that’s shared with GDI.
Hardware: Independent Flip Indicates the app does not have ownership of the screen, but is still swapping the displayed surface every frame.

So yes, AFAIK the first is DWM composition mode, routing your frame through DWM’s compositor for re-rendering and composition of the final frame image which is displayed on the monitor.

I’m not familiar with the underlying image display path of the 2nd, since I work primarily in OpenGL (albeit on NVIDIA GPUs).

This is solvable on OpenGL with flip present mode and proper command-queue management, though you probably don’t care since you’re working in Vulkan.

FWIW when properly driven, FullScreen GL apps on NVIDIA GPUs get the Hardware: Legacy Flip presentation mode, as observed in PresentMon:

PresentMode Description
Hardware: Legacy Flip Indicates the app took ownership of the screen, and is swapping the displayed surface every frame.

This avoids the many disadvantages of DWM composition presentation modes, letting your app’s rendered frame image largely drive monitor image display directly.

Thank @Dark_Photon.

The gutter effect is the white space that is visible in the screenshot that I posted between the window’s borders (bottom / right in the screen shot posted) and the content of the VK swapchain (which I kept in black in this test). Technically if things were running smooth, there should be no such space. The white btw is just the Windows painting the client-area with the brush color (which happens to be white in this example).

So technically, in VK you can see the present mode scale and gravity option which I did but in the Layered mode they don’t work (I get that gutter effect). Somehow that effect seems to indicate this is a lag between the time when the DWM resizes the window and the time it displays the VK image. I get that the delay is possible, but in this cas, the scale/gravity options should fill the gap (if properly set of course).

When I switch to the “native” mode, that out-sync sizing issue goes away (that is the mode using the redirection surface). Worth noting that if I don’t set the gravity/scaling options, I do have the gutter effect in this mode. In otherwords, gravity/scaling only work in Native.

Finally I just don’t understnad what this DXGI option is in the first place. I understand it goes through a Direct3D swpachain, so it seems. Which is the only way by which you get the flip mode working with the DWM. If I get the WIndows doc right.

The problem is that when used with VK I do have the VK swapchain + the Direct3D swapchain. It seems to me that the Godot posts speaks about removing the VK swapchain all together and rendering / resolving into a Direct3D texture directly which is then passed to the Direct3D swapchain. That implementation makes sense. So I don’t know what the NV Layered mode does.

I also seem to have a bug in this mode. When I get the PresentMode to MAILBOX, the FPS averages to 60 over time. Not good. In Native, I get 4K.

I am actually looking into how to report this to NV with a some file where they can reproduce what I see.

I didn’t know what you meant here, but a websearch revealed the source:

NVIDIA Settings → Manage 3D Settings →

Sorry, no help here. I’ve always run with this set to Auto.

Very kind of you to follow up. Yes I have seen the description on the NV control panel and yes it’s auto by default which is a problem in itself. Because you don’t know what auto ends up choosing for you. In my case it seems to be DXGI which is in itself is a problem because in this mode not only the gutter effect shows up (not in Native) despite using VkSwapchainPresentScalingCreateInfoEXT and it seems to have a bug in MAILBOX present mode where the FPS averages to 60 fps instead of the few thousand FPS I get with Mailbox/Native.

As I said, I am about to package a case for NV to look into it.

This just sounds like VSync ON vs. VSync OFF behavior.

You may want to investigate whether you can trigger iFlip Immediate presentation mode with the DXGI Swapchain.

More detail: From your info above:

  • Prefer Layered on DXGI Swapchain gives you
  • Hardware: Independent Flip presentation mode, which yields
  • gutter effect

This brought to mind…:

  • iFlip (aka “Independent Flip”) presentation mode
    • Roughly equivalent to D3D9 FullScreen Exclusive with VSync ON.
  • iFlip Immediate present mode (aka Independent Flip with True Immediate Presentation)
    • Reportedly yields VSync OFF behavior (free-run).

Here’s a video I bookmarked years ago that describes this:

(Caveat: This is something I haven’t personally used but only read/heard about. Like I said, I primarily work in OpenGL on NVIDIA GPUs.)

UPDATE: Cheating and just asking ChatGPT how to get “iFlip” and “iFlip Immediate” in a Vulkan app suggests switching the Vulkan Present Mode between:

  • presentMode = VK_PRESENT_MODE_FIFO_KHR; (iFlip)
  • presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; (iFlip Immediate)

That said, it may be gaslighting me again. :slight_smile: So good luck!