dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.06k stars 1.17k forks source link

WPF - Putting a window into fullscreen severely degrades performance #3626

Open ajbadaj opened 4 years ago

ajbadaj commented 4 years ago

Essentially, I put a window into "fullscreen" mode by setting WindowStyle=None and WindowState=Maximized and Topmost=True. I do not know of another way to do that. Being in fullscreen results in a moderate loss of performance.

In my case, specifically, I have images on a canvas, and I am zooming (via mouse wheel) and dragging them around. I notice when my app is in fullscreen the dragging can lag severely, and the zooming chunks very heavily.

Actual behavior: Fullscreen reduces performance.

Expected behavior: Fullscreen does not reduce performance. In fact, historically with DirectX applications, performance is increased.

Minimal repro:

ClosetBugSlayer commented 4 years ago

It feels like WPF's problem is that it allocates too many VRAM buffers for its compositing, Somebody needs to deep-dive the primitives code.

ajbadaj commented 3 years ago

In my current use case, I just noticed that the "AnyCPU" configuration is performing much better than x64 configuration. Obviously performance degradation in x64 vs a 32-bit version is the opposite of what you would expect.

For reference, in my project, I have...

===Any CPU=== Platform Target: Any CPU Prefer 32-bit: true

===x64=== Platform Target: x64 Prefer 32-bit: false (only option obviously)

Seemingly same results with/without debugger, release or debug.

Landius4 commented 3 years ago

Faced the same issue today, sad story @ajbadaj does this fix the performance issue, or just ease it a bit? I mean Build config

Landius4 commented 3 years ago

@ajbadaj https://stackoverflow.com/questions/47043036/wpf-fullscreen-window-3d-rendering-performance check this, maybe it's related to that window is slightly bigger than your display/screen?

Landius4 commented 3 years ago

Moreover, I can provide a piece of sh.. code which helped me: public void MaximizeToScreen(Window window, System.Windows.Forms.Screen screen) { if (screen != null) { window.WindowState = System.Windows.WindowState.Normal; window.Left = screen.WorkingArea.Left + 50; window.Top = screen.WorkingArea.Top + 50; window.WindowState = System.Windows.WindowState.Maximized; window.Height = screen.WorkingArea.Height - 50; window.Width = screen.WorkingArea.Width - 50; } }

Doubt that this is the best solution, also I use System.Windows.Forms to switch monitors, but this 50 px I add or sub help. And even don't affect the window size, it's still fullscreen but no lag.

ajbadaj commented 3 years ago

@Landius4

Question 1) Does it fix perf fully to switch build configurations. I can't say if it would be completely better, but for my scenario it's enough where I would mark it as complete if it did that in x64.

Other point about working area, etc. The issue isn't that I can't calculate a working area, I am already essentially doing what you're suggesting though in a different way, but I'm still not convinced it is the source of the lag (it does not scale up with window size), and the extra 100px^2 wouldn't make much of a difference.

For reference, my scenario is that I'm building a composite image scene of a varying amount (typically 20-50) of images of various sizes, some very large (over 5k pixels in the largest dimension), some moderately small (64px in the largest dimension), all in a canvas with panning/zooming/etc. It works smoothly in WindowState.Normal mode, even if I size the window to be similar to what it would be in fullscreen, it just has issues in fullscreen (and now I've discovered primarily in x64 fullscreen).

ajbadaj commented 3 years ago

This miiigght be better in .net 5. I have to do more extensive tests, but preliminary results are that I'm impressed!

connordear commented 3 years ago

I have built very similar functionality in my WPF application and can confirm the issue persisted in Framework 4.8. I also tried migrating to .Net 5 but still experienced similar issues.

The performance issue first came to me as noticing that on some machines the performance was only smooth when the app window became deactivated (e.g. alt+tabbing out). I believe these may be correlated? #3982

EDIT: I was able to restore performance in fullscreen mode (WindowState="Maximized" WindowStyle="None") by modifying the WindowChrome WindowThickness:

See post further below for my updated soln.

This link described another rendering problem, and related it to the ActualHeight/ActualWidth reported properties being larger than the set resolution.

I'm wondering if these are performance issues related to the application extending beyond the display and then causing issues with certain video drivers.

dsun1 commented 3 years ago

I believe I'm encountering the same problem in an application I'm working on.

Using WPF performance suite, I can see the FPS almost exactly halves when fullscreen compared with an almost fullscreen window.

This also happens when I have a window that isn't fullscreen, but is split between two monitors. Funnily enough this doesn't happen between my 4k laptop screen and 1440p monitor, but does happen between two identical 1440p monitors?

I notice the HW IRTs per frame almost exactly doubles at the same time. This leads me to guess WPF is rendering the same window twice for some reason, thus the framerate halves. This also makes sense with the observation that it happens if I have the app on two monitors. Probably some sort of Windows bug that causes apps to sometimes render twice on multi monitor setups(sometimes)?

Using the above solution does not help for me as I think some part of the client area is still extending into another monitor, but removing windowchrome entirely and having the built-in chrome stops the fullscreen lag from happening, however the program FPS still halves when split across my two 1440p screens.

Just my two cents and observations.

connordear commented 3 years ago

@dsun1 I actually did have this issue come back actually (mine was only appearing on specific hardware) and had to fully change the way I was handling fullscreen in order to get it to work.

Instead of using WindowState="Maximized" WindowStyle="None", I used:

    ...
    WindowStyle="SingleBorderWindow"
    WindowState="Normal"
    ...
     <Window.Style>
          <Style TargetType="{x:Type local:ApplicationView}">
              <Setter Property="WindowChrome.WindowChrome">
                  <Setter.Value>
                      <WindowChrome
                          ResizeBorderThickness="0"
                          CaptionHeight="0"
                          CornerRadius="0"
                          GlassFrameThickness="0"
                          />
                  </Setter.Value>
              </Setter>
          </Style>
      </Window.Style>

And then bound my height/width of the view to the size of the screen to achieve fullscreen. IIRC the WindowStyle="SingleBorderWindow" needed to be anything other than None. My application will always be bound to a single monitor so I don't have the multiple monitor issue, but I wonder if changing WindowStyle to something else may also help your issue. Nice observations about the specific FPS numbers.

legistek commented 3 years ago

Does this issue occur for you all if set your display settings to only use a single monitor? In other words does the issue occur only when you have 2 or more monitors in extended desktop mode?

If so then this is a very old issue that has to do with the fact that "maximized" windows actually spill over by a few pixels onto the second monitor, which destroys Direct3D (the core of WPF) performance. The only solution is to manually set your window bounds to equal the size of the Screen - NOT to use the Maximized state.

lindexi commented 3 years ago

@ajbadaj Using WindowStyle=None & WindowState=Maximized & Topmost=True does not seem to be a good way.

Could you try my demo code to enter full screen?

My demo: https://github.com/lindexi/lindexi_gd/tree/5b0440c6617b87cdd9953dc68e706b22c5939ccb/KenafearcuweYemjecahee


Update:

This feature was merged to https://github.com/HandyOrg/HandyControl

And you can use it by install https://www.nuget.org/packages/HandyControl


Update:

Adding ITaskbarList2::MarkFullscreenWindow : https://github.com/lindexi/lindexi_gd/tree/46e400d9d4601730c1f5c974ea568416453fe48d/KenafearcuweYemjecahee

ajbadaj commented 3 years ago

@connordear - that's a cool solution! As you said, focused on single monitor which is a bit tough, but it will certainly avoid the problem!

ajbadaj commented 3 years ago

@lindexi - I will give it a go when I have some time, I peeked at it just now and I like the idea!

ajbadaj commented 3 years ago

@legistek - I think that is likely, but I'm not positive as I am taking steps to avoid that already as it's not aesthetically a great situation either. Maybe what I'm doing isn't enough to actually avoid it though, it's worth a shot - I'll give that a go!

legistek commented 3 years ago

not aesthetically a great situation either.

Oh that's an understatement! I have to do window sizing and manipulation completely from scratch. Everything down to double-clicking on the caption bar "maximizes". It's a horror show. But it was all I could come up with. If you find another solution would be very curious to see.

s-struk commented 10 months ago

Try to set CoreCompatibilityPreferences.EnableMultiMonitorDisplayClipping=true before initializing app. You can set this property using manifest file as well.

legistek commented 8 months ago

@s-struk that seems to cause the application to completely freeze when it uses WebView2.

lindexi commented 4 months ago

@lindexi - I will give it a go when I have some time, I peeked at it just now and I like the idea!

Do you test my demo? Thank you.