Per-monitor DPI-Aware: black window glitch with NVIDIA Optimus
Asked Answered
W

1

6

I would like to make a Per-Monitor DPI-Aware Direct2D application. I have extended Microsoft's "First Direct2D Program" example to handle WM_DPICHANGED as explained in Kenny Kerr's MSDN article. This works when both monitors use one video card, but suffers from a glitch when using my laptop's NVIDIA Optimus setup.

I can reproduce the same glitch by running the Per-Monitor Aware WPF Sample with these steps:

  • Different DPI scaling factor on each monitor.
  • Optimus enabled (laptop display on integrated graphics, external monitor on Quadro card)
  • The app starts on the primary display - the external monitor on the right.
  • Drag it over to the left, and it properly handles DPI change.
  • Drag it back to the right. When it handles DPI change, the portion of the window on the right monitor becomes black. The portion on the left is still drawn properly.

(See video of this bug)

I have only seen this bug with the above example app, and when I try to add Kerr's WM_DPICHANGED handler to a simpler example. Suspiciously, I have seen other apps (Chrome, Visual Studio itself) show a similar black window, but only temporarily, if I drag between monitors and maximize them very quickly.

So - is anyone familiar with this glitch? Is it some bug in my display drivers? Or is there something other apps do to rectify it, which the example code does not?

Winther answered 3/7, 2016 at 16:27 Comment(3)
Have you tried updating your display drivers in case it's just a driver bug?Vav
Yes, I tried Nvidia drivers 354.42 and the latest, 368.39. But (anticipating your potential future questions) I tried the oldest version I had stored, 332.21, and surprise - no glitch. (That old driver predates Windows 10 so frankly I'm surprised it worked at all). So it is a driver issue, but may need some more investigating..Winther
That said, NVIDIA does have a knowledgebase answer on "Why do I see artifacts or black screens when I drag an application...". This says "the application needs to properly handle the change in display adapter to transition without interruption." I'm only more confused now - it would be straightforward if the app always had to explicitly handle adapters, but the glitch only happens on certain driver versions, and only when attempting to resize for DPI change.Winther
F
3

NVIDIA Optimus you say? Those drivers are buggy as sin. Try initializing the render target with the D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS flag.

This was something that took me forever to figure out back in 2014 when I was finishing up Paint.NET 4.0, and I've still got a comment in the code warning me to never turn it off:

private PresentOptions hwndPresentOptions = 
    PresentOptions.Immediately | 
    PresentOptions.RetainContents; // If we don't use RetainContents, then we get awful
                                   // black flickering and mouse trails on some hardware
                                   // (e.g. NVIDIA Optimus)
Fulbert answered 10/7, 2016 at 18:51 Comment(1)
Adding that flag to the CreateHwndRenderTarget call didn't immediately solve the problem, but I'll keep this in mind for when I dig deeper. Thank you.Winther

© 2022 - 2024 — McMap. All rights reserved.